API · Notifications
Create, query, cancel and test sends; templates.
Base: https://api.pushtifly.com. Every response uses { errCode, errMsg, data, meta }. Authentication and keys · Error catalog
GET/v1/notifications
List of sends (notifications:read)
Key: sk_
Parameters
| Name | In | Type | Description |
|---|---|---|---|
appId | query | string | |
status | query | string | |
source | query | "api" | "panel" | "campaign" | "recurring" | |
page | query | integer | |
perPage | query | integer |
Responses: 200
curl -X GET "https://api.pushtifly.com/v1/notifications" \
-H "Authorization: Bearer sk_test_YOUR_SECRET_KEY"POST/v1/notifications
Create a send (sk_ with notifications:send). It is queued and responds 202.
Key: sk_
Targets: devices {ids|tokens}, external_users {ids}, topic {name}, all, test_devices. With a test-mode key
the send only reaches test devices. segment/filters, media and schedule other than now arrive in Phase 4.
validateOnly=true validates and estimates without creating. Errors: 2001/2002 validation, 2003 payload > 4 KB, 2004 platform,
2011 scheduling, 4005 Idempotency-Key reused with a different body. 2002 with errors.content = [blocked]: the
content links to a domain or URL blocked by the platform.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
Idempotency-Key | header | string | Repeating the same key (24 h) returns the original notification without duplicating it |
Body
| Field | Type | Description |
|---|---|---|
contentType | "alert" | "data_only" | "silent" | |
content | object | Per language, e.g. { en: { title, subtitle, body } } |
variables | object | They replace {{name}} in the text |
data | object | |
deepLink | string | max. 500 characters |
badge | integer | |
sound | string | default or a sound registered in the app (2002 if it doesn't exist) |
ttlSeconds | integer | 0–2419200 |
priority | "high" | "normal" | |
android | object | |
android.channelId | string | |
android.collapseKey | string | |
android.color | string | |
android.tag | string | |
android.icon | string | |
ios | object | |
ios.interruptionLevel | "passive" | "active" | "time-sensitive" | "critical" | |
ios.threadId | string | |
ios.collapseId | string | |
ios.relevanceScore | number | |
ios.mutableContent | boolean | |
appId | string | |
target* | object | |
target.type* | "devices" | "external_users" | "topic" | "segment" | "filters" | "all" | "test_devices" | |
target.segmentId | string | |
target.rules | object | AND/OR tree (maximum 3 levels, 20 conditions). Fields: platform, language, country, timezone, external_user_id, app_version, last_seen, tag (with key), topic, notifications_enabled, capability. |
target.ids | string[] | |
target.tokens | string[] | |
target.name | string | |
platforms | "android" | "ios" | "web"[] | |
category | "transactional" | "marketing" | |
schedule | object | now; at {sendAt, timezone}: fixed time (no offset = in timezone; defaults to the company's); local_time {date, time}: that time in each device's zone (~26 h). Maximum 365 days. Errors 2011 / 2012. |
schedule.type | "now" | "at" | "local_time" | |
schedule.sendAt | string | |
schedule.timezone | string | |
schedule.date | string | |
schedule.time | string | |
schedule.windowMinutes | integer | Gradual delivery · 0–1440 |
schedule.expireAt | string | Don't send after this (also caps the TTL) |
validateOnly | boolean | |
templateId | string | Template: what you send in the request takes priority; its variables are required (2001) |
media | object | Only the URL travels in the payload. Android: large image (or GIF/video poster); iOS: mutable-content + _ph.media for the extension. A file still processing is only accepted in scheduled sends (4009 if immediate). Carousel: type carousel with items (2 to 5 images); without an SDK that draws it, the first one is shown. |
media.type | "image" | "gif" | "audio" | "video" | "carousel" | |
media.mediaId | string | |
media.url | string | External https (requires type) |
media.fallback | "poster" | "none" | |
media.items | object[] | Only with type carousel: 2 to 5 images (mediaId or https url), with optional title (text or per language, up to 40 characters) and link · max. 5 items |
largeIcon | object | Image (Android, via SDK) |
largeIcon.mediaId | string | |
largeIcon.url | string | |
actions | object[] | max. 3 items |
Responses: 200202422
curl -X POST "https://api.pushtifly.com/v1/notifications" \
-H "Authorization: Bearer sk_test_YOUR_SECRET_KEY" \
-H "Idempotency-Key: order-123" \
-H "Content-Type: application/json" \
-d '{
"appId": "YOUR_APP_ID",
"target": {
"type": "external_users",
"ids": [
"customer-123"
]
},
"content": {
"en": {
"title": "Your order is on its way",
"body": "Arriving today between 2 and 4 p.m."
},
"es": {
"title": "Tu pedido va en camino",
"body": "Llega hoy entre 2 y 4 p. m."
}
},
"data": {
"orderId": "A-1029"
},
"deepLink": "myapp://orders/A-1029",
"category": "transactional"
}'POST/v1/notifications/test
Synchronous test console (up to 10 targets; doesn't use quota; daily limit 3006)
Key: sk_
Returns per target result, interpretation and suggestion (in Spanish), provider_response (HTTP status, code, body, latency) and the request without the full token. Mode validate_only only for FCM.
Body
| Field | Type | Description |
|---|---|---|
contentType | "alert" | "data_only" | "silent" | |
content | object | Per language, e.g. { en: { title, subtitle, body } } |
variables | object | They replace {{name}} in the text |
data | object | |
deepLink | string | max. 500 characters |
badge | integer | |
sound | string | |
ttlSeconds | integer | 0–2419200 |
priority | "high" | "normal" | |
android | object | |
android.channelId | string | |
android.collapseKey | string | |
android.color | string | |
android.tag | string | |
android.icon | string | |
ios | object | |
ios.interruptionLevel | "passive" | "active" | "time-sensitive" | "critical" | |
ios.threadId | string | |
ios.collapseId | string | |
ios.relevanceScore | number | |
ios.mutableContent | boolean | |
appId | string | |
useTestDevices | boolean | |
targets | object[] | max. 10 items |
mode | "send" | "validate_only" | |
environment | "auto" | "sandbox" | "production" | |
rawPayload | object | Final hand-written payload that replaces the generated one: fcm = FCM v1 message (without token), apns = APNs body (must include aps). Pushtifly adds the token and the APNs headers. Maximum 4 KB; error 2002 if it isn't valid. |
rawPayload.fcm | object | |
rawPayload.apns | object |
Responses: 200429
curl -X POST "https://api.pushtifly.com/v1/notifications/test" \
-H "Authorization: Bearer sk_test_YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"appId": "YOUR_APP_ID",
"targets": [
{
"token": "DEVICE_TOKEN"
}
],
"content": {
"en": {
"title": "Test",
"body": "Hello from the test console"
}
},
"mode": "send"
}'GET/v1/notifications/{id}
Status and counters of a send
Key: sk_
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id* | path | string |
Responses: 200404
curl -X GET "https://api.pushtifly.com/v1/notifications/ID_ID" \
-H "Authorization: Bearer sk_test_YOUR_SECRET_KEY"PATCH/v1/notifications/{id}
Edit a scheduled send: full body, or only {schedule} to reschedule (4009 if it already went out)
Key: sk_
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id* | path | string |
Responses: 200
curl -X PATCH "https://api.pushtifly.com/v1/notifications/ID_ID" \
-H "Authorization: Bearer sk_test_YOUR_SECRET_KEY"GET/v1/notifications/{id}/deliveries
Deliveries per device
Key: sk_
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id* | path | string | |
status | query | "queued" | "accepted" | "failed" | "invalid_token" | "expired" | "skipped" | |
page | query | integer | |
perPage | query | integer |
Responses: 200
curl -X GET "https://api.pushtifly.com/v1/notifications/ID_ID/deliveries" \
-H "Authorization: Bearer sk_test_YOUR_SECRET_KEY"POST/v1/notifications/{id}/cancel
Cancel (only while still queued; otherwise 4004)
Key: sk_
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id* | path | string |
Responses: 200409
curl -X POST "https://api.pushtifly.com/v1/notifications/ID_ID/cancel" \
-H "Authorization: Bearer sk_test_YOUR_SECRET_KEY"POST/v1/notifications/{id}/send-now
Send a scheduled notification now (4009 if it isn't scheduled)
Key: sk_
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id* | path | string |
Responses: 200
curl -X POST "https://api.pushtifly.com/v1/notifications/ID_ID/send-now" \
-H "Authorization: Bearer sk_test_YOUR_SECRET_KEY"GET/v1/templates
App templates (send with templateId + variables; notifications:read)
Key: sk_
Parameters
| Name | In | Type | Description |
|---|---|---|---|
appId | query | string |
Responses: 200
curl -X GET "https://api.pushtifly.com/v1/templates" \
-H "Authorization: Bearer sk_test_YOUR_SECRET_KEY"