Skip to content
Pushix Pushix
Features Developers Guides Pricing Questions
Sign in Start free
Menu
Features Developers Guides Pricing Questions
Sign in Create a free account
  1. Home
  2. Guides
  3. REST API

Push notification REST API

The Pushix notification API: send push notifications to Android, iOS and web with one HTTP request, target users and segments, and manage devices and templates.

Updated 31 October 2026 11 min read Your backend

Mobile apps

  • Flutter
  • Android
  • iOS
  • React Native

Websites

  • Web push
  • WordPress

Your backend

  • REST API
  • PHP, Node.js, Python

Switching

  • Switching to Pushix
  • All guides
On this page 12 sections
  1. Authentication
  2. Errors
  3. Quick start
  4. Notifications
  5. Templates
  6. Filters
  7. Segments
  8. Devices (players)
  9. Users (external user id)
  10. SDK endpoints
  11. App
  12. What's supported

One REST API sends push notifications to Android, iOS and web browsers. Your backend needs three things from App settings in the dashboard:

Where to find it
Base URLhttps://pushix.in/api/v1
App IDApp settings → Keys
REST API keyApp settings → Keys

Both URL styles work: /api/v1/notifications and /notifications are the same endpoint.

Authentication#

Endpoints that send or read data need the app's REST API key in the Authorization header. Any of these forms is accepted:

Code
Authorization: Basic YOUR_REST_API_KEY
Authorization: Key YOUR_REST_API_KEY
Authorization: Bearer YOUR_REST_API_KEY

Device endpoints used by the apps and the web SDK (create device, update device, sessions, click tracking, in-app messages) only need app_id. Never put the REST API key inside your app or website.

Errors#

Errors come as a JSON list with an HTTP status of 400, 402, 403, 404 or 500:

JSON
{ "errors": ["You must include which players, segments, or filters to send this notification to."] }

A send that matches nobody returns HTTP 200 with an explanation:

JSON
{ "id": "", "recipients": 0, "external_id": null, "errors": ["All included players are not subscribed"] }

Quick start#

Shell
curl -X POST https://pushix.in/api/v1/notifications \
  -H "Content-Type: application/json" \
  -H "Authorization: Basic YOUR_REST_API_KEY" \
  -d '{
    "app_id": "YOUR_APP_ID",
    "included_segments": ["Subscribed Users"],
    "headings": {"en": "Bonus unlocked"},
    "contents": {"en": "Your cart is waiting. Complete your order today and get free delivery."},
    "data": {"screen": "orders"}
  }'

Response:

JSON
{ "id": "b98881cc-1e94-4366-bbd9-db8f3429292b", "recipients": 1250, "external_id": null }

That one call reaches every subscribed Android phone, iPhone and browser. The same call from PHP:

PHP
$payload = [
    'app_id' => 'YOUR_APP_ID',
    'included_segments' => ['Subscribed Users'],
    'headings' => ['en' => 'Bonus unlocked'],
    'contents' => ['en' => 'Your cart is waiting.'],
    'data' => ['screen' => 'orders'],
];
$ch = curl_init('https://pushix.in/api/v1/notifications');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Authorization: Basic YOUR_REST_API_KEY'],
    CURLOPT_POSTFIELDS => json_encode($payload),
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);

A ready-made helper class is in libraries/php/PushixClient.php.

Notifications#

Create notification#

POST /api/v1/notifications — REST API key required.

Targeting#

Use exactly one of these: segments, filters, or ids. They cannot be combined.

FieldTypeDescription
included_segmentsarraySegment names, e.g. ["Subscribed Users"] or your own segments.
excluded_segmentsarraySegments to leave out (only with included_segments).
filtersarrayFilter rules, see Filters below.
include_external_user_idsarrayYour own user ids (set with Pushix.login).
include_aliasesobject{"external_id": ["u1", "u2"]}, or device ids with {"subscription_id": [...]}.
include_player_idsarrayPushix player ids (device ids).
include_subscription_idsarraySame as include_player_ids.
include_android_reg_idsarrayRaw FCM tokens of devices already registered with Pushix.
target_channelstringOptional. Only "push" is supported.

Id lists accept up to 10,000 entries per request.

Platforms#

By default a message goes to every platform the app has set up. Narrow it with platform flags or a plain list:

FieldDescription
isAndroid, isIos, isAnyWebtrue on some flags: only those platforms. false on a flag: everything except that platform.
isChromeWeb, isFirefox, isSafari, isEdge, isChromeAccepted for compatibility; all mean "web".
platformsPushix's own form: ["android", "ios", "web"]. Wins over the flags.

