Skip to main content
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: One fires on the requester side — the identity that sent that task: 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:
JSON
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.