Live Activities EndpointsView Markdown ↗

Live Activity Stream

Start a new Live Activity or update an existing one

Use a stable stream_key for each ongoing thing you want to show as a Live Activity. Send the latest content_state whenever it changes, and ActivitySmith will keep the Live Activity in sync. For timer streams, send duration_seconds to start or reset the timer; omit duration_seconds on later updates to preserve the existing timer window. Use secondary_action for a second button on alert, progress, segmented_progress, and value Live Activities. Optional tags to organize and filter notification history. On later stream updates, omit tags to keep the current tags, send tags again to replace them, or send an empty array to clear them.

PUT https://activitysmith.com/api/live-activity/stream/{stream_key}

Authentication#

Use your API key in the request header.

Authorization: Bearer $YOUR_API_KEY

Parameters#

stream_key#

path parameter. Required.

Stable identifier for one ongoing thing. Allowed characters: letters, numbers, underscores, and hyphens.

Type: string

Max Length: 255; Pattern: ^[A-Za-z0-9_-]+$

Request examples#

import ActivitySmith from "activitysmith";
const activitysmith = new ActivitySmith({
apiKey: process.env.ACTIVITYSMITH_API_KEY,
});
await activitysmith.liveActivities.stream("search-reindex", {
content_state: {
title: "Search Reindex",
subtitle: "catalog-v2",
type: "progress",
percentage: 42,
},
});

Bodyapplication/json

Send the latest state for a managed Live Activity stream. channels is the streamlined form for stream targeting. target.channels is also accepted for compatibility. If both are provided, they must match.

metadataMetadata
content_stateStreamContentStaterequired
actionLiveActivityAction
secondary_actionLiveActivityAction
Optional secondary action button. Supported for alert, progress, segmented_progress, and value Live Activities. Uses the same open_url, shortcuts://, and webhook shapes as action.
alertAlertPayload
channelsarray of string
Channel slugs. When omitted, API key scope determines recipients.
Min Items: 1
targetChannelTarget
tagsTagSlugs
Optional tags to organize and filter notification history. Omit this field on later updates to keep the current tags, send tags again to replace them, or send an empty array to clear them.

Additional Properties: false

metrics

{
"content_state": {
"title": "Server Health",
"subtitle": "prod-web-1",
"type": "metrics",
"metrics": [
{
"label": "CPU",
"value": 27,
"unit": "%"
},
{
"label": "MEM",
"value": 64,
"unit": "%"
}
]
}
}

channel targeted

{
"channels": [
"ops"
],
"content_state": {
"title": "Server Health",
"subtitle": "prod-web-1",
"type": "metrics",
"metrics": [
{
"label": "CPU",
"value": 27,
"unit": "%"
},
{
"label": "MEM",
"value": 64,
"unit": "%"
}
]
}
}

timer

{
"content_state": {
"title": "Benchmark Run",
"subtitle": "sampling",
"type": "timer",
"duration_seconds": 300,
"color": "cyan"
}
}

approval secondary actions

{
"content_state": {
"title": "Approval Needed",
"message": "Should I send the follow-up email to Brightlane?",
"type": "alert",
"color": "cyan"
},
"action": {
"title": "Send",
"type": "webhook",
"url": "https://example.com/hooks/approvals/send",
"method": "POST",
"body": {
"approval_id": "appr_123"
}
},
"secondary_action": {
"title": "Deny",
"type": "webhook",
"url": "https://example.com/hooks/approvals/deny",
"method": "POST",
"body": {
"approval_id": "appr_123"
}
}
}

Organize notification history with tags

{
"content_state": {
"title": "Search Reindex",
"subtitle": "catalog-v2",
"type": "progress",
"percentage": 42
},
"tags": [
"user:382",
"search-reindex"
]
}

Responses#

200#

Stream reconciled

Content type: application/json

Schema: LiveActivityStreamPutResponse#

Returned after a managed stream request is reconciled.

