Skip to Content

Run Endpoint

Overview

POST /api/agents/{agentId}/run is the single HTTP entry point for invoking an agent. It supports three execution modes: persisted chat (server-managed history), stateless chat (client-managed history), and prompt-only execution (template variables with no user turn).

PropertyValue
MethodPOST
Endpoint/api/agents/{agentId}/run
AuthenticationAuthorization (user JWT) or cf-api-key

Use the Accept header to choose how the response is delivered. Set request body fields (message, messages, or vars) to select an execution mode. See Execution Modes for details.

API Contract

Headers

HeaderRequiredDescription
Content-TypeYesapplication/json, or multipart/form-data for file uploads
AcceptNoapplication/json (default) or text/event-stream
Authorization or cf-api-keyYesSee Authentication
Accept headerResponse
text/event-streamSSE stream (AI SDK UI Message Stream )
application/json (default)Single JSON object { text, usage, finishReason, conversationId }

Mode 1 responses may include X-Conversation-Id when a new conversation is created.

Authentication

Authorization: Bearer <supabase_jwt>

Use for platform users with an active Supabase session.

Optional Headers

Pass 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, and content-length are removed before forwarding.

Request Body

FieldTypeModesDescription
messageUIMessage1Latest user turn (server-managed history)
messagesUIMessage[]2Full client-owned transcript
conversationIdstring1Conversation UUID; omit on first turn
varsRecord<string, any>1, 2, 3Template variables for the agent prompt

Response

JSON (Accept: application/json)

FieldTypeDescription
textstringGenerated output
usageobjectToken usage
finishReasonstringWhy generation stopped
conversationIdstring | nullSet when Mode 1 persistence is active
{ "text": "Generated output from the agent", "usage": { "inputTokens": 123, "outputTokens": 456, "totalTokens": 579 }, "finishReason": "stop", "conversationId": "550e8400-e29b-41d4-a716-446655440000" }

Streaming (Accept: text/event-stream)

Returns an AI SDK UI Message Stream  over SSE. Do not call response.json(); consume the stream incrementally.

Error Responses

StatusResponse
400{ "error": "Agent is not active" }
400{ "error": "Provide either \"message\" or \"messages\", not both" }
400{ "error": "No valid messages to process" }
401{ "error": "Unauthorized" }
403{ "error": "Forbidden" }
404{ "error": "Agent not found" }
500{ "error": "Internal server error" }

UIMessage Format

Structured messages follow the AI SDK UIMessage type, the same model used by useChat and the platform dashboard.

{ "id": "msg-1", "role": "user", "parts": [ { "type": "text", "text": "Hello" } ] }
Part typePurposeReference
textUser or assistant textTextUIPart
fileImage, PDF, or document attachmentFileUIPart

Assistant messages may also include tool-*, reasoning, and other part types when consuming streaming responses.

Execution Modes

Every request uses one of three execution modes. The mode is determined by which body fields you send, not by a separate mode flag.

Mode 1: Persisted (server-managed history)

Send the latest user turn only. Chocolate Factory loads prior turns from the database when conversationId is set, persists new messages, and returns X-Conversation-Id on the first turn.

FieldValue
messageLatest UIMessage
conversationIdOptional UUID. Omit on the first turn
Accepttext/event-stream (chat UI) or application/json

First turn

POST /api/agents/{agentId}/run Accept: text/event-stream Content-Type: application/json cf-api-key: YOUR_API_KEY
{ "message": { "role": "user", "parts": [{ "type": "text", "text": "Hello" }] } }

Read X-Conversation-Id from the response headers and send it on subsequent turns:

{ "conversationId": "550e8400-e29b-41d4-a716-446655440000", "message": { "role": "user", "parts": [{ "type": "text", "text": "What did I just say?" }] } }

Retrieve stored history later with GET /api/agents/{agentId}/conversations/{conversationId}.

Mode 2: Stateless (client-managed history)

Send the full transcript on every request. Nothing is stored server-side. Use this when your application owns conversation state.

FieldValue
messagesComplete UIMessage[] array
AcceptUsually text/event-stream
{ "messages": [ { "role": "user", "parts": [{ "type": "text", "text": "Hello" }] }, { "role": "assistant", "parts": [{ "type": "text", "text": "Hi! How can I help?" }] }, { "role": "user", "parts": [{ "type": "text", "text": "Summarize our chat so far." }] } ] }

Provide either message (Mode 1) or messages (Mode 2), never both.

Mode 3: Prompt-only (template execution)

Run the agent from its system prompt and template variables with no user turn. Typically used with Accept: application/json for forms, content generation, and backend jobs.

FieldValue
varsTemplate variables referenced by the agent prompt
Acceptapplication/json
{ "vars": { "title": "AI in logistics", "tone": "professional", "keywords": "automation, supply chain, forecasting" } }

You can combine vars with Mode 1 or Mode 2 when the agent prompt references runtime variables alongside user input.

File Attachments

Attach files by including FileUIPart entries in the parts array of your message or the last item in messages.

FileUIPart shape

{ "type": "file", "url": "https://example.com/report.pdf", "filename": "report.pdf", "mediaType": "application/pdf" }
  • url: HTTPS URL to a hosted file, or a data: URL (base64-encoded). Hosted URLs are passed through; data URLs are uploaded server-side automatically.
  • filename: Original file name (recommended).
  • mediaType: IANA media type (e.g. image/png, application/pdf).

Supported types

CategoryTypes
ImagesJPEG, PNG, GIF, WebP
DocumentsPDF, TXT, MD, DOCX, XLSX, XLS

Maximum size: 25 MB per file.

{ "message": { "role": "user", "parts": [ { "type": "text", "text": "Summarize this PDF" }, { "type": "file", "url": "https://example.com/report.pdf", "filename": "report.pdf", "mediaType": "application/pdf" } ] } }

Integration Examples

Server-managed history. Send only the latest turn. Read X-Conversation-Id from the response headers on the first turn and reuse it on subsequent requests.

const response = await fetch(`/api/agents/${agentId}/run`, { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json", "cf-api-key": "YOUR_API_KEY", }, body: JSON.stringify({ conversationId: "550e8400-e29b-41d4-a716-446655440000", message: { role: "user", parts: [{ type: "text", text: "Write a product announcement email" }], }, vars: { productName: "Chocolate Factory AI", audience: "existing customers", }, }), }); const data = await response.json(); console.log(data.text);

Best Practices

  • Mode 1 (persisted): chat widgets and platform-style UIs where Chocolate Factory should own history.
  • Mode 2 (stateless): integrations that already store transcripts externally.
  • Mode 3 (prompt-only): forms, batch jobs, and template-driven generation with Accept: application/json.
  • Reuse conversationId across turns in Mode 1.
  • Attach files as FileUIPart (type: "file"). See UIMessage docs .
  • Use x-agent-payload when MCP tools need extra HTTP headers.
  • Inspect usage to monitor token consumption.
Last updated on