Verify Delivery

Prove that universal push works — test-send to one device or token, app health counts, and the credential probe — with the exact response fields to read.

Universal push has no receipts (APNs and FCM answer at send time and that answer is final), so verification is three small endpoints instead of a delivery log.

1. Test send — one device or one token

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

Target either a registered device:

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

or an explicit raw token:

{
  "appId": 123,
  "appToken": "yourAppToken",
  "title": "Test to one token",
  "message": "Hello from the credentials probe.",
  "tokenType": "apns",
  "token": "9f8a7b6c…9d8e"
}
{
  "ok": true,
  "accepted": true,
  "transport": "apns",
  "result": "accepted",
  "reasonCode": null,
  "reasonPlainEnglish": null,
  "testSendId": 8841,
  "target": {
    "mode": "device",
    "deviceId": "A1B2C3D4-install-key",
    "platform": "ios",
    "subscriberId": "user_8241",
    "tokenType": "apns",
    "tokenMasked": "…b0c9d8e",
    "tokenSource": "device"
  },
  "checkedAt": "2026-09-23T09:44:02.000Z"
}

What to read:

  • resultaccepted or failed, straight from the real send pipeline, so it is what production would see.
  • reasonCode / reasonPlainEnglish — when it failed: Apple/Google's answer, translated. A credential-level reason for every token means fix the credentials first.
  • tokenMasked — responses never carry a full token; this is the last six characters only.

2. Health — what is in storage right now

GET https://app.nativenotify.com/api/universal/health/:appId/:appToken
{
  "ok": true,
  "appId": 123,
  "checkedAt": "2026-09-23T09:45:00.000Z",
  "source": "universal_push_devices/universal_push_tokens",
  "devices": { "ios": 640, "android": 661 },
  "tokens": { "apns": { "live": 640, "dead": 1 }, "fcm": { "live": 660, "dead": 2 } },
  "retired": 0,
  "masking": "counts only — no token material is ever returned"
}

Counts are exact and come from the universal service's own storage — use it to confirm that registration actually landed (devices > 0 after installing), and to see dead/struck tokens before a blast.

3. Credentials — live probe

POST /api/universal/credentials/validate   (admin-only)

Covered in full on Push Credentials: Google must mint an OAuth token from the service account, and Apple must answer the invalid probe token with BadDeviceToken.

Reading the failures

SymptomWhat it usually isDo this
failed with a credential reason on every tokenWrong/expired FCM service account or APNs keyRe-run the credential validate probe, re-save from the dashboard wizard
failed with a per-token reason (BadDeviceToken, Unregistered)That install is gone (uninstalled / token rotated)Re-register on next app launch — registration clears the dead flag
skipped counters in a sendNo credentials for that transport on the appSave the missing credential set
accepted but the device shows nothingOS-level delivery (focus, DND, permission revoked)Check notification permission on the device — acceptance is the transport's answer, not the OS's display