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

# Notifications

> Notify one user or your app's recent-user audience through Bankroll.

Your server can ask Bankroll to send a notification with your app's name on
the title. Tapping it opens a path on your app's origin. Notifications require a
[Bankroll-signed manifest](/build/verified) with a truthy `capabilities.push`
and an attested signing key. See [configuration and compatibility](/build/app-authentication).

## Methods

```ts theme={null}
import { notifyUser, notifyAudience } from "@joinbankroll/sdk/server";

await notifyUser({
  origin: "https://acme.example",
  to: session.user.wallet, // from your verified session
  title: "Match ready",
  body: "Your opponent is ready to play.",
  path: "/app/matches/9",
});

await notifyAudience({
  origin: "https://acme.example",
  title: "New season",
  body: "Season two is open.",
  path: "/app",
});
```

Both return `Promise<void>`, resolving when Bankroll accepts the request for
delivery. This is not confirmation that a device displayed it. `notifyUser`
targets one Bankroll user; `notifyAudience` targets your configured recent-user
audience. Bankroll applies your app's audience and mute policies.

| Field    | Required          | Meaning                                                                                   |
| -------- | ----------------- | ----------------------------------------------------------------------------------------- |
| `origin` | Yes               | Your canonical HTTPS origin, matching the signed manifest.                                |
| `to`     | `notifyUser` only | The recipient's Bankroll wallet address.                                                  |
| `title`  | Yes               | Text after your app's name. Trimmed; must be nonempty. Keep it short for device displays. |
| `body`   | Yes               | Notification text. Trimmed; must be nonempty.                                             |
| `path`   | No                | Path on your own origin, starting with `/` but not `//`. Defaults to `/`.                 |

## Authentication

With `BANKROLL_APP_KEY`, the SDK sends a [shared app JWT](/build/app-authentication)
in the Authorization header and an `application/json` body:

| Endpoint                                               | JSON body                                                         |
| ------------------------------------------------------ | ----------------------------------------------------------------- |
| `POST https://api.joinbankroll.com/api/push`           | `{ "to": "<wallet>", "title": "…", "body": "…", "path": "/app" }` |
| `POST https://api.joinbankroll.com/api/push/broadcast` | `{ "title": "…", "body": "…", "path": "/app" }`                   |

`path` is optional. The authenticated token supplies the origin.
`BANKROLL_API_URL` overrides the default API origin.

With only `BANKROLL_PUSH_KEY`, the SDK preserves the legacy `application/jwt`
request body, without an Authorization header. These JWTs use `alg: EdDSA`,
`iss: <app-origin>`, `aud: bankroll-push`, and a 60-second SDK lifetime.
The type is `bankroll-push+jwt` for unicast or `bankroll-push-broadcast+jwt`
for broadcast; content is in `title`, `body`, and optional `path`, with the
unicast recipient in `sub`. A legacy token does not grant general app access.

## Errors

A refused request throws `PushError`; its `code` is Bankroll's reason:

| Code                                                               | Meaning                                                             |
| ------------------------------------------------------------------ | ------------------------------------------------------------------- |
| `unauthenticated`, `unauthorized`                                  | Invalid shared or legacy authentication.                            |
| `app_not_verified`, `push_not_declared`                            | The signed manifest does not authorize this request.                |
| `push_muted`                                                       | Bankroll has muted the app's notification access.                   |
| `unknown_user`, `not_your_user`                                    | Unknown recipient or recipient outside your app's allowed audience. |
| `broadcast_not_configured`                                         | Your app's broadcast audience is not configured.                    |
| `invalid_request`, `invalid_title`, `invalid_body`, `invalid_path` | Invalid request fields.                                             |
| `unavailable`, `push_not_enabled`                                  | Bankroll cannot serve the request now.                              |

Configuration and network failures can throw other errors. The SDK does not
retry sends automatically; a lost reply may hide an accepted notification,
so retrying can send it twice.
