Resources

Conversations

List and inspect conversations, send messages to customers, and take a conversation over from the bot.

List Conversations

Returns a paginated list of all conversations for a given chatbot.

http
GET /api/dev/v1/chatbots/{chatbot_id}/conversations
Authorization: Bearer <api-key>

Query Parameters

Filters

statusstringoptional

Filter by conversation status. One of: ACTIVE, CLOSED, ARCHIVED, HANDOFF_PENDING, AGENT_ACTIVE.

channelstringoptional

Filter by channel (e.g. whatsapp, web, sms, api).

start_timestringoptional

Filter conversations created at or after this time (ISO 8601, e.g. 2026-01-01T00:00:00Z).

end_timestringoptional

Filter conversations created at or before this time (ISO 8601).

Pagination

limitintegeroptionaldefault: 50

Page size. Min 1, max 67.

cursorstringoptional

Pagination cursor from a previous response.

bash
curl -X GET "https://developers.sarufi.io/api/dev/v1/chatbots/<chatbot-id>/conversations?status=ACTIVE&channel=whatsapp&limit=25" \
  -H "Authorization: Bearer <your-api-key>"

Response - 200 OK

json
{
  "count": 1,
  "conversations": [
    {
      "id": "01JPQ...",
      "chatbot_id": "01JMXYZ...",
      "user_phone": "+255712345678",
      "contact_name": "John",
      "channel": "whatsapp",
      "status": "ACTIVE",
      "last_message_id": "01JRS...",
      "last_message_at": "2026-02-18T14:35:00Z",
      "last_message_preview": "Thanks for your help!",
      "unread_count": 2,
      "created_at": "2026-02-18T14:22:00Z",
      "updated_at": "2026-02-18T14:35:00Z"
    }
  ],
  "next_cursor": "eyJpZCI6IjAxSlBRIn0="
}

Get Conversation

Retrieves a single conversation by ID.

http
GET /api/dev/v1/chatbots/{chatbot_id}/conversations/{conversation_id}
Authorization: Bearer <api-key>
bash
curl -X GET https://developers.sarufi.io/api/dev/v1/chatbots/<chatbot-id>/conversations/<conversation-id> \
  -H "Authorization: Bearer <your-api-key>"

Response - 200 OK

json
{
  "id": "01JPQ...",
  "chatbot_id": "01JMXYZ...",
  "user_phone": "+255712345678",
  "contact_name": "John",
  "channel": "whatsapp",
  "status": "ACTIVE",
  "last_message_id": "01JRS...",
  "last_message_at": "2026-02-18T14:35:00Z",
  "last_message_preview": "Thanks for your help!",
  "unread_count": 2,
  "created_at": "2026-02-18T14:22:00Z",
  "updated_at": "2026-02-18T14:35:00Z"
}

Get Conversation Messages

Returns messages for a conversation, ordered oldest first.

http
GET /api/dev/v1/chatbots/{chatbot_id}/conversations/{conversation_id}/messages
Authorization: Bearer <api-key>

Query Parameters

Pagination

limitintegeroptionaldefault: 50

Page size. Min 1, max 67.

cursorstringoptional

Pagination cursor from a previous response.

bash
curl -X GET "https://developers.sarufi.io/api/dev/v1/chatbots/<chatbot-id>/conversations/<conversation-id>/messages?limit=25" \
  -H "Authorization: Bearer <your-api-key>"

Response - 200 OK

json
{
  "count": 2,
  "messages": [
    {
      "id": "01JRS...",
      "conversation_id": "01JPQ...",
      "message": { "text": "Hello, I need help with my order" },
      "response": { "text": "Hi! I'd be happy to help. What's your order number?" },
      "message_type": "text",
      "responder": "BOT",
      "responder_name": null,
      "received_at": "2026-02-18T14:22:05Z",
      "responded_at": "2026-02-18T14:22:06Z",
      "status": "delivered",
      "created_at": "2026-02-18T14:22:05Z"
    }
  ],
  "next_cursor": null
}

Send a Message to a Customer

Sends a message into an existing or new conversation on WhatsApp, Messenger or the web chat, outside of a chat session. Use it to answer from your own system, to follow up after an order, or to re-open a conversation with a WhatsApp template.

http
POST /api/dev/v1/chatbots/{chatbot_id}/messages
Authorization: Bearer <api-key>
X-Sarufi-Signature: t=<unix-seconds>,v1=<hmac-sha256>
Content-Type: application/json

Every send is signed

Besides the API key, each request carries a signature made with the chatbot's webhook_secret (see Chatbots). Sign the exact bytes you send: v1 is the hex HMAC-SHA256 of "<t>.<raw body>", where t is the current Unix time in seconds. A signature older than five minutes is refused.

Request Body

Fields

channelstringrequired

WHATSAPP, MESSENGER or WEB.

tostringrequired

Who receives it. WhatsApp: the phone number in international format. Messenger: the page-scoped user id. Web: the conversation_id of the visitor's chat.

messageobjectrequired

One message, chosen by its type. See Message shapes.

metadataobjectoptional

Anything you want stored with the message, for example your own order id.

sender_namestringoptional

