Skip to content

Flows API ​

Enterprise

Flows is an Enterprise module. These routes need an Enterprise license and answer 402 with requiresEnterprise: true without one. Concepts and the editor are in the Flows guide.

Read flows, start runs and follow them. Authoring (create, edit, publish, import) is done in the dashboard; the client API has the read and run surface only.

All routes live under /api/client/v1, take Authorization: Bearer cpeer_… and need the flows service (GET read, everything else write, except where noted). A token sees only its own project and acts for its owner. Field names are camelCase and timestamps are ISO strings. Errors use { "error": "message" }.

Endpoints ​

Endpoint
GET /flowsList flows
GET /flows/{idOrKey}Get a flow
POST /flows/{idOrKey}/runsStart a run
GET /flows/runsList runs
GET /flows/runs/{runId}Get a run
GET /flows/runs/{runId}/eventsRun events
POST /flows/runs/{runId}/cancelCancel a run
POST /flows/runs/{runId}/resumeResume a run
POST /flows/runs/{runId}/approvalDecide an approval

{idOrKey} is the flow id or its key.

Permission levels ​

LevelRoutes
ReadGET /flows, GET /flows/{idOrKey}, GET /flows/runs, GET /flows/runs/{runId}, and deciding an approval (the run's own rule decides who may)
WriteStart, cancel and resume, GET /flows/runs/{runId}/events, and ?steps=1 on a run. A token with write also sees a run's input and output.

A read-only token gets run summaries without input and output.

List flows ​

GET /flows?agentKey=&status=&search=&limit=&offset=
QueryMeaning
agentKeyOnly the flows of this agent.
statusactive or archived.
searchText search, up to 200 characters.
limit1 to 200.
offsetSkip this many.
json
{
  "items": [
    {
      "id": "6720b4c3d2e1f0a9b8c7d6e5",
      "key": "refund-request",
      "name": "Refund request",
      "status": "active",
      "surface": "headless",
      "agentKey": "support-bot",
      "revision": 12,
      "publishedVersion": 3,
      "publishedAt": "2026-11-10T09:14:02.000Z",
      "lastRun": { "runId": "…", "status": "succeeded", "startedAt": "…", "durationMs": 1840 },
      "tags": [],
      "inputs": [{ "name": "orderId", "type": "string", "required": true }],
      "createdBy": "…"
    }
  ],
  "total": 1
}

surface is headless or conversation. inputs are the declared inputs of the draft and are the flow's input schema.

Get a flow ​

GET /flows/{idOrKey}

Returns { "flow": { … } }: the fields above plus draft, the flow definition (inputs, outputs, variables, nodes, edges, settings). 404 when the flow does not exist in the token's project.

Start a run ​

POST /flows/{idOrKey}/runs
json
{
  "input": { "orderId": "A-1042" },
  "version": "published",
  "waitMs": 30000,
  "idempotencyKey": "refund-A-1042",
  "unattended": false,
  "chatId": "support-chat-7"
}

All fields are optional; unknown fields are refused with 400.

FieldDescription
inputAn object with the flow's declared inputs.
version"published" (default), "draft" or a version number. A flow that was never published cannot be run without naming "draft" or a number (409). An archived flow cannot run (409).
waitMsWait up to this long for the run to settle, 0 to 120000. Default: do not wait.
idempotencyKey1 to 255 characters; also read from the Idempotency-Key header. A start repeated with the key of an existing run answers that run and starts nothing.
unattendedtrue when nobody is there to answer; recorded on the run.
chatIdLetters, digits, _ and -, up to 100. Agent steps keep one conversation across the runs with the same chatId. It is scoped to the caller, so two callers never share a conversation.

Response: 200 when the run settled inside waitMs, 202 when it is still going.

json
{ "run": { "id": "…", "status": "running", "…": "…" }, "settled": false }

A failed run is still a successful request: the failure is in run.status and run.failureReason. Poll GET /flows/runs/{runId} to follow it.

The run object ​

json
{
  "id": "6720b5a1d2e1f0a9b8c7d700",
  "flowId": "6720b4c3d2e1f0a9b8c7d6e5",
  "flowKey": "refund-request",
  "flowName": "Refund request",
  "flowVersion": 3,
  "status": "waiting",
  "trigger": { "type": "api" },
  "input": { "orderId": "A-1042" },
  "output": null,
  "runAs": { "kind": "token", "tokenId": "…", "label": "token:billing" },
  "createdBy": "…",
  "depth": 0,
  "unattended": false,
  "wait": { "kind": "approval", "nodeId": "…", "since": "…", "approval": { "title": "Approve refund", "approverUserIds": [], "requireDistinctApprover": true, "onTimeout": "reject" } },
  "stepCount": 4,
  "activeMs": 1210,
  "usage": { "inputTokens": 812, "outputTokens": 96 },
  "queuedAt": "…",
  "startedAt": "…",
  "lastEventSeq": 9
}
FieldNotes
statusqueued, running, waiting, succeeded, failed, canceled.
failureReasonOn a failed run: step_failed, interrupted_at_step, timeout, permission_lost, validation, limit_exceeded, context_too_large or internal. error has message and code.
flowVersionThe version number, or null for a draft run.
trigger.typemanual, test, api, agent_tool, agent_conversation, webhook, schedule, subflow or import. Runs started through this API are api.
waitSet while waiting: kind is delay, approval, input, form, subflow or agent_action, with resumeAt, prompt or approval details.
input, outputLeft out for a read-only token.
parentRunId, rootRunId, depthSet for runs started by a Run flow step.
finishedAt, durationMs, usage.costUsdWhen the run ended and what it cost.

List runs ​

GET /flows/runs?flowId=&agentKey=&status=&trigger=&since=&until=&limit=&offset=

since and until are dates. status and trigger take the values above. limit is 1 to 200. Response: { "items": [run, …], "total": 42 }.

Get a run ​

GET /flows/runs/{runId}?steps=1

Returns { "run": { … } }. With steps=1 (or true) it adds steps, one entry per executed step with nodeKey, nodeType, iterationPath, attempt, status, input, output, error, logs, handle, truncated, usage and timings. A token without write access that asks for steps gets 403. 404 for an unknown run.

Run events ​

GET /flows/runs/{runId}/events?after=&limit=

after is a sequence number (events with a higher seq), limit is 1 to 1000. Needs write.

json
{
  "events": [
    { "seq": 1, "type": "run.queued", "at": "…" },
    { "seq": 2, "type": "run.started", "at": "…" },
    { "seq": 3, "type": "step.started", "at": "…", "data": { "nodeKey": "llm_1" } }
  ]
}

Event types: run.queued, run.started, run.waiting, run.resumed, run.succeeded, run.failed, run.canceled, step.started, step.succeeded, step.failed, step.skipped, step.retrying, approval.requested, approval.decided, message, log.

Cancel a run ​

POST /flows/runs/{runId}/cancel

No body. Returns { "run": { … } }. 409 when the run has already finished.

Resume a run ​

POST /flows/runs/{runId}/resume
json
{ "payload": { "message": "Yes, go ahead" }, "waitMs": 10000 }

Continues a run that waits for a delay, an input or a form. payload is what the wait receives (for a form, { "values": { … } }); waitMs is as for starting. Response: { "run": …, "settled": … } with 200 or 202. 409 when the run is not waiting for something a caller can answer. Approvals are decided with the next route.

Decide an approval ​

POST /flows/runs/{runId}/approval
json
{ "decision": "approved", "comment": "Checked with finance" }

decision is approved or rejected; comment is optional, up to 2000 characters. Who may decide is the run's own rule: the users named on the approval step, otherwise a flows admin. A step that requires a distinct approver refuses the person who started the run (403). The decision is recorded in the audit log as flows.approval.decide. Response: { "run": …, "settled": … }.

Errors ​

StatusWhen
400Invalid body or query (issues lists the fields), invalid JSON, or a version that is not a positive integer.
402No Enterprise license (requiresEnterprise: true).
403The token's permission or the run's approval rule does not allow it.
404Flow or run not found in the token's project.
409The flow is archived or not published, or the run is in the wrong state.
422The flow definition does not validate.
429A quota or plan allowance is used up (code: "quota_exceeded" or a plan-limit refusal).

See also ​

Studio · Pulse · Console · Agent SDK and more — the Cognipeer documentation hub