Skip to content

Cancel an action waiting for approval

POST
/v1/actions/{id}/cancel
curl --request POST \
--url http://127.0.0.1:8080/v1/actions/example/cancel \
--header 'Authorization: Bearer <token>' \
--header 'Deedglass-Version: 2026-10-01'

Only from pending_approval: the action goes cancelled, then sealed, its approval is cancelled and its budget reservation goes back. From any other state the answer is 409 conflict: “This action is already executing, so it can’t be cancelled.” while it runs, and “This action has already finished, so there is nothing to cancel.” once it ended. The agent’s own key (with actions:execute), an admin+ Console session (with the Deedglass-CSRF header) or an org admin key. Another agent’s action is 404 not_found, exactly like an id that doesn’t exist.

id
required
string

The action id (act_…).

Deedglass-Version
string
/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/

The API version (YYYY-MM-DD). Leave it out to use your org’s pinned version (public routes use the latest). An unknown version is 400 api_version_invalid.

Deedglass-CSRF
string

Needed when the request uses a Console session (it changes state); without it the answer is 403 csrf_failed. Not sent with an API key.

Idempotency-Key
string
>= 1 characters <= 255 characters

1 to 255 printable ASCII characters. A retry with the same key and body returns the stored response with Deedglass-Idempotent-Replayed: true for 24 hours.

The action, status: cancelled, sealed.

Media typeapplication/json

One agent action. Its sections mirror the deed’s. status is the one field an agent needs; state is the exact lifecycle state (docs/GATE.md). The Gate’s own responses (POST /v1/actions and its result report) add execution.result and witness.reasons; lists leave both out.

object
object
required
string
Allowed value: action
id
required
string
/^act_[0-7][0-9a-hjkmnp-tv-z]{25}$/
created_at
required
string format: date-time
livemode
required

true for a dg_live_ key, false for a dg_test_ key. Recorded, not enforced: connectors have no test mode in v1.

boolean
agent
required
object
id
required
string
name
required
string
tool
required
string
connector
required
string | null
mode
required
string
Allowed values: gateway proxy
state
required
string
Allowed values: received authenticated evaluated denied pending_approval executing executed failed witnessing verified mismatch unverifiable sealed expired cancelled
status
required

executed: the tool ran and the action is sealed, whatever the verdict. failed: the tool certainly didn’t apply the call. authorized: proxy mode, run the tool at the edge now. processing: still executing or witnessing. pending_approval: waiting for a person. denied: a policy, a budget or Stop refused it, and nothing ran. expired and cancelled: it waited for approval and never ran. A sealed action keeps the status of the state it was sealed from.

string
Allowed values: processing authorized pending_approval denied executed failed expired cancelled
on_behalf_of
required
string | null
session
required
string | null
undo

The action’s undo object (S23). undoes names the action an undo puts back; undone_by names the undo that put this one back; pending an undo waiting for approval or running. eligible is cheap (L2 evidence from a bound transaction, gateway mode, sealed, not undone, within undo.max_age, the row images kept): it only decides whether the Console shows Preview undo. The full answer is always the preview.

object
undoes
required
string | null
undone_by
required
string | null
pending
string | null
eligible
required
boolean
schedule

S40, additive: the window an approved action runs in, stored once at creation and never changed. Absent when the request carried no schedule.

object
not_before
required
string format: date-time
not_after
required
string format: date-time
decision
required

The policy decision as an agent reads it: S11’s decision, its source, its message verbatim, the policy version that made it (pinned: a later activation doesn’t change it), and the shadow decision next to it. null until the action is evaluated.

object
outcome
required
string
Allowed values: allow deny require_approval
code
required

The refusal code (policy_denied, budget_exceeded, agent_stopped, tool_unknown, …), approval_required, or null for an allow.

string | null
source
required

builtin is the Gate’s own decision, such as tool_unknown.

string | null
Allowed values: stop budget rule default builtin
rule_id
required
string | null
reason
required
string | null
message
required

The sentence the agent sees

string | null
policy
required

The policy id (pol_…).

string | null
policy_version
required

