Skip to content
Chatvia Docs

API reference

Conversations

Get in touch: Ahmad Mayahi, creator of Chatvia, Spectra and Shakomako

These endpoints let your software chat with an agent, and read or delete the chat history of an agent.

For example, your help desk tool can open a conversation when a ticket comes in, send the customer's question, and show the agent's suggested answer to your support person. Or a nightly job can copy yesterday's conversations into your data warehouse.

A chat over the API works like a chat in the Hosted Chat. The agent uses the same instructions, sources and tools, and every reply counts toward your message limit.

Read the overview first for the base URL, keys, errors and paging.

How a chat works

  1. Open a conversation. You get its id.
  2. Send a message to it. The answer holds the agent's reply.
  3. Send more messages to the same conversation. The agent remembers what was said before.

The conversation object

json
{
  "id": "0199f3f1-0a1b-7c2d-8e3f-4a5b6c7d8e9f",
  "title": "Return a damaged item",
  "sentiment": "neutral",
  "tone": "confused",
  "handoff_status": "ai",
  "last_activity_at": "2026-10-25T10:31:09+00:00",
  "created_at": "2026-10-25T10:28:40+00:00"
}
Field Type Meaning
id string The conversation's id.
title string or null The title. Made from the chat after the first reply, unless you set one.
sentiment string or null The visitor's mood: positive, neutral or negative. null until the conversation is analyzed.
tone string or null neutral, frustrated, urgent, confused or satisfied. null until analyzed.
handoff_status string or null Who answers: ai, pending (a person was asked for), human (a teammate took over) or returned (handed back to the AI). See Human handoff.
last_activity_at string or null When something last happened in it.
created_at string When it was opened.

List conversations

Returns the agent's conversations from every surface, the most recently active first.

text
GET /api/v1/agents/{agent}/conversations

Who can call it: the owner, or a teammate with View conversations.

bash
curl https://chat.example.com/api/v1/agents/a3f9c2e17b4d08/conversations \
  -H "Authorization: Bearer $CHATVIA_API_KEY"

The answer is { "data": [conversation, …], "next_cursor": … }. See Pagination.

A conversation opened through the API shows up here only after the agent's first reply.

Open a conversation

Opens a new conversation with the agent, ready for messages.

text
POST /api/v1/agents/{agent}/conversations

Who can call it: anyone with access to the agent. No extra permission is needed, as in the dashboard's Playground.

Body field Type Required Default Notes
title string no New Chat Up to 255 characters.
chatter_id string no none The id of one of your chatters. The conversation is then counted as theirs: their monthly message limit applies, and your functions get their id in X-Chatvia-Chatter-Id. The chatter must have access to the agent. If not, you get a 422 error on chatter_id.
bash
curl https://chat.example.com/api/v1/agents/a3f9c2e17b4d08/conversations \
  -H "Authorization: Bearer $CHATVIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "title": "Ticket 8841" }'
json
{
  "data": {
    "id": "0199f3f1-0a1b-7c2d-8e3f-4a5b6c7d8e9f",
    "title": "Ticket 8841",
    "sentiment": null,
    "tone": null,
    "handoff_status": "ai",
    "last_activity_at": "2026-10-25T10:28:40+00:00",
    "created_at": "2026-10-25T10:28:40+00:00"
  }
}

The answer is 201 Created. A conversation that never gets a reply expires after a day.

Send a message

Sends a message to the agent and returns its reply.

text
POST /api/v1/agents/{agent}/conversations/{conversation}/messages

Who can call it: anyone with access to the agent. This endpoint has its own rate limit of 30 messages a minute.

You can only send messages to a conversation you opened through the API. A conversation from the hosted chat, the chat widget or a channel answers 404.

Body field Type Required Default Notes
message string yes Up to 32,000 characters.
stream boolean no false true sends the reply piece by piece as it is written. See Streaming the reply. An Accept: text/event-stream header does the same.
request_id string no none Your own id for this message, up to 64 characters. See Retrying safely.

The reply as one answer

By default you get the reply once it is finished:

