Conversations and messages
Three endpoints cover the whole flow: start or resume a conversation, send a message and get the reply, and read messages.
Start or resume a conversation
POST /api/v1/conversations
{
"user": { "id": "b7f3c2d1", "name": "Matthew", "metadata": { "role": "admin" } },
"conversation_id": "optional: resume this one"
}
Without conversation_id, the user's newest open conversation in the inbox is resumed. If there is none, a new one is created and the response status is 201. With conversation_id, that conversation is returned if it belongs to this user; otherwise not_found.
{
"conversation": { "id": "8c1e…", "status": "open", "mode": "assistant", "created": false },
"user": { "id": "b7f3c2d1", "customer_id": "d41a…" },
"messages": [
{ "id": "…", "role": "user", "content": "How do payouts work?", "created_at": "2026-09-14T18:02:11Z" },
{ "id": "…", "role": "assistant", "content": "Payouts are sent…", "created_at": "2026-09-14T18:02:15Z" }
]
}
messagesholds the last 50, oldest first, so you can render history on open.roleisuser(your user),assistant(the AI), oragent(a person on the TrolleyChat side).modeisassistantwhile the AI is answering andhumanonce a person has taken over.
Send a message and get the reply
POST /api/v1/conversations/{id}/messages
{ "content": "How do payouts work?", "message_id": "optional UUID v4 for safe retries" }
The response arrives when the reply is ready, typically in three to eight seconds:
{
"message": { "id": "…", "created_at": "…" },
"reply": { "id": "…", "role": "assistant", "content": "Payouts are sent…", "created_at": "…" },
"mode": "assistant"
}
contentis at most 4,000 characters.- If the assistant hands the conversation to a person,
reply.actionscontains{ "type": "escalated" }. The team is alerted; the assistant keeps answering until a person takes the conversation over, at which pointmodebecomeshuman. After an escalation, poll the read endpoint so the person's reply reaches your user. - When
modeishuman, your message is stored for the person andreplyisnull. - Retrying with the same
message_idreturns the original reply with"deduped": truerather than answering twice. Always set one when you retry.
Read messages
GET /api/v1/conversations/{id}/messages?since=2026-09-14T18:02:15Z
Returns everything visible in the conversation, oldest first, up to 100. With since, only messages created after that timestamp. Use it to pick up a person's replies after a handoff; polling every five to ten seconds while mode is human is fine.
{
"conversation": { "id": "8c1e…", "status": "open", "mode": "human" },
"messages": [ { "id": "…", "role": "agent", "content": "Hi Matthew, I can help with that.", "created_at": "…" } ]
}
What your team sees
Conversations started through the API appear in the inbox with an API badge. Your team can watch them, take over, and reply from the dashboard exactly as they do for the widget. Their replies reach your application through the read endpoint.