Silent messages (content_available) never go to browsers, because browsers must always show something.

Content#

FieldTypeDescription
contentsobjectMessage text per language: {"en": "Hello", "hi": "नमस्ते"}. Required unless content_available is true or a template supplies it.
headingsobjectTitle per language.
subtitleobjectiOS subtitle per language (the line under the title).
dataobjectExtra data delivered as additionalData.
url / app_urlstringLink or deep link for the apps. A https:// link is also used for browsers unless web_url is set.
big_picturestringPicture URL: large on Android and the web, a thumbnail on iPhone (2:1 works best).
large_iconstringAndroid: image URL (or drawable name) shown on the right.
buttonsarrayUp to 3: [{"id": "claim", "text": "Claim", "url": "https://…"}]. Shown on Android, on iPhone (apps with the Pushix notification service extension, or your own ios_category) and in browsers (the first 2 unless web_buttons is set).
content_availablebooleanData-only message with no visible notification (needs data, no contents). Android and iOS only.
template_idstringStart from a saved template; any field you send overrides the template's.
namestringInternal name shown in the dashboard.

Each device gets the language that matches its system language (hi, bn, ...), falling back to en.

Personalise text with the device's tags:

JSON
"contents": {"en": "Hi {{ name | default: 'friend' }}, you have {{ points }} reward points"}

{{ external_id }} and {{ player_id }} also work.

Android#

FieldTypeDescription
android_channel_idstringNotification channel. Default: the app's default (pushix_default, created by the SDK with high importance). existing_android_channel_id is accepted too.
small_iconstringDrawable name in the app, e.g. ic_stat_notification.
android_accent_colorstringFF9976D2 (ARGB) or #9976D2.
android_soundstringSound file name in res/raw without extension. On Android 8+ the channel decides the sound.
android_visibilityintegerLock screen: 1 public, 0 private, -1 secret.
android_groupstringGroup notifications together.

iOS#

iPhone messages go through Firebase Cloud Messaging with an APNs payload, so the app needs the Firebase key plus an APNs key uploaded to Firebase (see the iOS SDK or Flutter SDK guide).

FieldTypeDescription
ios_soundstringA sound file in the app bundle, "default", or "nil" for silent.
ios_badgeTypestringNone (default), Increase or SetTo.
ios_badgeCountintegerThe amount to add or set. Pushix keeps each device's count and resets it when the app opens.
ios_attachmentsobject{"id": "https://…/pic.jpg"}; the first URL is used as the picture. big_picture also works.
thread_idstringGroups notifications in Notification Center.
ios_categorystringA notification category your app registers, for custom iOS actions. Not needed for buttons: the iOS SDK's Notification Service Extension shows them.
ios_interruption_levelstringpassive, active, time-sensitive or critical.
ios_relevance_scorenumber0–1, for the notification summary.
mutable_contentbooleanLets your Notification Service Extension change the message. Set automatically when there is a picture.

Web#

FieldTypeDescription
web_urlstringOpened when the notification is clicked in a browser.
chrome_web_icon / firefox_iconstringIcon URL. Defaults to the icon in App settings → Web push.
chrome_web_imagestringLarge picture for browsers (defaults to big_picture).
chrome_web_badgestringSmall monochrome icon for Android Chrome's status bar.
web_buttonsarrayUp to 2: [{"id": "shop", "text": "Shop now", "url": "https://…"}].
persist_notification / require_interactionbooleanKeep it on screen until clicked (desktop Chrome and Edge).
web_push_topicstringA newer message with the same topic replaces the older one.

Delivery#

FieldTypeDescription
send_afterstringSchedule: "2026-11-01 09:00:00 GMT+0530", ISO 8601, or unix seconds.
ttlintegerSeconds the push service keeps trying if the device is offline. Default 259200 (3 days), max 28 days.
priorityinteger10 high (default, shows right away), 5 normal.
collapse_idstringA newer message with the same id replaces the older one (all platforms).
throttle_rate_per_minuteintegerSend at most this many per minute, so your backend is not hit by everyone opening the app at once.
external_id / idempotency_keystringSending the same key twice returns the first notification instead of sending again.

Response#

JSON
{ "id": "b98881cc-1e94-4366-bbd9-db8f3429292b", "recipients": 1250, "external_id": null }

recipients is the number of subscribed devices that match right now. Sending happens in the background: small sends go out within seconds; large sends are processed in batches of 500 by the worker.

Examples#

Send to your own user ids, only on their phones:

JSON
{
  "app_id": "YOUR_APP_ID",
  "include_external_user_ids": ["10234", "10235"],
  "isAnyWeb": false,
  "headings": {"en": "Order shipped"},
  "contents": {"en": "₹250 has been sent to your UPI ID."},
  "data": {"screen": "orders", "id": "OD-4821"}
}

Users with a tag above a value, or who haven't opened the app in two days:

JSON
{
  "app_id": "YOUR_APP_ID",
  "contents": {"en": "Your daily spin is ready"},
  "filters": [
    {"field": "tag", "key": "level", "relation": ">", "value": "5"},
    {"operator": "OR"},
    {"field": "last_session", "relation": ">", "hours_ago": "48"}
  ]
}

Scheduled, with buttons, a picture, an iOS badge and a website link:

JSON
{
  "app_id": "YOUR_APP_ID",
  "included_segments": ["Active Users"],
  "excluded_segments": ["Test Users"],
  "headings": {"en": "Diwali offer", "hi": "दिवाली ऑफ़र"},
  "contents": {"en": "Flash sale: 50% off today only", "hi": "आज ही 50% की छूट"},
  "big_picture": "https://yourdomain.com/img/diwali.jpg",
  "buttons": [{"id": "open", "text": "Open app"}, {"id": "share", "text": "Share"}],
  "ios_badgeType": "Increase", "ios_badgeCount": 1,
  "web_url": "https://yourdomain.com/diwali",
  "send_after": "2026-11-08 10:00:00 GMT+0530",
  "throttle_rate_per_minute": 2000
}

From a template, with one value filled in:

JSON
{ "app_id": "YOUR_APP_ID", "template_id": "TEMPLATE_ID", "include_external_user_ids": ["10234"] }

Data-only message (nothing shown; your app gets it in addSilentDataListener while open):

JSON
{ "app_id": "YOUR_APP_ID", "include_external_user_ids": ["10234"], "content_available": true, "data": {"refresh": "balance"} }

View notification#

GET /api/v1/notifications/{id}?app_id=YOUR_APP_ID — REST API key required.

JSON
{
  "id": "b98881cc-1e94-4366-bbd9-db8f3429292b",
  "app_id": "YOUR_APP_ID",
  "status": "completed",
  "contents": {"en": "Your cart is waiting."},
  "headings": {"en": "Bonus unlocked"},
  "data": {"screen": "orders"},
  "included_segments": ["Subscribed Users"],
  "platforms": ["android", "ios", "web"],
  "recipients": 1250,
  "successful": 1231,
  "failed": 17,
  "errored": 2,
  "converted": 140,
  "remaining": 0,
  "queued_at": 1793280000,
  "send_after": 1793280000,
  "completed_at": 1793280011,
  "canceled": false,
  "platform_delivery_stats": {
    "android": {"successful": 900, "failed": 12, "errored": 2, "converted": 104},
    "ios": {"successful": 250, "failed": 3, "errored": 0, "converted": 25},
    "web_push": {"successful": 81, "failed": 2, "errored": 0, "converted": 11}
  },
  "template_id": null,
  "error": null
}
FieldMeaning
statusscheduled, queued, processing, completed, canceled or failed
successfulAccepted by Firebase or the browser's push service
failedThe app was uninstalled or the browser unsubscribed; the device is unsubscribed automatically
erroredOther errors; the first one is in error
convertedDevices that clicked the notification (counted once each)
remainingNot sent yet

List notifications#

GET /api/v1/notifications?app_id=YOUR_APP_ID&limit=50&offset=0 — REST API key required.

limit is at most 50. Add kind=0 for dashboard sends only or kind=1 for API sends only.

JSON
{ "total_count": 312, "offset": 0, "limit": 50, "notifications": [ ... ] }

Cancel notification#

DELETE /api/v1/notifications/{id}?app_id=YOUR_APP_ID — REST API key required.

Cancels a scheduled message, or stops one that is still sending. Returns {"success": true}.

Track open#

PUT /api/v1/notifications/{id} — called by the SDKs when a notification is clicked.

JSON
{ "app_id": "YOUR_APP_ID", "player_id": "DEVICE_ID", "opened": true, "action_id": "claim" }

Templates#

Saved messages you can send by id. Create them in the dashboard (composer → Save as template) or here.

Endpoint
POST /api/v1/templatesCreate. Body: app_id, name, and any content fields (headings, contents, big_picture, buttons, ios_*, web_*, …). Returns {"id", "name"}.
GET /api/v1/templates?app_id=…&limit=50&offset=0List (names and ids).
GET /api/v1/templates/{id}?app_id=…View with content.
PATCH /api/v1/templates/{id}Update (app_id in the body). Fields you send replace the saved ones.
DELETE /api/v1/templates/{id}?app_id=…Delete.

