Agent API
Manage AI agents, publish control, chat interaction, and statistics queries
Endpoint Overview
The Agent API provides agent lifecycle management, chat interaction, and statistics query capabilities. Base path: /api/v1/agents.
| Method | Path | Purpose |
|---|---|---|
| GET | /api/v1/agents | List agents accessible to the current user |
| POST | /api/v1/agents | Create a new agent |
| GET | /api/v1/agents/{agent_id} | Get agent details (including full configuration) |
| PUT | /api/v1/agents/{agent_id} | Update agent configuration |
| DELETE | /api/v1/agents/{agent_id} | Permanently delete an agent |
| POST | /api/v1/agents/{agent_id}/publish | Publish an agent |
| POST | /api/v1/agents/{agent_id}/unpublish | Unpublish an agent |
| POST | /api/v1/agents/{agent_id}/duplicate | Duplicate an agent (the copy is always private + draft) |
| GET | /api/v1/agents/{agent_id}/media/video-status | Query an async video generation task |
| GET | /api/v1/agents/{agent_id}/public | Get the public agent info used by the chat page |
| POST | /api/v1/agents/{agent_id}/chat | Non-streaming chat |
| POST | /api/v1/agents/{agent_id}/chat/stream | SSE streaming chat |
| POST | /api/v1/agents/{agent_id}/chat/runs | Queue a durable run (202 Accepted) |
| GET | /api/v1/agents/{agent_id}/chat/runs/{run_id}/stream | Subscribe to a run's event stream (after_sequence resume) |
| POST | /api/v1/agents/{agent_id}/chat/runs/{run_id}/stop | Cooperatively stop a run |
| POST | /api/v1/agents/{agent_id}/messages/{message_id}/regenerate | Regenerate |
| POST | /api/v1/agents/{agent_id}/messages/{message_id}/edit/stream | Edit a user message and create a branch |
| GET | /api/v1/agents/{agent_id}/messages/{message_id}/versions | Query message versions |
| POST | /api/v1/agents/{agent_id}/messages/{message_id}/switch-version | Switch version |
| GET | /api/v1/agents/{agent_id}/conversations | List the caller's conversations for one agent |
| GET | /api/v1/agents/conversations/my | List all of the caller's conversations |
| GET | /api/v1/agents/conversations/{conversation_id} | Get a conversation and its messages |
| PATCH | /api/v1/agents/conversations/{conversation_id} | Rename a conversation |
| DELETE | /api/v1/agents/conversations/{conversation_id} | Delete a conversation |
| DELETE | /api/v1/agents/conversations/{conversation_id}/messages/{message_id} | Delete a single message |
| GET | /api/v1/agents/{agent_id}/stats | Query agent statistics overview |
| GET | /api/v1/agents/{agent_id}/stats/trends | Query trend data |
| GET | /api/v1/agents/{agent_id}/stats/tool-usage | Query tool usage statistics |
Authentication
All endpoints require an authenticated JWT user session. Chat endpoints additionally support API Keys (with bound agent permissions).
Required scopes:
| Scope | Purpose |
|---|---|
agent:read | List and view agents |
agent:create | Create agents |
agent:update | Update agents |
agent:delete | Delete agents |
agent:publish | Publish or unpublish agents |
agent:chat | Chat with agents |
conversation:read | View conversations and their messages |
conversation:delete | Delete conversations and conversation messages |
List Agents
GET /api/v1/agentsGet all agents accessible to the current user, with pagination, team filtering, status filtering, and keyword search.
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
page | integer | No | 1 | Page number |
page_size | integer | No | 20 | Items per page |
team_id | string | No | - | Filter by team UUID |
status | string | No | - | Filter by status: draft, published |
visibility | string | No | - | Filter by visibility: private, team, public (legacy compatibility value) |
keyword | string | No | - | Search by name or description |
own_only | boolean | No | false | Only show agents created by the current user |
Request Example
curl -X GET "https://your-domain.com/api/v1/agents?page=1&page_size=20" \
-H "Authorization: Bearer YOUR_TOKEN"Response Fields
| Field | Type | Description |
|---|---|---|
id | string | Agent UUID |
name | string | Name |
description | string | Description |
icon | string | Icon emoji or URL |
avatar_url | string | Avatar URL |
team | object | Team info (id, name, avatar_url) |
model | object | Model info (id, name, provider, model_id), null if unset |
status | string | draft or published |
visibility | string | private or team |
conversation_count | integer | Number of conversations |
message_count | integer | Number of messages |
created_by | object | Creator info (id, username, avatar_url) |
created_at | string | ISO 8601 timestamp |
updated_at | string | ISO 8601 timestamp |
Success Response (200 OK)
{
"code": 0,
"data": {
"items": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Customer Support Agent",
"description": "Helps customers with common questions",
"icon": "🤖",
"avatar_url": "https://example.com/avatar.png",
"team": {
"id": "team-123",
"name": "Support Team",
"avatar_url": "https://example.com/team.png"
},
"model": {
"id": "model-456",
"name": "GPT-4",
"provider": "openai",
"provider_display_name": "OpenAI",
"model_id": "gpt-4"
},
"status": "published",
"visibility": "team",
"conversation_count": 156,
"message_count": 1234,
"created_by": {
"id": "user-001",
"username": "alice",
"avatar_url": "https://example.com/avatars/alice.jpg"
},
"created_at": "2026-02-11T10:00:00Z",
"updated_at": "2026-02-11T15:30:00Z"
}
],
"total": 42,
"page": 1,
"page_size": 20
},
"msg": "success"
}Get Agent Details
GET /api/v1/agents/{agent_id}Get the complete configuration of a specified agent, including system prompt, tool configuration, knowledge base associations, and RAG parameters.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id | string | Yes | Agent UUID |
Request Example
curl -X GET "https://your-domain.com/api/v1/agents/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer YOUR_TOKEN"Response Fields
In addition to the list fields above, the details endpoint returns the full configuration:
| Field | Type | Description |
|---|---|---|
model_id | string | Team model UUID |
system_prompt | string | System prompt |
max_iterations | integer | Max tool call iterations (1–200, default 5) |
hide_tool_calls | boolean | Hide tool call details in chat UI |
hide_message_actions | boolean | Hide token usage/speed stats |
hide_reasoning | boolean | Hide reasoning/chain-of-thought |
tools_config | array | Tool configs (type/name/tool_id/server_id/skill_id/config) |
enable_attachments | boolean | Enable file and image attachments |
enable_user_input_request | boolean | Enable model-callable ask_user tool |
enable_memory | boolean | Enable cross-conversation memory |
rag_mode | string | RAG mode: off, auto, agentic (agentic by default with a knowledge base; normalized to off when the response knowledge_bases list is empty) |
variables | array | Chat input variable definitions |
knowledge_bases | array | Attached knowledge-base response objects (knowledge_base, retrieval_top_k, score_threshold, search_mode) |
Success Response (200 OK)
{
"code": 0,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Customer Support Agent",
"description": "Helps customers with common questions",
"system_prompt": "You are a helpful customer support agent...",
"max_iterations": 5,
"hide_tool_calls": false,
"tools_config": [
{
"type": "builtin",
"name": "web_search"
}
],
"enable_memory": false,
"rag_mode": "agentic",
"knowledge_bases": [
{
"id": "kb-assoc-001",
"knowledge_base": {
"id": "kb-789",
"name": "Product Documentation",
"description": "Product docs and FAQs",
"icon": "📚",
"document_count": 156
},
"retrieval_top_k": 5,
"score_threshold": 0.3,
"search_mode": "hybrid"
}
],
"status": "published",
"visibility": "team",
"created_at": "2026-02-11T10:00:00Z",
"updated_at": "2026-02-11T15:30:00Z"
},
"msg": "success"
}Error Response (404 Not Found)
{
"code": 6200,
"data": {
"agent_id": "550e8400-e29b-41d4-a716-446655440000"
},
"msg": "Agent not found"
}Create Agent
POST /api/v1/agentsCreate a new AI agent. The agent is in draft status by default and must be published before it can be used for chat.
Request Body
{
"name": "Customer Support Agent",
"description": "Helps customers with common questions",
"avatar_url": "https://example.com/avatar.png",
"team_id": "team-123",
"model_id": "model-456",
"system_prompt": "You are a helpful customer support agent...",
"max_iterations": 5,
"hide_tool_calls": false,
"tools_config": [
{
"type": "builtin",
"name": "web_search"
}
],
"enable_memory": false,
"rag_mode": "agentic",
"knowledge_base_configs": [
{
"knowledge_base_id": "kb-789",
"retrieval_top_k": 5,
"score_threshold": 0.3,
"search_mode": "hybrid"
}
],
"visibility": "team"
}Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Name (max 100 chars) |
description | string | No | Description (max 500 chars) |
icon | string | No | Icon emoji or URL (max 500 chars) |
avatar_url | string | No | Avatar URL |
team_id | string | Yes | Team UUID |
model_id | string | No | Team model UUID; uses team default if unset |
system_prompt | string | No | System prompt/instructions |
max_iterations | integer | No | Max tool call iterations (1–200, default 5) |
hide_tool_calls | boolean | No | Hide tool call details in chat UI (default false) |
hide_message_actions | boolean | No | Hide token usage/speed stats (default false) |
hide_reasoning | boolean | No | Hide reasoning/chain-of-thought (default false) |
tools_config | array | No | Tool configs (type/name/tool_id/server_id/skill_id/config) |
tools_credentials | object | No | Tool credentials (API keys, tokens, etc.) |
enable_attachments | boolean | No | Enable file and image attachments (default false) |
attachment_config | object | No | Attachment limits configuration |
enable_user_input_request | boolean | No | Enable ask_user tool (default false) |
enable_memory | boolean | No | Enable cross-conversation memory (default false) |
memory_config | object | No | Memory configuration |
context_compression_config | object | No | Context compression configuration |
enable_image_generation | boolean | No | Enable image generation tool (default false) |
image_generation_config | object | No | Image generation configuration |
enable_video_generation | boolean | No | Enable video generation tool (default false) |
video_generation_config | object | No | Video generation configuration |
rag_mode | string | No | RAG mode: off, auto, agentic (agentic by default with a knowledge base; normalized to off when no knowledge base is attached) |
knowledge_base_configs | array | No | Knowledge-base configs submitted on create/update (knowledge_base_id, retrieval_top_k, score_threshold, search_mode); an empty list forces rag_mode to off |
variables | array | No | Chat input variable definitions |
opening_message | string | No | Opening message shown in chat |
suggested_questions | array | No | Suggested questions |
visibility | string | No | private or team (default private; the legacy value public is treated as team) |
Request Example
curl -X POST "https://your-domain.com/api/v1/agents" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Customer Support Agent",
"description": "Helps customers with common questions",
"team_id": "team-123",
"model_id": "model-456",
"system_prompt": "You are a helpful customer support agent...",
"tools_config": [{"type": "builtin", "name": "web_search"}],
"knowledge_base_configs": [
{
"knowledge_base_id": "kb-789",
"retrieval_top_k": 5,
"score_threshold": 0.3,
"search_mode": "hybrid"
}
],
"rag_mode": "agentic"
}'Success Response (200 OK)
{
"code": 0,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Customer Support Agent",
"description": "Helps customers with common questions",
"status": "draft",
"visibility": "team",
"team": {
"id": "team-123",
"name": "Support Team",
"avatar_url": null
},
"model_id": "model-456",
"model": {
"id": "model-456",
"name": "GPT-4",
"provider": "openai",
"provider_display_name": "OpenAI",
"model_id": "gpt-4"
},
"created_at": "2026-02-11T10:00:00Z",
"created_by": {
"id": "user-001",
"username": "alice",
"avatar_url": null
}
},
"msg": "Agent created successfully"
}Error Response (1001 Validation Error)
{
"code": 1001,
"data": {
"errors": [
{
"field": "name",
"message": "Name is required"
},
{
"field": "model_id",
"message": "Invalid model ID"
}
]
},
"msg": "Validation failed"
}After creation, the agent is in draft status. Call the publish endpoint to make it available for chat.
Update Agent
PUT /api/v1/agents/{agent_id}Update the configuration of an existing agent. All fields are optional; only include the fields you want to update.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id | string | Yes | Agent UUID |
Request Body
{
"name": "Updated Agent Name",
"description": "Updated description",
"system_prompt": "Updated system prompt...",
"max_iterations": 8,
"tools_config": [
{"type": "builtin", "name": "web_search"},
{"type": "builtin", "name": "code_interpreter"}
],
"rag_mode": "auto"
}Request Example
curl -X PUT "https://your-domain.com/api/v1/agents/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Updated Agent Name",
"max_iterations": 8
}'Success Response (200 OK)
{
"code": 0,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Updated Agent Name",
"max_iterations": 8,
"updated_at": "2026-02-11T16:00:00Z"
},
"msg": "Agent updated successfully"
}Delete Agent
DELETE /api/v1/agents/{agent_id}Permanently delete the specified agent. This action cannot be undone.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id | string | Yes | Agent UUID |
Request Example
curl -X DELETE "https://your-domain.com/api/v1/agents/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer YOUR_TOKEN"Success Response (200 OK)
{
"code": 0,
"data": null,
"msg": "Agent deleted successfully"
}Error Response (6200 Not Found)
{
"code": 6200,
"data": {
"agent_id": "550e8400-e29b-41d4-a716-446655440000"
},
"msg": "Agent not found"
}Publish Agent
POST /api/v1/agents/{agent_id}/publishSet the agent status to published, making it available for chat. The publish operation does not validate whether a model is configured (model validation occurs in subsequent chat/access paths with error code 6202).
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id | string | Yes | Agent UUID |
Request Example
curl -X POST "https://your-domain.com/api/v1/agents/550e8400-e29b-41d4-a716-446655440000/publish" \
-H "Authorization: Bearer YOUR_TOKEN"Success Response (200 OK)
{
"code": 0,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "published"
},
"msg": "Agent published successfully"
}The publish endpoint only sets the status and does not validate the model. If the agent is in draft status during a subsequent chat, 6202 Agent not published will be returned.
Unpublish Agent
POST /api/v1/agents/{agent_id}/unpublishSet the agent status to draft, making it unavailable for chat.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id | string | Yes | Agent UUID |
Request Example
curl -X POST "https://your-domain.com/api/v1/agents/550e8400-e29b-41d4-a716-446655440000/unpublish" \
-H "Authorization: Bearer YOUR_TOKEN"Success Response (200 OK)
{
"code": 0,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "draft"
},
"msg": "Agent unpublished successfully"
}Duplicate Agent
POST /api/v1/agents/{agent_id}/duplicateDuplicate an existing agent within the same team, copying:
- Prompts: system prompt, opening message, suggested questions,
powered_by_text - Configuration: tools, attachments, memory, context compression,
rag_mode, variables, iteration limit - Media generation: image and video generation settings (both configs have
allow_model_overridestripped for security) - Knowledge bases: every knowledge base association and its retrieval settings
Requires access to the agent plus the team's agent:create permission.
The copy is always created with visibility: private and status: draft, and its name gets a " (Copy)" suffix. Publish it again before it can be used for chat. Tool credentials (tools_credentials) are not copied — tools in the copy need their keys reconfigured before they can call external services.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id | string | Yes | Agent UUID to duplicate |
Success Response (200 OK)
Returns the newly created AgentOut (status is draft):
{
"code": 0,
"data": {
"id": "new-agent-uuid",
"name": "Customer Support Agent (Copy)",
"status": "draft",
"visibility": "private"
},
"msg": "Agent duplicated successfully"
}Get Video Generation Status
GET /api/v1/agents/{agent_id}/media/video-status?task_id={task_id}Poll an asynchronous video generation task started by an agent; requires agent:read and access to the agent. The agent must have video generation enabled (enable_video_generation), otherwise the call returns 400 (code 1002, video_generation_not_enabled_for_agent).
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
task_id | string | Yes | Video generation task ID |
The response uses the same media.video shape as the chat media_result event, so clients can decide whether to keep polling:
{
"code": 0,
"data": {
"kind": "media.video",
"success": true,
"prompt": "",
"model": "veo-3",
"model_ref": "video-model-uuid",
"task_id": "video-task-uuid",
"status": "succeeded",
"progress": 100,
"video": {
"url": "/api/v1/upload/files/generated-videos/2026/09/9a8b7c6d5e4f_55667788.mp4",
"asset_ref": "a1b2",
"format": "mp4"
},
"estimated_time": null,
"requires_polling": false,
"poll_interval_ms": 3000,
"poll_timeout_s": 120,
"error": null
},
"msg": "success"
}| Field | Description |
|---|---|
status | Normalized task status; success is true only when the task has not failed and error is null. |
progress | Task progress percentage (null when the provider does not report one). |
video | The finished video object (url, asset_ref, format), or null while the task is still running. |
requires_polling | true while the task is queued/running — keep polling every poll_interval_ms. |
poll_interval_ms / poll_timeout_s | Taken from the agent's video_generation_config; default 3000 / 120. |
Fetch the protected video URL with the active JWT or API key.
Get Public Agent Info
GET /api/v1/agents/{agent_id}/publicReturns the public chat-page view: name, description, icon, opening message, suggested questions, variable definitions, and the attachment switch. The route is implemented in chat.py but mounted under /api/v1/agents, and it does not require agent:read.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id | string | Yes | Agent UUID |
Authentication behaviour
The route declares an optional-auth dependency, but the lookup still requires an authenticated identity (an unauthenticated caller gets 401 not_authenticated). Once authenticated, visibility is:
private: the creator, a superuser, or — for creator-less legacy rows — any member of the agent's team.team(including the legacy valuepublic): any member of the agent's team; superusers bypass the check.
Success Response (200 OK)
{
"code": 0,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Customer Support Agent",
"description": "Helps customers with common questions",
"icon": "🤖",
"avatar_url": "https://example.com/avatar.png",
"opening_message": "Hi! How can I help you today?",
"suggested_questions": ["What are your business hours?"],
"powered_by_text": null,
"variables": [],
"enable_attachments": false,
"attachment_config": null,
"hide_tool_calls": false,
"hide_message_actions": false,
"hide_reasoning": false,
"created_by": {
"id": "user-001",
"username": "alice",
"avatar_url": null
}
},
"msg": "success"
}Unlike GET /api/v1/agents/{agent_id}, this response never exposes the model, system prompt, tool configuration, or statistics fields.
| Error | Code | Description |
|---|---|---|
403 Forbidden | 6201 | The caller cannot see this agent |
404 Not Found | 6200 | Agent does not exist |
Chat (Non-Streaming)
POST /api/v1/agents/{agent_id}/chatSend a message to the agent and synchronously receive the complete response. Suitable for short responses; for long tasks, use the SSE streaming endpoint.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id | string | Yes | Agent UUID |
Request Body
{
"message": "What are your business hours?",
"conversation_id": "conv-123",
"file_urls": [
{
"asset_id": "asset-456",
"url": "https://your-domain.com/api/v1/upload/files/general/2026/09/7f3a1c9d2b10_a1b2c3d4.pdf",
"filename": "7f3a1c9d2b10_a1b2c3d4.pdf",
"size": 1048576,
"mime_type": "application/pdf"
}
],
"variables": {
"customer_tier": "premium"
}
}Submit url, filename, size, and mime_type exactly as returned by the upload response; do not construct /upload/files/{asset_id} from the asset ID. A generated media asset_ref is valid only within its conversation or workflow-run scope, and protected URLs require the active JWT or API key.
Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
message | string | Yes | User message (max 32000 chars) |
images | array | No | Vision images (asset_id or asset_ref, type, url) |
files | array | No | Parsed files (deprecated, use file_urls) |
file_urls | array | No | Asset metadata from the upload response (asset_id, filename, url, size, mime_type) |
conversation_id | string | No | Conversation UUID; creates a new one if not provided |
variables | object | No | Variable values for the chat input form |
history_override | array | No | Override conversation history (used for version switching/regeneration) |
Request Example
curl -X POST "https://your-domain.com/api/v1/agents/550e8400-e29b-41d4-a716-446655440000/chat" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"message": "What are your business hours?",
"conversation_id": "conv-123"
}'Success Response (200 OK)
{
"code": 0,
"data": {
"conversation_id": "conv-123",
"message": {
"id": "msg-456",
"conversation_id": "conv-123",
"role": "assistant",
"content": "Our business hours are Monday-Friday, 9 AM to 5 PM EST.",
"tool_calls": [],
"tool_name": null,
"model_used": "gpt-4",
"token_usage": {
"prompt": 150,
"completion": 25,
"total": 175
},
"duration_ms": 2300,
"rag_context": [
{
"document_id": "doc-789",
"document_name": "Business Hours Policy",
"chunk_id": "chunk-012",
"content": "Business hours: Monday-Friday, 9 AM to 5 PM EST",
"score": 0.95
}
],
"created_at": "2026-02-11T16:00:00Z",
"version_number": 1,
"version_count": 1
},
"usage": {
"prompt": 150,
"completion": 25,
"total": 175
}
},
"msg": "success"
}Chat (Streaming)
POST /api/v1/agents/{agent_id}/chat/streamReturn the response as a stream via SSE (Server-Sent Events). The request body is the same as the non-streaming endpoint; there is no stream flag parameter.
Request Example
curl -X POST "https://your-domain.com/api/v1/agents/550e8400-e29b-41d4-a716-446655440000/chat/stream" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"message": "What are your business hours?",
"conversation_id": "conv-123"
}'SSE Event Format
event: message_start
data: {"conversation_id": "conv-123", "message_id": "msg-456"}
event: content_delta
data: {"delta": "Our"}
event: content_delta
data: {"delta": " business"}
event: content_delta
data: {"delta": " hours"}
event: rag_context
data: {"contexts": [{"document_name": "FAQ", "content": "...", "score": 0.95}]}
event: message_end
data: {"usage": {"prompt_tokens": 150, "completion_tokens": 25, "total_tokens": 175}, "timing": {"first_token_ms": 320, "duration_ms": 2300, "tokens_per_second": 10.9}}| Event | Description |
|---|---|
message_start | Message started, returns conversation_id and message_id |
content_delta | Incremental text fragment |
rag_context | RAG retrieval context (document name, content, relevance score) |
message_end | Message ended, returns token usage and timing metrics |
SSE clients need to parse the event stream as text/event-stream. See SSE Streaming Events for details.
Regenerate
POST /api/v1/agents/{agent_id}/messages/{message_id}/regenerateRegenerate the response for a specified message. The request body structure is the same as the chat endpoint, and history_override can be used to adjust the historical context.
Edit Message and Create Branch
POST /api/v1/agents/{agent_id}/messages/{message_id}/edit/streamEdit a user message and generate a branch response, returned as an SSE stream.
Query Message Versions
GET /api/v1/agents/{agent_id}/messages/{message_id}/versionsQuery all versions of a specified message (including historical branches generated by regeneration and editing).
Switch Version
POST /api/v1/agents/{agent_id}/messages/{message_id}/switch-versionSwitch to a specified version as the currently active message.
Agent Conversations
These conversation endpoints are registered on the agents router, so the conversation segment resolves to /api/v1/agents/conversations/.... Every route is scoped to the authenticated user (Conversation.user): another user's conversation is treated as not found (404, code 6210).
A separate team/admin-oriented set of routes lives at /api/v1/conversations (GET list, GET detail, single/batch delete, statistics) — see Conversations API. This section covers only the caller's own conversations.
List Conversations for an Agent
GET /api/v1/agents/{agent_id}/conversationsReturns the caller's own conversations for one agent. Requires conversation:read and access to the agent (check_agent_access).
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
search | string | No | - | Match title or conversation ID (contains) |
created_after | string (ISO 8601) | No | - | Only conversations created at or after this time |
created_before | string (ISO 8601) | No | - | Only conversations created at or before this time |
sort_by | string | No | updated_at | Sort field: created_at, updated_at, message_count (any other value falls back to updated_at) |
page | integer | No | 1 | Page number (min 1) |
page_size | integer | No | 20 | Items per page (1-100) |
Results are ordered by the sort field descending and returned as a PageData[ConversationListOut] envelope (items, total, page, page_size), with agent_name/agent_icon filled in from the agent.
List My Conversations
GET /api/v1/agents/conversations/myReturns all of the caller's conversations across agents. Requires conversation:read.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
agent_id | string | No | - | Filter by agent UUID |
page | integer | No | 1 | Page number |
page_size | integer | No | 20 | Items per page |
The response is again a PageData[ConversationListOut] envelope; agent_name and agent_icon are null when the agent has been deleted.
Get Conversation
GET /api/v1/agents/conversations/{conversation_id}Returns the conversation together with its visible messages, each carrying version_count. Requires conversation:read, and only the owner can read it.
The response data is a ConversationWithMessages: the ConversationOut fields (id, agent_id, agent_name, agent_icon, title, variables, message_count, token_usage, created_at, updated_at) plus messages (a MessageOut[]; the message shape is documented in the Chat API).
Update Conversation
PATCH /api/v1/agents/conversations/{conversation_id}Rename a conversation. Requires conversation:read, and only the owner can update it.
{
"title": "Updated Conversation Title"
}| Field | Type | Required | Description |
|---|---|---|---|
title | string | No | New title (1-200 chars) |
Omitting title leaves the conversation unchanged; the success response has msg_key conversation_updated.
Delete Conversation
DELETE /api/v1/agents/conversations/{conversation_id}Permanently delete a conversation (messages cascade). Requires conversation:delete, and only the owner can delete it. The agent's conversation_count and message_count are decremented first.
{
"code": 0,
"data": {
"id": "conv-123"
},
"msg": "Conversation deleted successfully"
}Delete a Single Message
DELETE /api/v1/agents/conversations/{conversation_id}/messages/{message_id}Delete one message from a conversation. Requires conversation:delete, and the message must belong to the caller's conversation. The conversation's message_count and token_usage are updated in the same row-locked transaction that removes the message, so concurrent deletes cannot drift the counters.
| Error | Code | Description |
|---|---|---|
404 Not Found | 6210 | Conversation does not exist or is not owned by the caller |
404 Not Found | 6211 | Message does not exist or does not belong to that conversation |
{
"code": 0,
"data": {
"id": "msg-456"
},
"msg": "Message deleted successfully"
}Agent Statistics
GET /api/v1/agents/{agent_id}/statsQuery the usage statistics overview of an agent within a specified time range.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id | string | Yes | Agent UUID |
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
period | string | No | 7d | Time range: 24h, 7d, 30d, all |
Request Example
curl -X GET "https://your-domain.com/api/v1/agents/550e8400-e29b-41d4-a716-446655440000/stats?period=30d" \
-H "Authorization: Bearer YOUR_TOKEN"Success Response (200 OK)
{
"code": 0,
"data": {
"period": "30d",
"overview": {
"total_conversations": 156,
"total_messages": 1234,
"user_messages": 620,
"assistant_messages": 610,
"tool_messages": 4,
"active_users": 23
},
"tokens": {
"prompt_tokens": 250000,
"completion_tokens": 206789,
"total_tokens": 456789
},
"performance": {
"avg_response_time_ms": 2300,
"first_token_ms": {
"p50": 1200,
"p95": 9000,
"avg": 2500,
"samples": 480
}
},
"tools": {
"tool_call_count": 512
},
"health": {
"completed": 90,
"failed": 6,
"stopped": 4,
"interrupted": 3,
"unrecognised": 0,
"in_flight": 2,
"total": 103,
"success_rate": 0.8738
},
"interventions": {
"steer": 12,
"stop": 3,
"follow_up": 5,
"total": 20
}
},
"msg": "success"
}health counts this agent's runs by outcome:
| Field | Meaning |
|---|---|
completed / failed / stopped | Runs that reached that terminal state. |
interrupted | Terminal. The worker executing the run was lost (crash, restart, eviction), so the run never reached completion. Counts toward total and lowers success_rate. |
unrecognised | A stored status this build does not know (typically written by a different release). Reported separately so enum drift stays visible instead of being folded into a known bucket or failing the request. |
in_flight | Non-terminal runs (queued, running, stopping, completing, waiting). Excluded from total and from the success_rate denominator. |
total | Terminal runs only: completed + failed + stopped + interrupted. |
success_rate | completed / total, or 0 when there are no terminal runs. |
Trend Data
GET /api/v1/agents/{agent_id}/stats/trendsReturns a clock-aligned point grid: 24 points for 24h, 7 for 7d, 30 for 30d. Missing buckets are filled with 0.
{
"code": 0,
"data": {
"period": "24h",
"granularity": "hour",
"data": [
{
"timestamp": "2026-09-13T13:00:00+08:00",
"label": "13:00",
"conversations": 12,
"messages": 87,
"tokens": 32100,
"avg_response_time_ms": 2150.5,
"first_token_p50_ms": 1180.0,
"first_token_p95_ms": 8700.0
}
]
},
"msg": "success"
}first_token_p50_ms and first_token_p95_ms are null for a bucket with no measured sample, so the latency line breaks instead of dropping to 0; clients must handle null.
Tool Usage
GET /api/v1/agents/{agent_id}/stats/tool-usagetools[].name is the internal tool identifier and display_name is the localized label (MCP tools render as a server prefix plus the tool name). Tools are sorted by call count descending, and total_calls sums every call.
{
"code": 0,
"data": {
"period": "7d",
"tools": [
{
"name": "web_search",
"display_name": "Web Search",
"count": 312
}
],
"total_calls": 512
},
"msg": "success"
}This endpoint deliberately disables MCP enumeration (enumerate_mcp_tools=False), so a statistics request never makes a network call to an external MCP server. MCP tool labels therefore use the known server prefix rather than a live tool list.
Other Statistics Endpoints
Both supplemental statistics endpoints require the /api/v1 prefix, a valid JWT current user, and pass through check_agent_access:
| Endpoint | Description | Parameters |
|---|---|---|
GET /api/v1/agents/{agent_id}/stats/trends | Trend data | period: 24h/7d/30d |
GET /api/v1/agents/{agent_id}/stats/tool-usage | Tool usage statistics | period: 24h/7d/30d/all |
Period boundary behaviour: for the overview and tool-usage endpoints any value other than 24h, 7d, or 30d is treated as all; the trends endpoint treats anything other than 24h or 7d as 30d.
Access control: the statistics endpoints call check_agent_access(..., require_write=True) — superusers are allowed; a private agent is readable only by its creator (creator-less legacy agents fall back to team scope and additionally require a team admin); team/public agents require team access, and a non-creator must be a team admin. In other words, agent statistics are an admin/monitoring view; an ordinary team member cannot read them. Denied requests return 403, missing resources 404.
Access Boundaries
- The agent must be in
publishedstatus to be used for chat. - The API Key must have the corresponding permissions; if the API Key is bound to a specific agent, it can only access agent IDs in the allowlist.
- The agent's attachment limits, tool iteration caps, and model quotas still apply during API calls.
Error Codes
| Code | Message | Description |
|---|---|---|
6200 | Agent not found | Agent does not exist |
6201 | Access denied | Current user does not have access to the agent |
6202 | Agent not published | Agent is in draft status |
3000 | Permission denied | Insufficient permissions |
1001 | Validation failed | Invalid request data |
5104 | Duplicate name | Agent name is already taken |
The current endpoints do not implement individual rate limiting; there is no rate-limit middleware.
Related Documentation
- API Get Started — Create an API Key, configure the base URL, and send your first request
- Agent Chat — Send messages, attachments, variables, and consume streaming responses
- SSE Streaming Events — Parse SSE events for agents and workflows
- Error Handling — Recover by HTTP status and business error codes
How is this guide?