Quickstart: your first push
This is the shortest path from a new OpenPush account to a notification on a real phone: create an app, upload one platform credential, initialize an SDK, register the device as a test subscription, and send. Budget about twenty minutes, most of which is Apple or Google paperwork.
When to use this page
Use it for your first integration, or whenever you add a new app to an existing workspace. If you only want to understand the vocabulary first, read the overview.
Prerequisites
- An OpenPush account. The API is served from
https://app.openpush.ai, which is what every example on this page uses. - An app. Creating one is a console action:
POST /v1/appsis reserved for the platform-level key held by the OpenPush team, so the console is your route in. Everything after step 1 is on the REST API with your own app keys. - One set of provider credentials:
- Android or web: a Firebase project and a service account JSON with the Firebase Cloud Messaging API enabled.
- iOS: an Apple Developer account and an APNs Auth Key (.p8), plus its Key ID, your Team ID, and the app's bundle id.
- A device or simulator you can install a build onto. Push does not work on the iOS Simulator.
Step 1 — Create the app
Create the app in the console. An app id is a slug you choose; it becomes part of every API path,
so pick something short and permanent — acme-app is the one used throughout this guide.
The new-app form can import your app's identity. Paste a Google Play or App Store link, or your website, and OpenPush fills in the icon, tile artwork, app name and a Brand details section: about the app, industry, audience and language to avoid. You can review and edit them before you create the app. A link you set but never import is still read when the app is created. If neither link can be read, the app is still created without brand details. Store artwork is copied into OpenPush media. The app's icon is hidden on its All Apps tile by default; tick Show app icon on the All Apps tile to show it.
Creating an app also creates its three API keys and two default segments (Total Subscriptions
and Active Subscriptions), and puts it in the workspace you are signed into. The underlying
route, POST /v1/apps, is one of the two platform-level routes that a customer REST key cannot
reach — see security and limits.
Verify: the app appears in the console with the id you chose.
Step 2 — Collect the app's keys
The console shows all three on the app's settings page. Over the API, with the app's own REST key:
Code
Code
Keep them straight from the start:
- The REST key goes in
X-OP-API-Keyfrom your backend. It is full admin of this app. Never ship it in a binary. - The SDK key goes in your app bundle. It is ingest-only by design.
Export them for the rest of this guide:
Code
Step 3 — Upload platform credentials
Credential upload is a console action. There is no /v1 route for it, because the file is a
secret that gets encrypted at rest and bound to the app. In the console, open your app and go to
Settings → Platforms.
Android (and web)
Upload the Firebase service account JSON. OpenPush uses FCM HTTP v1 only — there is no legacy
server-key path, so a key=AAAA… string will not work.
Upload it under Android. This is the single most common setup mistake. The sender only ever reads the credential stored under the
androidplatform. If you upload the service account under Web only,webpush-configwill work and the Web readiness badge will turn green, but every real send falls back to the platform-wide credential or fails outright. Web push is delivered through the same Android FCM credential.
iOS
Upload the .p8 file and fill in Key ID, Team ID and bundle id. OpenPush supports p8 provider tokens only — there is no p12 or certificate path. The key must be a PKCS#8 EC P-256 private key; anything else is rejected by name.
There is also a Sandbox checkbox at the app level, which chooses between Apple's production and
sandbox hosts. A device that registers with its own sandbox flag overrides that app-level
setting, so a TestFlight build and an App Store build can live in one OpenPush app.
Verify:
Code
The platforms object reports per-app APNs, FCM and web readiness. The APNs check actually signs a
JWT with your stored key rather than just checking that a file is present, so a green iOS badge
means the credential really works.
Step 4 — Initialize an SDK
Android is shown here because it is the fastest to get to a visible notification. The other SDKs follow the same shape: iOS, Unity.
Add the dependencies:
Code
The Maven artifact is not published yet. Those coordinates are the intended ones, but until they are on a repository you add the library as a composite build from a source checkout. See Android SDK for the
settings.gradle.ktssubstitution that works today.
Declare the messaging service in your manifest, alongside the usual Firebase setup and the
POST_NOTIFICATIONS permission:
Code
Initialize once, then hand OpenPush the FCM token:
Code
If you would rather keep the SDK key out of source, put it in manifest meta-data as
ai.openpush.sdk_key and call the three-argument
OpenPush.initialize(context, appId, serverURL) form. The SDK refuses to configure — loudly,
through onLog and onRegistrationFailed — if the key is absent, rather than silently doing
nothing.
Ask for notification permission from an activity when the moment is right:
Code
Then link the device to your own user id once you know who they are:
Code
Verify: run the app, then list subscriptions.
Code
You should see a row with your platform, language and a truncated token. Tokens are shown as the first 20 characters plus an ellipsis on every list route — the full token only exists in the NDJSON export.
If nothing appears, check OpenPush.onLog output first: a wrong SDK key, a wrong app id or a
missing server URL all report themselves there.
Step 5 — Register the device as a test subscription
Test subscriptions exist so you can send to yourself without touching campaign statistics. They also bypass the frequency cap and quiet hours on every send, including ordinary campaigns they happen to be in the audience of — so use them for development devices, not for a colleague's phone you also want realistic numbers from.
Code
You may pass token instead of subscription_id. Calling it again for the same device renames it
rather than creating a duplicate.
Code
Step 6 — Send a test push
send-test targets only registered test subscriptions and never creates a Sent Messages row.
Code
Code
If you get 404 no test subscriptions — add one first, go back to step 5.
Step 7 — Send for real
The main send endpoint is POST /v1/apps/{app_id}/messages. With no include_segments, it targets
every sendable subscription in the app.
Code
Code
There is no idempotency on this route. If the call times out, check
GET /v1/apps/acme-app/messages before retrying — a blind retry sends the campaign twice.
Step 8 — Read the report
Code
Provider Accepted fills in immediately. Device Received, Confirmed Receipt and Clicked
arrive only as the SDK posts them back to /v1/ingest, which the Android and iOS SDKs do for you
once integrated. If those three stay at zero while Provider Accepted climbs, the message reached
the provider and the receipt path is not wired up.
Common errors
| Response | Cause | Fix |
|---|---|---|
401 bad X-OP-API-Key (org routes need the global key) | Called POST /v1/apps with an app REST key | App creation is not on the customer API — create the app in the console |
404 no matching subscriptions — did the app register? | Immediate send with an empty audience | Confirm a device registered in step 4 |
400 need title+body or a known template | Neither the body nor a resolved template supplied both fields | Supply title and body, or a valid template |
404 no test subscriptions — add one first | send-test with no test devices registered | Complete step 5 |
400 data is not provider-safe JSON: … | data contains something FCM's string-only map cannot carry | Keep data to JSON-safe values; nested objects are serialized for you |
| Sends fail with "no FCM credentials" while the Web badge is green | Service account uploaded under Web only | Re-upload it under Android |
Limits
- App creation and app listing are platform-level routes, not customer ones; there is no org-scoped variant. Create apps in the console.
- Platform credential upload and media upload are console-only. Everything else in this guide is on the REST API.
- The default request body ceiling is 8 MB (150 MB for import uploads).
- The send route is not rate-limited, and offers no idempotency key.
FAQ
Can I skip the SDK and register a device myself?
Yes — POST /v1/apps/{app_id}/subscriptions with the SDK key takes a raw token. That is how the
web test client works. You lose the receipt ladder unless you post those events too.
Do I need both an APNs and an FCM credential? Only for the platforms you ship to. iOS devices with a real APNs token go to Apple; everything else goes through FCM. An iOS device that is still carrying an FCM registration token — common right after a OneSignal migration — is routed to FCM automatically.
Why did my first message report Delivered but nothing appeared on the phone?
Delivered here means the provider accepted it. Check that notification permission was granted,
that the app is not in a quiet-hours hold, and that your Android manifest declares the messaging
service.
Can I send to one specific person without a segment?
Yes. Use the target object with external_id, token, subscription_id, or an
{"label": …, "id": …} alias. See sending messages.
How do I roll a leaked key?
POST /v1/apps/{app_id}/keys/{kind}/rotate. It replaces the key in place with no grace window, so
deploy the new SDK key before rotating that one.