Skip to main content
ActivitySmith Live ActivitiesActivitySmith Push Notifications

Welcome to ActivitySmith

ActivitySmith is API service that lets you trigger and update Live Activities and send push notifications directly from your own infrastructure. Pair your iOS device(s), authenticate with an API key, and send real-time alerts from any backend, cron, agent, or automation. Without building or maintaining your own iOS app or dealing directly with APNs. Check out the following resources to get started: Want an SDK or Integration? Let us know at adam@activitysmith.com.

Prerequisites

Features

  • Push Notifications: send push notifications to all paired devices or target specific channels.
  • Live Activities: start, update and end a Live Activity on your lock screen or dynamic island, with optional channel targeting and action buttons.
  • Widgets: display any value on your Lock Screen with widgets - SaaS metrics, revenue, signups, uptime, habits, or anything else you want to track.
  • App Icon Badge Count: show the number you care about on your ActivitySmith app icon.
  • Inbound Webhooks: forward events from external services such as Vercel, Netlify, Railway, and more, into Push Notifications and Live Activities.

Powerful Capabilities

  • Glanceable observability: monitor real-time system state and long-running operations directly on your lock screen or dynamic island.
  • The hard stuff: APNs(Apple Push Notification service), certificates, orchestration
  • Customizability: adapt the experience to fit your unique needs.
  • Works with any backend: use with any backend, cron, agent, automation or AI tool.
  • iOS app: ready to use native iOS app for your iPhone or iPad. No need to build your own.

Push Notifications

To send a push notification, use the push-notification endpoint. It takes title and optional fields like message, payload, media, redirection, actions, and target.channels.
target.channels accepts channel slugs (for example ["devs", "ops"]).
  • media attaches an image, audio file, or video that users can preview or play when they expand the notification.
  • redirection opens an HTTPS URL or runs a specific iPhone Shortcut with a shortcuts://run-shortcut?name=... URL on normal tap.
  • actions (up to 4) appear when users expand the notification. open_url actions support HTTPS URLs and shortcuts://run-shortcut?name=... URLs; webhook actions call your backend.
  • media + redirection is supported.
  • media + actions is not supported in v1.
Push Notification
curl -X POST https://activitysmith.com/api/push-notification \
  -H "Authorization: Bearer $ACTIVITYSMITH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "New subscription 💸",
    "message": "Customer upgraded to Pro plan"
  }'
import ActivitySmith from "activitysmith";

const activitysmith = new ActivitySmith({
  apiKey: process.env.ACTIVITYSMITH_API_KEY,
});

await activitysmith.notifications.send({
  title: "New subscription 💸",
  message: "Customer upgraded to Pro plan",
});
import os
from activitysmith import ActivitySmith

activitysmith = ActivitySmith(
    api_key=os.environ.get("ACTIVITYSMITH_API_KEY", "YOUR-API-KEY")
)

activitysmith.notifications.send(
    title="New subscription 💸",
    message="Customer upgraded to Pro plan",
)
package main

import (
	"log"
	"os"

	activitysmithsdk "github.com/ActivitySmithHQ/activitysmith-go"
)

func main() {
	activitysmith, err := activitysmithsdk.New(os.Getenv("ACTIVITYSMITH_API_KEY"))
	if err != nil {
		log.Fatal(err)
	}

	input := activitysmithsdk.PushNotificationInput{
		Title:   "New subscription 💸",
		Message: "Customer upgraded to Pro plan",
	}

	_, err := activitysmith.Notifications.Send(input)
	if err != nil {
		log.Fatal(err)
	}
}
<?php

use ActivitySmith\ActivitySmith;

$activitysmith = new ActivitySmith($_ENV['ACTIVITYSMITH_API_KEY']);

$activitysmith->notifications->send(
    title: 'New subscription 💸',
    message: 'Customer upgraded to Pro plan',
);
require "activitysmith"

activitysmith = ActivitySmith::Client.new(
  api_key: ENV.fetch("ACTIVITYSMITH_API_KEY", "YOUR-API-KEY")
)

activitysmith.notifications.send(
  {
    title: "New subscription 💸",
    message: "Customer upgraded to Pro plan"
  }
)
activitysmith push \
  --title "New subscription 💸" \
  --message "Customer upgraded to Pro plan"
Response
{
  "success": true,
  "devices_notified": 3,
  "users_notified": 1,
  "timestamp": "2025-08-12T12:00:00.000Z"
}

Live Activities

There are six types of Live Activities:
TypeBest forRequired state
statsup to 8 labeled valuestitle, type, and a non-empty metrics array
metricsLive operational statstitle, type, and a non-empty metrics array
segmented_progressJobs tracked in stepstitle, type, number_of_steps, current_step
progressJobs with continuous progresstitle, type, and either percentage or value + upper_limit
alertFocused status updatestitle, type, and message
timerCountdowns or elapsed runtimetitle, type, and either duration_seconds or counts_down set to false
Stats Live Activity Metrics Live Activity update Progress Live Activity start Segmented Progress Live Activity update Alert Live Activity update Timer Live Activity update