bash
curl https://chat.example.com/api/v1/agents/a3f9c2e17b4d08/conversations/0199f3f1-0a1b-7c2d-8e3f-4a5b6c7d8e9f/messages \
  -H "Authorization: Bearer $CHATVIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "message": "Can I return a damaged item?", "request_id": "ticket-8841-1" }'
json
{
  "data": {
    "conversation_id": "0199f3f1-0a1b-7c2d-8e3f-4a5b6c7d8e9f",
    "message": {
      "id": "0199f3f1-4c5d-7e6f-8a7b-9c0d1e2f3a4b",
      "role": "assistant",
      "content": "Yes. You can return a damaged item within 30 days for a full refund [1]."
    },
    "sources": [
      {
        "id": "0199f3c1-2b3a-7d4e-9f50-6a7b8c9d0e1f",
        "label": "returns-policy.pdf",
        "kind": "file",
        "url": null,
        "page": 2,
        "passages": 1,
        "blocks": [1],
        "excerpt": "Damaged items can be returned within 30 days of delivery..."
      }
    ],
    "done_reason": "complete",
    "response_time_ms": 2140,
    "error": null
  }
}
Field Meaning
conversation_id The conversation.
message.id, message.role, message.content The reply. role is always assistant.
sources The sources the reply used, best first. Empty when the agent doesn't show its sources. Each has a label, a kind (file, media, website, text or video), a url or page when there is one, how many passages were used, the blocks that [1] style markers in the reply point to, and an excerpt.
done_reason complete, or error when the reply was cut short.
response_time_ms How long the reply took.
error null, or why the reply was cut short: code, message and retryable.

When a message fails

When the reply fails before any text was written, you get an error status:

json
{
  "message": "This agent has reached its monthly message limit. Please try again next month.",
  "code": "message_limit_reached",
  "retryable": false
}
code Status Meaning
message_limit_reached 429 The workspace used up its monthly messages.
chatter_message_limit_reached 429 The chatter of this conversation used up their monthly messages.
rate_limited 429 Too many messages right now. Try again in a minute.
access_blocked 403 The agent's security settings blocked this message.
upstream_unavailable 502 The AI provider didn't answer. Try again.
internal 500 Something else went wrong.

retryable is true when sending the same message again can work.

When the reply fails after some text was written, the answer is a 200 with done_reason: "error", the text so far in message.content, and the reason in error. That text is already saved in the conversation and counted. To try again, send a new message, not the same one.

Streaming the reply

Add "stream": true to get the reply as server-sent events: a stream of small messages over one open connection. Your user sees the reply appear while the agent writes it.

bash
curl -N https://chat.example.com/api/v1/agents/a3f9c2e17b4d08/conversations/0199f3f1-0a1b-7c2d-8e3f-4a5b6c7d8e9f/messages \
  -H "Authorization: Bearer $CHATVIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "message": "Can I return a damaged item?", "stream": true }'

The answer has the type text/event-stream. Each event is one data: line of JSON followed by an empty line:

text
data: {"v":1,"seq":0,"id":"0199f3f1-4c5d-7e6f-8a7b-9c0d1e2f3a4b","type":"start","data":{"assistant_message_id":"0199f3f1-4c5d-7e6f-8a7b-9c0d1e2f3a4b","user_message_id":"0199f3f1-4b2a-7c1d-9e8f-0a1b2c3d4e5f","request_id":null,"language":"en","replayed":false}}

data: {"v":1,"seq":1,"id":"0199f3f1-4c5d-7e6f-8a7b-9c0d1e2f3a4b","type":"delta","data":{"text":"Yes. You can"}}

data: {"v":1,"seq":2,"id":"0199f3f1-4c5d-7e6f-8a7b-9c0d1e2f3a4b","type":"delta","data":{"text":" return a damaged item"}}

data: {"v":1,"seq":3,"id":"0199f3f1-4c5d-7e6f-8a7b-9c0d1e2f3a4b","type":"done","data":{"reason":"complete","response_time_ms":2140,"finished_at":"2026-10-25T10:31:09+00:00"}}

Every event has the same outer fields:

