> ## Documentation Index
> Fetch the complete documentation index at: https://noorle.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Push Notifications

> Register a webhook and have the agent gateway POST task updates to it, with the delivery guarantees each kind of update carries

A long-running task does not require you to hold a connection open. Register a
webhook against the task and the agent gateway will `POST` task updates to it as
the task progresses.

The agent card advertises this on its `capabilities` object:

```json theme={null}
{ "capabilities": { "streaming": true, "pushNotifications": true } }
```

Push notifications complement [streaming](/docs/reference/a2a/message-stream) rather
than replacing it. Streaming is for a caller waiting on the result now; push is
for a caller that wants to hang up and be told later.

## Registering a target

Four methods manage push configs on a task. All are `POST` to the gateway root,
with the method name in the JSON-RPC envelope.

| Method                             | Purpose                           |
| ---------------------------------- | --------------------------------- |
| `CreateTaskPushNotificationConfig` | Register a webhook against a task |
| `GetTaskPushNotificationConfig`    | Read one config back              |
| `ListTaskPushNotificationConfigs`  | List every config on a task       |
| `DeleteTaskPushNotificationConfig` | Remove one                        |

```bash theme={null}
curl -X POST https://agent-my-agent.noorle.com/ \
  -H "Authorization: Bearer eyJhbGc..." \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "CreateTaskPushNotificationConfig",
    "params": {
      "taskId": "0198f2c1-...",
      "url": "https://hooks.example.com/noorle/task-updates",
      "token": "a-verifier-you-generate",
      "authentication": {
        "scheme": "bearer",
        "credentials": "YOUR_WEBHOOK_CREDENTIAL"
      }
    }
  }'
```

| Field            | Required | Description                                                                         |
| ---------------- | -------- | ----------------------------------------------------------------------------------- |
| `taskId`         | Yes      | The task to watch                                                                   |
| `url`            | Yes      | Where to `POST` the callback                                                        |
| `id`             | No       | Config identifier. Omit it and the server mints one                                 |
| `token`          | No       | An opaque value echoed back on every callback so you can verify it came from Noorle |
| `authentication` | No       | Credential the gateway attaches when calling your endpoint                          |

`authentication.scheme` accepts **`bearer`** or **`basic`**. Any other scheme is
refused rather than guessed at, so a credential is never sent under a scheme the
gateway did not recognize.

### URL rules

The callback URL is validated before anything is sent to it:

* **HTTPS only.**
* **No credentials in the URL** — no `user:password@` userinfo section.
* **Public hosts only.** Private-range and cloud metadata addresses are refused.

## What arrives at your endpoint

The gateway sends a `POST` whose body is the **full task snapshot**, wrapped as
an A2A stream response:

```json theme={null}
{
  "task": {
    "id": "0198f2c1-...",
    "contextId": "0198f2b0-...",
    "status": { "state": "TASK_STATE_COMPLETED" },
    "artifacts": [ /* ... */ ]
  }
}
```

This is byte-for-byte the shape `GetTask` returns for the same task, so an A2A
SDK deserializes a callback body with the same type it uses for a task read.
Your handler does not need a separate parser.

Two headers matter:

| Header                   | When                        | Value                                           |
| ------------------------ | --------------------------- | ----------------------------------------------- |
| `A2A-Notification-Token` | If you set `token`          | The exact value you registered                  |
| `Authorization`          | If you set `authentication` | `Bearer <credentials>` or `Basic <credentials>` |

Verify the token before acting on a callback. Because the body is a full
snapshot rather than a delta, a handler that processes callbacks out of order
still converges — take the latest snapshot and discard the older one.

## Delivery contract

**Not every update is equally durable, and the difference is deliberate.**
Notifications are sorted into two lanes by the task state they carry.

| Lane            | States                                                                                                                                             | Guarantee                                                                                    |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| **Reserved**    | `TASK_STATE_COMPLETED`, `TASK_STATE_FAILED`, `TASK_STATE_CANCELED`, `TASK_STATE_REJECTED`, `TASK_STATE_INPUT_REQUIRED`, `TASK_STATE_AUTH_REQUIRED` | Never dropped to make room for other traffic. Gets its own capacity and one retry on failure |
| **Best effort** | Intermediate `TASK_STATE_WORKING` and artifact-only progress updates                                                                               | **May be dropped under load.** No retry                                                      |

The reasoning is that the notifications you build on are "the task finished" and
"the task needs something from you." Those get a lane that heavy progress
traffic cannot starve. Progress chatter is useful when it arrives and safe to
lose when the system is busy.

<Warning>
  **Do not build a progress bar that assumes every `working` update arrives.**
  Treat intermediate updates as hints. If you need every intermediate step, use
  [`SendStreamingMessage`](/docs/reference/a2a/message-stream) or
  `SubscribeToTask`, which stream the full event sequence.
</Warning>

Delivery is best-effort overall, not transactional: a callback endpoint that is
down for the duration of a task's final notification will miss it even in the
reserved lane. For work where missing a completion is unacceptable, treat push
as the fast path and reconcile with `GetTask` on a slower timer.

## Choosing between push and streaming

| You want                                         | Use                                         |
| ------------------------------------------------ | ------------------------------------------- |
| The result now, connection held open             | `SendStreamingMessage`                      |
| Every intermediate event, reliably               | `SendStreamingMessage` or `SubscribeToTask` |
| To disconnect and be called back when it matters | Push notifications                          |
| To reattach to a task you already started        | `SubscribeToTask`                           |

## Related

* [Tasks](/docs/reference/a2a/tasks) — `GetTask`, `CancelTask`, `SubscribeToTask`
* [SendStreamingMessage](/docs/reference/a2a/message-stream)
* [A2A Protocol](/docs/reference/a2a/overview)