successbooleanrequired
operationstringrequired
Enum: ["started","updated","rotated","noop","paused"]
stream_keystringrequired
activity_idstring or null
previous_activity_idstring
devices_notifiedinteger
devices_queuedinteger
users_notifiedinteger
effective_channel_slugsarray of string or null
tagsTagSlugs
timestampstring<date-time>required

Additional Properties: false

started

{
"success": true,
"operation": "started",
"stream_key": "prod-web-1",
"activity_id": "h8QmSyYFTuwOIF6Wh3YcZlzHLhUcr034",
"devices_notified": 2,
"timestamp": "2025-08-12T12:00:00.000Z"
}

noop

{
"success": true,
"operation": "noop",
"stream_key": "prod-web-1",
"activity_id": "h8QmSyYFTuwOIF6Wh3YcZlzHLhUcr034",
"timestamp": "2025-08-12T12:05:00.000Z"
}

paused

{
"success": true,
"operation": "paused",
"stream_key": "prod-web-1",
"activity_id": null,
"timestamp": "2025-08-12T12:10:00.000Z"
}

tagged

{
"success": true,
"operation": "started",
"stream_key": "search-reindex",
"activity_id": "h8QmSyYFTuwOIF6Wh3YcZlzHLhUcr034",
"devices_notified": 2,
"tags": [
"user:382",
"search-reindex"
],
"timestamp": "2025-08-12T12:00:00.000Z"
}

400#

Bad request (invalid stream_key, payload, action, or channel targeting input)

Content type: application/json

Schema: BadRequestError#

errorstringrequired
messagestringrequired

Additional Properties: true

invalid stream key

{
"error": "Invalid stream_key",
"message": "stream_key must contain only letters, numbers, underscores, and hyphens"
}

invalid target

{
"error": "Invalid channel targeting",
"message": "channels must contain at least one channel"
}

invalid tags

{
"error": "Invalid tags",
"code": "invalid_tags",
"message": "tags must contain at most 20 unique values"
}

402#

Trial expired, trial allowance exhausted, or paid usage cap reached

Content type: application/json

Schema: BillingBlockedError#

errorstringrequired
Enum: ["trial_expired","trial_exhausted","billing_overage_cap_reached"]
messagestringrequired
trial_periodobject
trial_period.started_atstring<date-time>required
trial_period.ends_atstring<date-time>required
upgrade_urlstring<uri>required

Additional Properties: true

trial expired

{
"error": "trial_expired",
"message": "Your free trial has ended. Start a subscription or lifetime membership to resume using ActivitySmith.",
"trial_period": {
"started_at": "2026-09-01T00:00:00.000Z",
"ends_at": "2026-09-08T00:00:00.000Z"
},
"upgrade_url": "https://activitysmith.com/app/account?billing=upgrade"
}

403#

Forbidden (API key scope or channel assignment violation)

Content type: application/json

Schema: ForbiddenError#

errorstringrequired
messagestringrequired

Additional Properties: true

channel scope violation

{
"error": "Invalid channel targeting",
"message": "This API key can only target assigned channels. Requested channels include channels outside this key scope."
}

422#

No recipients found for effective channel target

Content type: application/json

Schema: NoRecipientsError#

errorstringrequired
messagestringrequired
effective_channel_slugsarray of string or null

Additional Properties: true

no devices

{
"error": "No recipients found",
"message": "No Live Activity devices matched the effective channel target",
"effective_channel_slugs": [
"ops"
]
}

429#

Rate limit exceeded

Content type: application/json

oneOf

Schema: RateLimitError

Schema: LiveActivityLimitError

rate limited

{
"error": "Rate limit exceeded",
"message": "Too many requests, please try again later."
}

concurrent live activity limit reached

{
"error": "Live Activity limit reached",
"message": "iOS supports up to 5 concurrent Live Activities per app on a device. End an active Live Activity before starting another.",
"limit": 5,
"active": 5
}

Download the OpenAPI specification