Mobile Push API
Beta
REST

Send Notification

Dispatch a push notification to a device token, all devices for a user, or a topic. Control priority and time-to-live, attach custom data, and receive a pushId for webhook correlation.

Device targeting

Address a single FCM or APNs token when you already know the handset.

User fan-out

Send once with type:user — every registered device for that userId receives the push.

Topic broadcast

Reach all devices subscribed to a topic without maintaining recipient lists.

Rich + data

Visible title/body/image plus silent data keys for deep links and in-app routing.

Endpoint

POST

/v1/push/send

Avg Accept

<200ms

95th percentile

Rate Limit

200/s

per API key

Default TTL

86400s

24 hours

POST
/v1/push/send
Core
Beta

Request body

application/json
JSON
{
"to": {
"type": "user",
"value": "user_abc123"
},
"title": "Payment received",
"body": "GHS 250.00 was credited to your wallet.",
"data": {
"type": "wallet_credit",
"amount": "250.00",
"currency": "GHS",
"screen": "wallet"
},
"image": "https://cdn.example.com/push/wallet.png",
"priority": "high",
"ttl": 3600
}

Parameters

FieldTypeRequiredDescription
toobject
required
Target descriptor: { type, value }.
to.type"device" | "user" | "topic"
required
How to resolve recipients.
to.valuestring
required
Device token, userId, or topic name (e.g. news).
titlestring
required
Notification title. Max 128 characters.
bodystring
required
Notification body. Max 1024 characters.
dataobjectoptionalCustom key/value map for the app. Not always shown in the system UI.
imagestring (URL)optionalHTTPS URL of an image for expanded notification views.
priority"high" | "normal"optionalDefault high. Use normal for non-urgent marketing to preserve battery.
ttlintegeroptionalSeconds the platform may store the message if the device is offline. Default 86400.

Targeting examples

JSON
{
"to": {
"type": "device",
"value": "dG9rZW4tZXhhbXBsZS1mY20tYW5kcm9pZA..."
},
"title": "Security alert",
"body": "A new login was detected on your account.",
"priority": "high"
}

Resolves to exactly one registered token. Returns 404 DEVICE_NOT_FOUND if the token was never registered or was deleted.

Priority & TTL

FieldValuesGuidance
priorityhigh (default), normalUse high for OTPs, security, and time-critical alerts. Use normal for promos so the OS may batch delivery and save battery.
ttl1 – 2,419,200 seconds (28 days)Short TTL for flash sales or OTPs (e.g. 300–3600). Longer for content that remains useful offline. After TTL, undelivered messages are dropped and may surface as expired.

Response

JSON
{
"success": true,
"code": "PUSH_QUEUED",
"message": "Push notification accepted for delivery.",
"requestId": "REQ-1782000001001",
"timestamp": "2026-07-12T11:20:00.000Z",
"data": {
"pushId": "PUSH-8c1a2b3d-4e5f-6789-abcd-ef0123456789",
"channel": "push",
"business": {
"id": "BU-VOIF86X7",
"name": "Letcol Technologies"
},
"target": {
"type": "device",
"value": "dG9rZW4tZXhhbXBsZS1mY20...",
"platform": "android",
"resolvedDevices": 1
},
"notification": {
"title": "Payment received",
"body": "GHS 250.00 was credited to your wallet.",
"image": "https://cdn.example.com/push/wallet.png",
"data": {
"type": "wallet_credit",
"screen": "wallet"
}
},
"delivery": {
"status": "queued",
"priority": "high",
"ttl": 3600,
"submittedAt": "2026-07-12T11:20:00.000Z"
},
"billing": {
"units": 1,
"pricing": {
"unitCost": 0.002,
"totalCost": 0.002,
"currency": "USD"
}
}
}
}

Code examples

Bash
curl -X POST 'https://api.sendexa.co/v1/push/send' \
-H 'Content-Type: application/json' \
-H 'Authorization: Basic YOUR_DASHBOARD_BASE64_TOKEN' \
-d '{
"to": { "type": "user", "value": "user_abc123" },
"title": "Payment received",
"body": "GHS 250.00 was credited to your wallet.",
"data": { "screen": "wallet" },
"priority": "high",
"ttl": 3600
}'
Platform payload mapping

Sendexa maps your REST body to native FCM and APNs fields. You do not need to craft platform-specific JSON unless you have advanced needs (contact support for custom APNs headers).

Sendexa fieldFCM (Android)APNs (iOS)
titlenotification.titleaps.alert.title
bodynotification.bodyaps.alert.body
imagenotification.image / android.notification.imagemutable-content + attachment (when supported)
datadata (string map)custom root keys alongside aps
priority: highandroid.priority = HIGHapns-priority: 10
priority: normalandroid.priority = NORMALapns-priority: 5
ttlandroid.ttlapns-expiration
Rate limits
ScopeLimitHeaders
Per API key200 requests / secondX-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset
BurstShort bursts up to 400/s may be absorbed; sustained overage returns 429Retry-After on 429
Topic fan-outCounts as 1 API request; delivery fan-out is asynchronous
Error reference
HTTPCodeWhen
400INVALID_TARGETMissing or invalid to.type / to.value
400INVALID_TOKENDevice target token format rejected
400TITLE_REQUIREDtitle missing or blank
400BODY_REQUIREDbody missing or blank
400PAYLOAD_TOO_LARGESerialized notification exceeds size limits
400INVALID_IMAGE_URLimage is not a valid HTTPS URL
400INVALID_TTLttl outside allowed range
401UNAUTHORIZEDAuth header missing or invalid
403PUSH_CREDENTIALS_MISSINGNo FCM/APNs credentials for resolved platform(s)
403INSUFFICIENT_CREDITSBalance too low for resolvedDevices units
404DEVICE_NOT_FOUNDtype=device and token not registered
404USER_HAS_NO_DEVICEStype=user with no registered devices
404TOPIC_EMPTYtype=topic with zero subscribers
429RATE_LIMIT_EXCEEDEDSustained over 200 req/s
Status lifecycle after send
  1. API returns queued with a pushId.
  2. Sendexa hands off to FCM/APNs → status sent (internal / webhook depending on provider feedback).
  3. Platform confirms delivery when available → push.delivered.
  4. User taps notification (app reports open) → push.opened.
  5. Permanent failure (invalid token, auth, etc.) → push.failed; unregister dead tokens.

Full webhook payloads are documented under Webhooks.