Runs and results

Every fire — cron, manual, or API — produces a run with a receipt you can poll. Polling always works; run webhooks deliver the same receipt without a loop on both api.dev.sume.com and api.sume.com.

Run lifecycle

StatusMeaning
queuedAccepted, not started.
processingThe Agent is working.
completedFinished. output and artifacts are populated.
failedFinished with an error.
canceledStopped by a cancel request.
skippedNever ran, because another run was active.

The Action vocabulary spells it canceled with one l, and it is a remapping of internal statuses — done surfaces as completed, error as failed, and cancelled as canceled. Do not assume job-side status strings transfer.

The run receipt

GET /v1/action-runs/{run_id} returns the full receipt.

FieldNotes
id, objectobject is action.run.
action{ "id", "title", "trigger_type" }.
statusSee the table above.
trigger{ "source": "cron" | "manual" | "api", "idempotency_key" }.
created_at, started_at, finished_atstarted_at and finished_at are null until they happen.
output_schema{ "name", "strict", "source" }, where source is default, action_default, or request_override.
outputStructured result. null unless status is completed.
output_error{ "code", "message", "details" } when projection failed. null unless status is completed. See When output cannot be produced.
primary_output_keynull unless status is completed.
primary_output_urlResolved URL for primary_output_key. null unless status is completed.
artifactsMedia harvested from the run. Empty until the run is terminal.
usage{ "currency": "USD", "billable_amount_usd_micros", "generation_spend_cap_usd_micros" }, or null when spend could not be read.
error{ "code": "action_run_failed", "message" }. Non-null only when status is failed.
skip_reasonprevious_run_active on a skipped run, otherwise null.
request_idLog this.
status_url, result_url, cancel_urlFollow these rather than building URLs.
events_urlAlways null. Run lifecycle events are not exposed over the API.
cancelabletrue while queued or processing.
next_actionRecommended next step — see below.
idempotency_hittrue when this receipt is an idempotency replay.

usage.billable_amount_usd_micros is the generation spend attributed to this run — the same running total the run's own generation_spend_cap_usd_micros is enforced against, counting both reserved and captured amounts. It climbs while the run is in flight and settles when the run terminates.

Two things it is not. It excludes the agent's own LLM turn, which bills the separate Agent wallet, so it is not the run's total cost. And it is a receipt figure, not an invoice — GET /v1/usage remains the authoritative billing record.

usage itself is null when spend could not be read at all. That is distinct from 0, which means the run really has spent nothing yet.

Poll for completion

GET /v1/action-runs/{run_id}/status returns a trimmed payload built for polling loops:

Branch on next_action:

next_actionWhenDo
poll_statusqueued or processingKeep polling with backoff.
retry_laterskippedAnother run was active; try again.
noneEvery terminal run — completed, failed, canceledNothing left to fetch. On a failure, read error and output_error on this receipt.

These three are the whole set. events_url is always null — there is no public run events route — so no receipt asks you to inspect one.

Fetch the result

GET /v1/action-runs/{run_id}/result returns the full receipt, but only once the run is terminal. While the run is queued or processing it returns 409 run_not_completed with the current status in details.status.

Structured output

Schedule runs use the same structured-output contract as Format runs, and it is documented once, on Structured output: the supported schema subset, SumeMediaFile, the built-in sume/action-run-output/v1 schema, the URL gate, primary_output_key resolution, and the output_error failure modes all apply here unchanged.

Two things are Scheduled's own:

  • A schedule binds its default schema in the dashboard rather than at author time, and that binding shows up on the receipt as output_schema.source: "action_default".
  • A per-request output_schema on POST /v1/actions/{action_id}/runs overrides it for that run, and shows up as request_override.

List runs

limit accepts 1–100 and defaults to 50. The response is a page: { "data": [ ... ], "has_more": false, "next_cursor": null }. Walk the whole history by passing next_cursor back as cursor until has_more is false; the cursor is opaque, and one we did not mint is rejected with 400 invalid_request. GET /v1/actions adds has_more and next_cursor, but pagination is not implemented — has_more is always false and next_cursor is always null.

A single run is also readable under its Action at GET /v1/actions/{action_id}/runs/{run_id}.

Cancel a run

Cancel requires actions:write and is idempotent. Canceling an already-terminal run returns that terminal receipt with 200.

End-to-end example

Use exponential backoff in production rather than a fixed five-second sleep.

Next