Live notification payload reference
PremiumThis feature is available for Premium plans. EnterpriseThis feature is available for Enterprise plans. UpdatedWhen you start or update a live notification through the API, you send two objects: attributes and content_state. Customer.io wraps them in the right platform payload and delivers them to the device. This page documents both layers: what you send and what arrives.
Attributes and content state
Every live notification splits its data into two parts, mirroring Apple’s ActivityKit model on both platforms:
| Object | Send | Contains |
|---|---|---|
attributes | On start | Static fields used to create the activity. They don’t change after start. These are things like an order number, a flight’s origin and destination, or the teams in a match. |
content_state | Required on start. For Android, include them again on update or end when the renderer needs those static fields; iOS uses them only at start. | The complete dynamic state the device should render—the current status, score, or ETA. Updates replace the previous state rather than patching it. |
Two conventions apply everywhere:
- Dates and timestamps are epoch seconds, not milliseconds. Use the Unix format.
- Each update carries the full content state. The device re-renders from the complete state on every push. There are no partial updates.
Built-in templates
You can use these built-in templates to send live notifications to both iOS and Android platforms. Or you can use them as starting points for your own custom templates.
You send static fields in attributes and dynamic fields in content_state; each template below shows a complete example, followed by the schema for both objects. Fields the templates render verbatim (header, title, status, substatus) are freeform text. The supported fields are the ones in each template’s schema below—the bundled templates don’t expose generic status-color, image, or logo fields.
Countdown timer
Use this template to create a countdown timer. You call this template with the notification type identifier io.customer.livenotifications.countdowntimer.
{
"attributes": {
"header": "Summer Sale"
},
"content_state": {
"title": "Flash sale ends in",
"statusMessage": "30% off everything",
"endTime": 1753603600
}
}
Attributes
- header stringRequired Top-row label of the notification.
Content state
- endTime integerCountdown target, in whole seconds since 1970 UTC. A time in the future renders a live countdown; omit it to render no timer. The countdown does not clear itself when it reaches zero — it rests at "0:00" until you send an update with a finished title and no endTime.
- statusMessage stringSecondary line under the title.
- title stringRequired Primary status line.
Multi-step tracker
Use this template to create a delivery process tracker or any tracker with steps. You call this template with the notification type identifier io.customer.livenotifications.segments.
{
"attributes": {
"header": "Chica's Tacos"
},
"content_state": {
"status": "Preparing your order",
"substatus": "We'll let you know when it's on the way",
"segmentsTotal": 4,
"segmentsComplete": 2,
"trailingText": "25 min"
}
}
Attributes
- header stringRequired Top-row label
Content state
- segmentsComplete integerRequired How many segments are filled; the remainder render as incomplete. Values above segmentsTotal are capped at segmentsTotal.
- segmentsTotal integerRequired The total number of segments in the progress bar. Values above 20 are capped at 20.
- status stringRequired Primary status line, like
Out for delivery. - substatus stringSecondary line under the status.
- trailingText stringShort text on the Dynamic Island trailing edge, e.g. "5 min". Keep it brief; the trailing region is narrow.
What Customer.io sends to iOS (APNs)
Customer.io delivers iOS live notifications as APNs pushes with the liveactivity push type at top priority. A start event looks like this:
{
"aps": {
"timestamp": 1721000000,
"event": "start",
"attributes-type": "DeliveryActivityAttributes",
"attributes": {
"orderNumber": "CIO-1234",
"cioInstanceId": "01J4YQZC3GJ0S6RY4E5NW6H9AB"
},
"content-state": {
"title": "Order received",
"progress": { "current": 1, "total": 4 },
"cioMetadata": {
"deliveryId": "RPILAgUBcRhIBqSfeiIwdIYYKxTuwqSjjqQ=",
"deliveryToken": "AbCdEfg...",
"deepLink": "yourapp://orders/1234"
}
},
"alert": {
"title": "Your order is on its way",
"body": "Track it live on your Lock Screen"
}
}
}
eventisstart,update, orend.attributes-typeandattributesappear only on start events—attributes are immutable after the activity is created. Customer.io injectscioInstanceIdso the SDK can correlate the activity.content-stateis your content state plus an injectedcioMetadataobject carrying the delivery ID, delivery token, and deep link. DeclarecioMetadataon yourContentStatetype (the SDK’sCIOMetadataCarryingprotocol) to get tap-through deep links and delivery attribution.alertcomes from thepush_payload.alertyou pass to the API. An iOS start requirespush_payload.alert. Updates and ends can be silent, whether Customer.io delivers directly through APNs or relays through Firebase. If you include an alert on an update or end, provide both itstitleandbody.
iOS apps that deliver push through Firebase
push_payload.alert on the start; updates and ends can be silent on either delivery path.What Customer.io sends to Android (FCM)
Android live notifications arrive as FCM data messages—there’s no notification block, so the SDK renders them even when your app is in the background:
{
"data": {
"cioInstanceId": "01J4YQZC3GJ0S6RY4E5NW6H9AB",
"event": "update",
"notification_type": "io.customer.livenotifications.segments",
"timestamp": "1721000000",
"link": "yourapp://orders/1234",
"payload": "{\"header\":\"Order\",\"status\":\"Out for delivery\",\"segmentsTotal\":4,\"segmentsComplete\":3}"
}
}
cioInstanceIdidentifies the activity; updates with the same ID replace the notification in place.notification_typeselects the template (or your custom renderer).payloadis a JSON string of your mergedattributesandcontent_state.
