Chat Endpoint
Integrate applications, websites, and widgets with agents using the streaming chat endpoint.
Deprecated. The Chat Endpoint has been superseded by the unified Run Endpoint. Use POST /api/agents/{agentId}/run with "stream": true instead — the request and response formats are identical. This endpoint remains available for backward compatibility and responds with a Deprecation: true header.
Endpoint Overview
The Chat Endpoint enables applications, websites, widgets, and custom integrations to communicate with an agent through a real-time streaming interface.
Use this endpoint when you want live responses from an agent, including support for tool execution, reasoning, and streaming message updates.
| Property | Value |
|---|---|
| Method | POST |
| Endpoint | /api/agents/{agentId}/chat |
| Response Type | Streaming SSE |
| Protocol | AI SDK UI Message Stream |
| Authentication | Authorization (user JWT) or cf-api-key |
This endpoint returns a streaming response and is optimized for chat experiences. It is not intended for traditional request/response JSON workflows.
Authentication
You can authenticate using a user session token or a scoped API key.
Bearer Token
Authorization: Bearer <supabase_jwt>Use for platform users with an active Supabase session.
Optional Headers
Pass x-agent-payload additional metadata to downstream MCP integrations.
x-agent-payload: {"x-user-id":"123","x-tenant-id":"acme"}- Must contain valid JSON.
- Only string, number, and boolean values are preserved.
- Unsafe headers such as
authorization,host, andcontent-lengthare automatically removed before forwarding.
Request Body
The Chat Endpoint uses the AI SDK UI Message format.
Message Object
Every message contains an identifier, a role, and one or more content parts.
{
"id": "msg-1",
"role": "user",
"parts": [
{
"type": "text",
"text": "Hello"
}
]
}Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
message | UIMessage | No | Latest user message |
messages | UIMessage[] | No | Complete conversation history |
id | string | No | Conversation ID or client session ID |
vars | Record<string, any> | No | Runtime variables injected into the agent prompt |
customTools | Array | No | Runtime-defined tools for advanced scenarios |
A request must contain either message or messages.
Runtime Variables
Use the optional vars field to provide runtime values that can be referenced by agent prompts, workflows, or tools.
{
"vars": {
"customerName": "My Customer",
"bookingId": "BK-12345",
"locale": "en-SG"
}
}Common use cases include:
- User identifiers
- Customer information
- Locale settings
- Tenant identifiers
- Business-specific context
Request Modes
The endpoint supports two conversation management modes depending on where conversation history is stored.
Server-Managed History
Use this mode when Chocolate Factory should automatically persist, retrieve, and manage conversation history on behalf of your application.
Your application sends only the latest user message. The platform automatically loads previous conversation history and provides the full context to the agent.
Recommended for:
- Customer support assistants
- Chatbots
- Long-running conversations
- Applications requiring persistent history
Request Example
{
"id": "existing-conversation-id",
"message": {
"id": "msg-2",
"role": "user",
"parts": [
{
"type": "text",
"text": "Show me the latest booking status"
}
]
},
"vars": {
"bookingId": "BK-12345"
}
}Client-Managed History
Use this mode when your application is responsible for storing and managing the complete conversation transcript.
The complete conversation history is included in each request. The platform uses the supplied messages as the conversation context and does not load historical messages from storage.
Recommended for:
- AI SDK applications
- Browser-based chat clients
- Frontend-managed state
- Applications that already persist conversation history
Request Example
{
"id": "client-chat-session-id",
"messages": [
{
"id": "msg-1",
"role": "user",
"parts": [
{
"type": "text",
"text": "Hello"
}
]
},
{
"id": "msg-2",
"role": "assistant",
"parts": [
{
"type": "text",
"text": "Hi, how can I help?"
}
]
}
]
}Recommended Integration: AI SDK
The Chat Endpoint natively returns the AI SDK UI Message Stream format, making the AI SDK the recommended integration approach. Using the AI SDK provides several advantages:
- Automatic stream handling
- No manual SSE parsing
- Built-in message state management
- Native support for streaming UI updates
- Consistent with Chocolate Factory reference implementations
"use client";
import { useChat } from "@ai-sdk/react";
import { DefaultChatTransport } from "ai";
const agentId = "YOUR_AGENT_ID";
export function ChatWidget() {
const transport = new DefaultChatTransport({
api: `${process.env.NEXT_PUBLIC_APP_URL}/api/agents/${agentId}/chat`,
headers: {
"x-agent-key": "YOUR_AGENT_KEY",
},
});
const { messages, sendMessage, status } = useChat({
transport,
id: `chat-${agentId}`,
});
return (
<div>
<button
onClick={() =>
sendMessage({
text: "Hello",
metadata: { agentId },
})
}
disabled={status !== "ready"}
>
Send
</button>
<pre>{JSON.stringify(messages, null, 2)}</pre>
</div>
);
}Integration Without AI SDK
If you are not using the AI SDK, you can integrate with the endpoint using any HTTP client that supports streaming responses.
Option 1: Server-Managed History
Send only the latest user message and allow the server to manage conversation persistence.
const agentId = "YOUR_AGENT_ID";
const response = await fetch(`/api/agents/${agentId}/chat`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-agent-key": "YOUR_AGENT_KEY",
},
body: JSON.stringify({
id: "optional-conversation-id",
message: {
id: `msg-${Date.now()}`,
role: "user",
parts: [{ type: "text", text: "Summarize this order for me" }],
},
vars: {
locale: "en-SG",
},
}),
});
if (!response.ok) {
throw new Error(`Chat request failed: ${response.status}`);
}
const reader = response.body?.getReader();
const decoder = new TextDecoder();
if (!reader) {
throw new Error("Missing response body");
}
let rawStream = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
rawStream += decoder.decode(value, { stream: true });
}
rawStream += decoder.decode();
console.log(rawStream);Do not use response.json(). The endpoint returns a stream that must be consumed incrementally.
Success Responses
The Chat Endpoint streams returns a streaming response using the AI SDK UI Message Stream protocol.
- Return HTTP
200 - Stream assistant responses incrementally
- Emit AI SDK UI Message Stream events
- May include metadata events
- May include tool execution events
- May include runtime information and annotations
If you require a traditional synchronous JSON response, this endpoint may not be the best fit. It is specifically designed for live conversational streaming.
Error Responses
| Status | Response |
|---|---|
400 | { "error": "Agent is not active" } |
400 | { "error": "Agent must belong to an organization" } |
400 | { "error": "No valid messages to process" } |
401 | { "error": "Unauthorized" } |
403 | { "error": "Forbidden" } |
404 | { "error": "Agent not found" } |
500 | { "error": "Internal server error" } |
Best Practices
- Prefer AI SDK for new chat applications.
- Use Server-Managed History when conversation persistence should be handled by Chocolate Factory.
- Use Client-Managed History when your application owns the complete conversation state.
- Use x-agent-key for websites, embedded chat widgets, and external integrations.
- Use vars to inject runtime context into prompts, workflows, or business-specific information.
- Use x-agent-payload when MCP tools require additional contextual metadata.
- Always process responses as streams rather than JSON payloads.
- Reuse conversation IDs to maintain context across multiple user interactions.