Start & Update Live Activity

Use stream updates to start, update, and dismiss Live Activities with a stable stream_key. Send the latest state for a stable stream_key, and ActivitySmith starts or updates the Live Activity. You do not need to keep local state between updates. When the work is done, call DELETE /live-activity/stream/:stream_key with the same stream_key to dismiss the Live Activity. You can include final values before it is removed. By default, iOS removes the Live Activity after two minutes. Set auto_dismiss_minutes to choose a different dismissal time, including 0 for immediate dismissal.

Action Buttons

Live Activities support an optional action button shown on the Lock Screen. Use it to have a one-tap path from a long-running job to the place where you can act on it. The action field is accepted on stream updates and works with all Live Activity types. alert, progress, and segmented_progress Live Activities also support secondary_action, which adds a second button beside the primary action. Both buttons use the same payload shape. For alert Live Activities, set content_state.color to tint the action and secondary action buttons. icon.color and badge.color only affect the icon and badge.
Metrics Live Activity with an action buttonAlert Live Activity with primary and secondary action buttons
There are two action types:
  • open_url: opens an HTTPS URL or runs a specific iPhone Shortcut with a shortcuts://run-shortcut?name=... URL.
  • webhook: ActivitySmith’s backend calls your HTTPS webhook with GET or POST.
The action and secondary_action objects accept:
FieldRequiredDescription
titleyesButton label shown on the Live Activity.
typeyesEither open_url or webhook.
urlyesFor open_url, use an HTTPS URL or a shortcuts://run-shortcut?name=... URL. For webhook, use an HTTPS endpoint.
methodwebhook onlyGET or POST.
bodywebhook onlyOptional JSON payload sent with the webhook request.

open_url

Use open_url when the button should jump the user to a dashboard or run page tied to the work. You can also use a shortcuts://run-shortcut?name=... URL to run a specific iPhone Shortcut, for example to open an app on your iPhone.
{
  "content_state": {
    "title": "Deploying payments-api",
    "subtitle": "Running database migrations",
    "number_of_steps": 5,
    "current_step": 3,
    "type": "segmented_progress"
  },
  "action": {
    "title": "Open Workflow",
    "type": "open_url",
    "url": "https://github.com/acme/payments-api/actions/runs/1234567890"
  }
}

webhook

Use webhook when the button should trigger an action in your backend, like pausing a job, acknowledging an alert, or canceling a workflow. ActivitySmith calls the URL server-side, so the user does not leave the Lock Screen.
{
  "content_state": {
    "title": "Reindexing product search",
    "subtitle": "Shard 7 of 12",
    "number_of_steps": 12,
    "current_step": 7,
    "type": "segmented_progress"
  },
  "action": {
    "title": "Pause Reindex",
    "type": "webhook",
    "url": "https://ops.example.com/hooks/search/reindex/pause",
    "method": "POST",
    "body": {
      "job_id": "reindex-2026-03-19",
      "requested_by": "activitysmith"
    }
  }
}

secondary_action

Use secondary_action when an alert, progress, or segmented_progress Live Activity needs a second button, for example an approval prompt with “Send” and “Deny” actions.
{
  "content_state": {
    "title": "Approval Needed",
    "message": "Should I send the follow-up email to Brightlane?",
    "type": "alert",
    "color": "green",
    "icon": {
      "symbol": "sparkles",
      "color": "green"
    },
    "badge": {
      "title": "Agent",
      "color": "green"
    }
  },
  "action": {
    "title": "Send",
    "type": "webhook",
    "url": "https://agent.example.com/live-activity/approve",
    "method": "POST",
    "body": {
      "approval_id": "approval_01JY3J7Q9S0P8M1V5PZK7DR4M2",
      "decision": "send"
    }
  },
  "secondary_action": {
    "title": "Deny",
    "type": "webhook",
    "url": "https://agent.example.com/live-activity/deny",
    "method": "POST",
    "body": {
      "approval_id": "approval_01JY3J7Q9S0P8M1V5PZK7DR4M2",
      "decision": "deny"
    }
  }
}
Notes:
  • open_url supports HTTPS URLs and shortcuts://run-shortcut?name=... URLs.
  • webhook URLs must use HTTPS.
  • Use action for the primary button.
  • Use secondary_action for a second button on alert, progress, and segmented_progress Live Activities.
  • Pass action or secondary_action on an update call to set or replace buttons on an active Live Activity.

Channel Targeting

You can use channels to target specific team members or devices when sending a push notification, live activity or app icon badge count update:
{
  "target": {
    "channels": ["devs", "ops"]
  }
}
  • If target is omitted and API key scope is all: send to all account recipients.
  • If target is omitted and API key scope is channels: send to channels assigned to that key.
  • If target.channels is present: only those channel slugs are used.