Runs
Browse conversation runs and best-effort projected framework history, inspect structural trajectories, and control channel-aware operator takeover by run ID.
The unified runs endpoint is the public browse surface for conversation runs across voice, SMS, WhatsApp, email, web, and iMessage, plus terminal framework runs that reached the durable projection. Framework-run projection is best-effort, so this endpoint is not a live or guaranteed-complete framework-run ledger. Use kind=framework to browse the projected framework history.
List Runs
Returns a paginated, newest-first list of conversation runs and projected terminal framework runs under one contract. Voice runs take started_at and ended_at from the call's start and end and sort by the call start. A text run starts at the conversation's creation, and a finished text run ends at its last update.
Use run_id for run-scoped operations. A voice run's source_call_sid is a separate, opaque call handle: current calls can use UUID-shaped references, while older records can retain carrier-style values. Preserve the returned string without parsing its format; see Calls.
Paginated, newest-first list of runs for the workspace behind the unified Run contract. Federates framework runs (Delta world.runs MV) and conversation runs (Lakebase world.conversations) at read time. Filter by kind (conversation / framework), channel (voice/sms/whatsapp/email/web/imessage — conversation runs only), status (live expands to running + paused), service_id (service UUIDs), and search (entity name, caller ID or phone number). Repeated filter values are ORed within each axis; axes combine with AND. Service filtering applies to conversation and live voice runs before pagination. Historical framework runs have no stored service attribution and are excluded when service_id is set. continuation_token is an opaque page cursor.
API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.
[]50Filter conversation and live voice runs by up to 100 service IDs. Historical framework runs have no stored service attribution and are excluded. Repeated values are ORed; combines with other filters using AND.
[]Case-insensitive substring match on a conversation run's entity name, caller ID or phone number, applied before pagination. Framework runs carry none of these and are excluded when search is set. Combines with other filters using AND.
Successful Response
Validation Error
GET /v1/{workspace_id}/runs HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"items": [
{
"run_id": "123e4567-e89b-12d3-a456-426614174000",
"workspace_id": "123e4567-e89b-12d3-a456-426614174000",
"kind": "conversation",
"status": "running",
"channel": "voice",
"framework": "claude-agent-sdk",
"entity_id": "123e4567-e89b-12d3-a456-426614174000",
"service_id": "123e4567-e89b-12d3-a456-426614174000",
"started_at": "2026-01-01T00:00:00.000Z",
"ended_at": "2026-01-01T00:00:00.000Z",
"entity_name": "text",
"service_name": "text",
"caller_id": "text",
"phone_number": "text",
"direction": "text",
"turn_count": 1,
"completion_reason": "text",
"source_call_sid": "text",
"source_conversation_id": "123e4567-e89b-12d3-a456-426614174000",
"source_framework_run_id": "123e4567-e89b-12d3-a456-426614174000",
"takeover": {
"eligible": true,
"mode_options": [
"listen"
],
"reason": "text"
}
}
],
"has_more": true,
"continuation_token": null
}Authentication
Workspace API key (bearer token) or operator identity token. The bearer's workspace must match the path workspace.
Status Mapping
The status field on each run is a canonical value derived from the underlying source:
Framework runs: Terminal status is projected on a best-effort basis. A framework run may be absent if its terminal projection was not recorded.
Conversation runs (voice): An active call with no completion reason maps to
running. A timed-out call maps totimed_out. Calls that ended due to errors or no audio map tofailed. All other completed calls map tocompleted.Conversation runs (non-voice): An open conversation updated within its channel's activity threshold maps to
running. One that has been idle past the threshold maps todormant: 5 minutes for web, 30 minutes for SMS, and 60 minutes for email, WhatsApp, and iMessage. The non-voice channels are SMS, WhatsApp, email, web, and iMessage. A dormant run is not live, has noended_at, and is not eligible for takeover, and its next turn makes itrunningagain. A conversation an operator holds stayspausedhowever long it is idle. Closed or completed conversations map tocompleted. Failed conversations map tofailed.
The virtual live status filter expands to running + paused, returning active conversation runs. It does not include dormant, which has its own filter value. Projected framework history is terminal-only.
Filter by Channel
The channel filter on the run list and Runs Summary accepts voice, sms, whatsapp, email, web, and imessage, the channels a conversation run can carry. Repeat it to match any of several. Another value, including the removed text, returns 422.
Search Runs
Pass search for a case-insensitive substring match on a conversation run's entity name, caller ID, or phone number. The match runs before pagination, so every page holds only matching runs. Framework runs carry none of these fields and are excluded while search is set. It combines with the other filters using AND.
Filter by Service
Pass service_id to list only the runs of one or more services, up to 100 IDs. Repeated values are ORed, and the filter combines with kind, channel, and status using AND. It applies to conversation runs and live voice runs before pagination, so every page holds only matching runs. Historical framework runs have no stored service, so they are excluded whenever service_id is set. The Runs Summary operation does not take this filter.
Example Request
Example Response
Error Responses
403 Forbidden
Bearer workspace does not match the path workspace.
422 Unprocessable Entity
Invalid query parameter, such as an invalid continuation_token or an unsupported sort_by. A sort_by error lists the allowed values, +started_at and -started_at.
502 Bad Gateway
Run data is temporarily unavailable.
Runs Summary
Summarizes the same unified inventory. Repeated kind and channel filters use OR semantics, and a channel filter restricts results to conversation runs. live counts running and paused runs, and dormant counts idle open conversations, which are not live.
The summary excludes a live entry when the same call already has a running conversation record. Reads can still observe different moments during call startup or completion, so counts can briefly differ from the list. Reconcile individual run identifiers when an exact operational count is required.
Aggregate counts for the workspace's runs behind the unified Run contract: total, live (running + paused), each canonical status, a full by_status map, and by_kind (conversation vs framework). Federates the Delta world.runs MV and Lakebase world.conversations with a cheap GROUP BY. Optional kind / channel filters mirror the list; a channel filter restricts to conversation runs.
API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.
Successful Response
Aggregate run counts for the Runs page summary strip.
Honest workspace totals the paginated list cannot derive client-side (it only
holds the loaded page). by_status carries the full canonical breakdown
(incl. any status beyond the named convenience fields); by_kind splits
framework vs conversation. live = running + paused. dormant counts
open conversations idle past their channel threshold, which are not live.
Validation Error
GET /v1/{workspace_id}/runs/summary HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"total": 1,
"live": 1,
"running": 1,
"paused": 1,
"completed": 1,
"failed": 1,
"timed_out": 1,
"dormant": 1,
"by_status": {
"ANY_ADDITIONAL_PROPERTY": 1
},
"by_kind": {
"ANY_ADDITIONAL_PROPERTY": 1
}
}Get a Run
Returns one available framework or conversation run. Framework results are limited to terminal runs that reached the best-effort projection. The workspace-scoped run_id is channel-neutral; inspect kind, channel, and the source_* fields to decide whether to open conversation detail, call detail, or framework trajectory next. Returns 404 when the run does not exist in the workspace.
A conversation run resolves by run_id at any age, for this read and for the run-scoped operations below. A projected framework run is looked up among recent framework history, so an older framework run can return 404 even though it appears in an earlier list page.
Resolve a single run by its channel-neutral run_id and return the canonical Run — at any status (live, completed, failed, timed out). Federates the Delta world.runs MV (framework runs), Lakebase world.conversations (conversation runs), and the live-voice registry, matched by run_id and scoped to the workspace. Use the returned kind / channel / source_* fields to open the channel-appropriate detail (voice call, text conversation, framework trace). 404 if the run does not exist in this workspace.
API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.
Successful Response
One item in the canonical unified Runs read model.
run_id is a dedicated UUID (not an overloaded call_sid / conversation_id);
the originating subsystem's ids are kept as source_* provenance fields so a
run can always be traced back to its channel/framework origin. Conversation runs
carry a channel and no framework; framework runs carry a framework and
no channel — enforced below.
Validation Error
GET /v1/{workspace_id}/runs/{run_id} HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"run_id": "123e4567-e89b-12d3-a456-426614174000",
"workspace_id": "123e4567-e89b-12d3-a456-426614174000",
"kind": "conversation",
"status": "running",
"channel": "voice",
"framework": "claude-agent-sdk",
"entity_id": "123e4567-e89b-12d3-a456-426614174000",
"service_id": "123e4567-e89b-12d3-a456-426614174000",
"started_at": "2026-01-01T00:00:00.000Z",
"ended_at": "2026-01-01T00:00:00.000Z",
"entity_name": "text",
"service_name": "text",
"caller_id": "text",
"phone_number": "text",
"direction": "text",
"turn_count": 1,
"completion_reason": "text",
"source_call_sid": "text",
"source_conversation_id": "123e4567-e89b-12d3-a456-426614174000",
"source_framework_run_id": "123e4567-e89b-12d3-a456-426614174000",
"takeover": {
"eligible": true,
"mode_options": [
"listen"
],
"reason": "text"
}
}Get a Framework Trajectory
Returns ordered structural steps for a framework run. Check truncated before treating the returned sequence as complete.
Returns 404 when the run does not exist and 409 when the run is a conversation run. Use conversation detail for per-turn conversation history.
Ordered structural steps (perception / decision / tool / completion) of a FRAMEWORK run, read from the durable Delta trace source by the run's correlation id. 404 if the run does not exist in this workspace; 409 if the run is a conversation run (use /conversations/{id} for per-turn detail).
API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.
Successful Response
Validation Error
GET /v1/{workspace_id}/runs/{run_id}/trajectory HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"steps": [
{
"seq": 1,
"kind": "text",
"actor": "text",
"state": "text",
"tool_name": "text",
"tool_input_summary": "text",
"tool_result_summary": "text",
"tool_succeeded": true,
"decision_from_state": "text",
"decision_to_state": "text",
"effective_at": "text"
}
],
"truncated": true
}Takeover Eligibility
Every run carries a server-computed takeover object based on its channel and status. Clients should use it for those eligibility checks and also confirm that the selected voice runtime supports the requested control. A live realtime-provider call can be listed without supporting operator takeover or guidance.
The voice eligibility object exposes listen and takeover; execution requires a supported platform-managed voice session. Live non-voice runs (SMS, WhatsApp, email, web, and iMessage) expose takeover only; an operator drives those channels by staging authored turns rather than joining a live media stream. Framework and non-live runs are not eligible.
Operator Takeover
The Developer Console's operator pages and takeover controls are retired. These retained API operations require an integration that provides its own controls, authorized operator identity, and a supported runtime. The Console's All runs Live filter is only a browse filter.
An operator can take over a live run and hand it back by channel-neutral run_id. Voice takeover uses a live media session and supports listen or drive mode. Non-voice takeover pauses the agent while the operator stages the next outbound turn.
All five operations below require Operator:Update, which the operator, admin, and owner roles carry. The operator_id in the body must match the authenticated operator; impersonation is rejected.
Take Over a Run
Registers the operator on a live run. In takeover mode the agent is suspended so the human drives; in listen mode the operator monitors without driving. Non-voice channels support takeover mode only.
Register the caller's operator identity on a LIVE run and (in takeover mode) suspend the agent so the human drives; listen mode monitors without driving. Addressed by the channel-neutral run_id. Requires admin (Operator:Update), bound to the caller's own operator identity (no impersonation). 404 if the run is not live in this workspace; 409 if its channel does not support live takeover yet, or if the operator has no phone number configured. For voice, Twilio dials the operator's phone and the response carries the resulting conference/participant SIDs.
API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.
takeoverPossible values: Successful Response
Validation Error
POST /v1/{workspace_id}/runs/{run_id}/takeover HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 72
{
"operator_id": "123e4567-e89b-12d3-a456-426614174000",
"mode": "takeover"
}{
"run_id": "123e4567-e89b-12d3-a456-426614174000",
"mode": "listen",
"participant_call_sid": "text",
"conference_sid": "text"
}Hand a Run Back
Releases the operator from the run. For non-voice channels, the stored status moves from paused back to active; for voice, the operator leaves the live media session and the agent is resumed. Subsequent behavior uses whatever conversation state and takeover evidence the runtime successfully retained; the handback response does not guarantee a complete transcript of operator activity.
Release the caller's operator from a run they took over — the agent resumes. Addressed by run_id. Requires admin (Operator:Update), bound to the caller's own operator identity. 404 if the run is not live in this workspace; 409 if its channel does not support live takeover yet.
API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.
Successful Response
Validation Error
POST /v1/{workspace_id}/runs/{run_id}/handback HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 54
{
"operator_id": "123e4567-e89b-12d3-a456-426614174000"
}{
"run_id": "123e4567-e89b-12d3-a456-426614174000",
"success": true
}Author a Non-Voice Turn
Stages the next operator-authored reply on a taken-over SMS, WhatsApp, email, web, or iMessage run. A run can hold one pending authored reply; staging another before it is consumed replaces the earlier text. The reply is consumed before downstream delivery completes, so a later delivery failure does not restore that pending value automatically. This is not an exactly-once delivery guarantee. Wait for a staged turn to be consumed before staging another.
Voice runs return 409 because the operator drives them through live audio.
Stage an operator-authored reply for a NON-voice run (sms/whatsapp/email/web/imessage) the caller has taken over. The agent-engine send-gate substitutes it for the agent's next outbound (exactly-once), so the caller receives the operator's words while the agent stays suspended. Repeatable — each call stages the next turn. Addressed by the channel-neutral run_id. Requires admin (Operator:Update), bound to the caller's own operator identity (no impersonation). 404 if the run is not live in this workspace; 409 for voice (voice takeover drives the live audio leg — use the conference, not an authored turn).
API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.
Successful Response
Validation Error
POST /v1/{workspace_id}/runs/{run_id}/authored-turn HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 68
{
"operator_id": "123e4567-e89b-12d3-a456-426614174000",
"text": "text"
}{
"run_id": "123e4567-e89b-12d3-a456-426614174000",
"staged": true
}Switch Mode
Toggles an operator who has already joined a voice run between listen and takeover. Non-voice runs return 409 because they support authored-turn takeover only.
Toggle the operator between listen (monitor) and takeover (drive) on a run they have already joined, addressed by the channel-neutral run_id. For voice this mutes/unmutes the operator's conference participant. Requires admin (Operator:Update), bound to the caller's own operator identity (no impersonation). 404 if the run is not live in this workspace; 409 if its channel does not support live takeover yet.
API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.
Successful Response
Validation Error
POST /v1/{workspace_id}/runs/{run_id}/switch-mode HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 100
{
"operator_id": "123e4567-e89b-12d3-a456-426614174000",
"participant_call_sid": "text",
"mode": "listen"
}{
"run_id": "123e4567-e89b-12d3-a456-426614174000",
"mode": "listen"
}Operator Audio
Browser-audio access tokens have been retired. Operators join supported voice calls by phone through the operator join workflow. Use run takeover and mode-switch controls for the corresponding operator state changes.
Send Guidance
Sends text guidance to a live voice run. Guidance is delivered as a prioritized instructional event that can interrupt current agent speech, unlike a factual external event, which queues behind current speech. The returned delivery status does not guarantee exact response timing or that the model follows the instruction verbatim. Non-voice channels return 409; use authored-turn takeover when an operator must send a reply.
The audit record captures the run, channel, operator identity, and a content fingerprint, never the raw guidance text.
Send text guidance to the agent handling a LIVE run, addressed by the channel-neutral run_id. The agent incorporates it into its next response without the operator taking over. Requires admin (Operator:Update) and is bound to the caller's own operator identity (no impersonation). 404 if the run is not a live run in this workspace; 409 if its channel has no live guidance transport yet.
API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.
Operator guidance for a live run. operator_id is in the body because this
router is not under /operators/{operator_id} — it is bound to the authenticated
caller by _enforce_operator_identity (no impersonation).
Successful Response
Delivery status
Run the guidance was sent to
Validation Error
POST /v1/{workspace_id}/runs/{run_id}/guidance HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 71
{
"operator_id": "123e4567-e89b-12d3-a456-426614174000",
"message": "text"
}{
"status": "delivered",
"run_id": "123e4567-e89b-12d3-a456-426614174000"
}Agent Forge CLI
Agent Forge v0.1.44+ exposes the unified read surface:
Add --json for the raw response. The CLI accepts one value per filter flag and prints --continuation-token when another page is available; pass that token unchanged to the next run list call. The REST API itself supports repeated filter values.
Rate Limits
Each list, summary, detail, and trajectory operation allows 60 requests per minute. Each takeover, handback, authored-turn, mode-switch, and guidance operation allows 10 requests per minute. Limits are enforced per authenticated credential and operation. Successful limit checks return X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset; a 429 response also returns Retry-After.
Last updated
Was this helpful?

