Skip to main content
These routes answer what a workflow run waits for: input to a step that called ctx.suspend(), a decision on an approval step, an edit to the payload under review, a signal a step waits on, and the reassignment of one person’s approvals and schedules to another. Acting on a run needs workflows:execute on the agent; reading a payload needs workflows:read. Approving, denying, editing a payload, and reassigning are human-only: a typed API credential is refused with 403 APPROVAL_REQUIRES_HUMAN. Starting, listing, and recovering runs are on Workflows, which also holds the error codes and the base URL, scopes, and envelope pointer; the ledger these decisions land in is on Workflow events. Verified against lua-cli 3.33.0.

Step input

POST /workflows/:agentId/runs/:runId/steps/:stepId/resume

Resumes a step that called ctx.suspend() and is waiting for input. Creator or a workflows:execute holder.
any
required
Validated against the step’s resumeSchema; at most 256 KB.
Response 200 with { "resumed": true, "runStatus" }, or the no-op { "resumed": false, "reason": "already_resumed", "recorded"?, "runStatus" } when someone got there first. Errors Equivalent: lua workflows resume <runId> --step <stepId> --data '{"answer":42}', Workflows.resume().

Approvals

POST /workflows/:agentId/runs/:runId/approvals/:approvalId/resolve

Approves or denies an approval step. The approvalId (wfa_...) is on the run’s suspensions[].suspend.approvalId, on the approval.requested event, and on the inbox card. Person only.
string
default:"api"
Where the decision is made: desktop, inbox, cli, or chat. The organization’s approval policy can restrict surfaces and demand a recent sign-in, which only desktop and inbox satisfy.
string
required
approve or deny.
string
At most 2,000 characters.
object
A replacement payload; only when the step declared editable: true and editablePaths.
string
The payloadFingerprint of the revision you looked at (at most 128 characters). Required once the payload has been edited; a stale value is 409 PAYLOAD_MISMATCH.
string[]
At most 5 artifact ids uploaded for this run.
Response 200 with { "resolved": true, "outcome": "approved" | "denied", "runStatus", "stepId"? }, or the no-op { "resolved": false, "outcome": "noop", "reason": "already_resolved" | "expired" | "cancelled" | "run_gone", "decision"?, "decidedBy"? }. Errors Equivalent: lua workflows approve <runId> --approval <id> --decision approve --note "Go ahead".

GET /workflows/:agentId/runs/:runId/approvals/:approvalId/payload

Reads the current approval payload, whole or paged. Needs workflows:read.
string
A dotted path to an array inside the payload, for example drafts, to page that array; any other target is 400 VALIDATION_FAILED.
string
The index to start the page at; nextCursor from the previous page.
integer
default:"100"
Items per page, at most 100.
Response 200 with { approvalId, editRevision, payloadFingerprint?, editable, editablePaths, size } and either kind: "whole" with payload (payloads up to 1 MB), kind: "paged" with arrays { <key>: { totalItems } } for a larger payload, or, with path, { path, items: [{ index, value }], nextCursor?, totalItems }. 404 RUN_NOT_FOUND or APPROVAL_NOT_FOUND; 413 PAYLOAD_PAGE_REQUIRED (offloaded: true) when the original payload is stored out of line and cannot be returned whole. Equivalent: lua workflows approval-payload <runId> --approval <id>.

PATCH /workflows/:agentId/runs/:runId/approvals/:approvalId/payload

Edits the payload with a JSON Patch before deciding. Person only.
string
required
The fingerprint the editor loaded; at most 128 characters.
array
required
At most 200 operations of { op: "replace" | "add" | "remove", path, value? } with RFC 6901 paths of at most 1,024 characters.
string
At most 2,000 characters.
Response 200 with { "applied": true, "editRevision", "payloadFingerprint" }; use the new fingerprint to resolve. 400 PATCH_INVALID or RESUME_SCHEMA_INVALID; 403 APPROVAL_REQUIRES_HUMAN, NOT_AN_APPROVER, or APPROVAL_SURFACE_DENIED; 404 RUN_NOT_FOUND or APPROVAL_NOT_FOUND; 409 PAYLOAD_MISMATCH, EDIT_NOT_ALLOWED, or NOT_SUSPENDED; 503 CONTROL_UNAVAILABLE. Equivalent: lua workflows approve <runId> --approval <id> --edit @file --fingerprint <f> edits and decides in one step.

GET /workflows/:agentId/runs/:runId/approvals/:approvalId/items

