Metadata-Version: 2.4
Name: activitysmith
Version: 1.3.0
Summary: Official ActivitySmith Python SDK
Author-email: ActivitySmith <adam@activitysmith.com>
License: MIT
Project-URL: homepage, https://activitysmith.com
Project-URL: documentation, https://activitysmith.com/docs
Project-URL: source, https://github.com/ActivitySmithHQ/activitysmith-python
Project-URL: issues, https://github.com/ActivitySmithHQ/activitysmith-python/issues
Keywords: activitysmith,live activities,push notifications,api,sdk
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: urllib3>=1.25.3
Requires-Dist: python-dateutil>=2.8.2
Requires-Dist: pydantic>=2
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: ruff>=0.5; extra == "dev"
Dynamic: license-file

# ActivitySmith Python Library

The ActivitySmith Python library provides convenient access to the ActivitySmith API from Python applications.

## Documentation

See the [API reference](https://activitysmith.com/docs/api-reference/introduction).

## Table of Contents

- [Installation](#installation)
- [Setup](#setup)
- [Push Notifications](#push-notifications)
  - [Send a Push Notification](#send-a-push-notification)
  - [Rich Push Notifications with Media](#rich-push-notifications-with-media)
  - [Actionable Push Notifications](#actionable-push-notifications)
- [Live Activities](#live-activities)
  - [Simple: Let ActivitySmith manage the Live Activity for you](#simple-let-activitysmith-manage-the-live-activity-for-you)
  - [Advanced: Full lifecycle control](#advanced-full-lifecycle-control)
  - [Stats Type](#stats-type)
  - [Metrics Type](#metrics-type)
  - [Segmented Progress Type](#segmented-progress-type)
  - [Progress Type](#progress-type)
  - [Live Activity Action](#live-activity-action)
- [Channels](#channels)
- [Widgets](#widgets)

## Installation

This package is available on PyPI:

```sh
pip install activitysmith
```

Alternatively, install from source with:

```sh
python -m pip install .
```

## Setup

```python
import os
from activitysmith import ActivitySmith

activitysmith = ActivitySmith(
    api_key=os.environ["ACTIVITYSMITH_API_KEY"],
)
```

## Push Notifications

### Send a Push Notification

  Push notification example

```python
activitysmith.notifications.send(
    {
        "title": "New subscription 💸",
        "message": "Customer upgraded to Pro plan",
    }
)
```

### Rich Push Notifications with Media

  Rich push notification with image

```python
activitysmith.notifications.send(
    {
        "title": "Homepage ready",
        "message": "Your agent finished the redesign.",
        "media": "https://cdn.example.com/output/homepage-v2.png",
        "redirection": "https://github.com/acme/web/pull/482",
    }
)
```

Send images, videos, or audio with your push notifications, press and hold to preview media directly from the notification, then tap through to open the linked content.

  Rich push notification with audio

What will work:

- direct image URL: `.jpg`, `.png`, `.gif`, etc.
- direct audio file URL: `.mp3`, `.m4a`, etc.
- direct video file URL: `.mp4`, `.mov`, etc.
- URL that responds with a proper media `Content-Type`, even if the path has no extension

### Actionable Push Notifications

  Actionable push notification example

Actionable push notifications can open a URL on tap or trigger actions when someone long-presses the notification.
Webhooks are executed by the ActivitySmith backend.

```python
activitysmith.notifications.send(
    {
        "title": "New subscription 💸",
        "message": "Customer upgraded to Pro plan",
        "redirection": "https://crm.example.com/customers/cus_9f3a1d",  # Optional
        "actions": [  # Optional (max 4)
            {
                "title": "Open CRM Profile",
                "type": "open_url",
                "url": "https://crm.example.com/customers/cus_9f3a1d",
            },
            {
                "title": "Start Onboarding Workflow",
                "type": "webhook",
                "url": "https://hooks.example.com/activitysmith/onboarding/start",
                "method": "POST",
                "body": {
                    "customer_id": "cus_9f3a1d",
                    "plan": "pro",
                },
            },
        ],
    }
)
```

## Live Activities

  Metrics Live Activity screenshot

There are four types of Live Activities:

- `stats`: best for compact business or product stats like revenue, orders, conversion, and average order value
- `metrics`: best for live operational stats like server CPU and memory, queue depth, or replica lag
- `segmented_progress`: best for step-based workflows like deployments, backups, and ETL pipelines
- `progress`: best for continuous jobs like uploads, reindexes, and long-running migrations tracked as a percentage

When working with Live Activities via our API, you have two approaches tailored
to different needs. First, the stateless mode is the simplest path - one API
call can initiate or update an activity, and another ends it - no state
tracking on your side.

This is ideal if you want minimal complexity, perfect for automated workflows
like cron jobs.

In contrast, if you need precise lifecycle control, the classic approach offers
distinct calls for start, updates, and end, giving you full control over the
activity's state.

In the following sections, we'll break down how to implement each method so you
can choose what fits your use case best.

### Simple: Let ActivitySmith manage the Live Activity for you

Use a stable `stream_key` to identify the system or workflow you are tracking,
such as a server, deployment, build pipeline, cron job, or charging session.
This is especially useful for cron jobs and other scheduled tasks where you do
not want to store `activity_id` between runs.

#### Stats

  Stats stream example

```python
status = activitysmith.live_activities.stream(
    "sales-hourly",
    {
        "content_state": {
            "title": "Sales",
            "subtitle": "last hour",
            "type": "stats",
            "metrics": [
                {"label": "Revenue", "value": "$2430", "color": "blue"},
                {"label": "Orders", "value": "37", "color": "green"},
                {"label": "Conversion", "value": "4.8%", "color": "magenta"},
                {"label": "Avg Order", "value": "$65.68", "color": "yellow"},
                {"label": "Refunds", "value": "$84", "color": "red"},
                {"label": "New Buyers", "value": "18", "color": "cyan"},
            ],
        },
    },
)
```

#### Metrics

  Metrics stream example

```python
status = activitysmith.live_activities.stream(
    "prod-web-1",
    {
        "content_state": {
            "title": "Server Health",
            "subtitle": "prod-web-1",
            "type": "metrics",
            "metrics": [
                {"label": "CPU", "value": 9, "unit": "%"},
                {"label": "MEM", "value": 45, "unit": "%"},
            ],
        },
    },
)
```

#### Segmented progress

  Segmented progress stream example

```python
activitysmith.live_activities.stream(
    "nightly-backup",
    {
        "content_state": {
            "title": "Nightly Backup",
            "subtitle": "upload archive",
            "type": "segmented_progress",
            "number_of_steps": 3,
            "current_step": 2,
        },
    },
)
```

#### Progress

  Progress stream example

```python
activitysmith.live_activities.stream(
    "search-reindex",
    {
        "content_state": {
            "title": "Search Reindex",
            "subtitle": "catalog-v2",
            "type": "progress",
            "percentage": 42,
        },
    },
)
```

Call `stream(...)` again with the same `stream_key` whenever the state changes.

#### End a stream

Use this when the tracked process is finished and you no longer want the Live
Activity on devices. `content_state` is optional here; include it if you want
to end the stream with a final state.

```python
activitysmith.live_activities.end_stream(
    "prod-web-1",
    {
        "content_state": {
            "title": "Server Health",
            "subtitle": "prod-web-1",
            "type": "metrics",
            "metrics": [
                {"label": "CPU", "value": 7, "unit": "%"},
                {"label": "MEM", "value": 38, "unit": "%"},
            ],
        },
    },
)
```

If you later send another `stream(...)` request with the same `stream_key`,
ActivitySmith starts a new Live Activity for that stream again.

Stream responses include an `operation` field:

- `started`: ActivitySmith started a new Live Activity for this `stream_key`
- `updated`: ActivitySmith updated the current Live Activity
- `rotated`: ActivitySmith ended the previous Live Activity and started a new one
- `noop`: the incoming state matched the current state, so no update was sent
- `paused`: the stream is paused, so no Live Activity was started or updated
- `ended`: returned by `end_stream(...)` after the stream is ended

### Advanced: Full lifecycle control

Use these methods when you want to manage the Live Activity lifecycle yourself:

1. Call `activitysmith.live_activities.start(...)`.
2. Save the returned `activity_id`.
3. Call `activitysmith.live_activities.update(...)` as progress changes.
4. Call `activitysmith.live_activities.end(...)` when the work is finished.

### Stats Type

Keep your key numbers on your Lock Screen. `stats` fits 1 to 8 labeled values,
such as revenue, orders, conversion, uptime, or any other business metric you
want visible at a glance. Each metric can use a formatted string or number as
its `value`. Add `color` to a metric to show an accent dot next to its label;
omit `color` to show the label without a dot.

#### Start

  Stats Live Activity with sales revenue, orders, conversion, and average order value

```python
start = activitysmith.live_activities.start(
    {
        "content_state": {
            "title": "Sales",
            "subtitle": "last hour",
            "type": "stats",
            "metrics": [
                {"label": "Revenue", "value": "$2430", "color": "blue"},
                {"label": "Orders", "value": "37", "color": "green"},
                {"label": "Conversion", "value": "4.8%", "color": "magenta"},
                {"label": "Avg Order", "value": "$65.68", "color": "yellow"},
                {"label": "Refunds", "value": "$84", "color": "red"},
                {"label": "New Buyers", "value": "18", "color": "cyan"},
            ],
        },
    }
)

activity_id = start.activity_id
```

#### Update

```python
activitysmith.live_activities.update(
    {
        "activity_id": activity_id,
        "content_state": {
            "title": "Sales",
            "subtitle": "last hour",
            "type": "stats",
            "metrics": [
                {"label": "Revenue", "value": "$3180", "color": "blue"},
                {"label": "Orders", "value": "51", "color": "green"},
                {"label": "Conversion", "value": "5.2%", "color": "magenta"},
                {"label": "Avg Order", "value": "$62.35", "color": "yellow"},
                {"label": "Refunds", "value": "$126", "color": "red"},
                {"label": "New Buyers", "value": "24", "color": "cyan"},
            ],
        },
    }
)
```

#### End

```python
activitysmith.live_activities.end(
    {
        "activity_id": activity_id,
        "content_state": {
            "title": "Sales",
            "subtitle": "last hour",
            "type": "stats",
            "metrics": [
                {"label": "Revenue", "value": "$3460", "color": "blue"},
                {"label": "Orders", "value": "58", "color": "green"},
                {"label": "Conversion", "value": "5.4%", "color": "magenta"},
                {"label": "Avg Order", "value": "$59.66", "color": "yellow"},
                {"label": "Refunds", "value": "$92", "color": "red"},
                {"label": "New Buyers", "value": "31", "color": "cyan"},
            ],
            "auto_dismiss_minutes": 2,
        },
    }
)
```

### Metrics Type

Use `metrics` when you want to keep a small set of live stats visible, such as
server health, queue pressure, or database load.

#### Start

  Metrics start example

```python
start = activitysmith.live_activities.start(
    {
        "content_state": {
            "title": "Server Health",
            "subtitle": "prod-web-1",
            "type": "metrics",
            "metrics": [
                {"label": "CPU", "value": 9, "unit": "%"},
                {"label": "MEM", "value": 45, "unit": "%"},
            ],
        },
    }
)

activity_id = start.activity_id
```

#### Update

  Metrics update example

```python
activitysmith.live_activities.update(
    {
        "activity_id": activity_id,
        "content_state": {
            "title": "Server Health",
            "subtitle": "prod-web-1",
            "type": "metrics",
            "metrics": [
                {"label": "CPU", "value": 76, "unit": "%"},
                {"label": "MEM", "value": 52, "unit": "%"},
            ],
        },
    }
)
```

#### End

  Metrics end example

```python
activitysmith.live_activities.end(
    {
        "activity_id": activity_id,
        "content_state": {
            "title": "Server Health",
            "subtitle": "prod-web-1",
            "type": "metrics",
            "metrics": [
                {"label": "CPU", "value": 7, "unit": "%"},
                {"label": "MEM", "value": 38, "unit": "%"},
            ],
            "auto_dismiss_minutes": 2,
        },
    }
)
```

### Segmented Progress Type

Use `segmented_progress` for jobs and workflows that move through clear steps or
phases. It fits jobs like backups, deployments, ETL pipelines, and checklists.
`number_of_steps` is dynamic, so you can increase or decrease it later if the
workflow changes.

#### Start

  Segmented progress start example

```python
start = activitysmith.live_activities.start(
    {
        "content_state": {
            "title": "Nightly database backup",
            "subtitle": "create snapshot",
            "number_of_steps": 3,
            "current_step": 1,
            "type": "segmented_progress",
            "color": "yellow",
        },
    }
)

activity_id = start.activity_id
```

#### Update

  Segmented progress update example

```python
activitysmith.live_activities.update(
    {
        "activity_id": activity_id,
        "content_state": {
            "title": "Nightly database backup",
            "subtitle": "upload archive",
            "number_of_steps": 3,
            "current_step": 2,
        },
    }
)
```

#### End

  Segmented progress end example

```python
activitysmith.live_activities.end(
    {
        "activity_id": activity_id,
        "content_state": {
            "title": "Nightly database backup",
            "subtitle": "verify restore",
            "number_of_steps": 3,
            "current_step": 3,
            "auto_dismiss_minutes": 2,
        },
    }
)
```

### Progress Type

Use `progress` when the state is naturally continuous. It fits charging,
downloads, sync jobs, uploads, timers, and any flow where a percentage or
numeric range is the clearest signal.

#### Start

  Progress start example

```python
start = activitysmith.live_activities.start(
    {
        "content_state": {
            "title": "EV Charging",
            "subtitle": "Added 30 mi range",
            "type": "progress",
            "percentage": 15,
        }
    }
)

activity_id = start.activity_id
```

#### Update

  Progress update example

```python
activitysmith.live_activities.update(
    {
        "activity_id": activity_id,
        "content_state": {
            "title": "EV Charging",
            "subtitle": "Added 120 mi range",
            "percentage": 60,
        }
    }
)
```

#### End

  Progress end example

```python
activitysmith.live_activities.end(
    {
        "activity_id": activity_id,
        "content_state": {
            "title": "EV Charging",
            "subtitle": "Added 200 mi range",
            "percentage": 100,
            "auto_dismiss_minutes": 2,
        }
    }
)
```

### Live Activity Action

Just like Actionable Push Notifications, Live Activities can have a button that opens provided URL in a browser or triggers a webhook. Webhooks are executed by the ActivitySmith backend.

  Metrics Live Activity with action

#### Open URL action

```python
start = activitysmith.live_activities.start(
    {
        "content_state": {
            "title": "Server Health",
            "subtitle": "prod-web-1",
            "type": "metrics",
            "metrics": [
                {"label": "CPU", "value": 76, "unit": "%"},
                {"label": "MEM", "value": 52, "unit": "%"},
            ],
        },
        "action": {
            "title": "Open Dashboard",
            "type": "open_url",
            "url": "https://ops.example.com/servers/prod-web-1",
        },
    }
)

activity_id = start.activity_id
```

#### Webhook action

  Live Activity with action

```python
activitysmith.live_activities.update(
    {
        "activity_id": activity_id,
        "content_state": {
            "title": "Reindexing product search",
            "subtitle": "Shard 7 of 12",
            "number_of_steps": 12,
            "current_step": 7,
        },
        "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-python",
            },
        },
    }
)
```

## Channels

Channels are used to target specific team members or devices. Can be used for both push notifications and live activities.

```python
activitysmith.notifications.send(
    {
        "title": "New subscription 💸",
        "message": "Customer upgraded to Pro plan",
        "channels": ["sales", "customer-success"],  # Optional
    }
)
```

## Widgets

  Lock screen widgets

ActivitySmith lets you display any value on your Lock Screen with widgets - SaaS metrics, revenue, signups, uptime, habits, or anything else you want to track. Create a metric in the web app (https://activitysmith.com/app/widgets), then update the metric value using our API, add a widget to your lock screen and it will fetch the latest update automatically.

  Create widget metric

```python
activitysmith.metrics.update("deploy.success_rate", 99.9)
```

String metric values work too.

```python
activitysmith.metrics.update("prod.status", "healthy")
```

## Error Handling

```python
try:
    activitysmith.notifications.send(
        {
            "title": "New subscription 💸",
        }
    )
except Exception as err:
    print("Request failed:", err)
```

Request/response models are included and can be imported from `activitysmith_openapi.models`.

## Requirements

- Python 3.9 or newer

## License

MIT
