Push notifications

App keys & token rotation

Use the publishable web key in browser code, and rotate your app token with a grace period for the old one.

Two credentials

App tokenPublishable web key
Looks like22 alphanumeric charactersnnweb_…
Can doEverything the app can: send, read inboxes, manage groups, read analyticsRegister or deregister one browser device, and read or mark that device's own inbox. Reads the app's public VAPID key.
Can't do—Send, list groups or subscribers, read another device's data, or touch Classic or account routes
Safe in page sourceNo, it can send to everyoneYes

Both go in the same place: wherever an endpoint takes appToken (the :appToken path parameter on GETs, the appToken body field on POSTs). The service tells them apart by the nnweb_ prefix. A web key used outside the list below answers 403 web_key_not_allowed. The app token keeps working everywhere.

Use the web key in every browser snippet, and keep the app token on your server and in native app builds.

What a web key may call

CallEndpoint
Register a web devicePOST /api/universal/device/register with { appId, appToken: <webKey>, platform: "web", deviceId, webPush }
Deregister itPOST /api/universal/device/deregister with { appId, appToken: <webKey>, deviceId }
List, unread countGET /api/universal/inbox/:appId/:webKey?deviceId=… and …/unread-count?deviceId=…
Mark, deletePOST /api/universal/inbox/read, read-all, delete or clear with { appId, appToken: <webKey>, deviceId, entryId? }
Public VAPID keyGET /api/universal/web-push/keys/:appId/:webKey

A web key reaches only these routes, and only devices it registered itself. A device registered with the app token, or on iOS or Android, is out of reach even if its deviceId is known (403 web_key_scope). A request on another app never matches (401, like a wrong token).

Read the web key

GET https://app.nativenotify.com/api/apps/<APP_ID>/web-key

This needs a dashboard session or MCP token; an app token is refused on /api/apps/*. Like the VAPID keypair, the key is created the first time you read it.

{
  "ok": true,
  "app": { "id": 123, "name": "Corner Bakery" },
  "webKey": "nnweb_1f1c…",
  "webKeyCreatedAt": "2026-09-29T12:00:00.000Z",
  "scope": { "canRegister": true, "canReadOwnDeviceInbox": true, "canSend": false },
  "webPush": { "tokenType": "web", "registerPath": "/api/universal/device/register", "maxPayloadBytes": 3993 }
}

In the dashboard, copy or regenerate it under App Settings → App keys → Publishable web key. The MCP tool is get_app_web_key.

Rotate the web key

POST https://app.nativenotify.com/api/apps/<APP_ID>/web-key/rotate    { "confirm": true }

The old key stops authenticating immediately, with no grace window. Owner or admin only; without "confirm": true the call answers confirmation_required. The MCP tool is rotate_app_web_key.

Sites set up by Agent Notify

After rotating, update NN_WEB_KEY in native-notify/web/nativeNotifyIds.js, where Agent Notify puts the key, or ask Agent Notify to, and redeploy, or visitors can't register.

Rotate the app token

Rotate after a leak. You choose how long the old token keeps working, so your own integration doesn't break.

GET  /api/apps/<APP_ID>/app-token
POST /api/apps/<APP_ID>/app-token/rotate           { "confirm": true, "graceDays": 7 }
POST /api/apps/<APP_ID>/app-token/retire-previous  { "confirm": true }
  • Rotate issues a new 22-character app token, valid immediately, and keeps the old one valid for graceDays (0–90, default 7; 0 retires it at once). It returns the new token and previousToken: { activeUntil, graceDays }, never the old value.
  • Get returns the current token and rotation: { previousTokenActive, previousTokenExpiresAt }.
  • Retire ends the grace window early. It's idempotent (retired: false when nothing was waiting). After the window, or a retire, the old token answers 401 like any unknown pair.
  • A second rotation replaces the grace. Only one previous token exists, so the older one stops at once.
  • Every mutation is audit-logged and owner or admin only (403 admin_only for a developer teammate).

The MCP tools are get_app_token_status, rotate_app_token and retire_previous_app_token. In the dashboard, use App Settings → App keys → App token.

Data tied to the token (devices, subscribers, Classic inboxes, scheduled pushes) follows the app to the new token. Update whatever authenticates with the old token, such as your app binary, server config or .env, before the grace window ends. Rotating leaves the web key, your devices and your inbox history alone.