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 events may share a subscription with email, SMS/MMS, iMessage, and call-lifecycle notifications. Configure the subscription on the identity even before Agent2Agent is enabled. Conversation context may be configured for received communication events on the same subscription, but A2A payloads do not include it.
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.

Verified domains and actual senders

data.caller remains the task’s original requester. The optional data.sender identifies the actual author for message events, including worker replies. Both participants may have an optional affiliation containing domain, verifier: "Inkbox", last_success_at, and valid_until. Webhook affiliations are snapshots created with the event. Use the existing timestamp as the snapshot time; retries retain the same payload. A later hide, release, or expiry does not rewrite a delivered event. Fetch the authorized task for current participant assertions and reject expired evidence in cached events. Hiding a domain from public discovery does not suppress it for authorized peers.