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:
result—acceptedorfailed, 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
| Symptom | What it usually is | Do this |
|---|---|---|
failed with a credential reason on every token | Wrong/expired FCM service account or APNs key | Re-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 send | No credentials for that transport on the app | Save the missing credential set |
accepted but the device shows nothing | OS-level delivery (focus, DND, permission revoked) | Check notification permission on the device — acceptance is the transport's answer, not the OS's display |
Related
- Tokens & Receipts — how strikes and dead tokens work on both paths.
- Send Notifications — what a full audience send reports.