WhatsApp Gateway
API referenceSessions

List sessions

Lists the sessions (attached WhatsApp numbers) belonging to the caller's organization. Requires the `manage` capability. Each item shows the session's current status, the attached number once paired, and which gateway currently holds it. The response is org-scoped — sessions in other organizations are never returned. **Pagination.** This list is returned in a single page (no cursor is consumed); the response carries a `nextCursor` field for forward compatibility, which is null when there are no further pages. **Errors.** `unauthorized` (401) — missing or invalid credentials. `forbidden` (403) — the caller lacks the `manage` capability.

GET
/api/v1/sessions

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/sessions"
{  "data": [    {      "autoRead": false,      "createdAt": 1719662400000,      "createdByUserId": "user_01J9DEF...",      "gatewayId": "gw-sg-1",      "id": "01J9ZX8K2QHV0M3T6R7P4N5W8C",      "isAdminSession": false,      "label": "Support line",      "lastConnectedAt": 1719662400000,      "organizationId": "org_01J9ABC...",      "phoneNumber": "6281234567890",      "presenceTyping": true,      "ratePerHour": 600,      "ratePerMin": 20,      "status": "working",      "updatedAt": 1719662400000,      "waJid": "6281234567890@s.whatsapp.net",      "waLid": "205227043110953@lid"    }  ],  "nextCursor": "string"}
{  "error": {    "code": "not_found",    "details": {      "property1": null,      "property2": null    },    "message": "session not found"  }}

Start a session data backfill (super_admin) POST

Start an in-memory background backfill for one WhatsApp session, re-pulling the directly fetchable WhatsApp data for that number. The job pulls only the data WhatsApp exposes through a direct fetch: **cached contacts** and **joined group metadata/members**. Ordinary chat history is **not** part of a backfill — message history arrives asynchronously through WhatsApp `HistorySync` events, and there is no generic "fetch all messages" API. ### Asynchronous behavior - Returns **202 Accepted** immediately with the created/running `BackfillJob`; the work continues in the background. - Poll `GET /admin/sessions/{session}/backfill` to observe progress and completion. ### Idempotency / concurrency - At most **one** backfill may run per session at a time. If a backfill is already in progress for this session, the request is rejected with **409** rather than starting a second one — it is **not** a no-op merge into the existing job. ### Preconditions - Requires the platform **super_admin** role (login JWT only; api-keys and org roles are rejected with 403). - The session must exist. ### Errors - `forbidden` (403) — caller is not a platform super_admin. - `not_found` (404) — no session with the given id exists. - `conflict` (409) — a backfill is already running for this session; wait for it to finish (poll the status endpoint) before retrying. - `not_implemented` (501) — backfill is unavailable in this build/configuration for the requested session.

Create a session POST

Creates a new session — a slot for one WhatsApp number — in the caller's organization. Requires the `manage` capability. The session starts **unpaired**: no WhatsApp number is attached yet. To attach a number, link a device by scanning the QR code (`GET /sessions/{session}/qr`) or by requesting a phone pairing code (`POST /sessions/{session}/pairing-code`). **Side effects / async behavior.** When the request body sets `start: true`, the gateway begins QR pairing right away and the returned session reflects the early connecting state; pairing then proceeds asynchronously (watch the event stream for `auth.qr` and connection events). When `start` is omitted or false, the session is created stopped. **Not idempotent:** each call creates a distinct session. **Errors.** `validation_error` (400) — the body failed validation (e.g. an invalid field). `unauthorized` (401) — missing or invalid credentials. `forbidden` (403) — the caller lacks the `manage` capability. On success returns **201 Created** with the new session row.