Templates
A template is a notification you will send more than once: the per-locale copy, the data payload, the presentation options, TTL, collapse id, priority and the silent flag. Unlike a campaign draft it is held to the strict content schema — a template exists to be sent, so it must be sendable the moment it is saved.
{
"name": "order-shipped",
"content": {
"en": { "title": "Your order is on its way", "body": "Order #{{orderId}} ships today.", "url": "acme://orders/{{orderId}}" },
"tr": { "title": "Siparişin yola çıktı", "body": "#{{orderId}} bugün kargoda.", "url": "acme://orders/{{orderId}}" },
"_default": "en"
},
"presentation": { "channelId": "orders", "interruptionLevel": "active" },
"collapseId": "order-{{orderId}}",
"ttl": 86400
}
Placeholders work as everywhere else — the worker fills them per subscriber at send time, so one template serves every order.
Where they come from
- The wizard — Save as template on the content step stores the current copy, data, presentation, TTL and collapse id. Load from template pulls one in; the campaign then carries its own copy, and the badge on the step says where it came from.
- Templates in the dashboard lists them with locale count, use count and last update; rename, describe, delete, or start a campaign from one (Campaign).
- The API —
POST /v1/templatesand friends, with a secret key.
Sending with one
curl -X POST https://push.example.com/v1/notifications \
-H "Authorization: Bearer sk_live_…" -H "content-type: application/json" \
-d '{ "target": { "externalIds": ["user_123"] }, "templateId": "66f1…", "ttl": 3600 }'
POST /v1/campaigns takes templateId the same way. Precedence is request field → template field → default: the call above keeps the template's copy and channel but overrides its TTL. The campaign row remembers templateId and bumps the template's useCount, but it holds its own copy of everything — editing the template afterwards changes future sends, not this one.
A silent template (silent: true) needs no content; a call with neither content, templateId nor silent: true is 422.
Names
Names are unique per app (409 duplicate_name). The name is the campaign's default name when sending from the API.