Overview
Notify is the web-push notification platform. Browsers never hold Notify secrets: a trusted product backend bridges every call server-to-server, so each browser talks only to its own same-origin product backend, which in turn talks to Notify with push-platform auth.
Architecture at a glance
The browser UI calls only its same-origin product backend, which holds its own bridge secrets (push-platform token; optional editor token) and forwards to notify-api. Notify delivers through notify-sender to the browser push service and service worker; interaction events flow back through the product backend to notify-api. Mongo: notify-api writes subscriptions_webpush and ingests interaction_events_webpush; notify-sender updates notifications_webpush after delivery.
The golden rule
The browser calls only its own same-origin product backend. That backend calls Notify server-to-server with push-platform auth.
- Never call Notify directly from the browser.
- Never use
player_id: 0in a product integration — it is reserved for the internal dashboard smoke bucket.
Two-token auth model
Each token has a platform canonical name (what Notify stores) and a consumer copy (what your backend holds). The values must match; the env var names do not.
| Token | Your backend (consumer) | Notify platform (canonical) | Used for | Routes |
|---|---|---|---|---|
| Push-platform auth | Your bearer token secret (name yours) | NOTIFY_API_PUSH_PLATFORM_CALLERS_JSON | browser lifecycle | client-config, subscriptions, deactivate, events/browser, events/semantic |
| Editor token | Your editor bearer token (optional) | INAPP_EDITOR_API_AUTH_TOKEN | admin authoring | template CRUD, /api/v1/tenants/, /webpush/send, /webpush/activity |
Env-var NAME mismatch footgun. A consumer app names its own var differently (e.g. the dashboard uses NOTIFY_PUSH_PLATFORM_TOKEN) from the platform-side NOTIFY_API_PUSH_PLATFORM_CALLERS_JSON that Notify validates against. The consumer's token value must be listed as a token in that caller policy; the names differ because they belong to different services.
Current workspace status
lumio_admin_dashboard is the canonical committed Notify browser integration in this workspace today. The casino player-facing integration is in progress: online-services-front (React + Vite client) bridged through the online-services-player Node proxy, documented in Casino Integration.
Identity model
Every subscription, delivery, and event is scoped to a tenant and player. Your bridge sends tenant_id and player_id — both resolved server-side from trusted session/config, never from the browser.
| Field | Rule |
|---|---|
tenant_id | Casino/brand context from server config or session |
player_id | Positive integer from authenticated session/profile lookup |
player_id: 0 is reserved for internal dashboard smoke tests only (lumio_admin_dashboard).
One player can have multiple active subscriptions (different browsers/devices). Delivery fans out to every active endpoint for that (tenant_id, player_id) pair.
Event trust split
| Channel | Route | Events | Verified by |
|---|---|---|---|
| Browser telemetry | events/browser | displayed / clicked / closed | opaque interaction_token |
| Semantic app events | events/semantic | opened / read | explicit tenant_id + positive player_id |
These are separated because browsers can lie about semantics, so meaning-bearing events carry server-resolved identity. Telemetry is idempotent and non-mutating, so it is verified only by the opaque token Notify issued.
Where to go next
| Page | What it covers |
|---|---|
| Integration Guide | Build a new browser + backend integration end to end |
| API Reference | Every route, request/response, error code |
| Configuration & Secrets | Env vars, caller policy, VAPID, retention |
| Push Service Environment Config | Per-environment vars your backend must configure |
| Reference: Dashboard | The canonical working integration |
| Casino Integration | online-services-front via the player Node proxy |