Webhooks and events
Live events: stream inbox updates with SSE
GET /api/events keeps an HTTP connection open and pushes inbox changes of one workspace as server-sent events: new messages (incoming and sent), conversation updates and sync progress.
How do I connect?
GET https://whatsappx.si/api/events with the usual authentication. A read API key is enough. The response is text/event-stream and stays open.
- Server-side (recommended): send
Authorization: Bearer <key>with any HTTP client that can read a streaming response. - In the browser:
EventSourcecannot send custom headers, so it only works inside the app with the session cookie and?tenant=<workspace id>in the URL. Do not put API keys in browser code.
curl -N "https://whatsappx.si/api/events" \
-H "Authorization: Bearer $WHATSAPPX_API_KEY"What does the stream look like?
retry: 3000
: connected
event: message.created
data: {"type":"message.created","workspace_id":"8d0f6c2e-…","payload":{…},"at":"2026-10-02T14:31:08.123Z"}
: ping
- The stream starts with
retry: 3000(reconnect after 3 seconds) and a: connectedcomment. - A
: pingcomment is sent every 15 seconds to keep the connection open. Ignore lines starting with:. - Each event has an
event:line with its type and onedata:line with a JSON envelope:
| Field | Type | Description |
|---|---|---|
type | string | Same as the event: line. |
workspace_id | uuid | The workspace. |
payload | object | Event data (see below). |
at | string | When the event was published, RFC 3339 in UTC. |
Which events are sent?
message.created
A message was stored: incoming, sent through the app or API, or sent by an automation.
| Field | Description |
|---|---|
conversation_id | Conversation id. |
channel_provider | scan or meta. |
message | The full Message object. |
conversation.updated
Something about a conversation changed. Refetch the conversation (or the list) to get its new state. The payload depends on the cause:
| Cause | Payload |
|---|---|
| New message, or a conversation was started | conversation_id, channel_provider |
| Marked as read | conversation_id, channel_provider, unread_count: 0 |
| Assigned | conversation_id, assignee_id, assignee_name |
| Unassigned | conversation_id, assignee_id: null |
| Chats synced after linking a QR number | channel_provider: "scan", reason: connected_sync or history_sync (no conversation_id) |
sync.progress
Progress of the chat sync after a number is linked by QR code.
| Field | Description |
|---|---|
phase | starting, history, connected or complete. |
batch | History batch number (left out when 0). |
conversations_seen | Conversations WhatsApp offered so far. |
conversations_selected | Conversations being imported. |
messages | Messages imported so far. |
done | true when the sync has finished. |
Ignore event types you do not recognise: other event types may appear on the stream and new ones may be added.
What happens if I disconnect or fall behind?
- Events have no
id:lines, soLast-Event-IDis not supported and missed events are not replayed. After reconnecting, refetch the conversation list (and any open conversation’s messages) to catch up. - Each connection buffers up to 16 events. If your client reads too slowly, newer events are dropped for that connection. Read the stream continuously and do slow work elsewhere.
- Through proxies, make sure response buffering is off; the server sends
Cache-Control: no-cache, no-transformandX-Accel-Buffering: no.