Skip to main content

Push Notifications API

Send push notifications to your end users’ iOS and Android devices through Apple Push Notification service (APNs) and Firebase Cloud Messaging (FCM). Orbit holds your provider credentials and exposes a single send endpoint that fans out to the right transport. Base path: /api/v1/push Authentication: API key (X-API-Key) or session JWT.

Using the SDKs

Python (same call via the SDK’s escape hatch):
The Python SDK is core-scope — it wraps the 8 core resources (messaging, voice, contacts, campaigns, verify, numbers) and reaches everything else through the generic client.request() escape hatch above. See the Python SDK. Returns the typed ApiResponse envelope. See the SDK index at SDK quickstart.

Device tokens

Your mobile app registers each device’s push token after the user grants permission. Re-register on token rotation; APNs and FCM both rotate tokens periodically.

Register a device token

POST /api/v1/push/register and POST /api/v1/push/device-tokens are the same operation — the first exists for older SDK clients; new integrations should call /device-tokens. Supply the native APNs or FCM token for ios / android / huawei, or a Web Push subscription envelope for platform: web. Registering a token that already exists just refreshes its owner and last-seen time — it does not create a duplicate.
201 Created returns the token’s Orbit id — save it if you want to target specific devices when sending:

List device tokens

GET /api/v1/push/device-tokens lists the tenant’s registered tokens, newest first, capped at 200 rows. Pass ?user_id=<id> to scope the list to one user.
200 OK returns the rows — use the id values to target a send by device_token_ids, and enabled to see whether a token currently receives pushes:

Unregister a device token

DELETE /api/v1/push/device-tokens/{id} removes a token so the device no longer receives pushes — for example on sign-out.
Success is 204 No Content with an empty body. An unknown id returns 404 Not Found (NOT_FOUND).

Sending

Example — send to a user’s devices

Target a send with either user_ids (every registered device for those users) or device_token_ids (specific device tokens). At least one of the two is required.
To notify specific devices instead, pass device_token_ids with the ids returned from /api/v1/push/device-tokens:
Either variant returns 201 Created on an immediate send. The response carries one notifications[] entry per targeted device, so an APNs rejection or a frequency-cap skip on one device never masks the others’ delivery:
Each entry in the response notifications[] array carries a transport field — apns, fcm, webpush, or hms — identifying which transport was used to reach that device, alongside its deviceTokenId and delivery status. A status of sent, failed, or skipped is per-device; when a device could not be reached, its entry carries an error describing why.

List sent notifications

GET /api/v1/push/notifications returns the tenant’s notification log, newest first — the per-device rows recorded by /push/send — with delivery status and the delivered/opened timestamps the SDK ack endpoints set. Page older rows with ?cursor=<created_at of the last row>&limit=50; each page is capped at 200 rows.
200 OK returns the page:

VoIP call devices

A separate registry from the device tokens above, used ONLY to deliver inbound-call pushes that wake a backgrounded or terminated mobile app — Apple PushKit (CallKit) on iOS, a high-priority FCM channel on Android. Registration is handled by the mobile app SDK; the list and revoke endpoints let a backend integration or admin tool audit and manage a user’s registered call devices. Register with the raw PushKit token on iOS, or the call-channel FCM token on Android. Re-registering the same token refreshes it and clears any prior revocation.
201 Created returns the registered device:
The list response includes revoked devices (revoked_at set) alongside active ones, so you can see why a device stopped receiving call pushes — a bad token is marked revoked rather than deleted, and re-registering the same token clears the revocation automatically. Results are capped at 200 rows.
200 OK returns the devices, newest-seen first:
Unregister with the device’s Orbit id:
Success is 204 No Content with an empty body; an unknown id returns 404 Not Found (NOT_FOUND).

Scheduled pushes

To send later, add an ISO 8601 send_at to POST /api/v1/push/send. When send_at is in the future the notification is stored instead of dispatched and the request returns 202 Accepted; a background worker replays it through the same fan-out and suppression logic when the time arrives. Omit send_at (or pass a past instant) to send immediately.
202 Accepted confirms the push was queued, not sent — read it back or cancel it with the scheduled-push id:
Manage scheduled pushes that have not yet been sent: List the queue with GET /api/v1/push/scheduled — soonest send_at first, capped at 200 rows:
Read one scheduled push by id — including its full payload, attempt count, and any error from a failed dispatch:
An unknown id returns 404 Not Found (NOT_FOUND).

Cancelling a scheduled push

DELETE /api/v1/push/scheduled/{id} cancels a push that is still in the scheduled state. Cancel is a guarded status flip, not a hard delete — the row remains queryable with status: "cancelled".
A successful cancel returns 200 OK with the new status:
Cancellation only succeeds while the push is still pending. If the worker has already dispatched it (sent / failed) or it was cancelled by an earlier request, the endpoint returns 409 Conflict with error code SCHEDULED_PUSH_NOT_CANCELLABLE — the push has already left and can no longer be recalled. Branch on this code rather than treating the cancel as a silent success. An unknown id returns 404 Not Found (NOT_FOUND).

See also