Conversations
A conversation is a text thread between one of your contacts and your workspace on one channel: WhatsApp, email, web chat, Instagram or Messenger. Every message in it, from the contact, from the agent or from a person on your team, is stored as a message on that thread. When the agent that answered the thread finishes, Jelliu attaches its analysis to the conversation: a summary, an outcome, sentiment scores and the fields the agent was configured to collect.
With the Conversations API you can read your inbox, open a thread with its messages, start a new WhatsApp or email conversation, reply as a person, and mark threads where the agent asked for human help as handled.
Phone calls are not conversations. Voice calls have their own record, transcript and analysis under Calls.
How it works
- One thread per contact and channel. Inbound messages and your own sends are matched to the same conversation by a channel-specific key, so a reply from the contact lands in the thread you started instead of opening a second one. A
closedthread is reopened when a new message arrives on it, rather than duplicated. - Two statuses. A conversation is
activeorclosed. There is no separate “handed off” status: when the agent needs a person it raises a flag on the thread (see Human handoff) and keeps answering. - Analysis arrives later. The analysis is produced after the exchange ends. A background sweep runs every 90 seconds, picks up threads that have been quiet for at least 3 minutes, and stores the result. Until then every analysis field is
null(or{}for the two result objects). Each new agent turn resetsanalysis_fetched_at, and the analysis is fetched again, covering the whole thread, once it goes quiet.
Object
Conversation
Returned by GET /api/conversations (one per item) and GET /api/conversations/{conversationId}. Both endpoints shape the conversation the same way: the stored columns plus a few fields joined from the contact, the agent and the latest message.
qualification has this shape:
Message
Returned in the messages array of GET /api/conversations/{conversationId}.
Keys you may find in metadata:
Treat metadata as informational: read the keys you need and ignore the rest.
Human handoff
An agent working a text channel can decide that a person has to step in: a refund it is not allowed to approve, a request for a manager, a question about something it cannot see. When that happens:
- The conversation gets
needs_human_atandneeds_human_reason, and your workspace receives an in-app notification. - The contact is told nothing. The thread is not closed or paused, and the agent keeps answering normally.
- Raising the flag again while it is still waiting does nothing, so
needs_human_atkeeps meaning “waiting since”. - A person reads the thread, optionally replies with
POST /api/conversations/{conversationId}/messages, and marks it handled withPOST /api/conversations/{conversationId}/needs-human/resolve. Resolving sends nothing to the contact.
The flag is closed, not erased: needs_human_at and needs_human_reason remain and needs_human_resolved_at is set. If the agent raises it again later, a new episode starts.
Every list response carries needsHumanWaiting, the number of threads waiting across the whole workspace, independent of the page you asked for.
Poll GET /api/conversations?needsHuman=waiting to build a work queue. It returns only unresolved requests, oldest wait first, so the person who has waited longest is at the top.
Common tasks
Read the inbox
List active conversations
GET /api/conversations returns active conversations only, most recently active first.
1-based page number.
Items per page, 1 to 100. Larger values are capped at 100.
Pass waiting to return only threads whose handoff request is unresolved, ordered by needs_human_at ascending. Any other value is ignored.
total counts active conversations matching the filter, so you can compute the number of pages.
Open a conversation and its messages
GET /api/conversations/{conversationId} returns the conversation, in any status, with its messages in chronological order.
The detail endpoint returns at most the first 50 messages of a thread, oldest first. On a longer thread the most recent messages are not included; use last_message, last_message_at and last_message_role for the latest activity.
Start a conversation
POST /api/conversations sends a first message to a phone number on WhatsApp or an email address, and creates or reuses the thread for it.
1 to 254 characters. For whatsapp, a strict E.164 number such as +573001234567. For email, an email address.
whatsapp or email. Web chat, Instagram and Messenger conversations cannot be started from the API.
1 to 4096 characters. Required unless you send a WhatsApp templateId.
1 to 998 characters. Required when channel is email.
WhatsApp only: an approved template from your workspace. Use it to reach someone who has not written to you in the last 24 hours.
Values for the template placeholders, as an ordered array or an object of string values.
What happens:
- Jelliu looks for an existing contact in your workspace: by WhatsApp number for
whatsapp, by email (case-insensitive) foremail. A contact that already belongs to a campaign is reused and not moved. - If none exists, a contact is created in a workspace campaign named Manual Conversations, created on first use and bound to your oldest agent. A workspace with no agents gets
422. - The message is sent through the channel, with all of its checks: opt-out, suppression list, the WhatsApp 24-hour window and allowed hours, and the daily send cap.
- Only after a successful send is the thread created (or reopened) and the message stored with
role: "agent".
externalMessageId is the provider’s message ID for WhatsApp and null for email.
A freeform WhatsApp message is only accepted when the contact wrote to you within the last 24 hours. Outside that window the request fails with 422 OUTSIDE_24H_WINDOW: send an approved templateId instead.
Reply to a conversation
POST /api/conversations/{conversationId}/messages sends a reply written by a person on your team. The agent is not invoked: only your text is delivered and stored.
1 to 4096 characters. Required unless you send a templateId.
WhatsApp conversations only. Rejected with 400 VALIDATION_FAILED on any other channel.
Values for the template placeholders.
Delivery depends on the thread’s channel:
The provider is called before the message is stored, so a rejected send never leaves a message in the thread that the contact did not receive.
A reply that fails with 5xx after reaching the provider may still have been delivered. Before retrying, re-read the conversation and check whether your message is there, so the contact is not messaged twice.
Resolve a handoff request
Talk to an agent over web chat
POST /api/webchat/message sends a message as a visitor and returns the agent’s reply in the same response. Use it for a custom chat interface on your own backend, or to test an agent. To embed chat on a website, use the web chat widget instead.
1 to 5000 characters.
1 to 100 characters from A-Z, a-z, 0-9, _ and -. Identifies the visitor’s thread. Required unless you pass conversationId.
Continue an existing conversation. Required unless you pass visitorId.
The agent that answers. It must belong to your workspace, otherwise 403 FORBIDDEN.
Two related endpoints work on the same threads: GET /api/webchat/{conversationId}/history returns { id, role, content, contentType, createdAt } for each message (the same first-50 cap applies), and POST /api/webchat/{conversationId}/close closes the conversation and returns { "data": { "closed": true } }.
Agent replies and silence
A few rules decide whether the agent answers at all. They apply to every text channel.
- Reply budget. The agent sends at most 10 AI replies per conversation in any 24 hours. When the budget is spent, the contact receives one fixed closing notice (stored with
metadata.source: "canned_reply"andcanned: "budget"), the thread is flagged for a person and closed. Replies from your team, fixed notices and recorded outbound emails do not count toward the budget. - Paused or deleted agent. A paused agent answers with a fixed notice and the thread stays open, so it resumes where it left off. A thread whose agent was deleted is answered with a notice and closed; no other agent takes over.
- Opt-out means total silence. A WhatsApp message that is exactly an opt-out keyword (
STOP,STOPALL,STOP ALL,CANCEL,UNSUBSCRIBE,QUIT,END,BAJA,CANCELAR,DARME DE BAJA,DAR DE BAJA,NO MOLESTAR, case-insensitive, trailing punctuation ignored), or a clear request not to be contacted, marks every matching contact asdnc, adds the number to your suppression list and sends nothing back, not even a confirmation. From then on, API sends to that contact are refused.
Errors
Validation failures return 400 VALIDATION_FAILED with a field map in details (see Errors). Refusals from the messaging channel use the standard envelope with the codes below. Note that some of them use 423.
A provider refusal looks like this:
Limits
See Rate limits for the per-plan general limit and Authentication for scopes. None of these endpoints requires a full key.
Other limits:
- Daily send caps. Each workspace can send up to 1,000 WhatsApp messages and 1,000 emails per day by default. A failed send does not consume the cap. Contact support to raise it.
- Plan allowance. AI replies on text channels, web chat included, count toward your plan’s monthly included chat messages.
- Reply budget. 10 AI replies per conversation per 24 hours, as described in Agent replies and silence.
- Freshness. List and detail responses are cached for up to 30 seconds. A reply sent through the API clears the cache for its conversation and your inbox, so an immediate re-read includes it.
Webhooks
There are no dedicated conversation events. Related events from the catalog:
To react to new messages or handoff requests, poll GET /api/conversations (for example with needsHuman=waiting) and compare updated_at and last_message_at.
Related
The people behind each thread, opt-outs and suppression.
Configure the agent that answers, its channels and what it collects.
Voice calls, their transcripts and analysis.
Proactive outreach on WhatsApp, email and voice.
Put an agent on your website.
Every endpoint, parameter and response.