The policy version id (pv_…).

string | null
anomaly

S27, additive: the decision trace’s line about the anomaly facts the policy saw, like anomaly facts: volume_spike, or anomaly facts: detector_stale (…) when detection was behind and the policy treated the agent as anomalous. Absent when no anomaly fact was active.

string
shadow
required

What the shadow policy would have decided. Recorded, never enforced.

object
outcome
required
string
Allowed values: allow deny require_approval
rule_id
required
string | null
policy_version
required
string | null
policy
required
object
id
required
string | null
version_id
required
string | null
mode
required
string
Allowed values: enforce shadow
decision
required
string | null
Allowed values: allow deny require_approval
rule_id
required
string | null
approval
required

The approval the action waits for, or waited for. null when no rule asked for one.

object
id
required

The approval id (apr_…).

string
status
required
string
Allowed values: pending approved denied expired cancelled
expires_at
required
string format: date-time
decision_reason

S22, additive: the reason a person gave when they denied it. Absent otherwise.

string
execution
required
object
status
required
string | null
Allowed values: succeeded failed unknown
started_at
required
string | null format: date-time
finished_at
required
string | null format: date-time
latency_ms
required
integer | null
error_code
required
string | null
error_message

A short, redacted message from the tool or the Gate (at most 1 KiB).

string | null
<= 1024 characters
result

The tool’s result. Only on the Gate’s own responses (POST /v1/actions and POST /v1/actions/{id}/result); never on lists. GET /v1/actions/{id} has it as the top-level result.

witness
required

The Witness’s verdict about the action (S19): one level, one verdict and the method of that level. A verdict is never stronger than its evidence: VERIFIED needs a clean level at or above required_level; any contradicting evidence is MISMATCH; missing evidence is UNVERIFIABLE. Lists carry the claim only. The Gate’s own responses and GET /v1/actions/{id} add summary, reasons (violations and gaps; passes and notes are in the detail) and witnessed_at; ?expand[]=witness.detail adds detail. An executed action answers 200 whatever the verdict: the tool ran, and the verdict says what that means.

object
object
required
string
Allowed value: witness
level
required
string
Allowed values: L0 L1 L2
verdict
required
string
Allowed values: VERIFIED MISMATCH UNVERIFIABLE
method
required

The claimed level’s method: reported, edge_reported or response.schema (L0); readback.<connector type>.<read tool>, readback.postgres.row or postcondition.<connector type> (L1); postgres.pgoutput (L2).

string | null
required_level
required

The level the policy’s verify: asks for (null on actions recorded before S19).

string | null
Allowed values: L0 L1 L2
summary

One sentence a support engineer can read aloud.

string
reasons
Array<object>

One piece of evidence, or one missing piece. The class and the message come from the reason catalog (docs/witness/REASONS.md). The full WitnessReason schema is in openapi.yaml.

object
witnessed_at
string format: date-time
detail_digest
required

sha256: of JCS(witness_detail): the deed’s witness.detail_digest.

string | null
detail

Witness_detail v1 (S19): what actions.witness_detail holds and what the deed’s witness.detail_digest is the digest of. Changes are additive only; S21 fills levels.L2. The full WitnessDetail schema is in openapi.yaml.

object
history

GET /v1/actions/{id} only (S21): every witness section sealed about the action, oldest first: the action deed, then any amendment deeds (a later verdict never edits a deed; at most three amendments). An entry a later amendment replaced names the reason it stopped where it did (l2_timeout, …).

Array<object>
object
deed
required
string
/^deed_[0-7][0-9a-hjkmnp-tv-z]{25}$/
kind
required
string
Allowed values: action amendment
level
required
string
Allowed values: L0 L1 L2
verdict
required
string
Allowed values: VERIFIED MISMATCH UNVERIFIABLE
at
required
string format: date-time
reason
string
cost
required
object
amount
required
integer
currency
required
string
/^[a-z]{3}$/
request_digest
required

“sha256:” + lowercase hex of SHA-256.

