Skip to main content
POST
Start a new run on the conversation

Authorizations

Authorization
string
header
required

Bearer authentication header of the form Bearer <token>, where <token> is your auth token.

Path Parameters

id
string<uuid>
required

The conversation's UUID. UUID identifying a conversation. Returned from POST /agents/conversations and used in every other agent endpoint that operates on this conversation.

Example:

"bc2505b7-068d-44ed-8055-a6f6ffe54ab1"

Body

application/json

Start a new run on the conversation.

Required fields:

  • client_op_id — your-generated UUID for idempotency.
  • expected_version — the conversation's current version, read just before this call. Triggers a 409 Version Conflict if the version moved.
  • payload — the run's input.

Optional fields:

  • tool_choice — biases tool selection on iteration 1 of this run only.
  • config_override — sparse override of the conversation's defaults for this run.
client_op_id
string<uuid>
required

A UUID you generate for each POST .../runs call. Acts as an idempotency key: re-sending the same client_op_id returns the original run row unchanged. This lets you retry network blips, request timeouts, etc. without accidentally starting a second workflow.

Scope: (company_id, user_id, client_op_id) is the uniqueness key. One client_op_id means one run for you, on whichever conversation it first landed — posting it again against a different conversation returns that first run rather than starting a new one.

Example:

"696b022c-e86d-4b3e-b6d7-ceb7eb1a495e"

expected_version
integer
required

Monotonic per-conversation counter, bumped by 1 (or more) every time a successful run appends messages. Two roles:

  1. Delta cursor for GET .../messages?since=N — fetch only messages with sequence_no > N.
  2. Compare-and-swap token for POST .../runs — set expected_version to the conversation's current head; if it doesn't match at run-creation time, you get a Version Conflict (HTTP 409).

Always start a new run cycle by reading the current version from GET /agents/conversations/{id} rather than caching a value from earlier.

Required range: x >= 0
Example:

4

payload
object
required

The run's input. Discriminated by kind:

  • user_message — fresh user turn.
  • tool_outputs — resuming a paused run with the tool answers.
tool_choice
Auto · object

Per-run policy that biases the model toward (or away from) using tools on the first iteration of the run. From iteration 2 onward the model is back on {"kind": "auto"} regardless.

Per-run, not per-conversation: every new run picks its own tool_choice. To re-force a particular tool on every follow-up run (for example, always asking the user for confirmation), set it on each POST .../runs body.

Three shapes, discriminated by kind:

Example:
config_override
object | null

Sparse override applied to a single run. Any field set here replaces the corresponding defaults field for that run only. Fields not set inherit from defaults.

Two list fields (mcp_servers, tools) replace the whole list when set, not merge — if you provide them in the override, the conversation defaults' lists are ignored entirely for that run.

Every field may also be sent as null, which means the same as leaving it out: the run inherits the conversation's value. A null cannot clear a default.

system_prompt is not in this object — it's pinned at conversation creation and cannot be overridden.

Response

Run accepted; workflow is starting. Body carries the run row, initially with status: "pending". Poll GET /agents/runs/{id} for terminal state.

An idempotent retry (a client_op_id posted before) also gets a 202, carrying the original run, which may have moved past pending.

Run state as returned by POST /agents/conversations/{id}/runs (Accepted, 202) and GET /agents/runs/{id} (OK, 200). Which optional fields are populated depends on status:

  • completed → iterations_used, usage, submitted_inference_job_ids, and exactly one of final_text / final_structured_output. The two are mutually exclusive: text-mode runs (no output_format_schema supplied) populate final_text; structured-mode runs populate final_structured_output with the caller-schema-conforming JSON.
  • requires_action → pending_tool_calls, iterations_used, usage, submitted_inference_job_ids.
  • failed → error, possibly partial iterations_used/usage/submitted_inference_job_ids.
  • pending / running → only the at-creation fields (id, conversation_id, started_at, etc.) plus submitted_inference_job_ids if any iterations have started.
id
string<uuid>
required

