Webhooks let your server react to QueueUp activity in real time. When something happens on a waitlist (a signup, a confirmation), QueueUp signs and POSTs an event to a URL you configured.
This page documents the wire protocol: the JSON shape of every event, the headers that ride alongside it, and the retry policy. For panel configuration see Webhook integrations. For verification code samples see Verifying webhooks.
The binding model
A webhook integration is org-scoped configuration: a name plus a URL plus a signing secret. To start receiving events you bind it to one or more waitlists from the waitlist’s setup page (under Integrations).
Each binding is a routing rule. A single waitlist can have multiple bindings, and the same integration can be bound more than once on the same waitlist with different event scopes. That’s useful when you want different events to fire different consumers, or just want explicit per-event rules.
Event filtering is per-binding (per-waitlist), not per-integration. The same webhook URL can subscribe to all events on waitlist A and only subscriber.confirmed on waitlist B.
Event envelope
Every delivery has the same outer shape. The data field carries the event-type-specific payload.
{
"id": "evt_42",
"type": "webhook.ping",
"created_at": "2026-05-03T18:30:00Z",
"data": {
"integration_id": 7,
"tested_by": "[email protected]"
}
}
Use id as your idempotency key. Deliveries are at-least-once: a network blip during your 200 OK response can cause a retry, so dedupe on the consumer side.
Headers
Every delivery includes the following request headers:
| Header | Value |
|---|---|
X-QueueUp-Event | The event type, e.g. subscriber.joined |
X-QueueUp-Delivery-Id | A unique id per delivery attempt |
X-QueueUp-Timestamp | Unix seconds at sign time |
X-QueueUp-Signature | v1=<hex hmac> (see Verifying webhooks) |
Any custom headers configured on the integration ride alongside these on every delivery. The reserved set above plus Content-Type, Content-Length, Host, and User-Agent are managed by QueueUp and can’t be overridden.
Event catalog
The envelope shape is stable across every event. What changes is the data payload. Each event below is documented with a complete example and a field reference. Timestamps are RFC 3339 strings in UTC.
webhook.ping
Sent only when you click Send test on a webhook integration’s detail page. Useful for confirming signature verification and routing without waiting for a real signup. This event bypasses per-binding event scoping; it always lands at the integration you tested.
{
"id": "evt_42",
"type": "webhook.ping",
"created_at": "2026-05-03T18:30:00Z",
"data": {
"integration_id": 7,
"tested_by": "[email protected]"
}
}
| Field | Type | Notes |
|---|---|---|
integration_id | number | The integration that received the test. |
tested_by | string | The email of the panel user who clicked the button. Optional. |
subscriber.joined
Fires once per signup, on every new subscriber row. When the waitlist requires email confirmation, the row is in pending state at emit time and a follow-up subscriber.confirmed will land later if the link is clicked. When confirmation is off, state is active and subscriber.joined is the only signal you’ll get for this subscriber.
Idempotent re-signups on a still-pending row re-emit subscriber.joined (gated by a per-email cooldown) so a fresh confirmation email goes out. Use the envelope id to dedupe.
{
"id": "evt_1042",
"type": "subscriber.joined",
"created_at": "2026-05-03T18:30:12Z",
"data": {
"subscriber_id": 8401,
"waitlist_id": "46dc645f-6d47-4cbd-86cd-c68f2cce0901",
"email": "[email protected]",
"state": "pending",
"referral_code": "K7M9PX",
"referrer_id": 8377,
"status_token": "9b1f4a...32 hex chars",
"priority_score": 5,
"joined_at": "2026-05-03T18:30:12Z"
}
}
| Field | Type | Notes |
|---|---|---|
subscriber_id | number | Stable id for this subscriber row. |
waitlist_id | string (UUID) | The waitlist this signup belongs to. |
email | string | The email exactly as the subscriber submitted (display case preserved). |
state | string | "pending" when double opt-in is on and the email hasn’t been confirmed yet, "active" otherwise. |
referral_code | string | The 6-character code minted for this subscriber. |
referrer_id | number | The subscriber_id of whoever referred this signup (matched on ?queueup_ref=<code>). Omitted when there’s no referrer. |
status_token | string | The 32-character hex token used in the hosted status page URL (/s/<token>). |
priority_score | number | The subscriber’s current priority score. Bumps when this subscriber refers others. |
joined_at | string | RFC 3339 timestamp of the signup. |
subscriber.confirmed
Fires when a pending subscriber clicks the confirmation link and the row flips to active. Only emitted by waitlists with email confirmation turned on; waitlists without double opt-in will never produce this event.
{
"id": "evt_1108",
"type": "subscriber.confirmed",
"created_at": "2026-05-03T18:42:55Z",
"data": {
"subscriber_id": 8401,
"waitlist_id": "46dc645f-6d47-4cbd-86cd-c68f2cce0901",
"email": "[email protected]",
"confirmed_at": "2026-05-03T18:42:55Z",
"status_token": "9b1f4a...32 hex chars"
}
}
| Field | Type | Notes |
|---|---|---|
subscriber_id | number | Same id as the matching subscriber.joined. |
waitlist_id | string (UUID) | The waitlist the subscriber belongs to. |
email | string | The email exactly as the subscriber submitted. |
confirmed_at | string | RFC 3339 timestamp of the flip from pending to active. |
status_token | string | The hosted status page token. |
Retry policy
Failed deliveries retry on a schedule with jitter. Total wall-clock budget per delivery is about 33 hours.
| Attempt | Delay before next |
|---|---|
| 1 | 1 minute |
| 2 | 5 minutes |
| 3 | 30 minutes |
| 4 | 2 hours |
| 5 | 6 hours |
| 6 | 24 hours, then dead-letter |
Decision rules:
- 2xx. Success.
- 4xx (other than 408 and 429). Dead-letter immediately. We assume your server is reporting a real bug; retrying won’t fix it.
- 5xx, 408, 429, transport errors. Retry until the budget runs out.
Dead deliveries stay in your dashboard. You can manually re-enqueue any of them with the Redeliver button.
Read next
- Verifying webhooks. Verify the
X-QueueUp-Signatureheader on your server in Node, Python, and Go. - Webhook integrations. Configure URL, custom headers, and rotate the signing secret.