Push notifications

Verify delivery

Check that pushes work with a test send, app health counts and a live credential check.

APNs and FCM send no delivery receipts: they answer at send time, and accepted is the strongest signal a native token gives.

Each check is one API call. Native Notify runs the same three under your project's Setup & docs → Push notifications setup → Verification.

Simulators and emulators

An iOS Simulator (Xcode 14 or newer, iOS 16 or newer, on a Mac with Apple silicon or a T2 chip) and an Android emulator with Google Play services both register and receive pushes, so a test send works without a physical phone. An iOS build needs the Push Notifications capability: no valid “aps-environment” entitlement string found means it is missing.

1. Send a test push

POST https://app.nativenotify.com/api/universal/test-send

Target a registered device:

{
  "appId": 123,
  "appToken": "yourAppToken",
  "title": "Test from Native Notify",
  "message": "If you can read this, APNs/FCM accepted it.",
  "deviceId": "A1B2C3D4-install-key"
}

Or one raw token. tokenType is "apns", "fcm" or "web"; for web, token is the subscription's endpoint URL:

{
  "appId": 123,
  "appToken": "yourAppToken",
  "title": "Test to one token",
  "message": "Hello from the credentials probe.",
  "tokenType": "apns",
  "token": "0c9d8e…"
}

pushData, bigPictureURL and the rich fields work as in a normal send. To see a bigPictureURL on iOS, test on an iPhone: the Simulator shows the text without the picture (Images). A deviceId test also writes the send record and one notification inbox entry for that device. A raw token writes nothing.

{
  "ok": true,
  "accepted": true,
  "transport": "apns",
  "result": "accepted",
  "reasonCode": null,
  "reasonPlainEnglish": "Apple accepted the notification for delivery to this device. APNs has no delivery receipts — whether the device displayed it is not knowable from the server, so 'accepted' is the strongest signal a native token can give.",
  "attempted": 1,
  "testSendId": 8841,
  "target": {
    "mode": "deviceId",
    "deviceId": "A1B2C3D4-install-key",
    "platform": "ios",
    "subscriberId": "user_8241",
    "tokenType": "apns",
    "tokenMasked": "…0c9d8e",
    "tokenSource": "universal"
  }
}
FieldMeaning
accepted, resulttrue and "accepted", or false and "failed", straight from the real send pipeline. The request answers 200 either way.
reasonCode, reasonPlainEnglishWhy it failed, in Apple's, Google's or the browser push service's words. A credential reason on every token means fix the credentials first.
targetmode is "deviceId" or "token". tokenSource is "universal" (the registered token) or "explicit". tokenMasked is … plus the last six characters; responses never carry a full token.

Errors

StatusCodeMeaning
400missing_field, invalid_field, invalid_bodyMissing appId, title or message, or an invalid appId or rich field.
400missing_target, invalid_targetNo target, both a deviceId and a token, or only one of tokenType and token.
400invalid_token_type, invalid_token_formattokenType isn't apns, fcm or web, or the token doesn't match its shape.
403trial_expiredThe free trial ended, or sending is paused for an unpaid invoice. Nothing was sent.
404app_not_found, device_not_foundThe app isn't accessible to this caller, or no device has that deviceId.
409no_deliverable_targetThe device has no live token for its platform, or the app has no credentials for it.

2. Check health

GET https://app.nativenotify.com/api/universal/health/:appId/:appToken
{
  "ok": true,
  "appId": 123,
  "checkedAt": "2026-09-23T09:45:00.000Z",
  "devices": { "total": 1349, "mass": 1228, "subscriber": 121 },
  "tokens": { "apns": 640, "fcm": 660, "web": 45, "totalLive": 1345 },
  "retired": {
    "apns": 1,
    "fcm": 2,
    "web": 1,
    "total": 4,
    "note": "dead = true — excluded from every future send. Web push subscriptions are retired on the first 404/410 the push service reports; native tokens after 2+ dead-class failures behind DELETE_DEAD_TOKENS=1."
  }
}

Counts are exact and carry no token material. devices splits registered devices into mass (no subscriber id) and subscriber. tokens counts live tokens per type, and retired the ones excluded from future sends.

3. Validate credentials

POST /api/universal/credentials/validate   (owner / admin)

Checks the stored FCM and APNs credentials live. See Push credentials.

Reading failures

SymptomUsuallyDo this
failed with a credential reason on every tokenWrong or expired FCM service account or APNs keyRe-run the credential check and re-save in Native Notify (Settings → Push credentials).
failed with a per-token reason (BadDeviceToken, Unregistered, UNREGISTERED, web NotFound or Gone)That install is gone: uninstalled, token rotated or browser unsubscribedRe-register on the next launch. Registration clears the dead flag.
failed with web EndpointNotAllowedThe endpoint isn't a public push service, so the server refused to connect (never a strike)Register the browser's real PushSubscription endpoint.
skipped counters in a sendNo credentials for that transportSave the missing credential set.
devices: 0 on an all sendNo device is registered in the send's environment, or none has a live tokenCheck the environment and the health counts.
accepted, but the device shows nothingAndroid: the app never posted the FCM data message. Otherwise OS delivery: focus, Do Not Disturb or a revoked permissionAdd the display code from your recipe, and check the device's notification permission.

Strikes and dead tokens on both paths are covered in Tokens & receipts.