Push notification configs
A TaskPushNotificationConfig tells an agent where to POST the same StreamResponse objects a stream carries, with credentials you chose, after your request has returned.
A test run can outlast any connection the planner wants to hold open. So the planner sends SendMessage with returnImmediately: true and a webhook, gets the task back in TASK_STATE_SUBMITTED, and closes the connection. From then on test-runner posts eight notifications to http://localhost:41250/a2a-events.
When you finish this section, you can register a webhook, authenticate what arrives, and build a receiver that stays correct when a notification comes twice.
The configuration object
TaskPushNotificationConfig: the object that tells an agent where to post updates for one task and how to authenticate them. Only url is REQUIRED. The optional token is unique to the task or the session, and the optional authentication holds a scheme such as Bearer and its credentials. The server assigns the config's id. The prose calls this object PushNotificationConfig, a type the proto does not define, so use the proto name (conflict D4).
…
"method": "SendMessage",
"params": {
"message": {
"messageId": "85750621-02fb-4d4f-b57f-bc5af71a1bfc",
…
"configuration": {
"returnImmediately": true,
"taskPushNotificationConfig": {
"url": "http://localhost:41250/a2a-events",
"token": "planner-run-0006",
"authentication": {
"scheme": "Bearer",
"credentials": "hook_secret_91d2"
}Inline, as here, the config rides in configuration.taskPushNotificationConfig. That leaves no gap, because the kit and the reference SDK store it before the first event. For a task that already exists, CreateTaskPushNotificationConfig takes the config itself, with its taskId. The prose and Appendix A name a CreateTaskPushNotificationConfigRequest instead, which the proto does not define (conflict D5).
Agents SHOULD validate the url, as Security requirements explains.
What arrives at the webhook
Each notification is an HTTP POST whose body is one StreamResponse. The JSON is always the HTTP+JSON form, whatever binding the agent speaks. So test-runner posts a plain statusUpdate with no JSON-RPC envelope, as figure 4.8 shows.
Content-Type: application/a2a+json
Authorization: Bearer hook_secret_91d2
X-A2A-Notification-Token: planner-run-0006
{
"statusUpdate": {
"taskId": "d7d3dceb-7333-4676-90ce-36542116a45c",
"contextId": "e051d022-3c39-4f5c-bd9c-7a902ae474cd",
"status": {
"state": "TASK_STATE_WORKING",
…
"timestamp": "2026-10-06T09:00:05.000Z"The agent must put the credentials from PushNotificationConfig.authentication in the request headers. The specification gives the token no transport, and the kit sends it in X-A2A-Notification-Token, the reference SDK's header.
The specification's request format uses application/a2a+json, and the reference SDK posts application/json, as the kit README lists. The SDKs also differ on the token header and the timeout, and none retries:
| SDK | Content-Type | Token header | Timeout | Retries |
|---|---|---|---|---|
| a2a-python 1.2.2 | application/json | X-A2A-Notification-Token | set by the httpx client the server passes in | none |
| a2a-go | application/json | A2A-Notification-Token | 30 s | none |
| a2a-java | application/json | X-A2A-Notification-Token | none set | none |
| a2a-js | application/a2a+json | X-A2A-Notification-Token, only when authentication is empty | 5 s | none |
| a2a-dotnet | no sender: every config operation returns -32003 | |||
| a2a-rs | application/json | A2A-Notification-Token | 30 s | none |
Every sender in the table posts one StreamResponse per event. So accept both content types, read either token header, and put the secret you rely on in authentication. The specification does not say which events are posted, and the reference SDK also posts the first Task, so handle every StreamResponse member.
Delivery is attempted at least once
At least once means a notification can arrive twice, so the receiver has duties too. It must answer with an HTTP 2xx status to confirm receipt. It should process notifications idempotently, because duplicates can arrive. It must check that the task id matches a task it expects.
A status update is safe to apply twice, keyed by taskId and timestamp. An artifactUpdate with append: true is not, and the specification defines no delivery id. So treat each notification as a signal and read the task with GetTask, as the project's guide suggests.
Retries are optional: an agent is allowed to retry a failed delivery with exponential backoff. No SDK in the table retries, so a receiver that was down reads the task with GetTask when it comes back.
Managing configurations
Four operations manage the stored configs of a task: create, get, list, and delete. The capture lists, reads, and deletes its config after the run, as figure 4.8 shows. A config must stay until the task completes or until a client deletes it, and a delete must be idempotent.
Get and list return the stored credentials unchanged, in the kit and the reference SDK, so whoever can call them can read the webhook secret. All four operations need pushNotifications on the card, or they return PushNotificationNotSupportedError.
A2A protocol 1.0.1 · 3303592 · 2026-05-28 · Edition 2026.10