OpenPush overview
OpenPush is a hosted push notification platform, run by the OpenPush team and served from
https://app.openpush.ai. You hold the APNs and FCM credentials, and every notification leaves
OpenPush for Apple or Google on those credentials — the same call you would make yourself, with a
console on top. It delivers to iOS, Android and web browsers, and ships native SDKs for Android,
iOS and Unity. Everything you can do in the console is also reachable over the REST API.
What "open" means here. It is a claim about the mechanism, not about the source code. Your credentials, your Apple and Google developer accounts, no delivery network of ours in between, and no per-message transport fee — because there is no transport of ours to charge for. It is not a claim about published code, and it is not an invitation to run the platform yourself: the OpenPush server is not published, and it cannot be run by anybody but the OpenPush team. The client SDKs are published separately. What that buys you in practice is verifiability — the sends show up in your own Firebase or Apple console, under your own service account, without taking our word for anything.
When to use this page
Read this first if you are new to OpenPush. It defines the nouns the rest of the documentation uses — app, user, subscription, external ID, tag, segment, message — and points at the guide for each feature. If you want a working push in the next ten minutes, skip to the quickstart.
Architecture at a glance
- The platform exposes a versioned REST API under
/v1, plus a browser console. Both are served fromhttps://app.openpush.ai. - Delivery goes straight to Apple over APNs with a p8 provider token, and to Google over FCM HTTP v1 with a service account. There is no third party between OpenPush and the provider.
- A scheduler tick runs every few seconds inside the platform. It fires scheduled messages, releases sends that were parked by quiet hours or per-user delivery timing, retries transient provider failures, and advances journeys.
- The SDKs are receive-only. No SDK can send a message. They register the device, report identity and tags, and post delivery receipts back to OpenPush.
Core concepts
App
An app is the unit of isolation. It owns its own subscriptions, users, segments, templates,
messages, credentials and API keys. An app id is a slug you choose (acme-app), and it appears in
every API path: POST /v1/apps/acme-app/messages.
Creating an app also creates its three API keys and two default segments. See apps, keys and settings.
Subscription
A subscription is one addressable destination: one push token on one device on one platform.
It carries the token, the platform (ios, android or web), the app version, device model,
language, country, timezone, an optional sandbox flag, and a numeric status.
A subscription is targetable when its status is positive and it has not been retired. On iOS the positive status doubles as Apple's authorization bitmask, so a provisional-authorization device (bit 64) is subscribed and targetable like any other.
User
A user is a person, and owns one or more subscriptions — a phone, a tablet, a browser. Tags, country, language, session counts and aliases live on the user, not on the individual device. This is why a tag you set on one device targets that person's other devices too.
Without an external ID, each subscription is effectively its own user record.
External ID
The external ID is your own stable identifier for a person — your database's user id. Setting it
via login() on an SDK is what unifies several subscriptions into one user, and what lets you
target someone by identity instead of by token.
Getting the external ID right is the single highest-leverage thing in an OpenPush integration. Segments, journeys, per-user personalization and cross-device targeting all key off it.
If you turn on identity verification for the app, an external ID claim must be accompanied by an HMAC your server computes. See users and subscriptions.
Aliases
Aliases are extra {label: id} identifier pairs on a user, beyond the external ID — for example a
CRM id or a support-desk id. The product cap is 10 pairs per user, and the label external_id is
reserved. Aliases can be used as a direct send target.
Tags
Tags are key/value pairs on a user. Tag values are strings on every SDK — there are no numeric, boolean or date tag types. Segment rules can still compare a tag numerically, and a tag whose value is a word simply does not match a numeric comparison rather than erroring.
Deleting a tag is expressed as setting it to an empty string. Empty and null tag values are dropped from the personalization namespace, matching that convention.
Tags do two jobs: they build segments, and they are the variables available to Liquid personalization.
Segment
A segment is a saved audience rule set, evaluated live at send time — never a frozen list. Rules AND within a group and OR between groups, exactly two levels deep. Counts are exact, not estimated. See segments.
Message
A message is one send: content plus an audience plus timing. "Notification" is reserved for the artifact that appears on the device. A message can carry per-language copy, A/B variants, an image, a deep link, a custom data payload, up to three action buttons, and delivery options (TTL, priority, collapse key). See sending messages.
Template
A template is reusable content — name, title, body, and optionally image, deep link and data. Referencing it on a send fills in whatever the send body does not override. Liquid inside a template is validated when you save it, not when you send. See templates.
The two key kinds
Every app gets two credentials with deliberately different powers. Neither can do the other's job: the key kind is part of the lookup, so an SDK key can never satisfy an admin route and a REST key can never satisfy an ingest route.
| Kind | Header | What it does | Where it belongs |
|---|---|---|---|
| REST API key | X-OP-API-Key | Full admin of one app: send, read the audience, manage segments, templates, journeys, settings, export | Your backend only. Never in an app binary. |
| SDK key | X-OP-SDK-Key | Ingest only: register a device, post receipts, post custom events, register Live Activity tokens | Ships inside your mobile app binary, by design |
| Legacy key | X-OP-API-Key | Treated exactly like a REST key; exists for migration | Your backend only |
A REST key is scoped to a single app and cannot read or write another. It is not role-scoped —
console roles (viewer / manager / admin) apply to browser sessions only, never to API keys.
OpenPush also carries two platform-level keys, held by the OpenPush team, that match on every app. They are part of how the platform is administered, not something you configure. See security and limits.
The three platforms
| Platform | Transport | SDK | Notes |
|---|---|---|---|
ios | APNs directly, p8 provider token | openpush-ios (iOS 16+) | Per-device sandbox flag lets TestFlight and App Store builds coexist in one app |
android | FCM HTTP v1, service account | openpush-android (API 26+) | Data-only messages; the SDK draws the notification |
web | also FCM | none — use your own Firebase JS integration | There is no OpenPush web push JavaScript SDK, and no direct VAPID sender |
Unity is supported as a fourth SDK surface that targets iOS and Android.
Be honest with yourself about web: OpenPush stores and publishes your web push credentials, and it delivers to browsers through FCM, but the browser-side subscribe flow is Firebase's, written by you. See web push.
email, sms, huawei, amazon and similar strings are recognised as skipped channels by the
CSV importer. They are not deliverable platforms here.
The delivery ladder
OpenPush deliberately refuses to collapse four different facts into the word "delivered":
- Provider Accepted — Apple or Google took the message off your hands.
- Device Received — the SDK on the device actually got the data.
- Confirmed Receipt — the notification was displayed.
- Clicked — someone tapped it.
Stages 2 through 4 arrive from the device via POST /v1/ingest, so they only appear if your app
integrates the SDK's receipt path. Message reports show all four, plus Failed, Capped
(suppressed by a frequency cap) and Held (waiting for quiet hours to open).
Feature map
| I want to… | Guide | API reference |
|---|---|---|
| Get a first push out | Quickstart | Messages |
| Install an SDK | Android · iOS · Unity | Subscriptions and users |
| Upload push credentials | APNs · FCM · Web | Apps, keys, settings |
| Compose and send | Sending messages | Messages |
| Show a message inside the app | In-app messages | In-app messages |
| Build an audience | Segments | Segments |
| Personalize copy | Personalization | Templates and dynamic content |
| Reuse content | Templates | Templates and dynamic content |
| Test two versions | A/B testing | Messages |
| Send at each person's best hour | Best-hour delivery | Messages |
| Understand identity | Users and subscriptions | Subscriptions and users |
| Track behaviour | Events | Events and ingest |
| Automate multi-step flows | Journeys | Journeys |
| Ship iOS Live Activities | Live Activities | Live Activities |
| Move data in or out | Import and export | Import and export |
| Migrate off OneSignal | Migrate from OneSignal | API overview |
| Handle keys safely | Security and limits | API overview |
Limits and honest notes
- No notification inbox. No inbox API exists on any of the three SDKs, and no compat module
provides one. In-app messages, by contrast, do ship: the server carries an in-app message
engine and nine routes, all three SDKs carry a real presenter and the impression/click receipt
path, and the OneSignal v5
InAppMessagesspellings resolve onto that engine rather than refusing at compile time. See in-app messages and the in-app messages API. - No outbound webhooks or event streams. Nothing in the server POSTs to a customer URL.
- No email or SMS channel. Push only.
- No conversion or attribution metrics. The four-stage ladder above is the whole measurement surface for a message.
- No idempotency on message creation. Retrying a create-message call sends the campaign a second time. See security and limits.
- Custom events do not reach segments. They exist to trigger journeys. Behavioural targeting is not expressible as a segment rule.
- There is no web push JavaScript SDK. Web works through your own Firebase integration.
FAQ
Is a user the same thing as a subscription? No. A subscription is one device or browser; a user is the person who owns them. Set an external ID to link several subscriptions into one user.
Can I put the REST API key in my mobile app? No. It is full admin of the app. Ship the SDK key — it is ingest-only and designed to be public.
What happens if I never set an external ID? Everything still works, but each subscription is its own user, so a tag set on the phone will not be seen when targeting the tablet, and cross-device deduplication is impossible.
Does OpenPush report "delivered"? It reports Provider Accepted, and separately Device Received and Confirmed Receipt when the SDK posts them back. It never calls provider acceptance "delivered", because that would be untrue.
Can one API key manage several apps? Not one of yours. Only the platform-level key held by the OpenPush team crosses apps. Per-app REST keys are scoped to exactly one app.