Push notifications look simple at the point of use: a user receives a message on a phone or browser. The delivery path behind that message is more involved. Your application server must identify a target, authenticate a request, hand the payload to a push service, and rely on the operating system to decide when and how the application can receive it.
Understanding this path helps teams diagnose missing notifications, design safer retry logic, and choose sensible payload and targeting strategies. It also clarifies which parts your product controls and which parts depend on device permissions, operating-system policy, network conditions, and push-provider behaviour.
The delivery path at a glance
A typical notification travels through these stages:
- Your server creates a notification request.
- Your server authenticates with the notification platform.
- The platform resolves the target into one or more registered devices.
- The platform hands the message to the relevant push service or services.
- The operating system receives, filters, and schedules the notification.
- The device SDK or operating system presents the notification and passes any data to the application when permitted.
- Your application processes lifecycle events and records the result where appropriate.
The path is not necessarily synchronous from your server's perspective. A successful API response usually confirms that the request was accepted for processing, not that a person has already seen the notification. Delivery, display, opening, and application processing are separate events and should be treated separately in your product and observability design.
1. Your server builds the request
A notification normally starts with an event in your backend: an order status change, a new message, a reminder, or another product action. The backend should decide whether a notification is appropriate, select the target, and construct the user-visible content.
With HoneyNotify, server-side sends use POST /v1/notifications. The request is authenticated with a Bearer API key and includes an Idempotency-Key. A notification requires a title, a body, and a target. Targets can address a device, user, tag, segment, or all enabled devices.
The target choice affects both correctness and cost control. A device target is precise but requires a reliable device identifier. A user target is usually a better fit when one person may use several devices. Tags and segments are useful for cohorts or subscriptions, while an all-enabled-devices target should be reserved for genuinely broad messages.
Keep notification composition on the server when it depends on private business rules or sensitive data. Do not place secrets in client payloads. If the client needs to fetch current information, send a stable reference or event type and let the application retrieve the details through its authenticated API.
2. Authentication and idempotency protect the send
The Bearer API key proves that the server is authorised to submit the request. Store it in a server-side secret manager or protected environment configuration, never in an iOS, Android, or web client bundle. Rotate keys according to your operational policy and restrict access to the systems that need to send notifications.
The Idempotency-Key is important when a request may be retried. Network failures can leave your server unsure whether the first request was accepted. Without idempotency, a retry could create duplicate notifications. Generate a stable key for the same logical send and reuse it when retrying that operation. Do not generate a new key for every attempt if your goal is to prevent duplicate submission.
Your send worker should distinguish between validation failures, authentication failures, throttling or temporary service errors, and an accepted request. These outcomes require different actions. A malformed payload should not be retried unchanged. A temporary failure may be retried with controlled backoff. An accepted request should not be submitted again merely because downstream delivery has not yet been observed.
3. Target resolution connects people to devices
A user, segment, or tag is an application-level concept. The delivery system must resolve it to enabled device registrations before the message can reach a device. This is why registration data needs to be maintained as carefully as user data.
Client SDKs cover device registration, identity, token lifecycle, payload handling, and lifecycle events across iOS, Android, and Web Push. During registration, the client obtains or receives the platform-specific information needed to address that installation and associates it with the relevant user or targeting metadata.
A single user can have several installations. Conversely, an installation can change hands if identity is not cleared correctly during sign-out. Your application should define what happens when a user signs out, signs in on a shared device, disables notifications, or reinstalls the application. Identity and device association rules should be explicit rather than inferred from the last event received.
Imported OneSignal subscription IDs can remain as device IDs when matching provider tokens later register. However, token rotation or another provider environment can prevent matching. Treat imported identifiers as migration data, not as a permanent guarantee that every future registration will map automatically. Verify the matching behaviour in your migration process and monitor registrations that cannot be associated confidently.
4. The push service and operating system take over
After the notification platform accepts and resolves the request, it hands the message to the relevant push service for the destination platform. The push service then communicates with the device through the operating system's notification infrastructure.
This hand-off introduces conditions outside your server's direct control. The device may be offline, the user may have denied permission, background activity may be restricted, or the operating system may defer delivery to preserve battery life. A browser may also require permission and an active service-worker arrangement before it can handle a web push message.
The operating system can decide whether to display an alert, deliver data to the application, delay processing, or suppress presentation according to permissions and platform policy. A message that reaches the push service is therefore not automatically a message that appears immediately on screen.
Design notification content with this uncertainty in mind. Notifications should remain useful if they arrive later than expected. Avoid making a push notification the only place where a critical state change exists; the source of truth should remain available through your application or other appropriate channels.
5. The device and SDK handle the payload
When the device receives the message, the operating system and client SDK determine how it is handled. Depending on the platform, application state, permissions, and payload, the user may see a notification, the application may receive data, or both may occur.
The SDK's responsibilities typically include token lifecycle management, registration, payload handling, and lifecycle events. Your application still needs to handle these events correctly. For example, it may need to refresh a server-side association after a token changes, update local state after a notification is opened, or route the user to the relevant screen after interaction.
Keep handlers fast and resilient. Background execution is constrained on mobile operating systems and in browsers. Do not assume that a handler can perform a long-running operation before the system stops it. If processing requires current data, use a compact payload to identify the event and retrieve details efficiently when the application is available.
Implementation considerations
Model notification states separately
Track at least the difference between requested, accepted, delivered where that signal is available, displayed, opened, and acted upon. These states answer different operational questions. A high accepted count with low opens may indicate irrelevant content, permission issues, or delayed delivery; it does not by itself identify one cause.
Make retries deliberate
Use idempotency for uncertain request outcomes, bounded retries for temporary failures, and a dead-letter or review path for messages that repeatedly fail. Do not retry permanent validation or authorisation errors. Include a correlation identifier in your own logs so a product event can be traced to a send attempt without putting sensitive information in the notification payload.
Treat tokens as changeable
Device and provider tokens can change. Registration should be repeatable and safe, and your backend should accept updated associations. Remove or disable registrations only when you have a reliable reason to do so; an intermittent network failure is not proof that a device is permanently invalid.
Test the full path
Test fresh installation, denied permission, permission granted later, token refresh, logout and login, reinstall, offline devices, multiple devices for one user, and both foreground and background application states. For Web Push, test browser permission and service-worker behaviour separately from mobile flows.
Common mistakes
- Treating an API acceptance response as proof that the notification was displayed.
- Putting a server API key in a mobile or browser application.
- Generating a new idempotency key for every retry.
- Assuming one user always maps to one device.
- Treating a device token as permanent.
- Sending private or complete business records in the payload.
- Relying on a notification as the only durable record of an important event.
- Ignoring sign-out, shared-device, and reinstall behaviour.
- Using broad targeting when a user or segment target is sufficient.
- Testing only the happy path with permission already granted and the application open.
Conclusion
A push notification is a chain of hand-offs rather than a direct server-to-screen connection. Your server controls the event, target, payload, authentication, and retry policy. The notification platform resolves registrations and submits the message, while the push service, operating system, permissions, network, and client SDK influence when and how it reaches the user.
Reliable implementations reflect those boundaries. Keep credentials server-side, use stable idempotency keys, maintain device and identity associations, handle token changes, separate delivery states, and test realistic device conditions. With that model, missing notifications become an observable systems problem instead of an unexplained failure.
