# Guide to Proxyclick Webhooks: Features and Best Practices

Proxyclick is a visitor management platform, now sold as Eptura Visitor. Companies use it to pre-register guests and check them in at a reception kiosk. Its webhooks push visitor and visit changes to other systems, for example a Wi-Fi system that texts a guest an access code at check-in, or a parking system that books a space when a visit is created.

This guide covers the events Proxyclick sends, what is and isn't documented about their payloads, how to authenticate requests with HTTP Basic credentials, and the practices that keep a receiver reliable in production.

## What are Proxyclick webhooks?

A Proxyclick webhook is an HTTP `POST` with a JSON body, sent to a destination URL you configure when one of the trigger events you selected happens in your Eptura Visitor account. Each webhook has a name, one destination URL and one or more triggers, and you can add several webhooks.

Proxyclick does not sign requests. The only security option is HTTP Basic authentication: you enter a username and password on the webhook, and Proxyclick sends them with each request.

## Proxyclick webhook features

| Feature | Details |
| --- | --- |
| Configuration | Eptura Visitor dashboard: Settings, **INTEGRATIONS**, **API and Webhooks** |
| Triggers | Six trigger events, at least one per webhook |
| Method and format | HTTP `POST` with a JSON body |
| Discriminator | None documented. Triggers are UI labels only |
| Destination URL | HTTP or HTTPS. Proxyclick recommends HTTPS |
| Authentication | Optional HTTP Basic username and password. No signature |
| Compatibility | Backward compatibility only for publicly documented attributes |
| Retries, timeout, source IPs | Not documented |

## Events

| Trigger | Fires when |
| --- | --- |
| Visitor on-site | A visitor is on site |
| Visitor check-in | A visitor checks in |
| Visitor check-out | A visitor checks out |
| Visit created | A visit is created, for example when a host pre-registers a guest |
| Visit updated | A visit is changed |
| Visit deleted | A visit is deleted |

The body depends on the trigger. Proxyclick documents one set of attributes for visitor check-in and check-out and another for visit created, updated and deleted, and says it only keeps backward compatibility for those documented attributes. Anything else you find in the JSON can change without notice.

Two gaps matter for a receiver. First, Proxyclick documents no field in the body that names the trigger, so a webhook that subscribes to several triggers sends you bodies you have to tell apart by their shape. Second, the attribute reference pages linked from the webhook article were not reachable when this guide was written, so this guide shows no example payload. Log a real delivery before you rely on any key.

The simplest way around the first gap is one webhook per trigger, each with its own URL path, such as `/webhooks/proxyclick/check-in` and `/webhooks/proxyclick/visit-created`. The path then tells you which trigger fired.