string
/^sha256:[0-9a-f]{64}$/
result_digest
required
string | null
payload_pruned_at
required
string | null format: date-time
deed
required
string | null
next_action
required

What the caller does next. await_approval: wait for a person (poll_url long-polls the action). execute_at_edge: proxy mode, run the tool at the edge and report the result to report_url before deadline. scheduled (S40): approved, it runs between not_before and not_after. null otherwise.

object
type
required
string
Allowed values: await_approval execute_at_edge scheduled
approval

await_approval only: the approval id.

string
not_before

scheduled only (S40): an approved action runs from this time.

string format: date-time
not_after

scheduled only (S40): past it the action is cancelled and sealed with schedule_missed; nothing runs.

string format: date-time
expires_at

await_approval only.

string format: date-time
poll_url

await_approval only: /v1/actions/{id}?wait=25.

string
report_url

execute_at_edge only: /v1/actions/{id}/result.

string
deadline

execute_at_edge only: after it, the action is sealed UNVERIFIABLE (edge_lost).

string format: date-time
Example
{
"object": "action",
"id": "act_01j9zt3a5c7e9g1j3m5p7r9t1v",
"created_at": "2026-10-02T10:14:03.401Z",
"livemode": true,
"agent": {
"id": "agt_01j9z9b1d3f5h7k9m1p3r5t7v9",
"name": "support-bot"
},
"tool": "postgres.execute",
"connector": null,
"mode": "gateway",
"state": "sealed",
"status": "executed",
"on_behalf_of": "u_4821",
"session": "chat_77",
"decision": {
"outcome": "allow",
"code": null,
"source": "rule",
"rule_id": "allow-order-updates",
"reason": "Order updates are allowed.",
"message": null,
"policy": null,
"policy_version": null,
"shadow": null
},
"policy": {
"id": null,
"version_id": null,
"mode": "enforce",
"decision": "allow",
"rule_id": "allow-order-updates"
},
"approval": null,
"execution": {
"status": "succeeded",
"started_at": "2026-10-02T10:14:03.455Z",
"finished_at": "2026-10-02T10:14:03.496Z",
"latency_ms": 41,
"error_code": null,
"error_message": null
},
"witness": {
"object": "witness",
"level": "L2",
"verdict": "MISMATCH",
"method": "postgres.pgoutput",
"required_level": "L0",
"detail_digest": "sha256:c3e1a07e5d1c9b20c3e1a07e5d1c9b20c3e1a07e5d1c9b20c3e1a07e5d1c9b20"
},
"cost": null,
"request_digest": "sha256:9c1e5b7d0a2f4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e",
"result_digest": null,
"payload_pruned_at": null,
"deed": "deed_01j9zt3q5s7v9w1y3a5c7e9g1j",
"next_action": null
}
Deedglass-Request-Id
string
/^req_[0-7][0-9a-hjkmnp-tv-z]{25}$/

This request’s id. Quote it to support; it matches error.request_id.

Deedglass-Version
string

The API version this response follows.

not_found: no such action in this org, or (for an agent key) another agent’s.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: invalid_request_error authentication_error permission_error policy_error rate_limit_error api_error
code
required
string
Allowed values: invalid_api_key api_key_revoked api_key_expired agent_suspended agent_stopped org_stopped insufficient_scope policy_denied approval_required approval_expired budget_exceeded intent_required intent_invalid intent_replay tool_unknown connector_unavailable upstream_error timeout rate_limited idempotency_conflict validation_failed not_found conflict internal_error authentication_required method_not_allowed request_too_large unsupported_media_type invalid_json api_version_invalid idempotency_key_invalid idempotency_key_in_use service_unavailable session_expired csrf_failed insufficient_role login_link_invalid login_code_invalid last_owner policy_unavailable policy_invalid credentials_missing destination_blocked vault_unavailable upstream_auth_failed upstream_not_found upstream_rate_limited response_too_large statement_refused row_limit_exceeded database_role_unsafe database_not_ready witness_not_configured approval_decided already_countersigned approver_not_eligible self_approval approval_needs_person context_changed approval_unsatisfiable approval_link_invalid approval_link_review_only approver_unmapped stripe_live_key_refused stripe_livemode_detected upstream_approval_pending schedule_needs_approval action_executing from_denied undo_unavailable undo_plan_stale already_undone undo_conflict replay_too_large replay_window_invalid suggestion_stale shadow_slot_taken suggestion_decided observe_not_enabled pro_required
message
required

