Create, list, read, cancel and promote campaigns, plus send-test to registered test devices only. Create is not idempotent: a retried request is a second send.
Preview an audience
Counts who a message would reach for the given include_segments,
exclude_segments, target and generic filters, broken down by the delivery guards that would hold or drop
devices, and renders title and body against a real sampled device from that audience
so the personalisation can be checked before sending.
Nothing is created and nothing is sent. Malformed rules or a half-specified target are a
400 here, exactly as they would be on the send.
path Parameters
app_idPreview an audience › Request Body
Body rendered against a sampled matching device.
Optional stricter frequency and pacing policy.
Segment names to exclude.
Inline audience filters, with the same semantics as message create.
Segment names to include.
Direct audience selector, including bounded recipient ID lists.
Title rendered against a sampled matching device.
Preview an audience › Responses
Audience counts plus the rendered title and body, with any render errors
List sent or scheduled messages
The Sent Messages report, newest-created first. Pass scheduled=1 for the
scheduled queue instead. Console drafts appear in neither list: a draft is not sent and
not scheduled either. Test sends are excluded too. limit is 1–200; pass next_cursor as
cursor for the next page. Optional status and name are exact filters. A cursor is bound
to its app, queue and filters and is invalid if any of those change. Rows that leave the
scheduled queue while paging are absent from later pages.
The funnel names are deliberately honest and mean different things: Provider Accepted (the provider took it) → Device Received (the SDK got the data) → Confirmed Receipt (it was displayed) → Clicked.
path Parameters
app_idquery Parameters
scheduledlimitcursorstatusnameList sent or scheduled messages › Responses
One report row per message, with the full delivery funnel and next_cursor
Create and send a message
Creates a message and either sends it immediately or schedules it.
Accepts content inline or by template, per-language content, A/B variants, saved
segments, generic inline filters, bounded direct recipient lists under target,
platform_options for iOS/Android presentation, and delivery options (ttl, priority,
collapse_key, delayed_option, delivery_time_of_day).
Idempotency. Send an
Idempotency-Keyheader (16-128 characters) and a retry is a retry, not a second send: for 24 hours the same key with the same body replays the original response — same status, same message id, nothing sent twice — carryingIdempotent-Replayed: true. The same key with a different body is a409, and so is a key whose first request has not answered yet. A create that is refused (a4xxraised before anything is sent) hands the key back, so the corrected request on the same key is a real send; once the send has started, whatever the request finally answers — including a5xx— is stored and replayed, so a retry after a failure can never become a second push. Without the header there is no deduplication: a retried create is a second send, and the way to recover from a timeout is to list messages and match on the campaignnamebefore retrying.
Collision warnings. The response carries a
warningsarray. Anaudience_collisionentry says this audience already received — or is already scheduled to receive — another message within 24 hours, either because the audience definition is identical or because at least 80% of the devices this send reached also took the other one. It is advisory: the send has already happened by the time you read it, and nothing about it is a refusal.
Blast-radius warnings. A
blast_radiusentry in the same array says this send reached at least 500 devices AND more than both three times the median audience of your last ten sends and half of everyone subscribed to the app. It carries the numbers it used (audience,median_recent,subscribed) and which bar was the binding one (reason:3x_medianorhalf_of_app). Advisory in exactly the same way — the console asks an operator to acknowledge a send this size, the API tells a program what it just did.
Two-person approval. When an app admin has turned it on, a create here is a request: the response is a
202with"status": "pending_approval", the message is created and held, and nothing is sent or scheduled until a manager or admin other than the requester approves it in the console under Scheduled Messages. A request made with an API key needs a person to approve it: the requester recorded on the message is the key's own name, which is nobody's address, so any manager or admin may be that second person — the key cannot approve what it asked for, and neither can it nominate who does. An OAuth-bound caller records the person behind the grant instead, and that person is then refused as the approver like any other requester. Rejection leaves the message unsent with the reason recorded. With anIdempotency-Key, a replay returns the same202— it never reports the send as done.
An immediate send resolves the audience before creating the row, so an empty audience is
a 404 and no message row is left behind. A scheduled send is accepted without that check.
provider_accepted in the response means the provider took the push; device receipts
arrive later via /v1/ingest. Unknown audience fields are rejected before the message is
stored.
path Parameters
app_idHeaders
Idempotency-KeyCreate and send a message › Request Body
A/B split and holdback configuration.
One to three mobile notification buttons. Invalid buttons reject the send. The app click callback receives the selected ID; server receipts count clicks without button attribution.
Notification body; Liquid is rendered per subscriber.
Legacy spelling of collapse_key.
Replaces an older pending notification with the same key.
Attribution label; defaults to api.
Additional message-level values used by preview and rendering.
Custom key/value payload delivered to the SDK.
Destination opened when the notification is tapped.
Fallback language code for localized content.
Best-Hour Delivery mode, such as best-hour delivery.
Optional frequency_cap and throttle_per_minute that tighten app limits for this message.
HH:MM local delivery time for time-of-day delivery.
Segment names to exclude.
Inline audience filter list. Predicates are ANDed; {operator:'or'} starts the next OR group. Supports tag, country, language, app_version, device_type, session, duration, test-user and location fields using the segment rule vocabulary. Intersects with segments and target.
HTTPS notification image URL or an OpenPush /media path.
Segment names to include.
Per-language content overrides.
Campaign name shown in reports and used as the caller's retry handle.
Validated iOS/Android presentation options; stored with the message and applied by the delivery pipeline.
Provider delivery priority.
ISO-8601 time or epoch seconds; absent sends immediately.
Optional notification subtitle.
One identity selector: external_id, external_ids, subscription_id, subscription_ids, token, alias:{label,id}, or aliases:{label,ids}. Up to 100 IDs; platforms may intersect it.
Template id or name; inline content overrides template fields.
Legacy spelling of template.
Notification title.
Seconds the provider may retain an undelivered push.
Legacy spelling of ttl, in seconds.
A/B variants keyed by variant name.
Variables available to Liquid templates for this send.
Create and send a message › Responses
The message id plus the send funnel, or the schedule confirmation
idstatusThe message's state. A delivery status for an immediate send, Scheduled for a future one, or pending_approval on a 202 when the app requires a second person to approve a send — in which case nothing has been sent or scheduled.
FCM/APNs accepted the push; this is not a device receipt.
Path of the message report.
Advisory only — never a refusal. An audience_collision entry means this audience already had, or is about to have, another message inside 24 hours: {code, message, message_id, name, at, overlap_pct}. overlap_pct is null when the two audience definitions are identical and nothing needed measuring. A blast_radius entry means this send is far larger than this app's usual one — at least 500 devices, and over both 3x the median of the last ten sends and half of everyone subscribed: {code, message, audience, median_recent, subscribed, reason}. median_recent is null when the app has never sent, and reason is 3x_median or half_of_app — whichever bar was binding.
Read a message report
The full report for one message: content as sent, audience and cap figures, the delivery funnel, per-variant numbers for an A/B test, and any render errors recorded at send time.
path Parameters
app_idmessage_idRead a message report › Responses
The full delivery report for one message
Cancel a scheduled message
Cancels a message that is still Scheduled. Only a scheduled message
can be cancelled — one that is already sending, sent or cancelled is a 409, and there is
no unsend. An unknown message id reads as the same 409, since neither is scheduled.
path Parameters
app_idmessage_idCancel a scheduled message › Responses
The message id and its Canceled status
List per-device delivery states for a message
One row per targeted device with its state — Waiting (best-hour delivery is
holding it), Held (quiet hours), Capped, Queued, Sent, Accepted (provider took it),
Retrying, Dead-lettered, Failed, Pending — and a detail string. by_state counts the
whole message regardless of paging. Filter with state; page with cursor (keyset on sub_id);
limit is capped at 1000.
path Parameters
app_idmessage_idquery Parameters
statelimitcursorList per-device delivery states for a message › Responses
Delivery rows with derived state, counts by state, and paging
Promote an A/B winner
Sends the winning arm of a finished A/B test to the holdback wave. The
holdback is device-disjoint from the tested arms, so nobody who saw a variant receives the
promotion. winner names the variant to promote.
A message with no holdback left, no variants, or an already-promoted test is a 409.
path Parameters
app_idmessage_idPromote an A/B winner › Request Body
winnerVariant name to send to the A/B holdback audience.
Promote an A/B winner › Responses
The promotion wave and its send funnel
Trace one user's delivery of a message
Why did — or didn't — one person get this message. Pass exactly one of
external_id, user_id, subscription_id. Every device the subject owns gets an outcome from a
closed vocabulary — not_in_audience, capped, held_quiet_hours, waiting_best_hour, queued,
retrying, dead_lettered, failed, oem_background_restriction_suspected,
accepted_no_receipt, received, confirmed, clicked, plus user_not_found, no_devices,
no_sendable_device and message_not_sent_yet — and the verdict is the best device, because one
reached device means the person was reached. oem_background_restriction_suspected is the Android
handset that was accepted by the provider, never reported a receipt, and is made by a manufacturer
known to kill background apps: a suspicion, worded as one. Audience membership is re-evaluated
now, and notes says so; a not_in_audience detail names the first targeting rule the device
fails.
path Parameters
app_idmessage_idquery Parameters
external_iduser_idsubscription_idTrace one user's delivery of a message › Responses
Per-device outcomes and a verdict
Preview rendered content
Renders every personalisation target — title, subtitle, body,
image_url and deep_link — against a caller-supplied sample device rather than one
drawn from the audience, so a variant can be checked without anybody matching it yet.
Per-field render errors come back in errors rather than failing the request; the field
then holds its unrendered source. Dynamic-content tables referenced by the content are
resolved and named back in dynamic_content, and an unknown one is an error.
path Parameters
app_idPreview rendered content › Request Body
Body to render.
Sample country code.
Sample custom data available to Liquid.
Deep link to render.
Sample external user id.
Image URL to render.
Sample language code.
Existing message whose content should be previewed.
Caller-supplied sample subscription fields.
Subtitle to render.
Sample user tags.
Title to render.
Preview rendered content › Responses
The rendered fields, per-field errors, and the dynamic content used
Send a test push
Sends to this app's test subscriptions only and never creates a Sent Messages row, so a test cannot pollute campaign reporting.
Test devices deliberately ignore the frequency cap and quiet hours, so a test send arrives
even inside a window a real send would be held for. An app with no test subscriptions is a
404 rather than a silent no-op.
path Parameters
app_idSend a test push › Request Body
A/B split and holdback configuration.
One to three mobile notification buttons. Invalid buttons reject the send. The app click callback receives the selected ID; server receipts count clicks without button attribution.
Notification body; Liquid is rendered per subscriber.
Legacy spelling of collapse_key.
Replaces an older pending notification with the same key.
Attribution label; defaults to api.
Additional message-level values used by preview and rendering.
Custom key/value payload delivered to the SDK.
Destination opened when the notification is tapped.
Fallback language code for localized content.
Best-Hour Delivery mode, such as best-hour delivery.
Optional frequency_cap and throttle_per_minute that tighten app limits for this message.
HH:MM local delivery time for time-of-day delivery.
Segment names to exclude.
Inline audience filter list. Predicates are ANDed; {operator:'or'} starts the next OR group. Supports tag, country, language, app_version, device_type, session, duration, test-user and location fields using the segment rule vocabulary. Intersects with segments and target.
HTTPS notification image URL or an OpenPush /media path.
Segment names to include.
Per-language content overrides.
Campaign name shown in reports and used as the caller's retry handle.
Validated iOS/Android presentation options; stored with the message and applied by the delivery pipeline.
Provider delivery priority.
ISO-8601 time or epoch seconds; absent sends immediately.
Optional notification subtitle.
One identity selector: external_id, external_ids, subscription_id, subscription_ids, token, alias:{label,id}, or aliases:{label,ids}. Up to 100 IDs; platforms may intersect it.
Template id or name; inline content overrides template fields.
Legacy spelling of template.
Notification title.
Seconds the provider may retain an undelivered push.
Legacy spelling of ttl, in seconds.
A/B variants keyed by variant name.
Variables available to Liquid templates for this send.
Send a test push › Responses
The test message id, the device count and the send funnel