> **Inspect Proxyclick webhooks as they arrive.** Paste a [Hookdeck Inspect](https://inspect.hookdeck.com) URL into the webhook's destination URL to see the exact headers and body Proxyclick sends for each trigger, with no account or setup required.

## Setting up Proxyclick webhooks

Pick a username and generate a long random password, for example with `openssl rand -hex 32`, and store both on your receiver.

1. In the Eptura Visitor dashboard, click the Settings gear in the left side menu.
2. Open **INTEGRATIONS**, find **API and Webhooks** and click **Settings**.
3. Click **Add webhook**.
4. Name the webhook, enter an HTTPS destination URL, and select at least one trigger.
5. Enter the username and password for Basic authentication.
6. Perform the trigger, such as checking in a test visitor, and confirm the request arrives.

The credentials must arrive on the first request. Proxyclick's documentation doesn't say whether it sends Basic credentials straight away or only after a `401` challenge with a `WWW-Authenticate` header. A sender that waits for a challenge will never authenticate against a receiver that doesn't issue one, so check the first test delivery for an `Authorization` header.

To put Hookdeck in front of your service, create a Hookdeck source with the **Proxyclick (Eptura Visitor)** type and paste its URL into the webhook's destination URL. Enter the same **Username** and **Password** on the source. Hookdeck does not send a `401` challenge, so it needs the credentials on the first request. Hookdeck still answers with a `200`, but a request with missing or wrong credentials is recorded as failed verification and never reaches your destination. The source accepts `POST`, which is the method Proxyclick uses.

## Securing Proxyclick webhooks

With Basic authentication, each request carries `Authorization: Basic base64(username:password)`. Decode it, split on the first colon, and compare the username and password with your stored values in constant time.

```javascript
const crypto = require('crypto');
const express = require('express');

function safeEqual(a, b) {
  // timingSafeEqual throws on unequal lengths, so check first.
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

function verifyBasicAuth(header, username, password) {
  if (!username || !password) return false; // never accept when unconfigured
  const match = /^basic\s+([A-Za-z0-9+/]+={0,2})\s*$/i.exec(header || '');
  if (!match) return false;
  const decoded = Buffer.from(match[1], 'base64');
  const colon = decoded.indexOf(0x3a); // split on the first colon: passwords may contain ':'
  if (colon === -1) return false;
  const userOk = safeEqual(decoded.subarray(0, colon), Buffer.from(username, 'utf8'));
  const passOk = safeEqual(decoded.subarray(colon + 1), Buffer.from(password, 'utf8'));
  return userOk && passOk; // evaluate both before deciding
}

const app = express();

// One webhook per trigger, so the path names the trigger.
app.post('/webhooks/proxyclick/:trigger', express.raw({ type: '*/*' }), (req, res) => {
  const ok = verifyBasicAuth(
    req.get('authorization'),
    process.env.PROXYCLICK_WEBHOOK_USERNAME,
    process.env.PROXYCLICK_WEBHOOK_PASSWORD
  );
  if (!ok) return res.sendStatus(401);

  let body;
  try {
    body = JSON.parse(req.body.toString('utf8'));
  } catch {
    return res.sendStatus(400);
  }

  switch (req.params.trigger) {
    case 'check-in':
    case 'check-out':
    case 'visit-created':
      // Queue body for processing.
      break;
    default:
      // Log and acknowledge anything else.
  }

  res.sendStatus(200);
});

```

The same check in Python:

```python
import base64
import binascii
import hmac
import os
import re

BASIC_PATTERN = re.compile(r"^basic\s+([A-Za-z0-9+/]+={0,2})\s*$", re.IGNORECASE)

def verify_basic_auth(header, username, password) -> bool:
    if not username or not password:
        return False  # never accept when unconfigured
    match = BASIC_PATTERN.match(header or "")
    if not match:
        return False
    try:
        decoded = base64.b64decode(match.group(1), validate=True)
    except (binascii.Error, ValueError):
        return False
    received_user, sep, received_password = decoded.partition(b":")  # first colon only
    if not sep:
        return False
    # Compare bytes: compare_digest raises TypeError on a non-ASCII str.
    user_ok = hmac.compare_digest(received_user, username.encode("utf-8"))
    password_ok = hmac.compare_digest(received_password, password.encode("utf-8"))
    return user_ok and password_ok

# verify_basic_auth(request.headers.get("authorization"),
#                   os.environ.get("PROXYCLICK_WEBHOOK_USERNAME"),
#                   os.environ.get("PROXYCLICK_WEBHOOK_PASSWORD"))

```

Basic credentials prove the sender knows the password. They do not cover the body and carry no timestamp, so a modified or replayed request still passes. Proxyclick accepts plain HTTP URLs, and over HTTP the credentials and the visitor's personal data travel in clear text, so always use HTTPS. Use a long random password and rotate it if it might have leaked.

> **Make Proxyclick webhooks production-ready.** [Hookdeck Event Gateway](/event-gateway) checks the Basic credentials, stores every visitor notification, and retries delivery to your service until it succeeds.

## Proxyclick webhook limitations and pain points

### Credentials have to arrive without a challenge

**The Problem:** Every request fails authentication even though the credentials are right.

**Why It Happens:** Some HTTP clients only send Basic credentials after a server answers `401` with a `WWW-Authenticate` challenge. Proxyclick's docs don't say which way its sender works, and a receiver that verifies the request as it arrives, as Hookdeck does, never issues that challenge.

**Workarounds:**

* Point the webhook at a Hookdeck Inspect URL first and check that the `Authorization` header is there.
* Ask Eptura support to confirm the header is sent on every request.

**How Hookdeck Can Help:** Hookdeck keeps every request, including those that fail verification, with full headers, so you can see straight away whether `Authorization` arrived.

### No event type in the body

**The Problem:** A webhook subscribed to several triggers delivers bodies you can't reliably route.

**Why It Happens:** The triggers are labels in the settings UI. Proxyclick documents no field that names the trigger, and visit created, updated and deleted share one documented attribute set.

**Workarounds:**

* Create one webhook per trigger with a distinct URL path or query parameter.
* If you must share a URL, log real deliveries for each trigger before writing routing rules.

**How Hookdeck Can Help:** Each webhook can point at a different Hookdeck source, or at one source with a different path, and [filters](/docs/filters) can route on the path or on body fields to separate connections.

### Delivery behaviour is undocumented

**The Problem:** You don't know whether a notification that hit a failing endpoint will be sent again, how long Proxyclick waits for a response, or which IP addresses it sends from.

**Why It Happens:** The webhook documentation covers setup, triggers and Basic authentication only. It says nothing about retries, timeouts or source IPs.

**Workarounds:**

* Assume a failed delivery may be lost, and reconcile against the Eptura Visitor API for anything that matters, such as the day's visit list.
* Respond quickly and process the notification from a queue.
* Don't depend on IP allowlisting.

**How Hookdeck Can Help:** Hookdeck accepts and stores each request as it arrives, then delivers it to your service with [retries](/docs/retries) you configure. You can replay any request after an outage, and [issues](/docs/issues) alert you when deliveries fail.

### Undocumented attributes can change

**The Problem:** An integration built on a field you found in a payload breaks after a Proxyclick release.

**Why It Happens:** Proxyclick keeps backward compatibility only for the attributes in its public reference. Everything else in the JSON is unsupported.

**Workarounds:**

* Use only documented attributes, and read everything else as optional.
* Validate the shape of each body and alert, rather than crash, when it changes.

**How Hookdeck Can Help:** Hookdeck [transformations](/docs/transformations) can map the Proxyclick body to a stable internal shape in one place, so a change upstream is fixed without redeploying every consumer.

## Best practices

### One webhook per trigger

Give each trigger its own webhook and URL path. Your handler then knows what happened without guessing from the body, and you can turn one trigger off without touching the others.

### Make processing idempotent

Proxyclick documents no delivery ID, and Basic authentication gives no replay protection. Key your writes on the visit or visitor ID in the body, and make repeated updates harmless. See our [guide to webhook idempotency](/webhooks/guides/implement-webhook-idempotency).

### Treat visitor data as personal data

Payloads can carry names, email addresses, mobile numbers and visitor photos. Use HTTPS, keep payload logs short-lived, and limit who can read them.

### Acknowledge fast

Return `200` once the request is authenticated and process it from a queue. See [why to process webhooks asynchronously](/webhooks/guides/why-implement-asynchronous-processing-webhooks).

## Conclusion

Proxyclick sends a JSON `POST` for six visitor and visit triggers, with no event field in the body, no signature and no documented retry policy. Use one webhook per trigger, an HTTPS URL and Basic credentials that arrive on the first request, compare them in constant time, and rely only on documented attributes.

[Hookdeck Event Gateway](https://hookdeck.com) checks the Basic credentials, keeps every request, and retries delivery to your service so a short outage doesn't lose a check-in.

[Get started with Hookdeck](https://dashboard.hookdeck.com/signup) for free and handle Proxyclick webhooks reliably in minutes.