qr mode of POST /v1/channels/whatsapp/connect pairs a channel without Embedded Signup: the client receives a QR, scans it with WhatsApp mobile (Settings -> Linked Devices -> Link a device) and when pairing completes receives the channel_id of the newly created channel. No browser step, no official WABA, no Cloud API. The integration uses WhatsApp multi-device under the hood.
This is what keebai whatsapp connect --qr does in the CLI.
General flow
1
Your backend starts the session
POST /v1/channels/whatsapp/connect with mode: "qr". Returns session_id + stream_url (relative SSE path).2
Subscribe to the SSE stream
GET {stream_url} with Accept: text/event-stream and Authorization: Bearer <PAT>. You’ll receive real-time events: qr, connecting, connected, failed, disconnected.3
Show the QR to the user
Each
qr event carries a string payload. Render it as a QR (in the terminal with qrcode-terminal, on web with qrcode, etc.). If the code expires before it’s scanned, a new qr arrives automatically.4
Receive the created channel
Once scanned successfully, the stream closes with a
connected event whose data includes channel_id, phone_number and push_name.Start a QR session
POST /v1/channels/whatsapp/connect
Required scope: channels:connect
Request
pipeline_id and coexistence_enabled don’t apply to QR mode. If you send them, the API responds 400 QR_MODE_CANNOT_USE_COEXISTENCE_OR_PIPELINE.
Response 201
SSE event stream
GET /v1/channels/whatsapp/connect/:session_id/qr-stream
Required scope: channels:connect
Headers: Accept: text/event-stream, Authorization: Bearer kbai_pk_xxx.
Events
When
connected, failed or disconnected arrives, the stream closes. The client should close the connection too.
curl example
Rendering the QR
In a terminal withqrcode-terminal (Node):
qrcode:
CLI equivalent
Channel ch_xxx connected (phone +56…, as Juan).
Troubleshooting
Expired QR
Pairing emits fresh QRs automatically every ~20 seconds. Don’t restart the session: just wait for the next
qr event.4 linked-device limit
WhatsApp allows up to 4 devices per account. If the session ends with
failed mentioning device limit, free a slot on the mobile (Settings -> Linked Devices) and call POST /v1/channels/whatsapp/connect again.Expired session (5 min)
If nobody scanned, the stream closes and the
session_id stops working. Request a new session.Don't use Cloud API against this channel
QR channels don’t support templates or bulk sends (Meta doesn’t expose Cloud API on multi-device). A
template message on channel: "whatsapp_qr" is rejected with 422 MESSAGE_TYPE_NOT_SUPPORTED_FOR_CHANNEL, and POST /v1/messages/bulk returns 400 QR_NOT_SUPPORTED_FOR_TEMPLATE_OR_BULK. Text and media work as usual.Sending messages
Once connected, QR channels show up inGET /v1/whatsapp/numbers with connection_type: "qr" and are used with the same endpoint as Cloud API ones: