# Track work

Keep one task’s current stage visible as work progresses. iOS uses ActivityKit on capable builds; native Android uses an ordinary ongoing progress notification through the same API.

HTML: https://notify.belweave.ai/docs/activity-api

## Begin a task

| Route | Purpose |
| --- | --- |
| `POST /hooks/:token/live-activities` | Start an activity. Returns 201. |
| `GET /hooks/:token/live-activities/:id` | Read the current state. |
| `PATCH /hooks/:token/live-activities/:id` | Apply a partial update. |
| `POST /hooks/:token/live-activities/:id/end` | Settle and dismiss the activity. |

Start one activity for a task that has several meaningful stages. `title` identifies the task and `status` describes its current stage; both are required. Here a warehouse pickup begins preparation.

```bash
curl -X POST https://notify.belweave.ai/hooks/whk_your_token/live-activities \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: pickup-42-start' \
  -d '{
    "title": "Pickup PKG-42",
    "status": "Preparing",
    "subtitle": "Pick and pack",
    "detail": "Warehouse team is gathering the parcel",
    "progress": 0,
    "symbol": "build",
    "accentColor": "#FF9F0A"
  }'
```

```json
{
  "ok": true,
  "activityId": "act_example_pickup",
  "sequence": 0,
  "status": "active",
  "accepted": 1,
  "failed": 0,
  "state": { "title": "Pickup PKG-42", "status": "Preparing", "progress": 0, "symbol": "build" },
  "expiresAt": "2026-10-12T02:04:11.000Z",
  "staleAt": "2026-10-11T22:04:11.000Z",
  "endedAt": null
}
```

Save `activityId` for subsequent writes. Alternatively, set a start `key` and use that alias in the URL. Start, update, and end accept service-scoped `Idempotency-Key` headers: a matching replay returns `idempotent: true`; a changed payload with the same key returns `409`.

> On iOS, a capable Notify build must register a push-to-start token. Native Android uses an ordinary ongoing progress notification through FCM on these same routes. A `201` with `accepted: 0` and a `message` means no eligible target accepted the start. Neither provider acceptance nor a successful response proves that a card is visible.

## Report the next stage

Update the existing task with `PATCH` instead of starting another one for each stage. Omitted fields keep their current values, and a committed update increments `sequence`. Include at least one changed field besides `ifSequence`.

```bash
curl -X PATCH https://notify.belweave.ai/hooks/whk_your_token/live-activities/act_example_pickup \
  -H 'Content-Type: application/json' \
  -d '{ "status": "Packing", "progress": 0.6, "accentColor": "#64D2FF" }'
```

- Clear an optional `subtitle`, `detail`, or `progress` value by sending `null`.
- For concurrent writers, send the last observed `ifSequence`. `409 Sequence conflict` includes the current state so the writer can reconcile.
- An ended or expired activity rejects updates with `409 Live Activity is already terminal`.

## Finish the task

```bash
curl -X POST https://notify.belweave.ai/hooks/whk_your_token/live-activities/act_example_pickup/end \
  -H 'Content-Type: application/json' \
  -d '{ "status": "Collected", "progress": 1, "symbol": "success" }'
```

End the activity when the pickup completes or stops. You may omit the body. On iOS, `dismissAfterSeconds` sets the finished card’s remaining visibility: 0–14,400 seconds, default 0.

An iOS start reports its update token asynchronously. A provider-accepted start remains `starting` until registration. Fresh starts share a durable 60-second interval per device across all agents, services, and interactive prompts; additional starts return `queued`. This precaution does not guarantee display. Updates and ends also queue while a token is missing. When delivery becomes possible, only the newest contiguous routine progress snapshot is sent; starts, interaction changes, and endings are preserved. `superseded` counts skipped snapshots without claiming delivery. End marks the logical activity ended immediately. Recovery runs every 15 seconds and work expires at its original deadline. `accepted`, `failed`, `queued`, and `superseded` are disjoint operation outcomes. Transient rejection stays queued. None of these counts alone confirms device display.

> The end route supplies `status: "Complete"` and `symbol: "success"` when omitted, replacing the previous values. Set them explicitly for a different final message.

## Track from a terminal

The CLI can start, update, inspect, and end the same activity lifecycle without a webhook. Use the returned ID or a start `--key`; select an iOS progress layout with `--style`. The example uses one key for a warehouse preparation task.

```bash
notify activity start --key pickup --replace --style ring \
  --title "Pickup PKG-42" --status "Preparing" --progress 0.1

notify activity update pickup --status "Packing" --progress 0.6 --if-sequence 0

notify activity end pickup --status "Collected" --progress 1 --dismiss-after 45s
```

- `--replace` deliberately ends activities occupying the target slot or key before starting this one.
- `--if-sequence` applies the write only at the expected sequence; reconcile a conflict before retrying.
- Progress styles are `standard`, `ring`, `hero`, `terminal`, and `steps`. An update can change the style.
- Inspect one activity with `activity get <id|key>`, or recent activity records with `activity list`.
