Identifiers on WhatsApp
The WhatsApp Cloud API reports several ids for the same person, and Niadra keeps each one as its own handle type. Send every id you receive in the same event: handles that arrive together on the same event are linked when they are strong, unblocked and consistent.
With WhatsApp usernames, the sender may no longer be a phone number: it becomes a BSUID. The link between a BSUID and a phone is never assumed. It needs an explicit assertion, such as the customer typing the number, an OTP or your own records. A username is a display attribute and never identifies anyone.
Steps
1. Record each inbound message with its WhatsApp id
Use the provider message id (wamid) as the idempotency_key. The WhatsApp Cloud API retries webhooks for days, and Niadra deduplicates by that key in the database: a repeated delivery is counted as a duplicate, never stored twice. Events are ordered by occurred_at, the time the message was sent, never by arrival, so a resync that replays old messages lands them in the right place.
track() returns at once. The SDK queues the event and sends it in batches of up to 15 events or every second. The raw event is written before the API answers, and the message is readable in the live layer in under a second: when Marina calls at 2:07 pm, the voice agent receives it in live.
2. Link the WhatsApp id to the phone the rest of the company knows
The voice agent looks Marina up byphone_e164; your CRM knows her by its own id. When you know those belong to the same person, say so with identify(). It goes out right away, so the next context() sees the linked profile.
3. Treat the thread as a conversation and let Niadra split sessions
Yourconversation_id is the thread, and a WhatsApp thread may last months. Niadra splits it into sessions: a session closes after about 20 minutes of inactivity on WhatsApp (configurable per channel). Each session is extracted into memory on its own, and billing counts a conversation once per window of activity, not once per message.
Read the context before every answer. Inside a session the pack is pinned, so the same bytes come back and the model provider keeps the prompt prefix cached; the SDK also caches it per conversation.
4. Raise the verification level with an OTP on WhatsApp
A message from a WhatsApp number is plausible by channel. Account details, documents and payments usually need more. Send a one-time code through WhatsApp; when the customer types it back correctly, record averify with method otp_whatsapp and level V3. The level applies to this conversation only, and an OTP on WhatsApp also proves possession of that number.
verify is sent immediately and drops the cached pack of that conversation. The next read comes back with the items the policy released at V3; before that, the pack said how many were withheld in withheld, so the agent knows verifying is worth asking for. A level above the ceiling of your source comes back as the item error verification_not_allowed.
5. Send voice notes and attachments by reference
Media never travels inside an event. Reserve an upload with thesubject it belongs to, PUT the bytes to the presigned URL with exactly the upload_headers of the answer (the store refuses anything else), then send the event with media_ref and the SHA-256. The SDKs do the first two steps in upload_media() and uploadMedia(). For voice notes, send your own transcript in transcript, with stt_confidence.
6. Record your agent’s answers and the handoffs
Record outbound messages withconversation.agent() (the WhatsApp message id as idempotency_key when you have it), attendant messages with human_agent() in Python or human() in TypeScript, and internal notes with visibility="internal": the customer never saw them, and the pack marks them as such. When the conversation moves to a person, record the handoff so the measurement can tell whether the destination read the context.
Next steps
Events and the batch
idempotency, ordering and per-item errors.
Identity and verification
assertions, merges and the levels.
Voice agents
the call at 2:07 pm.
Send a batch
the full request and response.

