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_KEYParameters#
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.
metadataMetadatacontent_stateStreamContentStaterequiredactionLiveActivityActionsecondary_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.
alertAlertPayloadchannelsarray of string- Channel slugs. When omitted, API key scope determines recipients.
- Min Items:
1 targetChannelTargettagsTagSlugs- 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.
successbooleanrequiredoperationstringrequired- Enum:
["started","updated","rotated","noop","paused"] stream_keystringrequiredactivity_idstring or nullprevious_activity_idstringdevices_notifiedintegerdevices_queuedintegerusers_notifiedintegereffective_channel_slugsarray of string or nulltagsTagSlugstimestampstring<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#
errorstringrequiredmessagestringrequired
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"] messagestringrequiredtrial_periodobjecttrial_period.started_atstring<date-time>requiredtrial_period.ends_atstring<date-time>requiredupgrade_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#
errorstringrequiredmessagestringrequired
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#
errorstringrequiredmessagestringrequiredeffective_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}