# Send Notifications (Universal)

Send one push notification to your universal audience — all devices, a device list, or a subscriber list — and read the per-transport accepted/failed result.

One endpoint sends one notification to the devices registered through the universal service:

```text
POST https://app.nativenotify.com/api/universal/notifications/send
```

## Request

```json
{
  "appId": 123,
  "appToken": "yourAppToken",
  "title": "Service this Sunday",
  "message": "Doors open at 9:00 — the 10:30 service is unchanged.",
  "audience": { "type": "all" }
}
```

| Field               | Required | Notes                                                                                                                                                  |
| ------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `appId`, `appToken` | yes      | Your app's pair.                                                                                                                                       |
| `title`             | yes      | Notification title.                                                                                                                                    |
| `message`           | yes      | Body text. `body` is accepted as an alias.                                                                                                             |
| `audience`          | yes      | **This service sends only to its own registered devices** — see the audience shapes below.                                                             |
| `pushData`          | no       | JSON object delivered to the app with the notification (deep links, ids).                                                                              |
| `bigPictureURL`     | no       | Image url (Android big picture / iOS attachment source).                                                                                               |
| …rich options       | no       | The message options the APNs/FCM transports support (subtitle, sound behavior, badge, and so on) are passed through where the transport supports them. |

### Audience shapes

```json
{ "audience": { "type": "all" } }
```

```json
{ "audience": { "type": "devices", "deviceIds": ["A1B2C3D4-install-key", "E5F6-install-key"] } }
```

```json
{ "audience": { "type": "subscribers", "subscriberIds": ["user_8241", "user_8242"] } }
```

- `all` — every registered universal device on the app.
- `devices` — the listed `deviceId`s.
- `subscribers` — every device registered under the listed `subscriberId`s (all of a user's devices, which is the supported pattern).

> **Live sends:**
>
> Sends are live and cannot be recalled. Agents are instructed to confirm title, body and audience with you before sending — do the same in scripts: a dry run means a `devices` audience with one device of your own.

## Response — `200`

```json
{
  "ok": true,
  "devices": 1284,
  "attempted": 1301,
  "accepted": 1298,
  "failed": 3,
  "byType": {
    "apns": { "attempted": 640, "accepted": 639, "failed": 1, "delivered": null },
    "fcm": { "attempted": 661, "accepted": 659, "failed": 2, "delivered": null }
  },
  "skipped": { "apns": 0, "fcm": 4 },
  "health": { "apns": { "struck": 0, "dead": 1 }, "fcm": { "struck": 1, "dead": 0 } },
  "checkedAt": "2026-09-23T09:30:00.000Z"
}
```

| Field                               | Meaning                                                                                                                                                     |
| ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `devices`                           | Devices the audience resolved to (a device counts once even when it has several tokens).                                                                    |
| `attempted` / `accepted` / `failed` | Tokens sent to, accepted by the transport, and rejected.                                                                                                    |
| `byType`                            | The same split per transport (`apns`, `fcm`). `delivered` is always `null` — native transports cannot prove delivery, and this service never fabricates it. |
| `skipped`                           | Tokens with no credentials configured for their transport. An app-config gap, never counted against the token.                                              |
| `health`                            | Tokens currently marked dead or repeatedly failing (see [Verify Delivery](/docs/universal-push/verification)).                                              |

Failures are per token: a rejected token is recorded with its transport answer, and repeatedly failing tokens accumulate strikes like the Expo path does (see [Tokens & Receipts](/docs/tokens-and-receipts)).

## What agents do

Connected agents have their own tools (mass/indie/group/topic sends, scheduling, analytics) and — for accounts on the universal path — the same REST contract above is what a "send to my Flutter app" script or tool call ends up doing. Every response is machine-readable so an agent can report accepted vs failed honestly.

## Related

- [Test send](/docs/universal-push/verification) — prove one device/token before a blast.
- [Scheduling](/docs/scheduling) — one-off and recurring sends.
- [Segments](/docs/segments) — named subscriber groups that sends and schedules can target.