The person replying, when it is a person. Trimmed and cut at 60 characters. Without it the message is signed with your API key's name.

Message shapes for sending

typeFields
textbody
buttonsbody, buttons (up to 3, each a string or { id, title }), optional header, footer
listbody, button_text, items (each { id, title, description?, section? }), optional header, footer
image, video, audio, documenturl, optional caption, filename for a document
cta_urlbody, display_text, url
templatename, language (default en), optional parameters. WhatsApp only

On WhatsApp a plain message is delivered only within 24 hours of the customer's last message. Outside that window send a template; a plain send is refused with window_closed.

bash
BODY='{"channel":"WHATSAPP","to":"+255712345678","message":{"type":"text","body":"Your order has shipped."}}'
T=$(date +%s)
SIG=$(printf '%s.%s' "$T" "$BODY" | openssl dgst -sha256 -hmac "<webhook-secret>" | awk '{print $NF}')

curl -X POST https://developers.sarufi.io/api/dev/v1/chatbots/<chatbot-id>/messages \
  -H "Authorization: Bearer <your-api-key>" \
  -H "X-Sarufi-Signature: t=$T,v1=$SIG" \
  -H "Content-Type: application/json" \
  --data "$BODY"

Response - 201 Created

json
{
  "message_id": "wamid.HBgLM...",
  "status": "sent",
  "channel": "WHATSAPP",
  "conversation_id": "01JPQ...",
  "responder": "HUMAN",
  "held": true
}

Response fields

message_idstring | null
The id the channel gave the message. null for web.
statusstring
sent, or queued when a web visitor is away: the message waits up to seven days and is shown when they return.
channelstring
The channel it went out on.
conversation_idstring
The conversation it was filed in. Poll its messages to read the customer's replies.
recipient_onlineboolean
Web only. Whether the visitor was there to read it.
responderstring
How the message was filed: HUMAN, under your API key's name.
heldboolean
true when this send put you in charge of the conversation. See Who is answering.

Errors

StatusWhen
401The signature header is missing or does not match the body.
400The channel is not connected to this chatbot.
422The message is malformed, or window_closed on WhatsApp.
404Web: no conversation with that id belongs to this chatbot.
410Web: the visitor has been away for more than seven days.
502The channel refused to deliver it.

Who Is Answering

A message sent through this endpoint is treated like a person stepping in from the inbox, not as something the bot said.

  • It is filed as a HUMAN message, signed with sender_name or, without one, your API key's name as responder_name. A web visitor sees a text reply under that name, as they would an inbox agent's.
  • If the bot was handling the conversation, your send takes it over: the conversation moves to AGENT_ACTIVE, held is true, and the bot stays quiet.
  • You keep the conversation for 15 minutes after your last send or action. Every send extends it. When you go quiet, the customer's next message is answered by the bot again.
  • A conversation an inbox agent already holds is not taken: your message is still delivered, held is false, and the agent keeps it.
  • Read what the customer writes back by polling Get Conversation Messages.

To hold a conversation before you have anything to say, or to hand it back the moment you are done, use the action below.


Hold or Release a Conversation

http
POST /api/dev/v1/chatbots/{chatbot_id}/conversations/{conversation_id}/action
Authorization: Bearer <api-key>
Content-Type: application/json

Request body

actionstringrequired

takeover to hold the conversation so the bot stays quiet, or release to hand it back to the bot at once.

bash
curl -X POST https://developers.sarufi.io/api/dev/v1/chatbots/<chatbot-id>/conversations/<conversation-id>/action \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: application/json" \
  -d '{"action":"release"}'

Response - 200 OK

json
{ "status": "released" }

takeover answers { "status": "held" }. A takeover on a conversation an inbox agent holds, or one that is closed, is refused with 409. A conversation id that is not this chatbot's answers 404.


Conversation Object

ConversationRecord fields

idstring
Conversation ULID.
chatbot_idstring
Parent chatbot ID.
user_phonestring
User phone number (e.g. +255712345678 for WhatsApp).
contact_namestring | null
Contact display name, if available.
channelstring
Integration channel: whatsapp, web, sms, api.
statusstring
Conversation status: ACTIVE, CLOSED, ARCHIVED, HANDOFF_PENDING, AGENT_ACTIVE.
last_message_idstring | null
ID of the last message in the conversation.
last_message_atstring
Timestamp of the most recent message.
last_message_previewstring | null
Preview text of the last message.
unread_countinteger
Number of unread messages.
created_atstring
When the conversation was created.
updated_atstring | null
When the conversation was last updated.

Message Object

MessageRecord fields

idstring
Message ULID.
conversation_idstring
Parent conversation ID.
messageobject | null
User input payload.
responseobject | null
System response payload.
message_typestring
Message type (e.g. text, image, document).
responderstring
Who responded: BOT or HUMAN.
responder_namestring | null
For a HUMAN reply, who it was: the inbox agent's name, or the API key's name for a message sent through this API.
received_atstring
When the user message was received.
responded_atstring | null
When the response was sent.
statusstring
Message delivery status.
created_atstring
When the record was created.

Want to chat with your bot via API?

Use the Chat API to create sessions and send messages programmatically. Conversations created via the Chat API appear here with channel=api.