Skip to main content
Trinity
API Reference

Chat API

API endpoints for agent chat, voice, streaming, and public chat access. All endpoints require JWT Bearer token unless noted. See Authentication for details.

Full interactive API docs are available at http://localhost:8000/docs when running locally.

Authenticated Chat

POST

/api/agents/:name/chat

Send a message to an agent. Returns stream-json output for real-time responses. Accepts files attachments (see File attachments).

curl -X POST -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"message": "Summarize the latest research findings"}' \
  http://localhost:8000/api/agents/research-agent/chat
GET

/api/agents/:name/chat/sessions

List all chat sessions for an agent.

GET

/api/agents/:name/chat/sessions/:id

Get a specific session with all its messages.

POST

/api/agents/:name/chat/sessions/:id/close

Close a chat session.

GET

/api/agents/:name/chat/history/persistent

Get persistent chat history across sessions.

DELETE

/api/agents/:name/chat/history

Reset the current chat session.

GET

/api/agents/:name/activity

Get an activity summary for the agent.

Voice Chat

POST

/api/enterprise/client-portal/agents/:name/voice/start

Start a Workspace voice call bound to a chat (portal_session_id); 409 while a reply is in flight.

POST

/api/agents/:name/voice/start

Start a per-agent voice session (retained for API clients; the UI starts calls in the Workspace).

POST

/api/agents/:name/voice/stop

Stop a voice chat session.

GET

/api/agents/:name/voice/status

Get the current voice session status.

WS

/ws/voice/:session_id

WebSocket endpoint for bidirectional audio streaming. Used as the audio bridge for voice chat — the URL is returned by voice/start.

The per-agent voice prompt, voice name and canvas panel routes are listed in Voice Chat.

Public Chat (No Auth)

Public chat endpoints do not require authentication. They use a unique token to identify the public chat session.

POST

/api/public/chat/:token

Send a message via public chat using a share token.

GET

/api/public/history/:token

Get chat history for a public chat session.

GET

/api/public/executions/:token/:execution_id/status

Status of a turn started from this link.

GET

/api/public/executions/:token/:execution_id/stream

Live activity for that turn (SSE).

POST

/api/public/executions/:token/:execution_id/terminate

Stop a turn started from this link. Scoped per link and per trigger: it stops only turns this public link started — never a scheduled run, an operator chat, or a Workspace turn on the same agent. A link with email verification requires the same session_token that started the turn.

GET

/api/public/canvas/:token

Resolve a canvas share link (the page at /canvas/s/:token). A public share renders with no credential; an authorized share answers 401 until the viewer signs in and is re-checked against the agent's access list. Unknown, revoked and expired tokens are told apart only where the holder already knew the canvas existed. See Agent Canvas.

Paid Chat (x402)

Paid chat endpoints use the x402 payment protocol. Clients receive a 402 response with payment requirements, then resubmit with a payment proof header.

POST

/api/paid/:agent_name/chat

Send a paid chat message. Returns 402 with payment requirements or 200 with the response.

GET

/api/paid/:agent_name/info

Get payment requirements and pricing info for an agent.

Task Execution

POST

/api/agents/:name/task

Submit a stateless task. async_mode: true returns at once with status: "accepted" and an execution_id; otherwise the call holds until the task finishes (see below). Accepts files attachments.

curl -X POST -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"message": "Generate a report on Q1 sales data"}' \
  http://localhost:8000/api/agents/research-agent/task
GET

/api/agents/:name/executions

List all executions (tasks and schedule runs) for an agent.

GET

/api/agents/:name/executions/:id

Execution details (status, response, cost) — the polling target for async_mode and for a receipt.

GET

/api/agents/:name/executions/:id/log

Full execution transcript (tool calls and results).

GET

/api/agents/:name/executions/:id/stream

Live execution log (SSE) while it runs.

GET

/api/agents/:name/executions/running

Executions currently running on the agent.

POST

/api/agents/:name/executions/:id/terminate

Stop a running or queued execution. Answers terminated, cancelled_while_queued, cancelled_while_parked, or already_finished; a stopped run ends as cancelled, not failed.

POST

/api/agents/:name/fan-out

Dispatch N tasks in parallel — see Fan-Out.

GET

/api/agents/:name/fan-out/:fan_out_id

Poll a fan-out batch while it runs — see Fan-Out → Polling a batch.

Sync task calls and the execution_id receipt

A synchronous /task call (the default, async_mode: false) holds the HTTP connection for the whole run — at capacity it queues on the same connection and long-polls until the execution reaches a terminal state. The MCP chat_with_agent(parallel=true) tool wraps this route and gives up before the MCP gateway does, answering with {status: "queued_timeout", execution_id} so you poll GET /api/agents/{name}/executions/{id} instead of re-sending — see MCP Integration. If you know the task will run long, send async_mode: true from the start.

A sync /task that fails, times out, or is cancelled releases its Idempotency-Key claim, so a legitimate retry with the same key goes through instead of answering 409 for the rest of the day; a call whose long-poll timed out while the execution was still queued or running completes the claim with the same queued_timeout receipt, so a replay answers 200 with the execution to poll.

File attachments

