Overview
The Chat API lets you programmatically converse with a published chatbot flow. This is useful for:
- Building custom chat UIs outside the web widget
- Automated testing of conversation flows
- Integrating chatbot capabilities into your own applications
The flow is simple:
- Create a session - you get back a
session_id(the session starts empty, no greeting yet) - Send messages - pass the
session_idwith each message, receive the bot's response synchronously. The bot's greeting is returned as the response to your first message - Sessions expire automatically after 30 minutes of inactivity
Requires a published flow
The chatbot must have a published conversation flow. Use the Flows API to publish one.
Create Chat Session
Creates a new conversation session. The session is created empty — the bot's greeting is returned as the response to the first message you send, exactly like the web and playground channels.
POST /api/dev/v1/chatbots/{chatbot_id}/chat/sessions Authorization: Bearer <api-key>POST /api/dev/v1/chatbots/{chatbot_id}/chat/sessions Authorization: Bearer <api-key>
curl -X POST http://localhost:3000/api/dev/v1/chatbots/<chatbot-id>/chat/sessions \ -H "Authorization: Bearer <your-api-key>"curl -X POST http://localhost:3000/api/dev/v1/chatbots/<chatbot-id>/chat/sessions \ -H "Authorization: Bearer <your-api-key>"
Response - 201 Created
{ "session_id": "01JPQ...", "channel": "api", "created_at": "2026-04-02T12:00:00Z" }{ "session_id": "01JPQ...", "channel": "api", "created_at": "2026-04-02T12:00:00Z" }
To receive the bot's greeting, send the user's first message to Send Message (POST /api/dev/v1/chatbots/{chatbot_id}/chat/sessions/{session_id}/messages). The response to that first message contains the flow's welcome/greeting (the same messages a user sees when opening the chat widget), following the GenericMessage structure.
Errors:
| Status | Detail |
|---|---|
400 | No published flow found for this chatbot |
404 | Chatbot not found |
Send Message
Sends a user message and returns the bot's response synchronously.
POST /api/dev/v1/chatbots/{chatbot_id}/chat/sessions/{session_id}/messages Authorization: Bearer <api-key> Content-Type: application/jsonPOST /api/dev/v1/chatbots/{chatbot_id}/chat/sessions/{session_id}/messages Authorization: Bearer <api-key> Content-Type: application/json
Request Body
Fields
messagestringrequiredUser message text. Max 4096 characters.
message_typestringoptionaldefault: text"text" or "button".
button_idstring | nulloptionalThe button or list item ID when the user clicks a button. When set, message_type is treated as "button" automatically.
Sending a text message
curl -X POST http://localhost:3000/api/dev/v1/chatbots/<chatbot-id>/chat/sessions/<session-id>/messages \ -H "Authorization: Bearer <your-api-key>" \ -H "Content-Type: application/json" \ -d '{"message": "I need help with my order"}'curl -X POST http://localhost:3000/api/dev/v1/chatbots/<chatbot-id>/chat/sessions/<session-id>/messages \ -H "Authorization: Bearer <your-api-key>" \ -H "Content-Type: application/json" \ -d '{"message": "I need help with my order"}'
Sending a button click
When the bot sends buttons or a list, use the button's id field:
curl -X POST http://localhost:3000/api/dev/v1/chatbots/<chatbot-id>/chat/sessions/<session-id>/messages \ -H "Authorization: Bearer <your-api-key>" \ -H "Content-Type: application/json" \ -d '{"message": "FAQ", "button_id": "faq"}'curl -X POST http://localhost:3000/api/dev/v1/chatbots/<chatbot-id>/chat/sessions/<session-id>/messages \ -H "Authorization: Bearer <your-api-key>" \ -H "Content-Type: application/json" \ -d '{"message": "FAQ", "button_id": "faq"}'
Response - 200 OK
{ "session_id": "01JPQ...", "messages": [ { "type": "text", "text": "Sure! Here are our most common questions:" }, { "type": "list", "text": "Select a topic", "button_text": "View topics", "sections": [ { "title": "General", "rows": [ { "id": "hours", "title": "Business hours" }, { "id": "pricing", "title": "Pricing" } ] } ] } ], "messages_count": 2, "current_state": "faq_menu", "timestamp": "2026-04-02T12:00:05Z" }{ "session_id": "01JPQ...", "messages": [ { "type": "text", "text": "Sure! Here are our most common questions:" }, { "type": "list", "text": "Select a topic", "button_text": "View topics", "sections": [ { "title": "General", "rows": [ { "id": "hours", "title": "Business hours" }, { "id": "pricing", "title": "Pricing" } ] } ] } ], "messages_count": 2, "current_state": "faq_menu", "timestamp": "2026-04-02T12:00:05Z" }
Errors:
| Status | Detail |
|---|---|
404 | Chat session not found |
410 | Chat session has been closed |
500 | Message processing failed |
Session Lifecycle
- Creation: Each
POST /sessionscreates a new isolated conversation with its own state. - Expiry: Sessions expire after 30 minutes of inactivity (no messages sent). After expiry, the bot resets to its initial state on the next message in a new session.
- Channel isolation: Chat API sessions use the
apichannel. They are completely isolated from the same chatbot'swhatsapp,web, orsmsconversations. - Conversation history: All sessions and messages are persisted and can be retrieved via the Conversations API using
channel=api.
Message Format
Bot responses use the GenericMessage format - the same structure used across all channels. Each message has a type field that determines which other fields are present.
Message Types
| Type | Description | Key Fields |
|---|---|---|
text | Plain text message | text |
buttons | Text with interactive buttons | text, buttons[] (each has id, title) |
list | Sectioned list with selectable rows | text, button_text, sections[] |
image | Image with optional caption | media_url, media_caption |
document | Document file | media_url, media_filename, media_caption |
video | Video file | media_url, media_caption |
audio | Audio file | media_url |
Example: Text message
{ "type": "text", "text": "Hello! How can I help?" }{ "type": "text", "text": "Hello! How can I help?" }
Example: Buttons
{ "type": "buttons", "text": "What would you like to do?", "buttons": [ { "id": "order_status", "title": "Check order" }, { "id": "new_order", "title": "Place order" } ] }{ "type": "buttons", "text": "What would you like to do?", "buttons": [ { "id": "order_status", "title": "Check order" }, { "id": "new_order", "title": "Place order" } ] }
Example: List
{ "type": "list", "text": "Select a product category", "button_text": "View categories", "sections": [ { "title": "Electronics", "rows": [ { "id": "phones", "title": "Phones", "description": "Smartphones and accessories" }, { "id": "laptops", "title": "Laptops" } ] } ] }{ "type": "list", "text": "Select a product category", "button_text": "View categories", "sections": [ { "title": "Electronics", "rows": [ { "id": "phones", "title": "Phones", "description": "Smartphones and accessories" }, { "id": "laptops", "title": "Laptops" } ] } ] }
Full Example
A complete conversation flow using curl:
# 1. Create a session SESSION=$(curl -s -X POST \ http://localhost:3000/api/dev/v1/chatbots/<chatbot-id>/chat/sessions \ -H "Authorization: Bearer <your-api-key>" | jq -r '.session_id') echo "Session: $SESSION" # 2. Send a message curl -s -X POST \ "http://localhost:3000/api/dev/v1/chatbots/<chatbot-id>/chat/sessions/$SESSION/messages" \ -H "Authorization: Bearer <your-api-key>" \ -H "Content-Type: application/json" \ -d '{"message": "What are your business hours?"}' | jq # 3. Send a follow-up curl -s -X POST \ "http://localhost:3000/api/dev/v1/chatbots/<chatbot-id>/chat/sessions/$SESSION/messages" \ -H "Authorization: Bearer <your-api-key>" \ -H "Content-Type: application/json" \ -d '{"message": "Thanks!"}' | jq# 1. Create a session SESSION=$(curl -s -X POST \ http://localhost:3000/api/dev/v1/chatbots/<chatbot-id>/chat/sessions \ -H "Authorization: Bearer <your-api-key>" | jq -r '.session_id') echo "Session: $SESSION" # 2. Send a message curl -s -X POST \ "http://localhost:3000/api/dev/v1/chatbots/<chatbot-id>/chat/sessions/$SESSION/messages" \ -H "Authorization: Bearer <your-api-key>" \ -H "Content-Type: application/json" \ -d '{"message": "What are your business hours?"}' | jq # 3. Send a follow-up curl -s -X POST \ "http://localhost:3000/api/dev/v1/chatbots/<chatbot-id>/chat/sessions/$SESSION/messages" \ -H "Authorization: Bearer <your-api-key>" \ -H "Content-Type: application/json" \ -d '{"message": "Thanks!"}' | jq
Python example
import requests BASE = "http://localhost:3000/api/dev/v1" HEADERS = {"Authorization": "Bearer <your-api-key>"} CHATBOT_ID = "<chatbot-id>" # Create session (returns session_id only — no greeting yet) resp = requests.post(f"{BASE}/chatbots/{CHATBOT_ID}/chat/sessions", headers=HEADERS) session_id = resp.json()["session_id"] # Send the user's first message — the response contains the greeting AND the reply. # Do not send a warmup message first; it would consume the greeting turn. resp = requests.post( f"{BASE}/chatbots/{CHATBOT_ID}/chat/sessions/{session_id}/messages", headers=HEADERS, json={"message": "Hello"}, ) print("Bot:", resp.json()["messages"])import requests BASE = "http://localhost:3000/api/dev/v1" HEADERS = {"Authorization": "Bearer <your-api-key>"} CHATBOT_ID = "<chatbot-id>" # Create session (returns session_id only — no greeting yet) resp = requests.post(f"{BASE}/chatbots/{CHATBOT_ID}/chat/sessions", headers=HEADERS) session_id = resp.json()["session_id"] # Send the user's first message — the response contains the greeting AND the reply. # Do not send a warmup message first; it would consume the greeting turn. resp = requests.post( f"{BASE}/chatbots/{CHATBOT_ID}/chat/sessions/{session_id}/messages", headers=HEADERS, json={"message": "Hello"}, ) print("Bot:", resp.json()["messages"])