# Send phone notifications

Your backend can attach a phone notification to an approved custom event.
Barua queues it for the person the event names and hands it to Apple for each
of their phones on its next run, once a minute.

## Before you start

The owner has [turned notifications on](/docs/guides/notifications.md) and
your backend [registers phones](/docs/guides/notification-devices.md). The
custom event also needs an enabled service policy, the same approval a
service email uses. Send with a live key that has `events:write` and
`service:write`. Backfill and test keys never send.

## Add the block

```json
{"event_id":"notes_ready:meeting-4812","name":"notes_ready","external_id":"4812","occurred_at":"2026-11-12T09:00:00Z",
 "service_notification":{"title":"Your notes are ready","body":"Open the app to read them.","data":{"screen":"notes"}}}
```

`title` is one line of at most 200 characters and `body` is the text. `data`
holds string values your app reads when the person taps; `aps` is Apple's
name and is refused. `expires_in_seconds` is 0 to 2,419,200, one day by
default, counted from when Barua accepted the event. Apple keeps it that long
for a phone that is offline. Barua tries for at most an hour, so `0` sends
nothing. An event whose notification is over Apple's 4,096 bytes is
quarantined.

Use `marketing_notification` for marketing, with the same fields. It also
needs the owner's marketing statement and the person's yes. An event carries
only one of the two blocks. Resending the same `event_id` with the other block is
an `event_id_conflict`.

It goes to every live device registered for that `external_id`, across your
apps. A merged person can hold two identity rows; only the one you name is
notified.

## When a request is refused

409 `notifications_not_enabled` refuses the whole request while
notifications are off, so drop the block or stop sending. 409 `marketing_notifications_not_enabled` refuses the whole request,
service events in it included, while the marketing statement is off. Keep
marketing notifications in a request of their own until it is on.

## Marketing answers

A missing answer ends the delivery `no_consent`. Send the person's answer
first, as `notification_consent_updated` or
`marketing_notification_opt_in` on `signed_up`, with the live key, a new
`event_id` for every change and the current time, and wait until it shows as
applied. The iPhone permission prompt is a separate question; your app needs
both.

## Read the outcome

```sh
curl https://barua.ai/api/integrations/v1/service-notifications/notes_ready%3Ameeting-4812 \
  -H "Authorization: Bearer $BARUA_EVENT_KEY"
```

Use the live key that sent the event. The answer has `class`, `status`,
`reason` (a code and a message for the owner) and a count per device
outcome, never the text. A 404 means the event isn't applied
yet, or another key sent it.

`queued` is waiting to send or to retry. `accepted` means Apple took it for
at least one phone; Apple delivers it when the phone is online, and the
person's settings decide whether it shows. `unconfirmed` means a
request reached Apple with no answer, and Barua never sends it again.
`no_devices` means no live phone, or Apple reported every token gone.
`no_consent` means no recorded yes. `cancelled` means an approval changed, or the
person was erased, before it went. `failed` means an
hourly limit was spent (20 per person and 1,000 per workspace, for each
kind), Apple refused it for every phone (`apple_refused`, or
`wrong_environment` for a token from the other build type), Apple refused
the app's key (`app_key_rejected`), or an hour passed without Apple taking
it (`expired`). A later device or a later yes does not revive a finished
delivery.

Nothing Barua does later, a pause or an erasure included, can recall what
Apple already accepted. Erasing a person removes the stored text and keeps
the status. Stored text has no retention window yet. Exact rules are in the
[events reference](/skills/barua-setup/references/events.md#phone-notifications).