One or more calm sentences with the next step.

string
param
required

The request field, query parameter or header the error is about.

string | null
request_id
required
string
/^req_[0-7][0-9a-hjkmnp-tv-z]{25}$/
doc_url
required
string format: uri
diagnostics

On policy_invalid only. Each problem with its line, code and hint.

Array<object>

One finding about a policy file, with its position and the next step. Codes are stable and listed in docs/POLICY_ERRORS.md. In the policy_invalid error envelope each diagnostic also carries object: policy_diagnostic. The full PolicyDiagnostic schema is in openapi.yaml.

object
action

One agent action. Its sections mirror the deed’s. status is the one field an agent needs; state is the exact lifecycle state (docs/GATE.md). The Gate’s own responses (POST /v1/actions and its result report) add execution.result and witness.reasons; lists leave both out. The full Action schema is in openapi.yaml.

object
checks

On undo_unavailable only. Every check of the undo, each with its fix. Additive (S23).

Array<object>

One of the twelve safety checks (S23 §3.3). Available means no check failed. The full UndoCheck schema is in openapi.yaml.

object
Example
{
"error": {
"type": "invalid_request_error",
"code": "not_found",
"message": "There's no endpoint at GET /v1/helth. Did you mean /v1/health?",
"param": null,
"request_id": "req_01j9zr3m5k8q2w7x4t6v0b1c9d",
"doc_url": "https://docs.deedglass.com/errors/not_found"
}
}
Deedglass-Request-Id
string
/^req_[0-7][0-9a-hjkmnp-tv-z]{25}$/

This request’s id. Quote it to support; it matches error.request_id.

conflict: the action isn’t waiting for approval.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: invalid_request_error authentication_error permission_error policy_error rate_limit_error api_error
code
required
string
Allowed values: invalid_api_key api_key_revoked api_key_expired agent_suspended agent_stopped org_stopped insufficient_scope policy_denied approval_required approval_expired budget_exceeded intent_required intent_invalid intent_replay tool_unknown connector_unavailable upstream_error timeout rate_limited idempotency_conflict validation_failed not_found conflict internal_error authentication_required method_not_allowed request_too_large unsupported_media_type invalid_json api_version_invalid idempotency_key_invalid idempotency_key_in_use service_unavailable session_expired csrf_failed insufficient_role login_link_invalid login_code_invalid last_owner policy_unavailable policy_invalid credentials_missing destination_blocked vault_unavailable upstream_auth_failed upstream_not_found upstream_rate_limited response_too_large statement_refused row_limit_exceeded database_role_unsafe database_not_ready witness_not_configured approval_decided already_countersigned approver_not_eligible self_approval approval_needs_person context_changed approval_unsatisfiable approval_link_invalid approval_link_review_only approver_unmapped stripe_live_key_refused stripe_livemode_detected upstream_approval_pending schedule_needs_approval action_executing from_denied undo_unavailable undo_plan_stale already_undone undo_conflict replay_too_large replay_window_invalid suggestion_stale shadow_slot_taken suggestion_decided observe_not_enabled pro_required
message
required

One or more calm sentences with the next step.

string
param
required

The request field, query parameter or header the error is about.

string | null
request_id
required
string
/^req_[0-7][0-9a-hjkmnp-tv-z]{25}$/
doc_url
required
string format: uri
diagnostics

On policy_invalid only. Each problem with its line, code and hint.

Array<object>

One finding about a policy file, with its position and the next step. Codes are stable and listed in docs/POLICY_ERRORS.md. In the policy_invalid error envelope each diagnostic also carries object: policy_diagnostic. The full PolicyDiagnostic schema is in openapi.yaml.

object
action

