Skip to content

Confirm a proposed action (the kernel fires it)

POST
/v1/proposed-actions/{id}/confirm
curl --request POST \
--url https://api.aerandil.com/v1/proposed-actions/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/confirm \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "applied_params": {}, "return_modified": false }'

Accept a proposed_action and commit its chained target_action. This is the gold-standard human-in-the-loop commit: a confirming principal (staff, a guest surface, or an approval gate) accepts the proposal, and the kernel — not the proposing agent — fires the frozen target_action through the scope-checked action engine (Return-of-Control), then records the confirmation on the proposal (proposal 0030 §5.2).

confirmer_scope (0030 §6). The caller must independently hold actions:{target_action}:apply for the proposal’s target action — the proposal does not launder away authorization. That grant is a dynamic per-proposal scope (it depends on which action the proposal chains), so it is not enumerable as a static security entry here; the engine enforces it when the chained action fires.

Idempotent via Idempotency-Key. The key is derived deterministically from the proposal id, so a crash between firing the action and recording the confirmation replays rather than double-fires; a replay adds idempotent_replay: true.

id
required
string format: uuid

Object id (UUID v7, server-generated at create time).

Idempotency-Key
string
>= 1 characters

Opaque idempotency token (Stripe-shape). Repeated POSTs with the same key replay the original response within the cache TTL rather than creating a duplicate object.

Media typeapplication/json
object
applied_params

The confirmer’s edit of the proposed parameters; absent → the frozen snapshot fires unchanged.

object
return_modified

Include the chained action’s modified-objects projection in the response.

boolean

Confirmed. The chained action fired and the proposal is applied. A replay adds idempotent_replay: true.

Media typeapplication/json
object
applied_action_correlation_id
required
string format: uuid
applied_target_ref

Ref of the primary object the chained action touched, when it produced one.

string | null
chained_action

The chained action’s apply envelope; present only when return_modified is true.

object
decision_status
required
Allowed value: applied
idempotent_replay

Present and true only on an idempotent replay.

boolean
proposed_action_id
required
string format: uuid
target_action
required
string
Example
{
"decision_status": "applied"
}

The confirmer lacks the target action’s actions:{target_action}:apply scope.

Media typeapplication/json

Structured error wrapper. Every non-2xx response from any Aerandil endpoint serialises to this shape; the HTTP status carries the failure class (4xx/5xx), the body adds a stable code for programmatic dispatch plus a human-readable message.

object
error
required
object
code
required

Stable, programmatic error code (e.g. unauthorized, forbidden, not_found, invalid_body, invalid_url, precondition_failed, no_secondary_key). Clients dispatch on code, not on the message (which may be localised or contextualised in future versions).

string
instance_id

Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.

string
message
required

Human-readable explanation of the failure.

string
parameters

Per-error structured detail. The shape varies by code (e.g. forbidden_action carries {"action": "..."}; precondition_failed carries {"current_version": N}).

Examplegenerated
{
"error": {
"code": "example",
"instance_id": "example",
"message": "example",
"parameters": "example"
}
}

No such proposed_action for this tenant, or its target action is not registered.

Media typeapplication/json

Structured error wrapper. Every non-2xx response from any Aerandil endpoint serialises to this shape; the HTTP status carries the failure class (4xx/5xx), the body adds a stable code for programmatic dispatch plus a human-readable message.

object
error
required
object
code
required

Stable, programmatic error code (e.g. unauthorized, forbidden, not_found, invalid_body, invalid_url, precondition_failed, no_secondary_key). Clients dispatch on code, not on the message (which may be localised or contextualised in future versions).

string
instance_id

Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.

string
message
required

Human-readable explanation of the failure.

string
parameters

Per-error structured detail. The shape varies by code (e.g. forbidden_action carries {"action": "..."}; precondition_failed carries {"current_version": N}).

Examplegenerated
{
"error": {
"code": "example",
"instance_id": "example",
"message": "example",
"parameters": "example"
}
}

not_confirmable — the proposal is in a terminal status or has expired.

Media typeapplication/json

Structured error wrapper. Every non-2xx response from any Aerandil endpoint serialises to this shape; the HTTP status carries the failure class (4xx/5xx), the body adds a stable code for programmatic dispatch plus a human-readable message.

object
error
required
object
code
required

Stable, programmatic error code (e.g. unauthorized, forbidden, not_found, invalid_body, invalid_url, precondition_failed, no_secondary_key). Clients dispatch on code, not on the message (which may be localised or contextualised in future versions).

string
instance_id

Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.

string
message
required

Human-readable explanation of the failure.

string
parameters

Per-error structured detail. The shape varies by code (e.g. forbidden_action carries {"action": "..."}; precondition_failed carries {"current_version": N}).

Examplegenerated
{
"error": {
"code": "example",
"instance_id": "example",
"message": "example",
"parameters": "example"
}
}

applied_params is present but is not a JSON object.

Media typeapplication/json

Structured error wrapper. Every non-2xx response from any Aerandil endpoint serialises to this shape; the HTTP status carries the failure class (4xx/5xx), the body adds a stable code for programmatic dispatch plus a human-readable message.

object
error
required
object
code
required

Stable, programmatic error code (e.g. unauthorized, forbidden, not_found, invalid_body, invalid_url, precondition_failed, no_secondary_key). Clients dispatch on code, not on the message (which may be localised or contextualised in future versions).

string
instance_id

Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.

string
message
required

Human-readable explanation of the failure.

string
parameters

Per-error structured detail. The shape varies by code (e.g. forbidden_action carries {"action": "..."}; precondition_failed carries {"current_version": N}).

Examplegenerated
{
"error": {
"code": "example",
"instance_id": "example",
"message": "example",
"parameters": "example"
}
}