Chat with an agent (v2)
POST /api/v2/agents/:agentId/chat — send a message and stream or receive the reply. Continue conversations, identify users, retry, submit tool results, and set feedback.
View as MarkdownPOST /api/v2/agents/:agentId/chat
Send a message to an agent. By default the reply streams in the v2 streaming format; set stream: false for a single JSON response. Omit conversationId to start a new conversation, or pass it to continue one.
Requires Authorization: Bearer bk_.... The key's workspace must own the agent; an agent-scoped key may only target its agent.
Path & body
| Field | In | Type | Required | Notes |
|---|---|---|---|---|
| agentId | path | integer | Yes | The agent id. |
| message | body | string | Yes | Non-empty after trimming. |
| userId | body | string | No | Your end-user id. Must match ^[a-zA-Z0-9._-]{1,128}$. Groups conversations per person. |
| conversationId | body | integer | No | Continue an existing conversation. Must belong to this agent. |
| stream | body | boolean | No | Defaults to true. Set false for a JSON response. |
Streaming request
curl -N https://app.bookbag.ai/api/v2/agents/123/chat \
-H "Authorization: Bearer $BOOKBAG_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "message": "Where is my order?", "userId": "user_8821" }'data: {"type":"text-delta","text":"Your order shipped yesterday."}
data: {"type":"finish","finishReason":"stop","metadata":{"messageId":"msg_789","conversationId":"456","userId":"user_8821","usage":{"credits":1}}}
data: [DONE]See the streaming guide for a full parsing example.
Non-streaming request
curl https://app.bookbag.ai/api/v2/agents/123/chat \
-H "Authorization: Bearer $BOOKBAG_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "message": "Where is my order?", "userId": "user_8821", "stream": false }'const res = await fetch(
"https://app.bookbag.ai/api/v2/agents/123/chat",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.BOOKBAG_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ message: "Where is my order?", stream: false }),
}
);
const { data } = await res.json();
const text = data.parts.map((p) => p.text).join("");{
"data": {
"id": "msg_789",
"role": "assistant",
"parts": [{ "type": "text", "text": "Your order shipped yesterday." }],
"metadata": {
"userMessageId": "msg_788",
"conversationId": "456",
"userId": "user_8821",
"finishReason": "stop",
"usage": { "credits": 1 }
}
}
}Status codes
| Status | Code | Meaning |
|---|---|---|
| 200 | — | Streamed or JSON reply. |
| 400 | VALIDATION_INVALID_BODY | Empty message, or userId that fails the pattern. |
| 401 | AUTH_MISSING_API_KEY / AUTH_INVALID_API_KEY | Missing or invalid key. |
| 403 | AUTH_INSUFFICIENT_PERMISSIONS | Agent-scoped key targeting a different agent. |
| 404 | RESOURCE_NOT_FOUND | Agent not found/archived, or conversationId not in this agent. |
| 429 | RATE_LIMIT_TOO_MANY_REQUESTS | Rate limit exceeded. |
| 500 | INTERNAL_SERVER_ERROR | Unexpected error (non-streaming path). |
Related actions
These operate on a conversation that belongs to the agent.
Retry — POST .../conversations/:conversationId/retry
Re-run the last user turn. Truncates the conversation at the user message that produced messageId and regenerates from there. Streams (or returns JSON) like chat.
| Field | Type | Required | Notes |
|---|---|---|---|
| messageId | string | Yes | The assistant message to retry (e.g. msg_789). The msg_ prefix is optional. |
| stream | boolean | No | Defaults to true. |
curl https://app.bookbag.ai/api/v2/agents/123/conversations/456/retry \
-H "Authorization: Bearer $BOOKBAG_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "messageId": "msg_789", "stream": false }'Tool result — POST .../conversations/:conversationId/tool-result
When the agent invokes a client-side tool/action, submit its result so the run can continue.
| Field | Type | Required | Notes |
|---|---|---|---|
| toolCallId | string | Yes | The id from the tool-call part. |
| output | any | No | The tool's result payload. |
curl https://app.bookbag.ai/api/v2/agents/123/conversations/456/tool-result \
-H "Authorization: Bearer $BOOKBAG_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "toolCallId": "call_abc", "output": { "status": "shipped" } }'{ "data": { "success": true } }Feedback — PATCH .../messages/:messageId/feedback
Set thumbs up/down on an assistant message. feedback is "positive", "negative", or null to clear.
curl -X PATCH https://app.bookbag.ai/api/v2/agents/123/conversations/456/messages/msg_789/feedback \
-H "Authorization: Bearer $BOOKBAG_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "feedback": "positive" }'{
"data": {
"id": "msg_789",
"role": "assistant",
"parts": [{ "type": "text", "text": "Your order shipped yesterday." }],
"createdAt": 1717286405,
"feedback": "positive",
"metadata": { "score": null }
}
}| Status | Code | Meaning |
|---|---|---|
| 200 | — | Action succeeded. |
| 400 | VALIDATION_INVALID_BODY / RESOURCE_MESSAGE_NOT_ASSISTANT / CHAT_RETRY_NO_USER_MESSAGE | Bad input for the specific action. |
| 404 | RESOURCE_NOT_FOUND / RESOURCE_MESSAGE_NOT_FOUND / RESOURCE_TOOL_CALL_NOT_FOUND / CHAT_RETRY_MESSAGE_NOT_FOUND | The agent, conversation, message, or tool call was not found. |
| 429 | RATE_LIMIT_TOO_MANY_REQUESTS | Rate limit exceeded. |
See Errors for the full envelope and codes.