All need the REST API key. Send with "template_id" on Create notification.

Filters#

Filters are an array. Rules next to each other must all match (AND). {"operator": "OR"} starts a new group.

FieldRelationsValue
tag=, !=, >, <, >=, <=, exists, not_exists, time_elapsed_gt, time_elapsed_ltkey and value. > and < compare numbers. time_elapsed_* treat the tag as a unix timestamp and value as seconds. != also matches devices without the tag.
platform (or device_type)=, !=android, ios, web (or a list)
last_session> (more than N hours ago), < (within N hours)hours_ago
first_session>, <hours_ago
session_count>, <, =, !=, >=, <=number
session_timesame as aboveseconds spent in the app
amount_spentsame as abovenumber
language=, !=, exists, not_existse.g. hi
app_version=, !=, exists, not_existse.g. 2.4.0
country=, !=, exists, not_existse.g. IN
device_model=, !=, exists, not_existse.g. Xiaomi Redmi Note 12
external_user_id=, exists, not_existsuser id

Examples:

JSON
[{"field": "tag", "key": "plan", "relation": "=", "value": "gold"}]
[{"field": "platform", "relation": "=", "value": "ios"}, {"field": "last_session", "relation": ">", "hours_ago": "72"}]
[{"field": "external_user_id", "relation": "not_exists"}]

Segments#

Built-in segments#

NameWho
Subscribed Users (also All, Total Subscriptions)Every device that can receive push
Active UsersOpened the app in the last 7 days
Engaged UsersOpened the app 10 or more times
Inactive UsersNot opened the app for more than 7 days
Android Users, iOS Users, Web SubscribersSubscribed devices on that platform
Test UsersDevices marked as test devices in the dashboard

Create segment#

POST /api/v1/apps/{app_id}/segments — REST API key required.

JSON
{ "name": "Gold members", "filters": [{"field": "tag", "key": "plan", "relation": "=", "value": "gold"}] }

Returns {"success": true, "id": "SEGMENT_ID"}. Segments are evaluated at send time, so new devices that match are included automatically.

List segments#

GET /api/v1/apps/{app_id}/segments?limit=300&offset=0 — REST API key required.

Delete segment#

DELETE /api/v1/apps/{app_id}/segments/{segment_id} — REST API key required.

Devices (players)#

A device is one app install or one browser. Its id is also called the player id or subscription id.

Add a device#

POST /api/v1/players — app_id only. The SDKs call this for you.

FieldDescription
app_idRequired
device_typeRequired. 1 Android, 0 iOS, 5 web (7, 8 and 17 are also treated as web)
identifierFCM token (Android and iOS) or the browser's push endpoint URL (web)
web_auth, web_p256Web only: the subscription's auth and p256dh keys
notification_types1 subscribed, -2 opted out, 0 no permission
languagee.g. en, hi
timezoneOffset in seconds, e.g. 19800 for IST
game_versionApp version
device_model, device_os, country, sdkDevice info
external_user_idYour user id
tags{"key": "value"}
session_count, amount_spent, test_typeOptional

Returns {"success": true, "id": "DEVICE_ID"}. Registering the same token or endpoint again returns the same id, so reinstalls don't create duplicates.

Edit a device#

PUT /api/v1/players/{id} — app_id only. Same fields as above. A tag value of "" deletes that tag. "clear_tags": true removes all tags first.

Sessions#

POST /api/v1/players/{id}/on_session — counts a new app open, updates last_active and resets the iOS badge count (unless the body sends badge_count, which is then stored as is). Same body as edit.

POST /api/v1/players/{id}/on_focus with {"app_id": "...", "state": "ping", "active_time": 60} adds seconds spent in the app.

View a device#

GET /api/v1/players/{id}?app_id=YOUR_APP_ID — REST API key required.

JSON
{
  "id": "5c6c4b1e-4f0e-4a5e-9a3b-0d3c3c8f2a11",
  "identifier": "fcm-token…",
  "platform": "android",
  "device_type": 1,
  "session_count": 14,
  "language": "hi",
  "timezone": 19800,
  "game_version": "2.4.0",
  "device_os": "14",
  "device_model": "Xiaomi Redmi Note 12",
  "tags": {"level": "5"},
  "badge_count": 0,
  "last_active": 1793280000,
  "playtime": 3600,
  "amount_spent": 0,
  "created_at": 1790000000,
  "invalid_identifier": false,
  "external_user_id": "10234",
  "notification_types": 1,
  "subscribed": true
}

