Skip to content

Acknowledge receipt of a dispatch

POST
/v1/participant-dispatches/{id}/ack
curl --request POST \
--url https://api.aerandil.com/v1/participant-dispatches/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/ack \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "data": { "ack": { "envelope_id_received": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "local_runner_version": "example", "received_at": "2026-04-15T12:00:00Z" }, "dispatch_kind": "example", "envelope_version": "1.0", "signature": { "alg": "ed25519", "kid": "example", "value": "example" } }, "datacontenttype": "application/json", "dataschema": "https://schema.aerandil.example/0022/dispatch_ack.v1.json", "id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "source": "example", "specversion": "1.0", "subject": "example", "time": "2026-04-15T12:00:00Z", "type": "aerandil.participant_dispatch.acknowledged" }'

Participant → coordinator. Confirms receipt of a dispatch envelope. Optional in v1 for HTTPS POST profiles (the original POST’s 2xx response is the implicit ack); REQUIRED for agent_installation SSE dispatches because the SSE channel is asymmetric.

Envelope shape. A signed CloudEvents 1.0 envelope with type = aerandil.participant_dispatch.acknowledged. Ed25519 detached signature over the canonical bytes (RFC 8785 JSON Canonicalization); kid resolves against the participation row’s runner_signing_key_ref.

Idempotency. The dispatch row carries the acknowledged-at timestamp; a second ack against an already-acknowledged row returns the same 200 without state change.

Auth. Requires the deployment-owned service principal with the internal:participant_dispatch:receive scope (not a tenant token).

id
required
string format: uuid

The participant_dispatch_attempt row id — same id the coordinator stamped into the CloudEvents subject and into the outbound dispatch envelope.

Signed dispatch_ack envelope (proposal 0022 §7.2).

Media typeapplication/json

Envelope with type = aerandil.participant_dispatch.acknowledged (§7.2). Body of POST /v1/participant-dispatches/{id}/ack. The data block carries the participant’s receipt confirmation; the schema at dataschema (/0022/dispatch_ack.v1.json) describes its shape.

object
data
required

Aerandil-specific payload (§5.5). Shape varies by type; the schema at dataschema is the contract.

object
datacontenttype
required
string
Allowed value: application/json
dataschema
required

URL of the schema describing data. v1 URLs are https://schema.aerandil.example/0022/...; receivers match on this to dispatch parsing.

string format: uri
id
required

UUID v7 per §5.1; reused across retries of the same logical dispatch.

string format: uuid
source
required

Producer URI; e.g. aerandil://coordinator/tenant=T-1/program=... or aerandil://participant/....

string
specversion
required

CloudEvents specversion — pinned at 1.0.

string
Allowed value: 1.0
subject
required

Composite key (e.g. <run_id>/<participation_id>/<slot>).

string
>= 1 characters
time
required

RFC 3339; checked against the ±5-minute replay window.

string format: date-time
type
required

Reverse-DNS message kind.

string
Allowed values: aerandil.participant_dispatch.dispatched aerandil.participant_dispatch.acknowledged aerandil.participant_dispatch.result_submitted aerandil.participant_dispatch.delivery_failed aerandil.participant_dispatch.quarantine_notice
data
required
object
ack
required
object
envelope_id_received
required
string format: uuid
local_runner_version
string
received_at
required
string format: date-time
dispatch_kind
required
string
>= 1 characters
envelope_version
required
string
Allowed value: 1.0
signature
required

Ed25519 detached signature over the canonical bytes of the surrounding envelope (RFC 8785 JCS with the signature field elided). Proposal 0022 §8.2.

object
alg
required

Signature algorithm — v1 supports ed25519 only.

string
Allowed value: ed25519
kid
required

Key identifier. Resolves against federated_participation.runner_signing_key_ref for participant-signed envelopes, or the coordinator signing config for coordinator-signed.

string
>= 1 characters
value
required

Base64 (RFC 4648 §4) detached signature bytes.

string
>= 1 characters
dataschema
required
Allowed value: https://schema.aerandil.example/0022/dispatch_ack.v1.json
type
required
Allowed value: aerandil.participant_dispatch.acknowledged

Ack accepted (or idempotent replay against an already-acknowledged row).

Missing or invalid bearer credential.

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"
}
}

Principal lacks internal:participant_dispatch:receive scope, or is not a service principal.

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 dispatch row with that id (or row is in a different tenant).

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"
}
}

Illegal status transition — the row is in a terminal state and cannot be re-acknowledged.

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"
}
}

Envelope parse / signature verification failed (malformed JSON, wrong type, expired time, signature mismatch).

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"
}
}