Conversations API
A single thread per contact-channel pair, regardless of which channel the message came in on. Conversations are how the inbox UI groups inbound messages, AI replies, and agent replies — and how you’d integrate the same lifecycle into your own UI. Base path:/api/v1/conversations
Authentication: API key (X-API-Key) or session JWT.
This page is a curated map of the whole surface, grouped by task. Every endpoint below is live and callable. For per-endpoint request/response schemas and copy-pasteable code samples in six languages, see the full Conversations endpoint reference.
Using the SDKs
ApiResponse envelope. See the SDK index at SDK quickstart.
Read & inspect
Lifecycle
Assignment & routing
assign targets an individual agent only — pass agent_id: null to unassign. To route a conversation into a team’s queue instead of to one person, use handoff with a target_queue; omit it to place the conversation in the org-wide queue.
AI handoff & copilot
For AI-led conversations, Orbit provides explicit handoff mechanics so a human agent picks up exactly where the AI left off.Custom fields, translation & sharing
Merge & link
Followers
Side conversations
Loop an external vendor or subject-matter expert into a child thread tied to the parent conversation, without exposing it to the customer.Worked request/response examples
Request and response envelopes side by side for the four operations an inbox integration calls first — reply, list the inbox, hand off to a human, and the bulk action. Each one pairs the curl call with the equivalent typed Node SDK call, and the response block shows the exact envelope the API returns, includingmeta.request_id and meta.pagination where it applies.
Reply to a conversation
202 Accepted: the message is queued onto the conversation and delivery continues asynchronously, so watch your message.delivered webhook or poll GET /:id/messages for the terminal state. The reply goes out on the conversation’s inbound channel unless you pass a channel override; a closed, snoozed, or archived conversation rejects the reply until you POST /:id/reopen.
List the inbox
Read the open queue with a channel filter, and page deeper with the cursor the response hands back.status, channel, sentiment, unread, has_agent, search, …) — combine them in one query string. Page with limit plus the meta.pagination.cursor the previous page returned; when has_more is false the list is exhausted. The SDK’s client.conversations.iter() walks every page for you when you don’t want manual cursor handling.
Hand off to a human
handoff parks the AI and places the thread into a queue for a human operator; the response returns the handoff packet inline so the owner of the queue can greet the customer with context.
GET /:id/handoff/queue-position returns the live position, and POST /:id/handoff/resolve marks it done. reason_category accepts cant_understand, policy_block, customer_request, tool_failed, escalation_threshold, or manual.
Bulk action across conversations
Apply one action — close, reopen, assign, add tags, remove tags — across a batch of conversation ids in a single call. The discriminator isaction; assign needs agent_id, the tag actions need a tags list. Up to 200 ids per request.
results reports ok: false with the error next to it, rather than leaving a partial state behind.
More worked samples
Worked request/response envelopes for the next operations an integration hits after the basics below: page a message thread, override the reply channel, tag and prioritize, answer a router offer, drive the conversation surface from webhooks, and loop in side-conversation participants. Each pairs the curl call with the typed Node SDK call, and every response block shows the exact envelope the API returns.Page a conversation’s messages
The thread is oldest-newest by default; page with theparticipant_id filter when a side conversation or a monitor session scaffolds extra participants into one thread and you want one side’s view.
GET /:id/activity. Internal notes live under the Inbox API, not the public thread.
Send a reply with a channel override
The reply goes out on the conversation’s inbound channel by default — passchannel to move the thread elsewhere (an email escalation on an SMS thread, a WhatsApp follow-up on a web-chat conversation). A closed conversation still rejects the reply until you POST /:id/reopen.
POST /:id/resume-channel with { "channel": "email" } instead. To check which sender identity a reply will use before sending, GET /:id/reply-sender returns { channel, from, source }.
Tag and prioritize a conversation
There is noPATCH /api/v1/conversations/{id} on this surface — status moves are explicit lifecycle verbs (close, snooze, reopen, escalate, assignment accept/decline), and the granular writes use their own paths. Replace the tags array and set the manual-triage flag in two calls.
PUT /tags replaces the whole array — send the full set, not a delta. The priority flag (none, low, medium, high, urgent) is a pure sort/filter marker: it never notifies anyone, matches the activity feed, and filters via GET /conversations?priority=urgent.
Answer a router offer
When the omnichannel router offers you a conversation, accept it to stamp the acceptance, or decline it so the router re-offers to the next best-fit agent (excluding everyone who already declined). The acting user must be the current assignee; a stale offer comes back as422 ASSIGNMENT_OFFER_STALE.
POST /:id/assignment/decline takes an empty body and returns the same shape with a next_offer summary when a replacement agent was found.
Drive the conversation surface from webhooks
The conversations surface emitsmessage.received, message.delivered, conversation.created, conversation.updated, and the status lifecycle events (see the webhook events reference). Subscribe a tenant-owned endpoint, then watch the delivery stream. Events filter by exact type repeat param or a comma-separated list.
DELETE /api/v1/webhooks/{id} when the receiver rotates. A delivery that keeps failing lands in the DLQ — replay one with POST /api/v1/webhooks/dlq/{delivery_id}/replay once the receiver is healthy. Verify signatures per the webhook consumer guide.
Loop in side-conversation participants
Side conversations carry anexternal_participants array — each entry is a { label, email?, phone?, role? } object, the E.164 phone optional when email is the channel. Create or list the child threads without exposing them to the customer.
POST /:id/side-conversations/{sideId}/reply; inbound replies from the external party carry their label as the author. Resolve with .../{sideId}/resolve and reopen within the window with .../{sideId}/reopen.
Work through it end-to-end
Four worked flows a contact-center integration hits almost immediately: reply, handle the WhatsApp window error, call the same flow from the Node SDK, and kick off an AI → human handoff.1. Reply on the conversation’s channel
channel override.
2. Handle the WhatsApp 24-hour window error
WhatsApp only accepts free-form messages within 24 hours of the contact’s last inbound message. Outside that window the reply returns422 with a typed error envelope:
3. Same flow from the SDKs
conversations is a covered resource in the Node SDK, so you don’t need raw fetch for the flow above:
assign, handoff, resolveHandoff, getHandoffQueuePosition, copilotSuggest, updateTags, close, snooze, reopen, and merge with full typings.
4. Kick off an AI → human handoff
Callhandoff when an AI-led conversation needs a human. The response returns the handoff packet inline — the clearance status, the auto-generated brief, the matched operators, and the customer’s live queue position — so the human picks up with full context.
GET /handoff/queue-position returns the live position, GET /handoff/packet returns the full packet again, and POST /handoff/resolve marks it done and closes the AI pause. To let the AI take the thread back, call POST /agent/resume.
Common operations
Four paired bash + Python snippets that cover the highest-traffic operator flows: filter the open inbox, reply and assign in one pass, escalate into a handoff, and read the sentiment timeline with the outcome prediction. All shapes here match the endpoint reference.1. List the open inbox filtered by channel + sentiment
Filter withstatus=open, channel=whatsapp, and sentiment=negative — single-value params, no CSV needed.
2. Reply, then assign the conversation
Post the reply, then write the queue-tag. The two calls are independent — a failed reply should not block assignment.PUT /tags replaces the whole array, so send the full set. To assign to an agent instead of a tag, post assign with { "agent_id": "usr_2ab" } (or null to unassign).
3. Escalate, then hand off — read the packet before resuming
Escalation notifies your configured recipients; a handoff parks the AI and queues the thread for a human. ReadGET /handoff/packet before posting /agent/resume so you hand the thread back with the resolution captured.
needs_human gates the resume call, handoff_brief is the human’s working context, and matched_operators / queue_position tell you who can take it and how long the customer waits.
4. Read the sentiment timeline and outcome prediction
Two reads, one conversation id in the path. The timeline returns the per-message trajectory oldest → newest; the prediction scores the live thread — resolution likelihood, escalation risk, and a predicted CSAT before any survey comes back.?refresh=1 forces a recompute. recommended_action is one of monitor, coach_agent, proactive_escalate, reassign, or offer_resolution — read it before deciding whether this thread needs a handoff at all.
See also
- Conversations endpoint reference — every endpoint with full request/response schemas and code samples
- Inbox API — collaboration, saved views, routing rules, macros
- Flows — automate reply, assign, and handoff sequences without code
- Inbox setup guide — channels, routing rules, and agent teams
- Webhooks → conversation events