Overview
Tag conversations with a userId to track per-user chat history. Once a conversation is associated with a user, you can list all of that user’s conversations and continue any of them by passing the conversationId.
Setting a User ID
Pass userId when creating a new conversation. The ID must follow these constraints:
Constraint Value Max length 128 characters Allowed characters a-z, A-Z, 0-9, ., _, -When applied Only on conversation creation (no conversationId in request) Mutability Immutable — cannot be changed or removed after creation
A conversation’s userId is set once at creation and cannot be changed. If you send userId with a conversationId, the userId field is ignored.
const response = await fetch (
"https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/chat" ,
{
method: "POST" ,
headers: {
Authorization: "Bearer YOUR_API_KEY" ,
"Content-Type" : "application/json" ,
},
body: JSON . stringify ({
message: "Hello!" ,
stream: true ,
userId: "user_abc123" ,
}),
}
);
The response metadata includes the userId:
{
"type" : "finish" ,
"finishReason" : "stop" ,
"metadata" : {
"conversationId" : "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" ,
"userId" : "user_abc123" ,
"usage" : { "credits" : 2 }
}
}
Continuing a Conversation
To send follow-up messages in the same conversation, pass the conversationId from a previous response:
const response = await fetch (
"https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/chat" ,
{
method: "POST" ,
headers: {
Authorization: "Bearer YOUR_API_KEY" ,
"Content-Type" : "application/json" ,
},
body: JSON . stringify ({
message: "Tell me more about that." ,
stream: true ,
conversationId: "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" ,
}),
}
);
The conversationId is returned in the streaming finish event’s metadata or in the non-streaming response’s metadata object. See Streaming for details.
If the conversation has ended (e.g. after a human takeover), the API returns a CHAT_CONVERSATION_NOT_ONGOING error. Start a new conversation instead.
Listing a User’s Conversations
Retrieve all conversations for a specific user with GET /api/v2/agents/{agentId}/users/{userId}/conversations.
Path Parameters
Parameter Type Description agentIdstringThe agent ID. userIdstringThe user ID to list conversations for.
Query Parameters
Parameter Type Default Description cursorstring— Opaque cursor from a previous response. Omit to start from the beginning. limitinteger20Number of items per page. Range: 1–100.
Response
{
"data" : [
{
"id" : "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" ,
"title" : "Quantum computing basics" ,
"createdAt" : 1770681600 ,
"updatedAt" : 1770681900 ,
"userId" : "user_abc123" ,
"status" : "ongoing"
},
{
"id" : "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e" ,
"title" : "Pricing questions" ,
"createdAt" : 1770595200 ,
"updatedAt" : 1770595500 ,
"userId" : "user_abc123" ,
"status" : "ended"
}
],
"pagination" : {
"cursor" : "eyJ0IjoiMjAyNC0wMS0xNVQxMDozMDowMC4wMDBaIiwiaWQiOiJhYmMxMjMifQ==" ,
"hasMore" : true ,
"total" : 42
}
}
Response Fields
Field Type Description idstringConversation ID. titlestring | nullConversation title. createdAtnumberUnix epoch timestamp (seconds). updatedAtnumberUnix epoch timestamp (seconds) of last activity. userIdstring | nullThe user ID associated with this conversation. statusstringConversation status: ongoing, ended, or taken_over.
async function fetchUserConversations ( agentId , userId , apiKey ) {
const conversations = [];
let cursor = undefined ;
do {
const params = new URLSearchParams ({ limit: "100" });
if ( cursor ) params . set ( "cursor" , cursor );
const response = await fetch (
`https://www.chatbase.co/api/v2/agents/ ${ agentId } /users/ ${ userId } /conversations? ${ params } ` ,
{
headers: { Authorization: `Bearer ${ apiKey } ` },
}
);
const { data , pagination } = await response . json ();
conversations . push ( ... data );
cursor = pagination . cursor ;
} while ( cursor );
return conversations ;
}
Full Example
Start a conversation with a user ID
Send the first message with a userId to associate the conversation: curl -N -X POST 'https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/chat' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"message": "What is quantum computing?",
"stream": true,
"userId": "user_abc123"
}'
Save the conversationId from the finish event.
Send a follow-up message
Continue the conversation by passing the conversationId: curl -N -X POST 'https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/chat' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"message": "How does it differ from classical computing?",
"stream": true,
"conversationId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
}'
List the user's conversations
Retrieve all conversations for the user: curl 'https://www.chatbase.co/api/v2/agents/YOUR_AGENT_ID/users/user_abc123/conversations?limit=20' \
-H 'Authorization: Bearer YOUR_API_KEY'
Exporting All Conversations
The Export conversations endpoint returns all conversations with full message history , regardless of source. This is different from the list endpoints above, which only return API-created conversations.
Key differences from list endpoints
List conversations Export conversations Sources API-only All (Widget, WhatsApp, Messenger, API, etc.) Messages Not included (metadata only) Full message history included Tool results Not included (metadata only) Sanitized — internal data stripped Tool call input Not included (metadata only) Omitted (not useful for export consumers)
Conversation sources
Exported conversations include a source field indicating where the conversation originated:
API, WhatsApp, Messenger, Instagram, Slack, Salesforce, Zendesk, Zendesk Messaging, Widget or Iframe, Iframe, Email, Agent page, Phone, Android SDK, iOS SDK, Chatbase site, Playground, and others.
Each conversation includes a messages array. Messages contain parts, which can be:
Part type Fields Description texttype, textText content from the user or assistant tool-calltype, toolCallId, toolNameA tool invocation by the agent (input is omitted in exports) tool-resulttype, toolCallId, toolName, outputThe sanitized result of a tool invocation
All tool results in the export follow a unified shape, so you can handle them with a single switch on status:
Status Shape Description success{ status: "success", data?: <T> }Tool completed successfully. data is present when there is a meaningful payload. error{ status: "error", error?: string }Tool encountered an error. pending{ status: "pending" }Tool execution is still in progress. ignored{ status: "ignored" }Tool was skipped by the user.
Example response
{
"data" : [
{
"id" : "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" ,
"title" : "Order status inquiry" ,
"createdAt" : 1770681600 ,
"updatedAt" : 1770681900 ,
"userId" : "user_abc123" ,
"source" : "WhatsApp" ,
"status" : "ended" ,
"messages" : [
{
"id" : "msg_001" ,
"role" : "user" ,
"parts" : [
{ "type" : "text" , "text" : "What's the status of my order?" }
],
"createdAt" : 1770681600
},
{
"id" : "msg_002" ,
"role" : "assistant" ,
"parts" : [
{ "type" : "text" , "text" : "Let me look that up for you." },
{
"type" : "tool-call" ,
"toolCallId" : "call_abc123" ,
"toolName" : "lookupOrder"
},
{
"type" : "tool-result" ,
"toolCallId" : "call_abc123" ,
"toolName" : "lookupOrder" ,
"output" : {
"status" : "success" ,
"data" : { "orderId" : "ORD-123" , "shipped" : true }
}
},
{ "type" : "text" , "text" : "Your order ORD-123 has been shipped!" }
],
"createdAt" : 1770681605 ,
"feedback" : "positive" ,
"metadata" : { "score" : 0.95 }
}
]
}
],
"pagination" : {
"cursor" : "eyJ0IjoiMjAyNC0wMS0xNVQxMDozMDowMC4wMDBaIiwiaWQiOiJhYmMxMjMifQ==" ,
"hasMore" : true ,
"total" : 1250
}
}
Paginating through all exports
async function exportAllConversations ( agentId , apiKey ) {
const conversations = [];
let cursor = undefined ;
do {
const params = new URLSearchParams ({ limit: "100" });
if ( cursor ) params . set ( "cursor" , cursor );
const response = await fetch (
`https://www.chatbase.co/api/v2/agents/ ${ agentId } /conversations/export? ${ params } ` ,
{
headers: { Authorization: `Bearer ${ apiKey } ` },
}
);
const { data , pagination } = await response . json ();
conversations . push ( ... data );
cursor = pagination . cursor ;
} while ( cursor );
return conversations ;
}
The export endpoint can return large amounts of data. Use a smaller limit (e.g., 20) if you’re processing messages as they arrive rather than collecting everything in memory.
Streaming Learn about streaming responses and event types.
Pagination How cursor-based pagination works across all list endpoints.
Export Conversations Full API reference for the export endpoint.
Client Actions How tool calls and tool results work in conversations.