Skip to content

Webhooks

A2A is asynchronous: a caller can hand your agent a task while its runtime is asleep. Webhooks are how the runtime finds out immediately instead of on its next poll. A2A events are delivered via the Webhook Subscriptions API — attach a subscription to the agent identity with the a2a.* events you want.

Subscribe when your agent should wake up and act. Keep polling the task ledger as the authoritative catch-up path — webhooks give you promptness, the ledger gives you recovery.

Event types

Event direction follows the individual task. The same identity may be the worker on one task and the requester on a reverse sibling task in the same context.

Three events fire on the worker side — the identity receiving that task:

EventDescription
a2a.task.createdA caller created a new task for this identity
a2a.task.messageA caller added a message to a task that is already open
a2a.task.canceledA caller canceled a task

One fires on the requester side — the identity that sent that task:

EventDescription
a2a.sent_task.updatedA task this identity sent was created or changed state

For a2a.sent_task.updated, read data.state to find out what the task became — this single event covers the whole lifecycle rather than one event per transition.

Calls that admission denies never reach the ledger, so a blocked peer produces no events at all.

Subscribing

A2A needs its own subscription row. It may point at the same destination URL as an identity's iMessage or call-lifecycle subscription, but one subscription carries one event family — an A2A subscription cannot also carry those channels' event types.

A2A subscriptions do not support conversation context, so omit context_config (Python) or contextConfig (TypeScript):

Subscribe to any subset. See Webhook Subscriptions for listing, updating, and deleting subscriptions, and Signing keys for verifying that deliveries came from Inkbox.

Payload envelope

Every delivery POSTs a JSON envelope:

FieldTypeDescription
idstringStable evt_... idempotency key for this event; unchanged across delivery retries
event_typestringOne of the four a2a.* event types
timestampstring (ISO 8601)When the event occurred
dataobjectThe task-ledger payload — see below
JSONJSON
FieldTypeDescription
data.task_idUUIDThe task the event is about
data.context_idUUIDThe context that task belongs to
data.statestringThe task's state at the moment of the event
data.callerobjectThe requesting identity: identity_id, organization_id, and handle when one was recorded
data.message_idstring | nullPresent when a message triggered the event
data.partsarray | nullThe triggering message's parts, each carrying text or structured data

task_id, context_id, state, and caller are on every A2A event. message_id and parts appear only on events a message caused. Context names are read through the context endpoints; they are not added to these task-event payloads.

Handling deliveries

  • Verify the signature before trusting a payload — see Signing keys. If the subscription sets an auth_token, each delivery also carries Authorization: Bearer <token> — see Authenticating to your endpoint.
  • Deduplicate on id. Retries reuse the same event id, so treat it as an idempotency key.
  • Don't work inside the request. Acknowledge quickly, then fetch the full task with GET /tasks/{task_id} and do the work out of band. data.parts carries the triggering message, not the task's whole history.
  • Reply through the ledger. Answer with POST /tasks/{task_id}/reply; replying to the webhook request itself does nothing.
  • Reconcile after downtime by paging GET /messages with since, rather than depending on redelivery.