Skip to content

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: EventSource cannot 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 : connected comment.
  • A : ping comment is sent every 15 seconds to keep the connection open. Ignore lines starting with :.
  • Each event has an event: line with its type and one data: line with a JSON envelope:
FieldTypeDescription
typestringSame as the event: line.
workspace_iduuidThe workspace.
payloadobjectEvent data (see below).
atstringWhen 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.

FieldDescription
conversation_idConversation id.
channel_providerscan or meta.
messageThe 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:

CausePayload
New message, or a conversation was startedconversation_id, channel_provider
Marked as readconversation_id, channel_provider, unread_count: 0
Assignedconversation_id, assignee_id, assignee_name
Unassignedconversation_id, assignee_id: null
Chats synced after linking a QR numberchannel_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.

FieldDescription
phasestarting, history, connected or complete.
batchHistory batch number (left out when 0).
conversations_seenConversations WhatsApp offered so far.
conversations_selectedConversations being imported.
messagesMessages imported so far.
donetrue 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, so Last-Event-ID is 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-transform and X-Accel-Buffering: no.