Skip to content

Wiring

Island Pulse uses a single JSON field, job_id, to decide whether an incoming webhook should start a new Live Activity or update an existing one. Getting this right is the key to a clean integration.

The job key

Every POST to /notify should include job_id when you need more than one concurrent job, or when you want a stable label for that run.

  • Format: 164 characters. Allowed characters: letters (A–Z, a–z), digits (0–9), underscore (_), and hyphen (-) only. No spaces or other symbols.
  • Omit job_id to use the implicit key default, which is fine when you only ever have one activity at a time.

Two POSTs with the same job_id target the same Live Activity. Two POSTs with different job_id values produce independent activities. Invalid job_id values return 400 INVALID_JOB_ID with an error message (no silent fallback to alternate field names).

Start → update → end lifecycle

You don’t need to manage state yourself. Island Pulse tracks whether a Live Activity is already running for a given job key:

  • No activity running → Island Pulse starts a new Live Activity on your phone.
  • Activity already running → Island Pulse updates it in place.
  • action: "end" → Island Pulse dismisses the activity.

In practice this means you can send the exact same payload structure throughout a job’s lifetime, Island Pulse handles the routing automatically.

Terminal window
# Step 1, first POST: no activity running, Island Pulse starts one
curl -X POST "YOUR_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{"job_id": "nightly-build", "message": "Build started", "status": "running"}'
# Step 2, subsequent POSTs: activity is running, Island Pulse updates it in place
curl -X POST "YOUR_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{"job_id": "nightly-build", "message": "Running tests…", "status": "running", "progress": 0.4}'
# Step 3, finish the job
curl -X POST "YOUR_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{"job_id": "nightly-build", "message": "All 142 tests passed", "status": "success"}'

Naming conventions

Use short, stable IDs such as github-deploy, api-health, or daily-report. The same string is shown as the task label on the Live Activity card.

PatternExample job_id
CI pipelinegithub-deploy, gitlab-staging
Uptime monitorapi-health, db-health
Cron jobdaily-report, invoice-sync
Metric pulsemrr-today, signups-today

Multiple concurrent jobs (Pro)

Free tier is limited to one concurrent Live Activity. If you POST a start for a second job while the first is still running, the request is rejected with a 403 TIER_LIMIT_EXCEEDED error.

Pro tier removes this limit (up to the iOS system cap of 5 simultaneous Live Activities per app). Run as many independent job_id values as you need, each one is tracked and updated separately.

Terminal window
# Pro: three independent jobs running at the same time
curl -X POST "YOUR_WEBHOOK_URL" -d '{"job_id": "deploy-prod", ...}'
curl -X POST "YOUR_WEBHOOK_URL" -d '{"job_id": "db-backup", ...}'
curl -X POST "YOUR_WEBHOOK_URL" -d '{"job_id": "report-gen", ...}'

Activity session length

Live Activities are capped by iOS at 8 hours. Pro users get automatic session renewal, if a session expires, the next update seamlessly starts a fresh one. Free users’ activities expire after 8 hours without renewal.

On the Free tier, if a session expires and a new activity runs into the concurrent limit, you’ll get a TIER_LIMIT_EXCEEDED error until the first activity is dismissed.

Custom notification title

When a new activity starts, iOS briefly shows a notification banner. By default, the banner title is your job_id string. You can override it with alertTitle:

{
"job_id": "deploy-prod",
"alertTitle": "Vercel Deploy",
"message": "Build queued",
"status": "running"
}

alertTitle only applies on the initial start push. Update pushes are silent by design.