Run callback

Runtime-facing endpoint used by an executing task to report progress, intermediate output, completion, failure, or to pause for human input.

It is not the only way a run reaches a terminal state. The platform also polls the runtime and, on the transition to terminal, retrieves the result and stores output_data, duration_ms and outputs — so a task that merely returns a value is still tracked. A failure alert webhook from the runtime is a third path. Whichever writes a terminal status first wins; the others become no-ops.

What the callback adds is immediacy — polling can lag by up to one poll interval — and two states polling cannot observe: intermediate output during a run, and waiting for human-in-the-loop.

Endpoint

POST /api/runs/{runId}/callback

Auth: Authorization: Bearer <agent_api_key>

The runId comes from payload.runId in the task payload that the platform sends to your runtime at trigger time. The agent_api_key is delivered to the runtime as an environment variable on the runtime environment — it is not in the per-run payload.

Payload variants

The body is a discriminated union on type.

started

Marks the run as running.

json
{ "type": "started" }

output

Reports intermediate or terminal output.

json
{
  "type": "output",
  "output": { "step": 1, "pages_scanned": 12 }
}

To mark the run complete, add complete: true:

json
{
  "type": "output",
  "output": { "summary": "done" },
  "outputs": 42,
  "complete": true
}

To mark the run failed, add failed: true and an error:

json
{
  "type": "output",
  "failed": true,
  "error": {
    "name": "TimeoutError",
    "message": "upstream did not respond within 30s"
  }
}
FieldTypeDescription
outputobjectDomain payload (rendered in the platform UI).
completebooleanSet true on success; transitions status → completed.
failedbooleanSet true on failure; transitions status → failed.
errorobject{ name?, message?, stack? } — required when failed=true.
outputsintegerCount of agent-defined output units; latest non-null value wins.

waiting

Pause the run for human-in-the-loop input. Supported only by runtimes that implement waitpoints — check the agent's runtime descriptor.

json
{
  "type": "waiting",
  "tokenId": "wait_abc123",
  "description": "Approve the generated summary",
  "url": "https://your-app.example.com/review/abc123",
  "output": { "draft": "…" }
}
FieldTypeDescription
tokenIdstringWaitpoint token id used by the runtime to resume execution.
descriptionstringShown to the human reviewer.
urlstringOptional. Absolute http(s) URL; when set, waiting-state notifications resolve {{run_url}} to this URL instead of the generic run-detail link — point reviewers at your own review UI. A malformed value is rejected with 400.
outputobjectOptional context displayed alongside the form.

To resume a run paused this way, use Complete waitpoint (POST /api/runs/{runId}/waitpoint).

Response

200 OK with an empty body on success.

Errors

StatusReason
401Missing or invalid agent_api_key.
404runId does not exist or does not belong to this agent.
409Backward state transition (e.g. callback after the run was cancelled).
422Payload failed validation.
429Per-agent rate limit.

SDK

ts
import { createAgentClient } from '@cxpa/sdk/agent'

const cxpa = createAgentClient({
  baseUrl: process.env.CXPA_API_URL!,
  // From the runtime environment — the payload never carries the agent key.
  apiKey: process.env.CXPA_REVENUE_CHAT_AGENT_API_KEY!,
  runId: triggerPayload.runId,
  credentialsToken: triggerPayload.credentialsToken,
})

await cxpa.started()
await cxpa.output({ output: { step: 1 } })
await cxpa.complete({ output: { summary: 'done' }, outputs: 42 })