UUID identifying a single run. Returned by POST /agents/conversations/{id}/runs and used in GET /agents/runs/{id} to poll progress.

Example:

"82eb9cb7-619e-46bb-ac1c-8a32b0112c1c"

conversation_id
string<uuid>
required

UUID identifying a conversation. Returned from POST /agents/conversations and used in every other agent endpoint that operates on this conversation.

Example:

"bc2505b7-068d-44ed-8055-a6f6ffe54ab1"

company_id
integer
required
Example:

1

user_id
integer
required
Example:

407

client_op_id
string<uuid>
required

A UUID you generate for each POST .../runs call. Acts as an idempotency key: re-sending the same client_op_id returns the original run row unchanged. This lets you retry network blips, request timeouts, etc. without accidentally starting a second workflow.

Scope: (company_id, user_id, client_op_id) is the uniqueness key. One client_op_id means one run for you, on whichever conversation it first landed — posting it again against a different conversation returns that first run rather than starting a new one.

Example:

"696b022c-e86d-4b3e-b6d7-ceb7eb1a495e"

status
enum<string>
required

Where the run is in its lifecycle. Three terminal states (completed, requires_action, failed) — you stop polling when you see any of them. The two in-flight states (pending, running) mean "keep polling."

  • pending — run row inserted by the API but the workflow hasn't picked it up yet. Usually < 1 second; if a run stays here for tens of seconds the workflow workers may be down.
  • running — workflow is mid-execution. One "running" you see roughly corresponds to one inference iteration; you might cycle through this state several times for a multi-iteration tool-use loop.
  • completed — model produced a final answer. Exactly one of final_text / final_structured_output is populated depending on whether the caller supplied an output_format_schema on the conversation defaults or run override.
  • requires_action — model called a client-side tool. pending_tool_calls is populated; resume by posting a new run with payload.kind: tool_outputs.
  • failed — non-recoverable error. error.type, error.message, error.title, error.docs_url are populated. See the error catalog for the per-type meaning. A run that was deliberately cancelled also lands here, tagged with error.type: AgentLoopCancelled so it is distinguishable from a genuine failure.
Available options:
pending,
running,
completed,
requires_action,
failed
effective_config
object
required

The fully-merged config that was used to run this turn — conversation defaults with config_override applied. Echoed back so you can see exactly what the model saw, especially helpful when debugging unexpected behavior caused by overrides.

submitted_inference_job_ids
string<uuid>[]
required

Inference job IDs (one per iteration) for cross-system tracing. Each ID is a row in the platform's jobs table — use it to pull the raw model request/response if you need to debug a specific iteration.

pending_tool_calls
object[]
required

Tool calls the run is waiting for the caller to answer. Empty unless status is requires_action.

started_at
string<date-time>
required
Example:

"2026-05-18T13:21:30.355180Z"

live
object
required

The conversation's current, still-mutating state (e.g. its auto-generated name). Populated on every read, independent of status.

tool_choice
Auto · object

The tool_choice the run was started with, or null if it had none.

Example:
iterations_used
integer | null

Number of inference iterations this run completed. Populated on terminal states. Equal to submitted_inference_job_ids.length for the same run.

Required range: x >= 0
Example:

6

usage
object | null

Token usage totals across every inference iteration in this run. Used for billing and capacity planning. Note that prompt_tokens grows with each iteration because each round re-sends the full conversation history to the model.

final_text
string | null

The model's final answer in plain text. Populated on status: completed when the caller did NOT supply an output_format_schema (text mode). Mutually exclusive with final_structured_output.

final_structured_output
any

The model's final answer as a JSON object conforming to the caller's output_format_schema. Populated on status: completed when the caller supplied an output_format_schema on the conversation defaults or run override (structured mode). The shape is the caller's schema verbatim — no top-level text field is required or implied. Mutually exclusive with final_text.

error
object | null

Populated only on status: failed.

completed_at
string<date-time> | null

When the run reached a terminal status. Null while in pending or running.