/conversation/*) takes it in the
request body under the conversation object.
Identifying a conversation
Theconversation object accepts one of four identifiers, plus channel
(required), the target channel’s public key. The resolver
evaluates them in this order: uuid → whatsapp_user_id → username →
phone: whatsapp_user_id looks up by exact match and username by a
case-insensitive match (case is ignored); phone is normalized to digits.
When the contact has a BSUID, phone and
whatsapp_user_id identify different values (see Note).
string
Stable key of a conversation you already know (for example, persisted from a
previous integration). The most direct path, though it can become stale if two
conversations of the same contact are merged — see the merge note below.
string
The contact’s BSUID (Meta’s opaque identity). Resolves by exact match against
the stored BSUID; if it does not resolve, the endpoint returns
404 without
falling back to phone. Recommended identifier going forward.string
The contact’s public WhatsApp username, with or without a leading
@ and
case-insensitive. Best-effort resolution against the last username observed by
the platform (users can change their handle); if several contacts share it,
the endpoint returns 409 (USERNAME_AMBIGUOUS).string
Number in E.164 format (
+5215512345678). Normalized to digits before the
lookup. Useful when all you have is the phone.string
required
The channel’s public key — copy it from the dashboard under Settings → Channels
(the Channel key field), or list them with
GET /channels. Required in every
request: it sets the target channel. It is case-insensitive (normalized
server-side). It does not identify on its own. On the contact-based paths
(phone, username, whatsapp_user_id) it restricts resolution to the given
channel; with uuid the engine ignores it, but the contract still requires it.
It disambiguates the channel, not the contact: if several contacts
share a phone or username, that ambiguity is resolved with
whatsapp_user_id or uuid. On the contact-based paths, if you send a key
that does not exist, the API returns 404 (CHANNEL_NOT_FOUND).phone and whatsapp_user_id are different identifiers: phone is the
phone number (wa_id without +) and whatsapp_user_id is the contact’s BSUID.
They coincide only while the contact has no BSUID. In responses,
whatsapp_user_id returns the real BSUID when present, with a fallback to the
phone so there is always a resolvable value. Watch the round-trip: if the contact
has no BSUID yet, this field carries the phone; re-send it as phone then, not as
whatsapp_user_id — the resolver matches whatsapp_user_id by exact match and
would return 404.When the same contact ended up recorded twice by identity (for example, first only
with their phone and later with their BSUID), the two conversations are
merged automatically into one: the full history moves to the survivor. The
absorbed conversation’s
uuid stops resolving and returns 404; the phone and the
BSUID migrate to the survivor. If a uuid you stored starts returning 404,
re-resolve the conversation by phone or whatsapp_user_id.Reading a conversation
You address a conversation with one of the references above: the public API does not offer a listing to enumerate them. Those references come from your own inbound —thephone or whatsapp_user_id of the contact who messaged you— or
from a uuid you have persisted.
With that reference, GET /conversation returns its state (conversation_info
and contact_info) and GET /conversation/messages its history. The full shape
and parameters are in Conversation and thread.
The 24h window
This is WhatsApp’s core concept and it decides what you can send.1
The contact messages you
WhatsApp opens a 24-hour window. Each new message from the contact
resets the timer.
2
Window open
You can send free-form messages: text, media, and quick replies.
3
24h pass with no reply
The window closes. The only allowed message is a template approved by
Meta.
4
Sending a template reopens the window
You can send free-form messages again.
Checking the window status
Before sending a free-form message, you can verify whether the window is open withPOST /conversation/status:
conversation.uuid (the conversation’s stable key),
window.status (open or closed), window.expires_at (ISO timestamp of the
window’s close; null if the contact never messaged), and window.hours_remaining,
plus the assignment, mailbox, tags, and inbox_status of the conversation. Use it
to decide between a free-form message and a template.
Reading the thread
The thread paginates backwards in time: the first call returns the most
recent items and
next_cursor moves towards the oldest ones.direction and author), what
happened (event), with what content (content_type and body), and when
(sent_at). Read in order, they look like the actual conversation:
type tells the two kinds of item apart: message is content that
travelled over WhatsApp (it carries content_type and status), and event is
something that happened in the history — a context note, an updated contact
field, a conversion — with no content sent.
Items within each page are in chronological order, and sent_at is the key that
orders the full thread as you page backwards.
Next steps
Send messages
Text, media, quick replies, and templates.
Templates
How to send templates when the 24h window is closed.