Skip to main content
Webhooks push pass lifecycle events to your systems the moment they happen, so you never need to poll. Manage them on the Webhooks page (endpoint management is owner-only; members can inspect deliveries) or via the webhooks API.

Events

Delivery payload

Every delivery is a JSON POST with the same envelope:
  • id: unique delivery ID. Use it to deduplicate (see Idempotency).
  • type: the event type from the table above.
  • timestamp: when the delivery was created (ISO 8601).
  • correlationId: ties the delivery to the API request or job that caused it, null when there was no correlated caller. Quote it in support requests.
  • data: the event’s subject.

What data contains

One rule across every event: data is the event’s subject, in the same shape the REST API uses for that resource, carrying only state the event establishes.
  • data.id is always the thing the event is about: the pass for a lifecycle event, the scan for a scan event.
  • State the event merely observed is deliberately absent. Deliveries are retried, and an offline scan report can sync hours after its operational scan time, so a pass label or a scan counter would arrive stale while looking authoritative. Fetch what you need, or cache it from the event that set it, keyed by externalPassId.
Every sample body below is generated from the same schemas the API validates deliveries against, so what you see is what your endpoint receives. The examples follow one membership pass: issued, updated, scanned, and finally voided.

pass.issued

pass.updated

changedFields semantics

changedFields lists the top-level pass fields the update touched. It is not a value-level diff:
  • A variable change is reported as variables. Individual variable names are never listed; to find out which variable changed, fetch the pass (GET /v1/passes/{id}) and compare with your source system.
  • redemption and expiresAt are always included whenever the update contained variables, because variables can drive the resolved redemption policy and expiry. Their presence does not guarantee those values actually changed.
  • A template upgrade reports templateVersionId (together with variables, redemption, and expiresAt). Data updates do not, so this entry is the way to tell upgrades and data updates apart.
  • An update that writes identical values still fires the event, with the same changedFields.
  • Treat unknown entries as possible and ignore ones you do not recognise. For example, manual_requeue appears when an operator requeues an update job from the console.

pass.voided

pass.failed

pass.scanned

The scan event carries the Scan object as data, byte for byte what GET /v1/scans/{id} returns. One parser handles the API and the webhook:
Per the rule above, the payload carries no pass label, status, or redemption counters: those are pass state the scan only observed. externalPassId is here so you never need them to route the event.

metadata

Whatever the scanning client attached (note, or any other key), plus two keys Passlet stamps itself:
  • conflict: present only on an offline-reported scan whose device verdict disagreed with what the server would have decided at report time. The value is the reason the server would have returned. The device’s verdict is what was acted on, so result and reason are never overwritten.
  • validateAsOf: the operator’s validity-date override (YYYY-MM-DD), when one was in force. It explains why the operational scannedAt date can differ from the real recordedAt date.

webhook.test

Sent only when you use Send test on an endpoint, so you can confirm your receiver verifies signatures and returns a 2xx before real traffic arrives. There is nothing to subscribe to, and it never reports pass or scan state: data names the endpoint you tested and nothing else.

Setting up an endpoint

  1. On Webhooks, click Add webhook.
  2. Enter your HTTPS endpoint URL and select the events to subscribe to.
  3. Save. The signing secret is shown once; store it like a password, because you need it to verify deliveries.
  4. Use Send test to queue a test event and confirm your endpoint responds.
Endpoints can be edited, disabled, enabled, and deleted at any time.

Verifying signatures

Every delivery is signed. The X-Passlet-Signature header has the form:
  • t: unix timestamp (seconds) when the delivery was signed.
  • v1: hex HMAC-SHA256 of "{t}.{rawBody}" using your endpoint’s signing secret.
To verify:
Compute the HMAC over the raw request body exactly as received, and parse the JSON only after verification. Reject deliveries with timestamps outside a 5 minute window in either direction.

Delivery tracking and retries

The Deliveries section records every attempt with its event type, status (PENDING, SUCCESS, FAILED), attempt count, and last response code or error. Failed deliveries are retried automatically with backoff; you can also redeliver a specific delivery manually (console or POST /v1/webhooks/deliveries/{id}/redeliver). Respond with a 2xx quickly and do the heavy processing asynchronously on your side. Non-2xx responses and timeouts count as failures.

Idempotency

Deliveries can arrive more than once (retries, redelivery). Use the delivery ID or the event’s entity state to make your handler idempotent.