Device Registration

Register and deregister devices with the framework-agnostic endpoint — deviceId, platform, APNs/FCM tokens, subscriber ids, and the exact rules and error codes.

Registration tells Native Notify "this device can receive pushes, on this token". Call it on every app launch (and whenever the push token changes) — it is an idempotent upsert, so repeats are cheap and never duplicate a device.

POST https://app.nativenotify.com/api/universal/device/register

Request

{
  "appId": 123,
  "appToken": "yourAppToken",
  "deviceId": "A1B2C3D4-install-key",
  "platform": "ios",
  "subscriberId": "user_8241",
  "appVersion": "2.4.0",
  "timezone": "America/New_York",
  "tokens": {
    "apnsToken": "9f8a7b6c5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f009f8a7b6c5d4e3f2a1b0c9d8e"
  }
}
FieldRequiredNotes
appId, appTokenyesYour app's pair from the dashboard.
deviceIdyesYour stable per-install key. Max 200 chars. This is the device's identity — choose it once and keep it.
platformyes"ios" or "android".
subscriberIdnoSend your user id to make it an indie device; omit (or empty) for a mass device. Max 256 chars. Numbers are accepted and coerced.
appVersionnoTrimmed, capped at 50 chars. Useful in support views.
timezonenoIANA zone, trimmed, capped at 60 chars.
tokens.apnsTokenone of the twoiOS only. Hex device token, 64+ characters. Aliases: apns_token, apnToken.
tokens.fcmTokenone of the twoAndroid only. FCM registration token, 32+ URL-safe characters. Alias: fcm_token.

At least one token is required. Token values are capped at 400 characters, and Expo push tokens are rejected here (unsupported_token_type) — that is a different service; see Universal Push.

Response — 201

{
  "ok": true,
  "device": {
    "appId": 123,
    "deviceId": "A1B2C3D4-install-key",
    "platform": "ios",
    "subscriberId": "user_8241",
    "appVersion": "2.4.0",
    "timezone": "America/New_York",
    "createdAt": "2026-09-20T14:02:11.000Z",
    "lastSeenAt": "2026-09-23T09:10:44.000Z"
  },
  "tokens": { "apnsToken": "ok" }
}

tokens reports per token what happened: "ok" (already on this device), "refreshed" (value updated), or "reassigned" (the token moved here from another device).

Semantics that matter

  • Re-registering never duplicates. The unique keys are (app, deviceId) for devices and (app, token type, token) for tokens. A token only ever exists once per app.
  • First registration wins for ages. createdAt is never bumped by a re-register; lastSeenAt refreshes every time.
  • Token rotation is normal. When APNs/FCM hands you a new token, register again — same deviceId, new token value.
  • A registration clears the token's dead flag. Presenting a token again is proof it is in current use. Failure strikes are stored per device — re-registering the same device keeps its history; a token that moves to a different device is treated as fresh (strikes reset).
  • Omitted optional fields keep their stored value — sending appVersion alone never wipes the subscriber id.
  • Platform pairing is enforced: apnsToken from an ios device, fcmToken from an android device.

Deregister

POST https://app.nativenotify.com/api/universal/device/deregister
{ "appId": 123, "appToken": "yourAppToken", "deviceId": "A1B2C3D4-install-key" }
{ "ok": true, "deviceId": "A1B2C3D4-install-key", "removed": true, "tokensRemoved": 1 }

Deregister is a hard delete — the device row is removed and its tokens cascade. It is idempotent: an unknown deviceId still answers 200 with "removed": false, so a logout that runs twice (or a retried request) never fails. Call it when a user logs out of an indie identity, or when you want to stop pushes for that install.

Error codes

Errors use the stable envelope { "error": { "code", "message", "field"? } }:

CodeMeaning
missing_fieldappId, deviceId, platform or both tokens are missing.
invalid_platformplatform is not ios or android.
invalid_device_id / invalid_subscriber_idToo long or wrong type.
no_tokens_providedNeither tokens.apnsToken nor tokens.fcmToken was sent.
invalid_token_formatToken does not match its shape (hex APNs / URL-safe FCM) or is over 400 chars.
token_platform_mismatchAn APNs token from an Android device, or an FCM token from an iOS device.
unsupported_token_typeAn Expo push token was sent — use the universal tokens instead.
app_not_foundThe app id is unknown; a wrong appToken answers 401 like the rest of the API.

Try it

Register, then immediately prove delivery with a test send to that deviceId, or check the app's counts through /api/universal/health.