Delivery errors & the log explorer

Every delivery attempt is recorded with a normalized code and the raw provider response, verbatim. GET /v1/messages/:id/deliveries or the dashboard's Messages tab shows the full per-device timeline.

Timeline events

acceptedTarget resolved into the send
sentPush service accepted it (APNs 200 / FCM 200 / push service 201)
failedSee error codes below — raw response attached
skippedSuppressed address, missing channel content, or missing credentials
clickedUser engaged (web today; mobile with native SDKs)

Error taxonomy

CodeMeaningRetry?Raw examples
address_goneToken permanently dead — app uninstalled, subscription expired. Notibase auto-expires the device.NoAPNs 410 Unregistered · FCM UNREGISTERED · web push 404/410
address_invalidMalformed token or token from another appNoAPNs BadDeviceToken, DeviceTokenNotForTopic · FCM INVALID_ARGUMENT
payload_invalidContent the provider rejects (usually size — web push ~4KB)NoAPNs PayloadTooLarge · web push 400/413
credentials_invalidYour APNs/FCM/VAPID credentials are wrong or revoked — fix in SetupNoAPNs 403 InvalidProviderToken · FCM SENDER_ID_MISMATCH, oauth 401
provider_throttledApple/Google asked us to slow downYes (backoff)APNs 429 TooManyRequests · FCM QUOTA_EXCEEDED
provider_downPush service outage or network failureYesAny 5xx · FCM UNAVAILABLE/INTERNAL
unknownUnmapped — the raw response tells the storyNo

The three that page you, decoded

credentials_invalid spike → your .p8 was revoked or the FCM service account was deleted. Upload fresh credentials in Setup; queued messages resume.

SENDER_ID_MISMATCH → the device token was minted by a different Firebase project than the service account you uploaded. Ship builds and credentials from the same project.

Rising address_gone rate → normal after app updates or long-dormant re-engagement sends. It's uninstall truth, not a delivery problem — and it's why Notibase counts stay honest.

Too lazy to decode? Same.

Every failed row in the dashboard has ✨ explain — the raw response goes to a model grounded on this exact taxonomy, and you get meaning / likely cause / fix. Cached per error class, so it's instant after the first ask.