Chatonio

This is taking longer than usual.

Chatonio

Messages

July 7, 2026 54 viewsChatonio API

List messages

Returns the messages in a conversation in chronological order (oldest first). Internal operator notes are never included.

GET/api/v1/conversations/{id}/messages/

List messages in a conversation (cursor-paginated, oldest first).

Response

200Success
{
  "results": [
    {
      "id": "a1000000-0000-4000-8000-000000000001",
      "conversation_id": "3f2b1c9a-7d4e-4b21-9c33-0a1b2c3d4e5f",
      "thread_id": null,
      "sender_type": "CLIENT",
      "content": "Where is my order?",
      "is_internal_note": false,
      "reply_to_id": null,
      "created_at": "2026-07-01T10:30:00+00:00",
      "attachments": []
    },
    {
      "id": "b2d7e410-3c88-4a15-9f60-7d8e9a0b1c2d",
      "conversation_id": "3f2b1c9a-7d4e-4b21-9c33-0a1b2c3d4e5f",
      "thread_id": null,
      "sender_type": "OPERATOR",
      "content": "It shipped this morning \u2014 tracking below.",
      "is_internal_note": false,
      "reply_to_id": null,
      "created_at": "2026-07-01T10:40:00+00:00",
      "attachments": []
    }
  ],
  "next_cursor": null,
  "has_more": false
}

The message object

  • id, conversation_id, thread_id (usually null).
  • sender_type — CLIENT (the customer), OPERATOR, AI, or SYSTEM.
  • content — the message text.
  • is_internal_note — always false here.
  • reply_to_id — id of the message this replies to, or null.
  • created_at — ISO-8601.
  • attachments — array of { id, filename, content_type, size }.

Send a message

Delivers a message to the customer through the conversation’s channel. The message is recorded as an OPERATOR message tagged as sent via the API. It appears live in the operator dashboard.

POST/api/v1/conversations/{id}/messages/

Send a message into an existing conversation.

Request

Body
{
  "content": "Your refund of $20.00 has been processed.",
  "reply_to_message_id": null,
  "sender_user_id": null
}

Responses

201Created
{
  "id": "b2d7e410-3c88-4a15-9f60-7d8e9a0b1c2d",
  "conversation_id": "3f2b1c9a-7d4e-4b21-9c33-0a1b2c3d4e5f",
  "thread_id": null,
  "sender_type": "OPERATOR",
  "content": "Your refund of $20.00 has been processed.",
  "is_internal_note": false,
  "reply_to_id": null,
  "created_at": "2026-07-01T10:41:00+00:00",
  "attachments": []
}
400Closed
{ "detail": "conversation_closed" }

Body fields

  • content — required; the message text (max 4096 characters).
  • reply_to_message_id — optional; id of a message in the same conversation to reply to.
  • sender_user_id — optional; attribute the message to a teammate instead of the key itself. See Who the message is from below.

Who the message is from

A message sent through the API is recorded as an OPERATOR message with no human behind it, so you decide whose name and picture the customer sees. There are two options, and you choose per message.

From the key itself (default)

Each API key has a sender name and an optional picture, set on the Developer page. Send without naming anyone and the customer sees those — for example a key called Order Bot appears as “Order Bot”. If you leave the sender name blank, the key’s own name is used, so a message is never anonymous.

From one of your teammates

Pass sender_user_id and the message is attributed to that person instead — their name and avatar, exactly as if they had typed it in the dashboard. This is what you want when you are relaying replies your agents wrote somewhere else.

{
  "content": "Your refund has been processed.",
  "sender_user_id": "7c1e5a02-9b43-4f18-8a77-2d6e0f4b9c81"
}

Get the ids from GET /api/v1/operators/. The person must be a member of the same project; anyone else returns 400 sender_user_not_a_project_member. Either way the acting key is recorded, so you keep an audit trail.

You cannot pass a free-form name or picture on a message. Attribution is an id so that it can be checked — otherwise any key could impersonate a named operator to your customers.

Names in other languages

The sender name can have a per-language version, like your AI assistant’s name and your operators’ nicknames. Customers see the name for their conversation’s language; a language you have not filled in falls back to the base name. Add them on the Developer page, under the key’s identity.

A key's sender identity, with a per-language name

Notes & limits

  • Sending to a CLOSED conversation returns 400 conversation_closed.
  • Group (Telegram group) conversations are not supported in v1 (400 group_conversations_not_supported).
  • An empty content returns 400 content_required.
  • Rate limit: 60 requests/minute per API key.

Was this article helpful?