Payload Reference
Use this as the single source of truth for the /notify request body.
Authentication (required)
Send your secret as a Bearer token on every request:
POST /notifyAuthorization: Bearer <uniqueID>Content-Type: application/jsonComplete JSON example
{ "job_id": "deploy-prod", "title": "Production Deploy", "message": "Running migrations...", "status": "running", "action": "update", "layout": "progress", "theme": "default", "metric": "Step 2/5", "progress": 0.4, "secondaryMetric": "LIVE", "metricA": "3", "metricB": "1", "subA": "HOME", "subB": "AWAY", "icon": "bolt.fill", "accentColor": "#00CFFF"}Field reference
| Field | Type | Required | Allowed / format | Default | Availability | Since (app) | Notes |
|---|---|---|---|---|---|---|---|
job_id | string | Yes | 1-64 chars, A-Z a-z 0-9 _ - | none | All tiers | 1.0 | Routing key only; not displayed as title. |
title | string | No | non-empty text recommended | derived from message or "Island Pulse" | All tiers | 1.0 | Display title in Live Activity UI. |
message | string | Yes* | non-empty string | none | All tiers | 1.0 | Primary body text. Required for start/update; not required for end. |
status | string | No | running | success | failed | running | All tiers | 1.0 | Visual status state. |
action | string | No | start | update | end | auto-selected | All tiers | 1.0 | Omit for normal auto-routing behavior. |
layout | string | No | default | progress | score | sports | default | Pro for non-default | 1.0 | Free requests are normalized to default. |
theme | string | No | implementation-defined | default | App feature dependent | 1.0 | Optional visual theme hint. |
metric | string | No | short text | none | All tiers | 1.0 | KPI/auxiliary metric. |
progress | number | No | 0.0-1.0 (or 0-100) | none | All tiers | 1.0 | Values above 1 are normalized as percentages. |
secondaryMetric | string | No | short text | none | All tiers | 1.0 | Secondary badge/label text. |
metricA | string | No | short text | none | All tiers | 1.0 | Sports/dual metric left value. |
metricB | string | No | short text | none | All tiers | 1.0 | Sports/dual metric right value. |
subA | string | No | short text | none | All tiers | 1.0 | Sports/dual metric left sublabel. |
subB | string | No | short text | none | All tiers | 1.0 | Sports/dual metric right sublabel. |
icon | string | No | SF Symbol name | layout default | All tiers | 1.0 | Per-push icon override. |
accentColor | string | No | CSS color or hex | app/theme default | All tiers | 1.0 | Per-push accent override. |
Since (app) is the first iOS app version that understands the field. The service accepts a field as soon as it is deployed, but an installed app only shows what it knows how to render, and unknown fields are ignored. Where each field appears (Lock Screen, compact island, expanded island) is listed in Layouts and changes between app versions; see the Changelog.
Tier behavior notes
- Free tier allows one active
job_idat a time per token. - Free tier uses
defaultlayout only; non-defaultlayoutvalues are coerced todefault. - Sending a different active
job_idon free returns403 FREE_TIER_JOB_LOCKED(TIER_LIMIT_EXCEEDEDsupport code). - Sending
startfor ajob_idthat is already running returns409 ACTIVITY_ALREADY_RUNNING(all tiers). Send updates instead, or end the activity first. - Pro tier supports multiple concurrent job streams (up to iOS system limits).
Versions and compatibility
- Payload fields are additive. A new field never changes the meaning of an existing one, and apps that don’t know a field ignore it.
- Every update replaces the whole state, so send
layoutand all of its fields on every update, not only the first. - Send
metricalongside a layout’s own fields (for example the batting score next tometricAon a sports update). Apps older than 1.3 show onlymetricin the compact island, so it works as a fallback.
Common errors
| HTTP | Error | Meaning |
|---|---|---|
| 400 | MISSING_UNIQUE_ID | Missing or invalid Bearer token. |
| 400 | MISSING_JOB_ID | job_id missing or empty. |
| 400 | INVALID_JOB_ID | job_id format invalid. |
| 400 | INVALID_ACTION | action is not start/update/end. |
| 403 | FREE_TIER_JOB_LOCKED | Free tier: a different job_id is already active. End it first. |
| 409 | ACTIVITY_ALREADY_RUNNING | A Live Activity for this job_id is already running. Send updates or end it before starting again. |
| 502 | APNS_PUSH_FAILED | APNs rejected delivery. |
| 502 | APNS_RECOVERY_FAILED | Update token was dead and start recovery failed too. |