One agent action. Its sections mirror the deed’s. status is the one field an agent needs; state is the exact lifecycle state (docs/GATE.md). The Gate’s own responses (POST /v1/actions and its result report) add execution.result and witness.reasons; lists leave both out. The full Action schema is in openapi.yaml.

object
checks

On undo_unavailable only. Every check of the undo, each with its fix. Additive (S23).

Array<object>

One of the twelve safety checks (S23 §3.3). Available means no check failed. The full UndoCheck schema is in openapi.yaml.

object
Example
{
"error": {
"type": "invalid_request_error",
"code": "conflict",
"message": "This action is already executing, so it can't be cancelled.",
"param": null,
"request_id": "req_01k6w4a3d5f7h9k1n3q5s7v9x1",
"doc_url": "https://docs.deedglass.com/errors/conflict"
}
}
Deedglass-Request-Id
string
/^req_[0-7][0-9a-hjkmnp-tv-z]{25}$/

This request’s id. Quote it to support; it matches error.request_id.

An error. Every error has this envelope; doc_url explains the code.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: invalid_request_error authentication_error permission_error policy_error rate_limit_error api_error
code
required
string
Allowed values: invalid_api_key api_key_revoked api_key_expired agent_suspended agent_stopped org_stopped insufficient_scope policy_denied approval_required approval_expired budget_exceeded intent_required intent_invalid intent_replay tool_unknown connector_unavailable upstream_error timeout rate_limited idempotency_conflict validation_failed not_found conflict internal_error authentication_required method_not_allowed request_too_large unsupported_media_type invalid_json api_version_invalid idempotency_key_invalid idempotency_key_in_use service_unavailable session_expired csrf_failed insufficient_role login_link_invalid login_code_invalid last_owner policy_unavailable policy_invalid credentials_missing destination_blocked vault_unavailable upstream_auth_failed upstream_not_found upstream_rate_limited response_too_large statement_refused row_limit_exceeded database_role_unsafe database_not_ready witness_not_configured approval_decided already_countersigned approver_not_eligible self_approval approval_needs_person context_changed approval_unsatisfiable approval_link_invalid approval_link_review_only approver_unmapped stripe_live_key_refused stripe_livemode_detected upstream_approval_pending schedule_needs_approval action_executing from_denied undo_unavailable undo_plan_stale already_undone undo_conflict replay_too_large replay_window_invalid suggestion_stale shadow_slot_taken suggestion_decided observe_not_enabled pro_required
message
required

One or more calm sentences with the next step.

string
param
required

The request field, query parameter or header the error is about.

string | null
request_id
required
string
/^req_[0-7][0-9a-hjkmnp-tv-z]{25}$/
doc_url
required
string format: uri
diagnostics

On policy_invalid only. Each problem with its line, code and hint.

Array<object>

One finding about a policy file, with its position and the next step. Codes are stable and listed in docs/POLICY_ERRORS.md. In the policy_invalid error envelope each diagnostic also carries object: policy_diagnostic. The full PolicyDiagnostic schema is in openapi.yaml.

object
action

One agent action. Its sections mirror the deed’s. status is the one field an agent needs; state is the exact lifecycle state (docs/GATE.md). The Gate’s own responses (POST /v1/actions and its result report) add execution.result and witness.reasons; lists leave both out. The full Action schema is in openapi.yaml.

object
checks

On undo_unavailable only. Every check of the undo, each with its fix. Additive (S23).

Array<object>

One of the twelve safety checks (S23 §3.3). Available means no check failed. The full UndoCheck schema is in openapi.yaml.

object
Example
{
"error": {
"type": "invalid_request_error",
"code": "not_found",
"message": "There's no endpoint at GET /v1/helth. Did you mean /v1/health?",
"param": null,
"request_id": "req_01j9zr3m5k8q2w7x4t6v0b1c9d",
"doc_url": "https://docs.deedglass.com/errors/not_found"
}
}
Deedglass-Request-Id
string
/^req_[0-7][0-9a-hjkmnp-tv-z]{25}$/

This request’s id. Quote it to support; it matches error.request_id.

Deedglass-Version
string

The API version this response follows.