Cumulus TalosDocs
Open Talos
On this page

Runs

A run executes one publication once: a cloud task or chat, or a phone call. Start it with one request, follow its events live, and read its transcript, recording, analysis, effects and cost when it ends.

Start a run

POST /api/v1/runs (member or admin key, Idempotency-Key required) admits a run and answers 201 with it at once. It runs the agent's head unless you name a version, and keeps that version and its digest for its whole life. metadata (string values) is stored with the run and never changes.

ChannelBodyWhat happens
cloud · task{ channel: "cloud", agent_id, mode: "task", input }The input is checked against the publication's input schema, becomes the agent's variables and its one user turn. The run ends with a result validated against the output schema.
cloud · chat{ channel: "cloud", agent_id, mode: "chat", input }A conversation: send each user turn with POST …/messages. It ends at the agent's end node, its turn limit or its idle timeout.
phone{ channel: "phone", agent_id, to, from?, dynamic_variables }An outbound call from one of your numbers. See Phone.

A chat run

Example
# Start a chat run: input fills variables; the conversation happens in messages.
POST /api/v1/runs
{ "channel": "cloud", "agent_id": "…", "mode": "chat", "input": { "customer_name": "Ada" } }

# Send the user's turn (Idempotency-Key required). 202: { "run_id": "…", "index": 0 }
POST /api/v1/runs/{run_id}/messages
{ "text": "Where is my order?" }

# The agent's reply arrives as a run.message event on GET /api/v1/runs/{run_id}/events.

Step-by-step samples in curl, TypeScript and Python are in Using the API.

Dynamic variables

An agent's prompts, transitions, transfer numbers and voicemail message can use {{variables}}, such as {{debtorName}}. A phone run fills them from dynamic_variables (string values), and so does a browser test (POST /api/v1/test-sessions). A chat test of a phone agent (mode: "chat", test: true) fills them from input. Every name the agent uses must have a value when the run starts. It can come from:

  • the run's dynamic_variables (or input, for a chat test);
  • the flow's own defaults (defaultDynamicVariables);
  • a value the call produces itself: an extract_dynamic_variables node or a tool's response;
  • the runtime: tenant_id, call_id, workflow_id, agent_id and system.channel.

If any name is left without a value, the run is refused before it dials. You get 400 invalid_request with details.reason: "missing_dynamic_variables", and the message names every missing variable at once. No run is created, so fix the body and send it again with a new Idempotency-Key.

curl -sS -X POST https://api.cumuluslabs.io/api/v1/runs \
  -H "Authorization: Bearer $CUMULUS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d "$(jq -n --arg agent "$PHONE_AGENT_ID" \
        '{channel: "phone", agent_id: $agent, to: "+14155550123", from: "+14155550100", dynamic_variables: {}}')" \
  | jq '.error // {run_id, state}'
# 400, and no run is created:
# { "code": "invalid_request", "retryable": false, "outcome": "none",
#   "message": "Flow references dynamic variables that were not supplied: agencyName, debtorName",
#   "details": { "reason": "missing_dynamic_variables" } }

To see what an agent needs before you call, read the flow of its head publication. It is in GET /api/v1/agents/{agent_id}/publications/{version}, under plan.flow. This recipe lists the names it references, minus the ones it provides itself:

VERSION=$(curl -sS "https://api.cumuluslabs.io/api/v1/agents/$PHONE_AGENT_ID" \
  -H "Authorization: Bearer $CUMULUS_API_KEY" | jq -r .head.version)
