> ## Documentation Index
> Fetch the complete documentation index at: https://docs.devhelm.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Python SDK

> Install and use the DevHelm Python SDK to manage monitors, incidents, and alerts programmatically

The `devhelm` Python package is a typed, synchronous client for the DevHelm REST API. It's built on `httpx`, ships full Pydantic models for every request and response, and has full mypy strict-mode type coverage.

<Note>
  The Python SDK is **synchronous**. There's no `AsyncDevhelm` client as of v1.3.0 — for concurrent usage, run the sync client in a thread pool (see [async usage](/sdk/python/async-usage)).
</Note>

## Install

```bash theme={null}
pip install devhelm
```

Requires Python 3.11 or later.

## Initialize

```python theme={null}
import os
from devhelm import Devhelm

client = Devhelm(token=os.environ["DEVHELM_API_TOKEN"])
```

| Constructor parameter | Type          | Default                  | Description                                                                                   |
| --------------------- | ------------- | ------------------------ | --------------------------------------------------------------------------------------------- |
| `token`               | `str`         | `""`                     | API token. Falls back to the `DEVHELM_API_TOKEN` env var when empty.                          |
| `base_url`            | `str`         | `https://api.devhelm.io` | API base URL — override for self-hosted.                                                      |
| `org_id`              | `str \| None` | `None`                   | Sets `x-phelm-org-id` header. Falls back to `DEVHELM_ORG_ID` env var, then `"1"`.             |
| `workspace_id`        | `str \| None` | `None`                   | Sets `x-phelm-workspace-id` header. Falls back to `DEVHELM_WORKSPACE_ID` env var, then `"1"`. |
| `timeout`             | `float`       | `30.0`                   | Per-request timeout in seconds.                                                               |

## Create a monitor

The SDK accepts request bodies as plain dicts (validated against the Pydantic request model) or as Pydantic instances. Both produce the same `MonitorDto` response:

```python theme={null}
monitor = client.monitors.create({
    "name": "API Health",
    "type": "HTTP",
    "config": {"url": "https://api.example.com/health", "method": "GET"},
    "frequencySeconds": 60,
    "regions": ["us-east", "eu-west"],
})

print(f"Created monitor: {monitor.id}")
```

`managedBy` is optional — omit it (defaults to `API` server-side) or set it
explicitly to one of `API`, `DASHBOARD`, `CLI`, `TERRAFORM`, or `MCP` to
record the provenance for drift detection.

Or using the typed request class:

```python theme={null}
from devhelm import CreateMonitorRequest

monitor = client.monitors.create(
    CreateMonitorRequest(
        name="API Health",
        type="HTTP",
        config={"url": "https://api.example.com/health", "method": "GET"},
        frequencySeconds=60,
    )
)
```

## List monitors

```python theme={null}
monitors = client.monitors.list()  # auto-paginates through every page

for monitor in monitors:
    print(f"{monitor.name}: {monitor.current_status}")
```

For manual pagination control:

```python theme={null}
page = client.monitors.list_page(page=0, size=50)
print(f"Total: {page.total_elements}")
for monitor in page.data:
    ...
```

## Get check results

```python theme={null}
results = client.monitors.results(monitor.id, limit=10)

for check in results.data:
    status = "OK" if check.passed else "FAIL"
    print(f"{check.region}: {status} ({check.response_time_ms}ms)")
```

`results()` returns a `CursorPage` — call it with `cursor=results.next_cursor` to fetch the next batch.

## Manage incidents

```python theme={null}
incidents = client.incidents.list()  # auto-paginates

for incident in incidents:
    if incident.status == "OPEN":
        print(f"Open: {incident.title}")

client.incidents.resolve(incident.id)
# or with a resolution note:
client.incidents.resolve(incident.id, {"body": "fixed by deploy"})
```

## Create an alert channel

```python theme={null}
channel = client.alert_channels.create({
    "name": "Slack Alerts",
    "config": {
        "channelType": "slack",
        "webhookUrl": os.environ["SLACK_WEBHOOK_URL"],
    },
})
```

The channel type is the `channelType` discriminator **inside** `config` (`slack`, `email`, `discord`, `pagerduty`, …) — there is no top-level `type` field on this request.

## Error handling

```python theme={null}
from devhelm import (
    Devhelm,
    DevhelmApiError,
    DevhelmAuthError,
    DevhelmNotFoundError,
    DevhelmRateLimitError,
)

try:
    client.monitors.get("nonexistent-id")
except DevhelmNotFoundError:
    print("Monitor not found")
except DevhelmRateLimitError as e:
    print(f"Rate limited (request_id={e.request_id}) — back off and retry")
except DevhelmAuthError:
    print("Bad token or insufficient permissions")
except DevhelmApiError as e:
    print(f"{e.status}: {e.message}")
```

Full taxonomy in the [Error handling guide](/sdk/python/error-handling).

## Next steps

<CardGroup cols={2}>
  <Card title="Client reference" icon="book" href="/sdk/python/client-reference">
    Every resource and method available on the client.
  </Card>

  <Card title="Concurrency patterns" icon="layer-group" href="/sdk/python/async-usage">
    Run the sync client concurrently with thread pools and asyncio.
  </Card>
</CardGroup>
