Notify docs
Troubleshooting

Why didn’t it arrive?

Every delivery that was not sent carries a reason. Find it, then find it here: what it means and what to do.


1

Find the reason

  1. Console: Notify › Recipients, open the user, and read their timeline: every delivery to them across notifications, with its state and reason. Explain for recipient runs a dry run of a type for that user and shows each channel’s decision now.
  2. API: GET /deliveries?notification_id=… or GET /recipients/{external_id}/timeline; each delivery has state, reason and explanation. Before sending, dry_run: true on the send returns the plan with the same reasons.
  3. Webhooks: delivery.skipped and delivery.failed carry the reason.
  4. An AI client: the MCP server’s explain tool answers with the fix below.

Nothing in the log at all? The send call failed before it was stored: check its HTTP status and error code on the error codes page. A recipient listed in the response’s skipped was left out of an otherwise accepted send.

A push shows sent but the user saw nothing? Apple and Google only report that they accepted it. Common causes on the device: notifications turned off for the app in system settings, Focus or Do Not Disturb, a sandbox token from a debug build (see iOS push), an Android notification channel the app never created, or the app being force-stopped on Android. The rendered text and Apple’s apns-id or Google’s message name are on the delivery, for Apple’s Push Notifications Console or Firebase.


2

It has not arrived yet: it is waiting

The delivery is in state scheduled or retry. Nothing is lost; it goes out on its own.

It has not arrived yet: it is waiting
ReasonWhat happenedWhat to do
held_quiet_hoursHeld until the recipient's quiet hours end.It is sent when the window ends. Mark the type critical if it must not wait.
scheduled_sendWaiting for the send time given in send_at or delay_seconds.It is sent at that time. Cancel it with the notification id or its cancellation_key.
awaiting_unreadA follow-up step waiting to see whether the recipient reads the inbox item first.Nothing to fix: it is sent when the after_unread_seconds timer ends and the item is still unread, and skipped as read_in_inbox otherwise.
email_budgetThe workspace email budget is spent for now; the email waits for the next window.It is sent automatically when the budget allows. Ask us to raise the budget if this is routine.
circuit_openThe provider is failing for this credential, so sends are paused briefly and retried.Nothing to fix: it retries on its own. Check the provider's status page if it lasts.

3

The recipient chose not to get it

Skipped on purpose. Critical types still reach recipients who opted out (but never past bounces, complaints or Mail suppression).

The recipient chose not to get it
ReasonWhat happenedWhat to do
suppressed_preferenceThe recipient turned this channel off for this type or its category.Nothing to fix: the recipient chose this. Mark the category channel mandatory only for messages they must receive.
unsubscribed_allThe recipient unsubscribed from all non-critical notifications.Only types marked critical still reach them; otherwise the recipient has to opt back in.
read_in_inboxThe recipient read the inbox item first, so the follow-up was not needed.Nothing to fix: this is how after_unread_seconds works.
actor_excludedThe recipient is the actor who caused the notification.Pass exclude_actor: false to notify the actor too.

4

There was nowhere to send it

Notify had no device, address or recipient for this channel. A fallback step, if the type has one, runs next.

There was nowhere to send it
ReasonWhat happenedWhat to do
no_deviceThe recipient has no active device for this channel.Register the device token from your app (POST …/devices) after the user grants permission.
no_addressThe recipient has no email address.Set email on the recipient, or pass it inline in the send.
prunedThe push provider said the device token is no longer valid; the device was removed.Nothing to fix: the app registers a fresh token the next time it opens.
recipient_not_foundNo recipient with this external id exists in the workspace.Create the recipient first (PUT /recipients/{external_id}), pass it inline with an email, or send create_missing: true.
recipient_erasedThe recipient was erased in the last 24 hours and cannot be recreated by a send yet.Wait 24 hours after the erasure, then create the recipient again.

5

Your setup is missing something

Fix it once in the console or the API and the next send goes through.

Your setup is missing something
ReasonWhat happenedWhat to do
channel_not_configuredThe channel is not set up in this workspace.Upload APNs or FCM credentials, generate web push keys, or enable Mail with a verified sender.
credential_invalidNo valid credential matches this device's app or environment.Upload the APNs key or FCM service account for this bundle id or project, in the right environment.
credential_errorThe push provider rejected the workspace credential.Upload a fresh APNs key or FCM service account; the channel resumes as soon as it validates.
template_missingThe type has no template for this channel.Add a template for the channel (any locale) to the notification type.
type_archivedThe notification type is archived.Unarchive the type or send a different one.
channel_restrictedThe send's channels list left this channel out.Add the channel to channels, or omit channels to use every channel of the type.

6

Email protection stopped it

These keep your sender reputation (and every other customer’s) intact. Critical types do not bypass them.

Email protection stopped it
ReasonWhat happenedWhat to do
email_invalidAn earlier email to this address hard-bounced.Update the recipient's email address; a new address clears the bounce.
email_complainedThe recipient marked an earlier email as spam.Email stays off for this recipient; reach them through another channel.
mail_suppressedProductCraft Mail suppressed the address (earlier bounces or complaints).Check the suppression list in Mail; remove the address only if you know it is valid.
mail_refused:<code>ProductCraft Mail refused the message (the code after the colon says why).Look up the Mail error code; usually the template name or sender needs fixing.
email_pausedEmail is paused for this workspace (high bounce or complaint rate).Check your sending in the console and resume email in Notify settings.
email_backlog_fullThe workspace already holds 10,000 emails waiting for budget, so this one was not queued.Send fewer emails or spread them out; ask us to raise the budget if this volume is routine.

7

A limit stopped it

Per-recipient budgets and per-type throttles protect your users from floods; the excess is skipped, not queued.

A limit stopped it
ReasonWhat happenedWhat to do
rate_limitedThe recipient already received the per-minute maximum of notifications.Send fewer notifications to one person, or batch them; critical types have their own budget.
throttledThe type's own throttle for this recipient was reached.Raise or remove throttle on the notification type if every message must go out.
payload_too_largeThe rendered push payload is over the provider's size limit.Shorten the template or move data out of the push payload.

8

Delivery ended without success

The delivery is final. The attempts in the message log show what the provider answered.

Delivery ended without success
ReasonWhat happenedWhat to do
expiredThe notification's time to live passed before it could be delivered.Raise ttl_seconds on the type if late delivery is still useful.
cancelledThe notification was cancelled, or the recipient was erased, before delivery.Nothing to fix.
provider_errorThe provider kept failing until retries ran out.Check the attempts for the provider status and code.