Skip to main content
An approval is a step that parks its run in needs_attention until someone approves or denies it; the decision resumes the run from its checkpoint. Reads work with a public key; the decision needs a secret key.

Endpoints

Listing

GET /approvals accepts: A decided approval stays listable as its audit trail. Each approval is:

Deciding

POST /approvals/{id}/decision applies the decision and resumes the run:
status must be approved or denied. args, when present, replaces the proposed tool arguments on the approved decision - approve-with-edits; the workflow receives them as the effective decision.args. The response is the decided approval. The decider is recorded from the authenticated caller: the X-Duraton-Actor header when a platform-issued key supplies one, otherwise the API key’s name. Scope does not grant that - a customer key is full-scope too, and one that could name a person would be signing their name to its own actions. The request body cannot set it, so a decision can never be attributed to someone who did not make it, and the approval record always agrees with the audit log. decidedVia records which surface the decision arrived through, alongside who made it. It is derived the same way - from how the request authenticated - and is likewise not settable by the body, because the surfaces do not carry the same weight: An auditor asking how a high-risk tool call was cleared needs that difference: the same person clearing a gate from a signed-in session and from a raw API call leaves the same decidedBy. A timeout resolution has no caller to derive either field from, so it records decidedBy: "system:timeout" alongside decidedVia: "timeout" rather than an empty decider that would read as an unattributed person.

Error codes