Push notification categories
A notification category is a per-tenant template you reference by identifier on a send — it carries an optional custom sound and up to 10 interactive action buttons so every send that names it expands to the same curated shape. Define the category once (dashboard or API), then pass itsidentifier as notification_channel on POST /api/v1/push/send.
This is a tenant-owned control: you curate which categories exist, and the send path expands them per request. Nothing here gates delivery — a send that names an unknown identifier proceeds with a plain, non-interactive notification.
1. Why curate categories
Push delivery fails or under-performs in predictable ways, and category hints address the content side:- Interactive actions ship uniformly. Instead of passing per-platform overrides on every send, you name one identifier and the send path expands its stored iOS actions, Android tap action, and sound.
- APNs payload rules are enforced at curation time. Identifiers are validated as
UPPER_SNAKE_CASE(max 64 chars), action titles are capped at 128 chars, and a category carries at most 10 actions — the constraints APNs enforces are caught when you author the category, not when APNs rejects a mis-shaped payload with a per-devicefailedresult. - Identifiers are wire-bound. The iOS / Android client registers and matches on the identifier string, so categories are immutable after create — delete and recreate to change one. This keeps in-flight pushes referencing the shape the client cached.
error strings like BadDeviceToken, suppression, and frequency-cap skips), see the push end-to-end guide.
2. Manage categories in the dashboard
Open Messages → Push → Manage push notifications → Notification Categories (/messages/push/manage/notification-categories). The page lists the categories defined for your tenant and sits beside the Scheduled pushes, Device Tokens, and Live Activities satellites.
The page is guarded for owner, admin, and developer roles — the same role set the other push management pages require.
3. Category shape
Each category record holds:
The API mirrors the shape exactly:
GET /api/v1/push/categories (newest first, capped at 200 rows — also the per-tenant creation limit), GET /api/v1/push/categories/:id, and DELETE /api/v1/push/categories/:id (empty 204). Identifier reuse is the supported update pattern: delete, then recreate — a conflicting identifier returns 409 PUSH_CATEGORY_IDENTIFIER_CONFLICT.
4. Apply a category on send
Pass the category’sidentifier as notification_channel on POST /api/v1/push/send:
- iOS — the APNs payload carries
category: "INVOICE_REMINDER", plus the category’s customsoundunless the send’s ownios.soundoverride wins. If the send supplies noactionsof its own, the category’s stored actions fill in. - Android — the FCM
click_actionis set to the identifier, and unless you overrideandroid.channel_idexplicitly,notification_channeldoubles as the Android channel id. - Unresolved identifier — the send proceeds as a plain notification; naming an unknown identifier is not a failure.
notifications[] array exactly as without categories: status of sent, failed, or skipped, with a provider error string (for example BadDeviceToken) on failures. Categories annotate delivery shape; the push end-to-end guide covers the failure taxonomy.
5. End-to-end example
- Create the category — with the
PAY_NOW/SNOOZEactions shown above, or through the dashboard’s Notification Categories page. - Send a test push — fire
POST /api/v1/push/test-sendwith"notification_channel": "INVOICE_REMINDER"against your own devices to validate the whole chain without polluting campaign stats. - Verify on device — the iOS device renders the notification with the registered
PAY NOW/SNOOZEbuttons and the custom chime; Android routes the tap throughclick_action: "INVOICE_REMINDER". - Read the result — each device in
notifications[]reportssent; afailedrow on an unregistered device still carries a raw provider error such asBadDeviceTokenfor you to act on.