Acknowledge receipt of a dispatch
const url = 'https://api.aerandil.com/v1/participant-dispatches/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/ack';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"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"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}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).
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”The participant_dispatch_attempt row id — same id the coordinator stamped into the CloudEvents subject and into the outbound dispatch envelope.
Request Bodyrequired
Section titled “Request Bodyrequired”Signed dispatch_ack envelope (proposal 0022 §7.2).
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
Aerandil-specific payload (§5.5). Shape varies by type; the schema at dataschema is the contract.
object
URL of the schema describing data. v1 URLs are https://schema.aerandil.example/0022/...; receivers match on this to dispatch parsing.
UUID v7 per §5.1; reused across retries of the same logical dispatch.
Producer URI; e.g. aerandil://coordinator/tenant=T-1/program=... or aerandil://participant/....
CloudEvents specversion — pinned at 1.0.
Composite key (e.g. <run_id>/<participation_id>/<slot>).
RFC 3339; checked against the ±5-minute replay window.
Reverse-DNS message kind.
object
object
Ed25519 detached signature over the canonical bytes of the surrounding envelope (RFC 8785 JCS with the signature field elided). Proposal 0022 §8.2.
object
Signature algorithm — v1 supports ed25519 only.
Key identifier. Resolves against federated_participation.runner_signing_key_ref for participant-signed envelopes, or the coordinator signing config for coordinator-signed.
Base64 (RFC 4648 §4) detached signature bytes.
Responses
Section titled “Responses”Ack accepted (or idempotent replay against an already-acknowledged row).
Missing or invalid bearer credential.
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
object
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).
Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.
Human-readable explanation of the failure.
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.
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
object
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).
Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.
Human-readable explanation of the failure.
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).
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
object
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).
Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.
Human-readable explanation of the failure.
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.
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
object
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).
Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.
Human-readable explanation of the failure.
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).
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
object
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).
Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.
Human-readable explanation of the failure.
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" }}