REST API
Base URL: https://api.notibolt.com/api/v1. Authenticate server-to-server calls with your app's REST API key:
Authorization: Key nb_your_rest_key # also accepted: "Bearer nb_…", "Basic nb_…" or the X-Api-Key header
Send a notification
POST /apps/{appId}/notifications{
"title": "Order shipped 📦",
"body": "Arrives Thursday",
"url": "myapp://orders/1234",
"imageUrl": "https://example.com/banner.png",
"data": { "orderId": "1234" },
"segment": {
"platforms": ["IOS", "ANDROID"],
"tags": { "plan": "pro" },
"tagFilters": [{ "key": "score", "op": "gt", "value": "100" }],
"languages": ["tr", "en"],
"countries": ["TR", "DE"],
"lastActiveWithinDays": 30,
"externalUserIds": ["user-42"],
"deviceIds": ["<uuid>"]
},
"scheduledAt": "2026-09-01T09:00:00Z",
"contents": {
"tr": { "title": "Kargon yola çıktı 📦", "body": "Perşembe kapında" },
"en": { "title": "Order shipped 📦", "body": "Arrives Thursday" }
},
"defaultLanguage": "en",
"sound": "default",
"badge": 3,
"androidChannel": "orders",
"interruptionLevel": "time-sensitive",
"collapseId": "order-1234",
"ttlSeconds": 86400,
"contentAvailable": false
}Only title and body are required. Returns the notification with status: "QUEUED" immediately — delivery happens asynchronously.
Field notes
| Field | Behavior |
|---|---|
segment | Omitted → all subscribed devices. All filters combine with AND. tagFilters ops: eq, ne, gt, lt, exists, not_exists, in. |
scheduledAt | Future ISO date → queued until then. Cancel while queued with DELETE /apps/{appId}/notifications/{id}. |
contents | Per-language title/body; each device gets its own language (BCP-47 prefix match), falling back to defaultLanguage, then top-level title/body. |
| Templates | {{externalUserId}}, {{language}} and {{tags.name}} in title/body are filled per-device. |
contentAvailable | Silent push — nothing rendered; only data is delivered (skips the in-app opt-out filter). |
Idempotency-Key header | Same key + same app → returns the original notification instead of sending twice. |
Read results
GET /apps/{appId}/notifications # latest 50
GET /apps/{appId}/notifications/{id} # live counters
GET /apps/{appId}/notifications/{id}/deliveries?take=100&status=FAILED
GET /apps/{appId}/notifications/stats/daily?days=14Counters: totalTargeted, totalSent, totalDelivered (device-confirmed), totalFailed, totalOpened. The deliveries endpoint includes a per-error breakdown.
Device endpoints (public, used by SDKs)
Authenticated by the public App ID; they never return push tokens or other devices' data. You normally don't call these yourself — the SDKs do.
POST /sdk/devices # register (upsert by push token)
PUT /sdk/devices/{deviceId} # update tags / user / prefs
POST /sdk/notifications/{id}/received # delivery confirmation
POST /sdk/notifications/{id}/opened # open trackingWebhooks
Create webhooks in the panel (App → Settings) or via POST /apps/{appId}/webhooks. Events:
| Event | Fires when |
|---|---|
notification.completed | A send finishes (with final counters) |
device.unsubscribed | A device's token goes dead and it is deactivated |
Payloads are signed: verify the X-Notibolt-Signature: sha256=… header with your webhook secret (HMAC-SHA256 of the raw body).
Delivery error reasons
errorReason | Meaning |
|---|---|
fcm_not_configured / apns_not_configured | Credentials missing for that platform |
UNREGISTERED, Unregistered, BadDeviceToken | Dead token — the device is auto-deactivated |
TopicDisallowed | Bundle ID not registered as an App ID in your Apple developer account |
timeout, connection_error: … | Transient — retried automatically with backoff |
Rate limits
Public SDK endpoints are limited to 120 requests/minute per IP. Sending endpoints are limited per plan — contact us if you need more.