Notification inbox

Mobile notification inbox

List a device's notifications, show an unread badge, and mark entries read or delete them.

Endpoints

The inbox is keyed by the deviceId you registered. Calls take your app id and app token.

CallEndpoint
ListGET /api/universal/inbox/:appId/:appToken?deviceId=&take=&skip=
Unread countGET /api/universal/inbox/:appId/:appToken/unread-count?deviceId=
Mark one readPOST /api/universal/inbox/read — { appId, appToken, deviceId, entryId }
Mark all readPOST /api/universal/inbox/read-all — { appId, appToken, deviceId }
Delete onePOST /api/universal/inbox/delete — { appId, appToken, deviceId, entryId }
ClearPOST /api/universal/inbox/clear — { appId, appToken, deviceId }

Plans

On Premium every inbox call answers 403 plan_upgrade_required. Sends still write entries, so they appear after an upgrade. See what each plan includes.

List the inbox

let url = URL(string: "https://app.nativenotify.com/api/universal/inbox/\(appId)/\(appToken)?deviceId=\(deviceId)&take=20")!
let (data, _) = try await URLSession.shared.data(from: url)
// decode: total, unread, entries

The answer holds this device's entries, newest first:

{
  "ok": true,
  "deviceId": "device-abc",
  "take": 20,
  "skip": 0,
  "total": 12,
  "unread": 3,
  "entries": [
    {
      "entryId": 4181,
      "appId": 123,
      "deviceId": "device-abc",
      "subscriberId": null,
      "environment": "production",
      "title": "New service times",
      "body": "This Sunday: 9am and 11am.",
      "data": { "url": "/news/service-times" },
      "audienceType": "all",
      "source": "api",
      "sentAt": "2026-09-24T14:03:11.000Z",
      "readAt": null,
      "read": false
    }
  ]
}
  • take is 1–200 (default 50). A larger value is a 400, never a silent cap. skip pages.
  • total and unread cover the whole inbox, so "load more" is exact.
  • Entries are written in the background, so one can appear a moment after the send. A send with skipInbox: true writes none.

Unread badge

const { unread } = await fetch(
  `https://app.nativenotify.com/api/universal/inbox/${appId}/${appToken}/unread-count?deviceId=${deviceId}`
).then((r) => r.json());

Poll while the app is open, or refresh when a push arrives.

Mark read and delete

CallResponse
Mark one read{ "ok": true, "entryId", "read": true, "readAt" }. Marking it again keeps the first readAt.
Mark all read{ "ok": true, "deviceId", "marked" } — how many entries changed.
Delete one{ "ok": true, "entryId", "removed" } — removed: false when it was already deleted.
Clear{ "ok": true, "deviceId", "removed" } — how many entries were cleared.

Delete and clear are soft and idempotent, and never touch another device's inbox.

Tap to open

Put a url in the send's pushData. The entry returns it as data.url:

{
  "title": "New service times",
  "message": "This Sunday: 9am and 11am.",
  "pushData": { "url": "/news/service-times" }
}

The inbox never navigates on its own — your app decides what the url means. See Push data & taps.

Errors

Errors use { "error": { "code", "message", "field"? } }.

StatusCodeMeaning
400missing_field, invalid_field, invalid_bodyA missing or bad field, such as take over 200.
400invalid_device_id, invalid_entry_idA malformed id.
401—The app id and app token don't match. The body is plain text.
403plan_upgrade_requiredThe account is on Premium.
404entry_not_foundThe entry isn't this device's, or you marked a deleted one read.
404app_not_foundA dashboard-session or MCP caller has no access to that app id.