For AI agents: fetch the complete documentation index at /llms.txt, the full documentation corpus at /llms-full.txt, the agent skill at /skill.md, or this page as Markdown at /docs/mobile/notifications.md (or send Accept: text/markdown).
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.