curl -sS "https://api.cumuluslabs.io/api/v1/agents/$PHONE_AGENT_ID/publications/$VERSION" \
  -H "Authorization: Bearer $CUMULUS_API_KEY" \
  | jq -r '.plan.flow as $flow
      | ([$flow | .. | strings | scan("\{\{\\s*([^{}]+?)\\s*\}\}")[0]] | unique)
        - ($flow.defaultDynamicVariables | keys)
        - [$flow | .. | objects | select(.kind? == "extract_dynamic_variables") | .variables[]?.name]
        - [$flow | .. | objects | (.responseVariables? // {}) | keys[]]
        - ["tenant_id", "call_id", "workflow_id", "agent_id", "system.channel"]
      | .[]'

The recipe also counts names that only appear in tool URLs, so it can list more than the API requires, never fewer. Publishing a new version can change the list. During a call, PATCH /api/v1/runs/{run_id} can add or change variables.

Test runs

"test": true marks a run as a test. It runs exactly like a live one, on the same numbers and capacity, but no customer webhook or event trigger ever sees it and its usage is not billed. Talos's tests are test runs. List them apart with GET /api/v1/runs?test=true (or false).

A test phone run still places a real call

Use a number you control as to while you test.

Lifecycle

state is the same on every channel: admitted, running, ending, completed, failed, cancelled, rejected, expired. A phone run also has phone_state for the call itself. When a run ends, outcome says how on four axes: transport (did the call connect), execution (did the agent finish), contact (human, voicemail or IVR) and the business result; disposition is the analysis verdict.

  • POST …/cancel ends an active run and returns 202 with the run. A live call is hung up at once and the run becomes cancelled when the call has ended. Repeating the request is safe.
  • PATCH /api/v1/runs/{run_id} changes a live phone call's dynamic variables or metadata and returns a receipt: 202 while it is applied, 200 once settled.
  • GET /api/v1/runs filters by agent_id, channel, state, time (after, before), disposition, contact, successful, version and test.

Events

Every run writes an ordered log of what it did: admitted, state changes, each node entered, a chat's messages, each action it took for you (a dial, a transfer, an HTTP action) when it settled, recording and analysis updates, and ended. GET /api/v1/runs/{run_id}/events returns them as a JSON page or streams them live (format and resume); add ?progress=live to a stream to also hear a call's transcript grow and each action's attempts land. Messages carry a reference to their content; read the words with the transcript, and every action's steps and receipts with GET …/effects.

What a run produced

ReadReturns
GET …/resultA cloud task's output object (state pending, ready, none or expired).
GET …/transcriptEvery turn with its role and text; for calls, timing and interruptions.
GET …/recordingPhone and browser runs: a URL to the recording that expires after five minutes.
GET …/analysisPost-run analysis: disposition, whether it succeeded and the fields the agent extracts.
GET …/effectsEach action the run took, its authorization decision and its receipts.
GET …/usageWhat the run metered and cost.

Capacity

Each channel has a limit of concurrent runs for your organization. GET /api/v1/runs/capacity returns each channel's limit and active runs. A run beyond the limit is refused with 429 rate_limited and details.reason: "capacity_exhausted"; nothing is created, so retry later with the same key.

Operations

OperationMCP toolKey rolePurpose
POST /api/v1/runsruns_creatememberAdmit a cloud or phone run of a publication (201; an idempotent replay returns 200)
GET /api/v1/runsruns_listviewerList runs
GET /api/v1/runs/capacityruns_capacityviewerRead admission capacity per channel: configured limit and runs holding it
GET /api/v1/runs/{run_id}runs_getviewerGet one run
PATCH /api/v1/runs/{run_id}runs_updatememberUpdate a live phone run's dynamic variables or metadata; returns a durable receipt (202 while pending, 200 once settled)
GET /api/v1/runs/{run_id}/updates/{update_id}runs_update_getviewerRead a live update's receipt
POST /api/v1/runs/{run_id}/cancelruns_cancelmemberCancel an active run (accepted: a live call settles cancelled when its media session ends)
POST /api/v1/runs/{run_id}/messagesruns_send_messagememberSend a user message to a cloud chat run
GET /api/v1/runs/{run_id}/eventsruns_eventsviewerRead the run's semantic events (JSON page or text/event-stream)
GET /api/v1/runs/{run_id}/effectsruns_effectsviewerRead the run's governed effects and receipts
GET /api/v1/runs/{run_id}/transcriptruns_transcriptviewerRead the run transcript
GET /api/v1/runs/{run_id}/resultruns_resultviewerRead what a cloud task run produced: its output object, validated against the publication's output schema
GET /api/v1/runs/{run_id}/recordingruns_recordingviewerGet a short-lived recording URL
GET /api/v1/runs/{run_id}/analysisruns_analysisviewerRead post-run analysis
GET /api/v1/runs/{run_id}/usageruns_usageviewerRead metered usage and cost of one run
Content version ac60a26fMarkdown source
Runs · Cumulus Talos docs