POST /chat and POST /task accept a files array of {name, mimetype, size, data_base64} (raw base64 or a data: URI). Images are passed to the agent as vision content; other files land in /home/developer/uploads/ inside the container. Accepted: images, plain text, CSV, JSON, and ZIP (stored unextracted — the agent unpacks it itself). Rejected: PDF, tar/gzip/rar, audio, video. Web limits: 3 files per message, 5 MB per file, 10 MB of images in total.

Model override

POST /chat, POST /task, and POST /api/agents/{name}/sessions/{id}/message (see Agent Sessions) accept an optional model. The value is checked before anything is dispatched:

  • Empty, whitespace, or omitted means the agent's default model.
  • Otherwise it must start with a known model family, ignoring case: a short alias (sonnet, opus, haiku, fable) or a full id (claude-…, gemini-…, gpt-…, codex…). Suffixes such as [1m] are kept.
  • Anything else is refused with 422, and the error names the value: '<value>' is not a model id. Use a short alias (sonnet, opus, haiku, fable) or a full id such as '…'.

A refused request starts no execution. It does not use up its Idempotency-Key, and a refused session turn leaves no unanswered message in the session. The check is on the shape only: an id with a valid prefix that the provider does not serve still fails when the run starts.

Deprecated: per-task timeout_seconds

The timeout_seconds field on the task request body is deprecatedand will be removed in a future release. The agent's execution timeout (GET/PUT /api/agents/{name}/timeout) is authoritative.

Current behavior: the field is still honored, but values above the agent's timeout cap are clamped down to the cap (the server logs a deprecation warning). Omit the field — the task then uses the agent's configured timeout. To run longer tasks, raise the agent's timeout cap instead.

Idempotency

Endpoints that trigger an execution accept an optional Idempotency-Key header so you can retry safely without creating duplicate executions. Pick any unique string per logical request (e.g., a UUID) and resend it on retry:

curl -X POST http://localhost:8000/api/agents/my-agent/task \
  -H "Authorization: Bearer <token>" \
  -H "Idempotency-Key: 7f3a2c1e-..." \
  -H "Content-Type: application/json" \
  -d '{"message": "Summarize the latest reports"}'
  • The same key within 24 hours returns the original result with the header X-Idempotent-Replay: true — no second execution is created.
  • A duplicate sent while the first request is still running returns 409 with the original execution_id to poll (for /fan-out, that field carries the batch's fan_out_id).
  • If the first attempt was rejected before dispatch (e.g., at capacity), the key is released so the retry goes through.
  • The header is optional and fail-open: omitting it preserves normal behavior, and a dedup-layer error never blocks a real request.

Wired boundaries: /api/agents/{name}/chat, /api/agents/{name}/task, /api/agents/{name}/fan-out, /api/agents/{name}/voip/call, webhook triggers (key auto-derived from token + body when the header is absent), and the MCP chat_with_agent / fan_out tools (deterministic key derived from the call arguments).

Endpoint Summary

EndpointMethodDescription
/api/agents/{name}/chatPOSTSend message (stream-json output); accepts files attachments
/api/agents/{name}/chat/sessionsGETList sessions
/api/agents/{name}/chat/sessions/{id}GETSession with messages
/api/agents/{name}/chat/sessions/{id}/closePOSTClose session
/api/agents/{name}/chat/history/persistentGETPersistent history
/api/agents/{name}/chat/historyDELETEReset session
/api/agents/{name}/activityGETActivity summary
/api/enterprise/client-portal/agents/{name}/voice/startPOSTStart a Workspace voice call bound to a chat
/api/agents/{name}/voice/startPOSTStart a per-agent voice session
/api/agents/{name}/voice/stopPOSTStop session
/api/agents/{name}/voice/statusGETSession status
/ws/voice/{session_id}WSAudio WebSocket bridge (URL returned by voice/start)
/api/public/chat/{token}POSTPublic chat
/api/public/history/{token}GETPublic history
/api/public/executions/{token}/{execution_id}/statusGETStatus of a turn started from this link
/api/public/executions/{token}/{execution_id}/streamGETLive activity for that turn (SSE)
/api/public/executions/{token}/{execution_id}/terminatePOSTStop a turn started from this link (scoped per link and per trigger)
/api/public/canvas/{token}GETResolve a canvas share link
/api/paid/{agent_name}/chatPOSTPaid chat (402/200)
/api/paid/{agent_name}/infoGETPayment requirements
/api/agents/{name}/taskPOSTSubmit a stateless task (async_mode: true returns an execution_id at once; otherwise holds until done); accepts files
/api/agents/{name}/executionsGETList executions
/api/agents/{name}/executions/{id}GETExecution details (status, response, cost) — polling target for async_mode and receipts
/api/agents/{name}/executions/{id}/logGETFull execution transcript (tool calls and results)
/api/agents/{name}/executions/{id}/streamGETLive execution log (SSE) while it runs
/api/agents/{name}/executions/runningGETExecutions currently running on the agent
/api/agents/{name}/executions/{id}/terminatePOSTStop a running or queued execution (ends as cancelled, not failed)
/api/agents/{name}/fan-outPOSTDispatch N tasks in parallel
/api/agents/{name}/fan-out/{fan_out_id}GETPoll a fan-out batch while it runs