WhatsApp Gateway
API referenceWebhooks

List webhooks

List the webhook endpoints configured for the caller's organization. Requires the `manage` capability. The response is scoped to the caller's organization — webhooks owned by other organizations are never returned, and secrets are never included. This endpoint returns the full set in one page (the response carries an empty `nextCursor`); no pagination parameters are accepted. Errors: `403 forbidden` if the caller lacks the `manage` capability.

GET
/api/v1/webhooks

Authorization

AuthorizationBearer <token>

Send Authorization: Bearer <token>. The router accepts two kinds of token and tries each in turn: a frontend-minted login JWT (verified against the frontend JWKS; the person's org + role are read from it), or an api-key for a script/service (carrying a fixed set of gateway permissions). The bearerFormat: JWT label describes the person-login case.

In: header

Response Body

application/json

application/json

curl -X GET "https://example.com/api/v1/webhooks"
{  "data": [    {      "active": true,      "createdAt": 1719662400000,      "customHeaders": {        "X-Tenant": "acme"      },      "events": [        "message",        "poll.vote"      ],      "id": "wh_01J9...",      "organizationId": "org_01J9ABC...",      "retryPolicy": {        "attempts": 15,        "delaySeconds": 2,        "policy": "exponential"      },      "sessionId": "01J9ZX8K2QHV0M3T6R7P4N5W8C",      "updatedAt": 1719662400000,      "url": "https://example.com/webhooks/wa"    }  ],  "nextCursor": "string"}
{  "error": {    "code": "not_found",    "details": {      "property1": null,      "property2": null    },    "message": "session not found"  }}

Vote on a poll message POST

Casts a vote on the poll message identified by `mid` (located by `chat`/`sender` in the body). `options` is the **complete** set of poll choices you want selected — it **replaces** your previous vote rather than adding to it. Send an empty array to clear your vote; for a single-choice poll send exactly one option. Returns **200** with a `SendResult`. ### Preconditions & errors - Requires the **`send`** capability. - **400 `validation_error`** — the target is not a poll or an option does not match the poll's choices. - **404 `not_found`** — the session or poll message does not exist or is not owned by your organization.

Create a webhook POST

Register a webhook endpoint for the caller's organization. Requires the `manage` capability. When a matching event fires, the gateway sends an HTTP `POST` to `url` whose body is the event envelope — the same JSON shape delivered over the realtime WebSocket. Use `events` to choose the event types to receive (`["*"]` for all) and `sessionId` to scope deliveries to one session (null/omitted = all of the organization's sessions). **Signing.** If you set a `secret`, every `POST` is signed: the gateway sends the lowercase-hex HMAC-SHA512 of the exact raw request body in the `X-Webhook-Hmac` header (with `X-Webhook-Hmac-Algorithm: sha512`). Recompute it on your end with the same secret to confirm the request really came from the gateway. The secret is stored encrypted and is never returned in any response. **Delivery headers.** Every `POST` also carries `X-Webhook-Request-Id` (the event id — use it to drop duplicate redeliveries) and `X-Webhook-Timestamp` (epoch milliseconds). Any `customHeaders` are applied last and can override the defaults. **Retries.** A delivery that returns non-2xx or fails to connect is retried on the `retryPolicy` schedule — by default exponential backoff (2s, 4s, 8s, …) for up to 15 attempts, after which it is given up (dead-lettered). On success returns `201` with the created webhook. Errors: `422 validation_error` if the body is malformed (e.g. `url` missing or not a valid URL); `403 forbidden` if the caller lacks the `manage` capability.