Field Meaning
v The format version, always 1.
seq Counts up from 0.
id The id of the reply message.
type What kind of event it is. See below.
data The event's content.
type data What to do
start assistant_message_id, user_message_id, request_id, language, replayed The reply began.
delta text Add text to the end of what you have.
replace text A safety check rewrote the reply. Throw away what you have and show text.
reasoning text The model's thinking, when the model shares it. It is not part of the reply.
sources sources The sources the reply used, in the same shape as above.
tool phase, tool_call_id, name and more The agent is using a tool. phase is start or end.
meta key, value Extra signals, such as handoff when a person takes over.
error code, message, retryable The reply failed. The codes are the same as above.
done reason, response_time_ms, finished_at The last event. reason is complete or error.

Skip event types you don't know. New ones may be added.

Retrying safely

Networks fail. If your request times out, you can't tell whether the agent replied. To make a retry safe, send a request_id of your own with each message. When you send the same request_id to the same conversation again within 10 minutes, Chatvia sends back the finished reply again. It doesn't ask the AI model again and doesn't count another message. In a stream, the start event then has "replayed": true.

Use a new request_id for every new message.

Good to know

  • Tools that need a person's approval are not offered to the agent here. The agent says it can't do that.
  • When a teammate has taken over the conversation in the dashboard, the agent doesn't answer. Your message goes to the teammate, the reply is empty, and a stream carries a meta event with the key handoff.

Get a conversation

Returns the conversation with its first 500 messages, oldest first.

text
GET /api/v1/agents/{agent}/conversations/{conversation}

Who can call it: the owner, or a teammate with View conversations.

bash
curl https://chat.example.com/api/v1/agents/a3f9c2e17b4d08/conversations/0199f3f1-0a1b-7c2d-8e3f-4a5b6c7d8e9f \
  -H "Authorization: Bearer $CHATVIA_API_KEY"
json
{
  "data": {
    "id": "0199f3f1-0a1b-7c2d-8e3f-4a5b6c7d8e9f",
    "title": "Ticket 8841",
    "sentiment": "neutral",
    "tone": "confused",
    "handoff_status": "ai",
    "created_at": "2026-10-25T10:28:40+00:00",
    "messages": [
      {
        "id": "0199f3f1-4b2a-7c1d-9e8f-0a1b2c3d4e5f",
        "role": "user",
        "content": "Can I return a damaged item?",
        "created_at": "2026-10-25T10:31:07+00:00"
      },
      {
        "id": "0199f3f1-4c5d-7e6f-8a7b-9c0d1e2f3a4b",
        "role": "assistant",
        "content": "Yes. You can return a damaged item within 30 days for a full refund [1].",
        "created_at": "2026-10-25T10:31:09+00:00"
      }
    ]
  }
}

A message's role is user (the visitor), assistant (the AI agent) or agent (a teammate who took over the chat). For longer conversations, use List messages.

List messages

Returns the conversation's messages, newest first. Use it to page through long conversations.

text
GET /api/v1/agents/{agent}/conversations/{conversation}/messages

Who can call it: the owner, or a teammate with View conversations.

bash
curl "https://chat.example.com/api/v1/agents/a3f9c2e17b4d08/conversations/0199f3f1-0a1b-7c2d-8e3f-4a5b6c7d8e9f/messages?per_page=100" \
  -H "Authorization: Bearer $CHATVIA_API_KEY"

The answer is { "data": [message, …], "next_cursor": … }, with messages in the shape shown above.

Delete a conversation

Erases the conversation and its messages.

text
DELETE /api/v1/agents/{agent}/conversations/{conversation}

Who can call it: the owner, or a teammate with Delete conversations.

bash
curl -X DELETE https://chat.example.com/api/v1/agents/a3f9c2e17b4d08/conversations/0199f3f1-0a1b-7c2d-8e3f-4a5b6c7d8e9f \
  -H "Authorization: Bearer $CHATVIA_API_KEY"

The answer is 204 No Content. The message text is wiped and the conversation disappears from your chat log and from the visitor's chat. This can't be undone.

Search guides, settings and commands.