Activities
Activities are the core resource in PushWard. Each activity represents a trackable item that can be displayed as a Live Activity on subscribed devices.
Each user can have a maximum of 25 activities. Attempting to create more returns 409 with {"error": "activity limit reached (max 25)"}.
Create Activity
/activitiesCreate a new activity. Starts in ENDED state. All user devices are automatically subscribed.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
slug | string | Yes | URL-safe identifier, unique per user |
name | string | Yes | Human-readable display name |
priority | integer | No | Eviction priority 0-10 (default: 0). Higher = kept longer. |
ended_ttl | integer | No | Seconds after ENDED transition before server auto-deletes the activity |
stale_ttl | integer | No | Seconds of inactivity while ONGOING before server auto-ends the activity |
curl -X POST https://api.pushward.app/activities \
-H "Authorization: Bearer hla_YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"slug": "dishwasher",
"name": "Dishwasher",
"priority": 3
}'Response (201):
{
"slug": "dishwasher",
"name": "Dishwasher",
"state": "ENDED",
"priority": 3,
"content": {},
"ended_ttl": null,
"stale_ttl": null,
"delete_at": null,
"created_at": "2025-06-15T10:30:00Z",
"updated_at": "2025-06-15T10:30:00Z"
}List Activities
/activitiesList all activities for the current user, including activities shared with you. Returns an empty array if none exist.
curl https://api.pushward.app/activities \
-H "Authorization: Bearer hla_YOUR_TOKEN"Response (200):
[
{
"slug": "dishwasher",
"name": "Dishwasher",
"state": "ONGOING",
"priority": 3,
"content": {
"template": "generic",
"progress": 0.65,
"state": "Washing",
"icon": "washer",
"remaining_time": 1800,
"subtitle": "Cycle 2 of 3",
"accent_color": "blue"
},
"ended_ttl": null,
"stale_ttl": null,
"delete_at": null,
"created_at": "2025-06-15T10:30:00Z",
"updated_at": "2025-06-15T11:00:00Z"
},
{
"slug": "ci-pipeline",
"name": "CI Pipeline",
"state": "ENDED",
"priority": 0,
"content": {},
"ended_ttl": 3600,
"stale_ttl": null,
"delete_at": "2025-06-15T12:00:00Z",
"created_at": "2025-06-15T10:00:00Z",
"updated_at": "2025-06-15T11:00:00Z"
},
{
"slug": "oven-timer",
"name": "Oven Timer",
"state": "ONGOING",
"priority": 0,
"content": {},
"ended_ttl": null,
"stale_ttl": null,
"delete_at": null,
"created_at": "2025-06-15T09:00:00Z",
"updated_at": "2025-06-15T10:00:00Z",
"is_shared": true,
"share_role": "viewer",
"owner_nickname": "Bob"
}
]Get Activity
/activities/{slug}Get a single activity by slug.
curl https://api.pushward.app/activities/dishwasher \
-H "Authorization: Bearer hla_YOUR_TOKEN"Delete Activity
/activities/{slug}Delete an activity and all associated subscriptions.
curl -X DELETE https://api.pushward.app/activities/dishwasher \
-H "Authorization: Bearer hla_YOUR_TOKEN"Response: 204 No Content
Update Activity (Primary Integration Endpoint)
/activity/{slug}Update an activity's state and content. State transitions automatically trigger push notifications to subscribed devices.
This is the main endpoint for integrations. Note the singular /activity/ path (not /activities/).
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
state | string | Yes | "ONGOING" or "ENDED" |
content | object | Yes | Template content (see Templates) |
priority | integer | No | Update eviction priority (0-10) |
State Transitions
| From | To | Push Action |
|---|---|---|
ENDED | ONGOING | Push-to-start (starts Live Activity) |
ONGOING | ONGOING | Push update (updates running activity) |
ONGOING | ENDED | Push end (dismisses after 4 hours) |
PREEMPTED | ONGOING | Push-to-start (restarts activity) |
ENDED | ENDED | No push (no-op) |
curl -X PATCH https://api.pushward.app/activity/dishwasher \
-H "Authorization: Bearer hla_YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"state": "ONGOING",
"content": {
"template": "generic",
"progress": 0.65,
"state": "Washing",
"icon": "washer",
"remaining_time": 1800,
"subtitle": "Cycle 2 of 3",
"accent_color": "blue"
}
}'Response (200):
The response includes the updated activity object.
{
"slug": "dishwasher",
"name": "Dishwasher",
"state": "ONGOING",
"priority": 3,
"content": {
"template": "generic",
"progress": 0.65,
"state": "Washing",
"icon": "washer",
"remaining_time": 1800,
"subtitle": "Cycle 2 of 3",
"accent_color": "blue"
},
"ended_ttl": null,
"stale_ttl": null,
"delete_at": null,
"created_at": "2025-06-15T10:30:00Z",
"updated_at": "2025-06-15T11:00:00Z"
}Content Object
The content object is shared across all templates. Two fields are always required:
| Field | Type | Description |
|---|---|---|
template | string | Required. One of: generic, countdown, steps, alert, gauge |
progress | float | Required. Value between 0.0 and 1.0 |
See the Templates section for template-specific fields.
Server-Side TTL
Activities support optional server-side time-to-live (TTL) for automatic lifecycle management:
| Field | Set On | Behavior |
|---|---|---|
stale_ttl | Create | If an ONGOING activity receives no updates for this many seconds, the server auto-ends it |
ended_ttl | Create | When an activity transitions to ENDED, the server schedules auto-deletion after this many seconds |
delete_at | Auto | Computed timestamp (read-only). Set automatically from ended_ttl when state becomes ENDED |
When stale_ttl expires, the server auto-ends the activity with a distinct visual state: it sets content.state to "Stale (auto-ended)", accent_color to #8E8E93 (system gray), and icon to clock.badge.xmark. The activity then transitions to ENDED and a push-end notification is sent to all subscribed devices. If ended_ttl is also set, the auto-delete timer starts from that point.
Use ended_ttl to let the server clean up finished activities automatically. Integration bridges typically set this on creation so activities don't accumulate indefinitely.
Error Responses
All errors return a JSON object with an error field:
{
"error": "activity not found"
}| Status | Meaning |
|---|---|
400 | Validation error (missing fields, invalid state, progress out of range) |
401 | Missing or invalid token |
403 | Integration key not allowed for this activity |
404 | Activity not found |
409 | Activity already exists or activity limit reached (on create) |
429 | Rate limit exceeded |