Authentication and conventions
Your channel token, what it opens, and the conventions every route shares.
The token
Every request under /v1 sends your channel token as a bearer token.
Authorization: Bearer <CHANNEL_TOKEN>A channel token is a random string of 43 characters (letters, digits, - and _) with no prefix. Examples on these pages write it as <CHANNEL_TOKEN>.
A token opens one channel: the one it was created for. A request for another channel's path is refused with 401 unauthorized.
WAgate stores only a hash of the token. The console shows it once, when you create it. Creating a new token replaces the old one. Keep it on your server. Never put it in a browser page or in an app you ship.
Base URL
All routes are under <API_ORIGIN>/v1, for example <API_ORIGIN>/v1/sessions/<CHANNEL_ID>/messages/text. The one exception is the liveness check, <API_ORIGIN>/health, with no /v1 and no token.
The console and the OpenAPI document at /docs/openapi.json show the exact origin for your deployment.
Channel ID, and "session" in paths
Paths say sessions/{name}. {name} is your channel ID, the name on the channel's row in the console. It matches ^[A-Za-z0-9_-]+$.
Addresses and IDs
| Value | Shape | Where it appears |
|---|---|---|
| Phone number | digits with country code, such as 66XXXXXXXXX | to, mentions |
| User JID | [email protected] | chat_jid, sender_jid, jid |
| LID | <digits>@lid | sender_lid, chat_lid, lid |
| Group or community JID | [email protected] | group, community paths |
| Message ID | starts with a letter or digit, then letters, digits, ., _ or -, up to 128 characters in all, such as 3EB0C767D26A1D8E2A41 | id, quoted, {message} paths |
| Media ID | 64 hex characters, a dot, an extension | media_id, GET media/{id} |
People are identified by phone number as <number>@s.whatsapp.net. WhatsApp sometimes addresses a person by a LID instead. WAgate publishes the phone JID whenever it knows it and gives the LID alongside; see Webhook events for the rules.
Requests
- Bodies are JSON with
Content-Type: application/json. - A body may be at most 1 MiB. A body with a field the route does not take is refused with 400. The code is
invalid_bodyorfield_not_allowed. - Do not send an account header. The public API refuses it with 400
header_not_allowed. - Times in responses use RFC 3339 with a timezone offset. Many timestamps use UTC (
Z); allowanceresets_atvalues use Bangkok time (+07:00). Parse the offset rather than assuming UTC.
Responses and errors
A success is 200, 201 (created) or 202 (accepted, as for a history request). An error is JSON with a stable code and a human error:
{ "code": "unauthorized", "error": "invalid bearer token" }Branch on code, never on error. Treat a code you do not know as a generic failure. Errors lists every code.
When a token is refused
- A missing, short or unknown token, or a channel ID that does not exist, answers 401
unauthorized. - A token that stops applying while a request is in flight answers 401
credential_stale. That happens when the token is replaced or the channel is removed. - A channel whose paid slot ended answers 401
slot_ended.
Replacing a token
The API cannot create, replace or revoke a token. To replace the token of a channel you already have, email [email protected]. A replaced token stops working at once.
Webhook secrets
Every new webhook receiver needs its own secret of at least 24 characters. WAgate signs each delivery with it so you can check the delivery came from WAgate. A request that adds a receiver without a secret is refused with 400 invalid_body.
When you send the receiver list again, omit secret on a receiver you already saved to keep its stored secret. Send a new value to replace it. A secret cannot be removed: delete the receiver and add it again with a new one. A receiver saved before this rule and still without a secret (secret_set: false in GET webhooks) keeps working. Add a secret to it with PUT webhooks. See Webhooks.
Health check
curl https://api-wagate.socialground.co/health{ "status": "ok" }