Lists the per-item approvals fanned out under a parent approval. Needs workflows:read. Response 200 with { approvalId, items: [{ index, approvalId, itemKey?, status, decision?, decidedBy?, itemPayloadFingerprint?, editRevision?, payload }], totalItems }. 404 RUN_NOT_FOUND or APPROVAL_NOT_FOUND; 503 CONTROL_UNAVAILABLE.

POST /workflows/:agentId/runs/:runId/approvals/:approvalId/items/:index

Decides one fanned-out item. Person only; the X-Lua-Surface header applies as on resolve.
string
required
approve or deny.
string
At most 2,000 characters.
string
The item’s itemPayloadFingerprint; a mismatch is 409 PAYLOAD_FINGERPRINT_STALE.
Response 200 with { "resolved": true, "item", "decision", "parentResolved", "runStatus"? }. 400 VALIDATION_FAILED for a bad index or decision; 403 APPROVAL_REQUIRES_HUMAN, NOT_ITEM_APPROVER, or CUSTOMER_PRINCIPAL_CANNOT_APPROVE; 404 RUN_NOT_FOUND, APPROVAL_NOT_FOUND, or ITEM_NOT_FOUND; 409 PAYLOAD_FINGERPRINT_STALE, ITEM_ALREADY_DECIDED, or NOT_SUSPENDED; 503 CONTROL_UNAVAILABLE.

Signals

POST /workflows/:agentId/runs/:runId/signals/:name

Delivers a named signal to a run.
string
required
The signal name, from 1 to 64 characters.
any
At most 64 KB; validated against the waiting step’s schema.
string
At most 128 characters; a repeat answers 200 with duplicate: true and delivers nothing.
Response Errors 400 VALIDATION_FAILED (an empty or over-long name) or SIGNAL_SCHEMA_INVALID (stepId, issues; the rejected payload keeps its dedupeKey free for a corrected retry); 404 RUN_NOT_FOUND; 409 RUN_TERMINAL; 413 PAYLOAD_TOO_LARGE; 422 SIGNAL_SCHEMA_UNCOMPILABLE; 429 SIGNAL_INBOX_FULL; 503 CONTROL_UNAVAILABLE. Equivalent: lua workflows signal <runId> <name> --payload '{"ok":true}', Workflows.signal().

POST /workflows/:agentId/signals/by-key

Delivers a signal to the live runs of a workflow started with a correlationKey, without knowing their ids.
string
required
The definition.
string
required
The key the runs were started with.
string
required
Signal name, at most 64 characters.
any
At most 64 KB.
boolean
Fan out to every matching run instead of refusing when several match.
string
At most 128 characters.
Response 200 with { "runIds", "delivered", "results": [{ runId, accepted, consumed?, duplicate?, signalId?, code? }] }; a per-run refusal is reported in code and never fails the call. Errors 400 CORRELATION_KEY_INVALID, SIGNAL_SCHEMA_INVALID, or VALIDATION_FAILED; 404 CORRELATION_KEY_NOT_FOUND (no live run); 409 CORRELATION_KEY_AMBIGUOUS with runIds when several match and allowMultiple is not set; 413, 422, 503 as on the per-run route. Equivalent: Workflows.signalByKey().

Gates

A gated or suspended run carries gate.kind, and each kind has one way out: The recovery verbs are on Workflows. A step waiting on a person shows as suspensions[].suspend.kind: input answers to the resume route, approval to the resolve route, and signal to the signal routes; using the wrong one is 409 USE_SIGNAL_ROUTE or APPROVAL_REQUIRES_HUMAN.

Reassignment

POST /workflows/reassign

Moves one user’s workflow assets to another user in the organization. Needs workflows:write on the organization, an organization admin (org:manage), and a person.
string
required
The organization; at most 128 characters.
string
required
The user leaving.
string
required
The user taking over; must be an organization member and, to inherit approvals, hold workflows:execute.
string[]
A subset of schedules, approvals, connections, drafts; defaults to all four.
boolean
Report what would move without moving it.
Response 200 with { "schedules": { moved, skipped }, "approvals": { rerouted, skipped, detail? }, "connections": { remounted, unmountable[] }, "drafts": { moved }, "dryRun", "unavailable"? }; unavailable names blocks the server did not walk, whose zeros are not results. 400 VALIDATION_FAILED (a missing id) or REASSIGN_SAME_USER; 403 NOT_ORG_ADMIN or APPROVAL_REQUIRES_HUMAN; 404 USER_NOT_IN_ORG (userId) or WORKFLOWS_DISABLED; 409 REASSIGN_TARGET_LACKS_EXECUTE. There is no CLI equivalent.

See also