Notiboltdocs

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
The REST key is a server-side secret — never ship it in a mobile app. Mobile SDKs only use the public App ID.

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

FieldBehavior
segmentOmitted → all subscribed devices. All filters combine with AND. tagFilters ops: eq, ne, gt, lt, exists, not_exists, in.
scheduledAtFuture ISO date → queued until then. Cancel while queued with DELETE /apps/{appId}/notifications/{id}.
contentsPer-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.
contentAvailableSilent push — nothing rendered; only data is delivered (skips the in-app opt-out filter).
Idempotency-Key headerSame 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=14

Counters: 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 tracking

Webhooks

Create webhooks in the panel (App → Settings) or via POST /apps/{appId}/webhooks. Events:

EventFires when
notification.completedA send finishes (with final counters)
device.unsubscribedA 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

errorReasonMeaning
fcm_not_configured / apns_not_configuredCredentials missing for that platform
UNREGISTERED, Unregistered, BadDeviceTokenDead token — the device is auto-deactivated
TopicDisallowedBundle 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.