List devices#

GET /api/v1/players?app_id=YOUR_APP_ID&limit=300&offset=0 — REST API key required. Newest first, limit at most 300.

Delete a device#

DELETE /api/v1/players/{id}?app_id=YOUR_APP_ID — REST API key required.

Import devices#

POST /api/v1/apps/{app_id}/players/import — REST API key required. Up to 2000 per request.

JSON
{ "players": [ {"id": "OLD-PLAYER-ID", "identifier": "fcm-token", "device_type": 1, "external_user_id": "10234", "tags": {"level": "5"}} ] }

Keeps the original ids. Android rows are imported; iOS and web subscribers register again when they next open your app or site. The dashboard's “Import CSV” button (Subscribers) uses this with a CSV export of your subscribers.

Users (external user id)#

Edit tags for a user#

PUT /api/v1/apps/{app_id}/users/{external_user_id} — REST API key required. Updates every device of that user.

JSON
{ "tags": {"balance": "250", "kyc": "done", "old_tag": ""} }

Returns {"success": true, "devices_updated": 2}.

View a user's devices#

GET /api/v1/apps/{app_id}/users/{external_user_id} — REST API key required.

SDK endpoints#

Called by the Pushix SDKs (Flutter, Android, iOS, React Native, web) with app_id only. Browsers may call them from any website (CORS is open on these paths).

Endpoint
GET /api/v1/apps/{app_id}/web_configPublic web push settings: VAPID public key, prompt texts, whether web in-app messages exist.
GET /api/v1/apps/{app_id}/in_app_messages?player_id=…In-app messages this device may see, with its session_count.
POST /api/v1/in_app_messages/{id}/events{"app_id", "player_id", "event": "impression" | "click" | "dismiss", "button_id", "platform"} (platform is optional: android, ios or web)

If the organization's plan doesn't include in-app messages, the in-app list is empty (no error), so apps keep working.

App#

GET /api/v1/apps/{app_id} — REST API key required. Returns players (all devices) and messageable_players (subscribed).

What's supported#

FeaturePushix
Android and iOS push (title, subtitle, text, picture, buttons, sounds, badges, deep links, data)Yes
Web push (Chrome, Edge, Firefox, Opera, Safari) with prompts, bell and welcome messageYes
Segments, filters, tags, external user ids, aliases, platform targetingYes
Scheduling (send_after), throttling, TTL, collapse id, idempotencyYes
Multiple languages, tag personalisationYes
Templates (template_id)Yes
A/B tests (2–5 variants, automatic or manual winner)Yes, from the dashboard
Automated messages (welcome, win-back, recurring)Yes, from the dashboard
In-app messages (pop-up, card, banners, full screen; triggers and frequency caps)Yes, in the Flutter, Android, iOS, React Native and web SDKs
Analytics: delivery by platform, clicks, active users, best time to send, CSV exportsYes
Email, SMS, Live ActivitiesNo
delayed_option timezone / intelligent deliveryNo (returns an error)
Location filtersNo
Previous guideWordPress push notifications Next guideSend push notifications from PHP, Node.js and Python

Send your first notification

Create an app in Pushix to get your App ID and REST API key, then follow this guide. The free plan needs no card.

Create a free account See pricing

On this page

  1. Authentication
  2. Errors
  3. Quick start
  4. Notifications
  5. Create notification
  6. View notification
  7. List notifications
  8. Cancel notification
  9. Track open
  10. Templates
  11. Filters
  12. Segments
  13. Built-in segments
  14. Create segment
  15. List segments
  16. Delete segment
  17. Devices (players)
  18. Add a device
  19. Edit a device
  20. Sessions
  21. View a device
  22. List devices
  23. Delete a device
  24. Import devices
  25. Users (external user id)
  26. Edit tags for a user
  27. View a user's devices
  28. SDK endpoints
  29. App
  30. What's supported
Back to top
Pushix Pushix

Push notification service for Android, iPhone and websites, from one dashboard or one API call. Built in West Bengal, India.

info@pushix.in

Product

Features Developers Pricing Questions Sign in Create an account

Guides

Flutter guide Android guide iOS guide React Native guide Web push guide WordPress guide REST API guide PHP, Node.js, Python guide Switching to Pushix guide All guides

Legal

Terms of Service Privacy Policy Cookie Policy Acceptable Use Policy Data Processing Addendum Refund & Cancellation Policy Service Delivery Policy

Company

Contact us All legal pages Support

© 2026 Pushix. All rights reserved.

Pushix · Powered by Pynix