> ## Documentation Index
> Fetch the complete documentation index at: https://supastack.dev/llms.txt
> Use this file to discover all available pages before exploring further.
> For the full documentation corpus in one file, fetch: https://supastack.dev/llms-full.txt

# Notifications and push

The in-app inbox, channel preferences, and the Expo push pipeline.

## The inbox and channel preferences

The notifications tab lists workspace notifications from GET /api/notifications and marks them read with a PATCH on the notification id. Settings → Notifications edits the shared channel preferences — emailBilling, emailInvites, inAppProduct — through GET and PATCH on the same route's preferences view, the exact contract the web app uses. The unread count surfaces on the home screen.


## Register a device for push

On sign-in — and again on every workspace switch — the app requests notification permission, resolves the EAS project id from the app config, obtains an Expo push token, and posts it to POST /api/mobile/push-tokens. Android registers on the default channel at high importance.

Registration reports registered, permission_denied, or unavailable and never throws — sign-in is never blocked by push. Expo Go and simulators cannot complete registration, so real coverage needs a development build. The token is kept in SecureStore (supastack.push.token) so sign-out can unregister it before the session cookie is destroyed.


## Server delivery and receipts

GET lists the member's tokens, POST upserts a token under the active workspace, and DELETE revokes — list and revoke stay user-scoped so a workspace-less account can still clean up. Each user keeps at most twenty device tokens; registering one more prunes the oldest.

Every in-app workspace notification is also pushed best-effort: the server sends to the Expo push API in chunks of one hundred, records ok tickets, and prunes DeviceNotRegistered tokens immediately. The optional server-only EXPO_ACCESS_TOKEN adds a Bearer header to those calls and is never logged. A platform schedule reconciles receipts every thirty minutes and sweeps stale tickets — it needs the same scheduler tick driver as the other platform schedules.

```
# Optional server-only token for authenticated Expo push sends:
# apps/web/.env.local
EXPO_ACCESS_TOKEN=
```


## Notification taps open app routes

Senders attach a web path as data.href. The app validates it — absolute slash paths only, bounded length, no traversal — and maps known paths to native routes, for example /billing to /settings/billing and /dashboard to /home. A tap that arrives while signed out is buffered and flushed after sign-in completes.


## Verification and troubleshooting

Test on a development build: grant and deny permission, toggle push under Settings → Notifications — the screen reports this device as enabled, disabled, or denied — and tap a notification cold and warm. If switching off shows an error, the server-side unregister failed and the device stays registered until it succeeds.

[Create a development build](https://supastack.dev/docs/mobile/eas-setup.md)


## Next

[Usage and credits](https://supastack.dev/docs/mobile/usage.md)
