Chat
The Chat endpoint receives a message through an API inbox, records the conversation in SquadOS, and normally runs the assigned agent. The response can return in the same request or be delivered later to a webhook.
POST /chat/{id}
Section titled “POST /chat/{id}”Prefer the API inbox ID for {id}. For backward compatibility, the endpoint also accepts the ID of an agent that has an active API inbox.
curl -X POST https://api.squados.io/v1/chat/API_INBOX_ID \ -H "Authorization: Bearer pk_your_key_here" \ -H "Content-Type: application/json" \ -d '{ "message": "What are your opening hours?", "sync": true }'The token and inbox must belong to the same organization. An inactive inbox, an inbox for another channel, or an inbox from another organization is rejected.
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
message | string | Conditional | Message text. Send text, at least one attachment, or both. |
role | user | assistant | No | Default: user. With assistant, the message is only stored in history; the agent does not run. |
conversation_id | string (UUID) | No | Continues a specific conversation in the organization. Takes precedence over external_user_id. |
external_user_id | string | No | Stable contact identifier from your system. Without conversation_id, reuses the latest conversation for this identifier in the organization. |
user_name | string | No | Contact name. Updates the conversation name and, when a contact is linked, the name shown in Conversations. |
sync | boolean | No | With true, returns the agent response in the same call. With false and webhook_url, queues asynchronous processing. |
webhook_url | string (HTTP/HTTPS URL) | No | Asynchronous callback destination. Without this URL, the response is direct. With sync: true, the response remains direct and no callback is sent. |
attachments | array of Attachment | Conditional | Images, audio, or files. Can replace message in an attachment-only request. |
metadata | object | No | Free-form correlation data. It is also returned in the asynchronous callback. |
onlyStorage | boolean | No | With true, stores the message without running the agent. Useful for syncing external history. |
Attachment fields
Section titled “Attachment fields”| Field | Type | Required | Description |
|---|---|---|---|
name | string | Recommended | File name. When omitted, SquadOS uses attachment. |
url | string | Yes | An HTTP/HTTPS URL accessible to SquadOS or a complete data URL such as data:image/png;base64,.... Raw base64 without the data: prefix is not accepted. |
type | image | audio | file | Recommended | Attachment category. If omitted or invalid, SquadOS tries to infer it from mimeType; video is treated as file. |
mimeType | string | Recommended | MIME type such as image/jpeg, audio/mpeg, or application/pdf. |
Actual processing depends on the agent’s capabilities and settings. For example, audio can be transcribed and file text can be extracted before reaching the model.
Conversation continuity
Section titled “Conversation continuity”SquadOS resolves the conversation in this order:
- If
conversation_idis provided, continue that conversation if it belongs to the token’s organization. - Without
conversation_id, ifexternal_user_idis provided, find the latest conversation for that identifier in the organization. - Without either value, create a new conversation.
If the matched conversation is archived, a new conversation is created. Always retain the returned conversation_id: it is the most precise way to continue a thread. external_user_id is useful when your system prefers to retain only its own contact identifier.
curl -X POST https://api.squados.io/v1/chat/API_INBOX_ID \ -H "Authorization: Bearer pk_your_key_here" \ -H "Content-Type: application/json" \ -d '{ "message": "I am back. What is my order status?", "sync": true, "external_user_id": "crm-customer-123", "user_name": "Maria Silva" }'Direct response
Section titled “Direct response”The response is direct when there is no webhook_url or when sync: true. The endpoint contract has no fixed 10-second timeout; configure your client timeout to accommodate the agent’s execution time.
Response 200
{ "success": true, "conversation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "message_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "response": "Our store is open Monday through Friday from 9 AM to 6 PM.", "model": "provider/model", "credits_used": 1, "attachments_processed": 0}model and credits_used reflect the actual execution and vary by agent, provider, and usage.
Asynchronous webhook response
Section titled “Asynchronous webhook response”Send webhook_url and do not use sync: true. The API acknowledges receipt with 202; this initial acknowledgment does not contain the assistant response or its message_id.
curl -X POST https://api.squados.io/v1/chat/API_INBOX_ID \ -H "Authorization: Bearer pk_your_key_here" \ -H "Content-Type: application/json" \ -d '{ "message": "Analyze the attached report", "sync": false, "webhook_url": "https://integration.example.com/squados/callback", "metadata": { "ticket_id": "TKT-12345" } }'With sync: false, processing goes through the asynchronous queue and the acknowledgment includes its group:
{ "status": "debounced", "group_id": "d4e5f6a7-b8c9-0123-def0-234567890123", "conversation_id": "c3d4e5f6-a7b8-9012-cdef-123456789012"}If sync is omitted, the asynchronous acknowledgment can use "status": "processing" and contain only status and conversation_id.
When processing finishes, SquadOS sends a POST to the supplied URL. A successful callback uses event: "message.completed" and includes success, agent_id, conversation_id, message_id, response, model, credits_used, attachments_processed, responding_agent_name, metadata, and timestamp. An agent transfer can produce an earlier callback with pre_transfer: true. See Webhooks for payloads and delivery considerations.
Store a message without running the agent
Section titled “Store a message without running the agent”Use role: "assistant" to record a message produced outside SquadOS, or onlyStorage: true to persist either role without running the pipeline. Provide conversation_id when the message must enter an existing conversation; without it, normal resolution rules apply and a conversation can be created.
curl -X POST https://api.squados.io/v1/chat/API_INBOX_ID \ -H "Authorization: Bearer pk_your_key_here" \ -H "Content-Type: application/json" \ -d '{ "message": "Your order has been processed.", "role": "assistant", "conversation_id": "550e8400-e29b-41d4-a716-446655440000" }'Response 200
{ "success": true, "conversation_id": "550e8400-e29b-41d4-a716-446655440000", "message_id": null}Send an attachment without text
Section titled “Send an attachment without text”message can be omitted when attachments contains at least one item:
{ "sync": true, "attachments": [ { "name": "contract.pdf", "url": "https://files.example.com/contract.pdf", "type": "file", "mimeType": "application/pdf" } ]}Common errors
Section titled “Common errors”| HTTP | code | When it happens |
|---|---|---|
400 | invalid_request | Invalid JSON, invalid role, wrong field type, or both text and attachments are missing. |
401 | unauthorized | Token is missing, invalid, revoked, or outside its validity period. |
403 | forbidden | The inbox does not belong to the token’s organization or is not an API inbox. |
403 | trigger_inactive | The API inbox is inactive or the legacy agent does not have an active API inbox. |
404 | not_found | Route or conversation_id was not found in the organization. |
Error responses use the shape { "error": "message", "code": "code" }. See Errors for the shared API contract.