The audience — device subscriptions and the users behind them, with external ids, aliases, tags, language and timezone. Registration is an SDK-key route; reading and editing the audience is admin.
Record an app session
Records a foreground observation or completed foreground duration without inventing a receipt — receipts belong to a message and a delivery row, and an app session has neither.
The server decides whether this counts as a new session: an observation inside the
configured session gap updates last_seen only and comes back {"counted": false}. SDKs
throttle their calls for battery etiquette, but that gap is the authoritative definition of
a session. Duration reports are idempotent and do not open another session.
path Parameters
app_idRecord an app session › Request Body
tokenRegistered device push token observed in the foreground.
Completed foreground time. Omit for a foreground observation.
Stable event key required with duration_seconds.
Record an app session › Responses
Whether a session or duration was newly recorded
List subscriptions
Subscriptions for one app. search matches on token, external id or
subscription id; test=1 restricts the list to test devices.
Push tokens are truncated to their first 20 characters here — a list route is for
looking, and nobody can migrate a device from a token prefix. GET /export.ndjson is the
route that returns them whole. Paging works exactly as on the users route: newest-first and
uncursored by default, ?order=id for a stable keyset walk, limit capped at 1000, and
total is the length of this page.
path Parameters
app_idquery Parameters
searchtestlimitcursororderList subscriptions › Responses
A page of subscriptions with truncated tokens and paging metadata
Register or update a device
Registers a push token, or updates the row that already holds it. The
upsert key is (app, token), so calling this on every cold start is the intended usage —
it is idempotent.
Absent, present-and-empty, and present-with-a-value are three different claims. A key
the body omits is not a claim and leaves the stored column alone; external_id: null
(or "") is an explicit detach. If the app has identity verification on, an
external_id, tags or aliases claim without a valid external_id_auth_hash is
downgraded, not rejected: the device still registers, and the response carries an
identity_rejected note. Values for a data-collection category the app has switched off
are silently dropped and named back in not_collected.
path Parameters
app_idRegister or update a device › Request Body
tokenDevice push token; the upsert key within the app.
Advertising id; stored only when collection is enabled.
Alias label to id.
Installed app version.
Country code.
Device model or family.
Human-readable device name.
Email; stored only when collection is enabled.
Your user id; explicit null or empty detaches identity.
Identity-verification hash when the app requires it.
Language code.
Latitude; stored only when collection is enabled.
Single-use link token for the shared sample app.
Longitude; stored only when collection is enabled.
Operating-system version.
Push platform.
Rooted or jailbroken device signal, when available.
Whether the APNs token targets the sandbox environment.
OpenPush SDK version.
Explicit device subscription status; omitted preserves it.
User tags; omitted leaves stored tags unchanged.
IANA timezone reported by the device.
Register or update a device › Responses
The subscription id, its resolved status, and any downgrade notes
Read one subscription
One device: its status with the operator-facing status_ui/status_help, the
user behind it, that user's tags, which active segments it matches right now, and its delivery
history with derived states. The push token is masked.
path Parameters
app_idsub_idquery Parameters
limitRead one subscription › Responses
One device profile with matching segments and deliveries
Add a test subscription
Marks a device as a test device, by subscription_id or by token. A
token that is not registered yet is registered first, exactly as the SDK would. Calling it
again for the same device renames rather than duplicating.
A test device ignores the frequency cap and quiet hours on every send — this is a device-level guard bypass, not a label. Anything quiet hours was holding for this device is released immediately.
path Parameters
app_idAdd a test subscription › Request Body
External id used when a new token is registered.
Human label for the test device.
Platform used when a new token is registered.
Existing subscription id; supply this or token.
Existing or new push token; supply this or subscription_id.
Add a test subscription › Responses
The test device's label and subscription id
Remove a test subscription
Removes the test-device marking from one subscription. The subscription itself is untouched and keeps receiving ordinary sends — what it loses is the cap and quiet-hours bypass.
path Parameters
app_idsub_idRemove a test subscription › Responses
Confirmation that the marking was removed
List users
Users for one app with their tags, aliases and subscription count.
search matches on external id or tags.
Two orderings, named. A bare call returns the newest sessions first, limit rows, with
no cursor — that ordering is not unique or stable, so it cannot be walked. Pass ?order=id
(or any ?cursor=) to switch to a stable keyset walk that emits next_cursor. limit is
capped at 1000, and total has always meant the length of this page, not of the table.
path Parameters
app_idquery Parameters
searchlimitcursororderList users › Responses
A page of users with paging metadata
Read one user
Identity, tags, aliases, every device (tokens masked), the sendable device
count, and the most recent deliveries across all of this person's devices with their derived
state. Answers "what did this person actually receive?" — then
GET /messages/{message_id}/trace says why for one message.
path Parameters
app_iduser_idquery Parameters
limitRead one user › Responses
One user profile with devices and recent deliveries
Set or delete user aliases
Server-side alias writes: {"set": {label: value}, "delete": [label]}. Labels
follow the tag charset and the 60-character cap, values are at most 300 characters, and the
per-user alias cap is the same one the SDK identity call and the CSV importer are held to —
an eleventh alias is a 400, not a silent drop.
external_id is not an alias: it is set by the SDK identity call, and naming it here is a
400. Returns the resulting alias map.
path Parameters
app_iduser_idSet or delete user aliases › Request Body
deleteAlias labels to remove; external_id is refused here too. Removing a label the user does not have is not an error. set and delete together are capped at 100 changes per call.
Alias label to id. Labels follow the tag charset — [A-Za-z0-9_-.] with no empty segment, at most 60 characters — and an alias needs a value, of at most 300 characters. A label in both set and delete is set, not deleted. external_id is reserved: it is set by the SDK identity call, so naming it here is a 400. An eleventh alias on one user is a 400, not a silent drop.
Set or delete user aliases › Responses
The user's aliases after the change
Create Subscription Admin
path Parameters
app_iduser_idCreate Subscription Admin › Request Body
consentExplicit current permission or opt-in state.
platformtokenPush token. Accepted only in a request body.
iOS sandbox environment only.
Create Subscription Admin › Responses
Successful Response
Set or delete user tags
Server-side tag writes: {"set": {key: value}, "delete": [key]}. Keys are
[A-Za-z0-9_-.] with no empty segment and at most 60 characters, values at most 300, and at
most 100 changes per call. set wins over delete for a key in both; deleting a key the user
does not have is not an error. Returns the resulting tag map.
Until now only the device SDK could write a tag, which meant a server that knew something about a person (a purchase, a plan change) had no way to say so. The rules are the console's own — one enforcement point for the form, this route and the MCP tools.
path Parameters
app_iduser_idSet or delete user tags › Request Body
deleteTag keys to remove. Deleting a key the user does not have is not an error. set and delete together are capped at 100 changes per call.
Tag key to value. Keys are [A-Za-z0-9_-.] with no empty segment and at most 60 characters; values are at most 300 characters. A key in both set and delete is set, not deleted.
Set or delete user tags › Responses
The user's tags after the change
Fetch the web push configuration
Everything a browser needs to subscribe to web push for this app: the public half of the VAPID pair, the browser push configuration, the app's ingest-only SDK key, the site URL, and whether devices on this app need a link code.
This route is deliberately unauthenticated, and that list is the whole of what it publishes. The service-account JSON and the VAPID private key are never read by it. The SDK key it returns can register a device and post a receipt; it can never read an audience, send a push or rotate anything.
path Parameters
app_idFetch the web push configuration › Responses
VAPID public key, browser push config, SDK key and site URL