Chat API
Send messages to agents via HTTP
The Chat API allows you to send messages to agents and receive responses over HTTP. There are two endpoints: one that identifies agents by their Convex document ID, and one that uses human-readable slugs.
Endpoints
| Method | Path | Description |
|---|---|---|
POST |
/v1/chat |
Chat by agent ID |
POST |
/v1/agents/:slug/chat |
Chat by agent slug |
Both endpoints require a Bearer token (API key) for authentication. The API key determines which environment (development or production) the request operates in.
POST /v1/chat
Send a message to an agent by its Convex document ID.
Request
Headers:
| Header | Value |
|---|---|
Authorization |
Bearer YOUR_API_KEY |
Content-Type |
application/json |
Body:
{
"agentId": "abc123def456",
"message": "Hello, can you help me schedule a session?",
"threadId": "thread_xyz789",
"externalThreadId": "my-app:user-123"
}
| Field | Type | Required | Description |
|---|---|---|---|
agentId |
string |
Yes | The Convex document ID of the agent |
message |
string |
Yes | The user's message to the agent |
threadId |
string |
No | An existing thread ID to continue a conversation |
externalThreadId |
string |
No | An external identifier for thread reuse (e.g., "whatsapp:+1234567890") |
Response
{
"threadId": "thread_xyz789",
"message": "I'd be happy to help you schedule a session. What subject and time works best?",
"usage": {
"inputTokens": 1250,
"outputTokens": 45,
"totalTokens": 1295
}
}
| Field | Type | Description |
|---|---|---|
threadId |
string |
The thread ID for this conversation |
message |
string |
The agent's response text |
usage |
object |
Token usage for this interaction |
usage.inputTokens |
number |
Number of input tokens consumed |
usage.outputTokens |
number |
Number of output tokens generated |
usage.totalTokens |
number |
Total tokens used |
Example
curl -X POST https://your-deployment.convex.site/v1/chat \
-H "Authorization: Bearer sk_dev_abc123" \
-H "Content-Type: application/json" \
-d '{
"agentId": "jd72k3m4n5p6q7r8",
"message": "What sessions are scheduled for tomorrow?"
}'
POST /v1/agents/:slug/chat
Send a message to an agent by its slug. This is the preferred endpoint for integrations as slugs are stable and human-readable.
Request
Headers:
| Header | Value |
|---|---|
Authorization |
Bearer YOUR_API_KEY |
Content-Type |
application/json |
Body:
{
"message": "Hello, can you help me schedule a session?",
"threadId": "thread_xyz789",
"externalThreadId": "my-app:user-123"
}
| Field | Type | Required | Description |
|---|---|---|---|
message |
string |
Yes | The user's message to the agent |
threadId |
string |
No | An existing thread ID to continue a conversation |
externalThreadId |
string |
No | An external identifier for thread reuse |
Note that agentId is not needed since the agent is identified by the :slug URL parameter.
Response
The response format is identical to the /v1/chat endpoint.
Example
curl -X POST https://your-deployment.convex.site/v1/agents/scheduler/chat \
-H "Authorization: Bearer sk_prod_xyz789" \
-H "Content-Type: application/json" \
-d '{
"message": "Book a math session with Mr. Smith for Tuesday at 3 PM"
}'
Thread Management
Creating New Threads
If neither threadId nor externalThreadId is provided, a new thread is created automatically. The response includes the threadId which you should store for subsequent messages.
Continuing Conversations
Pass the threadId from a previous response to continue the conversation. The agent receives the full message history from the thread, maintaining context across messages.
curl -X POST https://your-deployment.convex.site/v1/agents/support/chat \
-H "Authorization: Bearer sk_dev_abc123" \
-H "Content-Type: application/json" \
-d '{
"message": "Actually, make that Thursday instead",
"threadId": "jd72k3m4n5p6q7r8"
}'
External Thread IDs
The externalThreadId field allows you to map external identifiers to Struere threads. If a thread with the given externalThreadId already exists, it is reused. Otherwise, a new thread is created.
This is useful for integrations where you want to maintain a single conversation thread per external user or channel:
{
"message": "What is my account balance?",
"externalThreadId": "slack:U12345678"
}
Common patterns:
whatsapp:+1234567890for WhatsApp conversationsslack:U12345678for Slack user threadsapp:user-abc123for your application's user IDs
Environment Scoping
The API key determines the environment for the entire request:
- Development API keys (
sk_dev_...) access development agent configurations, development entities, and development threads - Production API keys (
sk_prod_...) access production agent configurations, production entities, and production threads
There is no way to specify the environment in the request body. It is always derived from the API key.
Execution Flow
When a chat request arrives:
- The API key is validated and the environment is extracted
- The agent and its configuration are loaded for the matching environment
- A thread is retrieved or created
- The system prompt is processed (template variables and function calls resolved)
- The LLM is called in a loop (up to 10 iterations) to handle tool calls
- Each tool call is permission-checked against the actor context
- The final response, thread ID, and usage stats are returned
Error Responses
401 Unauthorized:
{ "error": "Unauthorized" }
400 Bad Request:
{ "error": "agentId and message are required" }
{ "error": "message is required" }
500 Internal Server Error:
{ "error": "Agent not found" }
{ "error": "No active config found for agent \"scheduler\" in production" }