Skip to main content

Openstatus Python SDK

PyPI Python versions License: MIT

Official Python SDK for Openstatus — the open-source status page and uptime monitoring platform.

Status: pre-alpha. APIs may change without notice until v1.0.

Table of contents

Features

  • Sync and async clients — OpenstatusClient and AsyncOpenstatusClient, both backed by httpx.
  • Typed messages — request and response types are generated from the upstream protobuf schema, with .pyi stubs for editor and pyright support.
  • All services covered — Health, Monitor, StatusReport, StatusPage, Maintenance, and Notification.
  • JSON over HTTP — uses Connect-RPC's JSON mode; no binary protobuf required at runtime.
  • Predictable errors — Connect-style error envelopes are mapped to a typed exception hierarchy.

Installation

pip install openstatus
# or
uv add openstatus

Requires Python 3.10 or newer.

Quick start

from openstatus import OpenstatusClient
from openstatus._gen.openstatus.monitor.v1.assertions_pb2 import (
    NumberComparator,
    StatusCodeAssertion,
)
from openstatus._gen.openstatus.monitor.v1.http_monitor_pb2 import (
    HTTPMethod,
    HTTPMonitor,
)
from openstatus._gen.openstatus.monitor.v1.monitor_pb2 import Periodicity, Region
from openstatus._gen.openstatus.monitor.v1.service_pb2 import (
    CreateHTTPMonitorRequest,
    ListMonitorsRequest,
)

with OpenstatusClient() as client:
    created = client.monitor.v1.MonitorService.create_http_monitor(
        CreateHTTPMonitorRequest(
            monitor=HTTPMonitor(
                name="My API",
                url="https://api.example.com/health",
                method=HTTPMethod.HTTP_METHOD_GET,
                periodicity=Periodicity.PERIODICITY_1M,
                regions=[Region.REGION_FLY_AMS, Region.REGION_FLY_IAD],
                active=True,
                status_code_assertions=[
                    StatusCodeAssertion(
                        comparator=NumberComparator.NUMBER_COMPARATOR_EQUAL,
                        target=200,
                    )
                ],
            )
        )
    )
    print(f"Created monitor id={created.monitor.id}")

    monitors = client.monitor.v1.MonitorService.list_monitors(ListMonitorsRequest())
    print(f"Total monitors: {monitors.total_size}")

Authentication

The SDK reads OPENSTATUS_API_KEY from the environment by default:

export OPENSTATUS_API_KEY="..."

Or pass it explicitly:

from openstatus import ClientOptions, OpenstatusClient

client = OpenstatusClient(ClientOptions(api_key="..."))

Override the base URL with OPENSTATUS_API_URL or ClientOptions(base_url=...). The default is https://api.openstatus.dev.

Sync and async

Both clients expose the same nested namespace path (client.<service>.v1.<ServiceName>.<method>):

from openstatus import OpenstatusClient
from openstatus._gen.openstatus.health.v1.health_pb2 import CheckRequest

with OpenstatusClient() as client:
    health = client.health.v1.HealthService.check(CheckRequest())
import asyncio
from openstatus import AsyncOpenstatusClient
from openstatus._gen.openstatus.health.v1.health_pb2 import CheckRequest

async def main() -> None:
    async with AsyncOpenstatusClient() as client:
        health = await client.health.v1.HealthService.check(CheckRequest())
        print(health.status)

asyncio.run(main())

Custom HTTP client

Supply your own httpx.Client to control timeouts, transports, proxies, or TLS configuration:

import httpx
from openstatus import ClientOptions, OpenstatusClient

http = httpx.Client(
    timeout=httpx.Timeout(connect=2.0, read=10.0, write=10.0, pool=10.0),
    transport=httpx.HTTPTransport(retries=3),
)
client = OpenstatusClient(ClientOptions(http_client=http))

When you pass a client in, the SDK does not close it; manage its lifetime yourself.

Services

Each method takes a typed protobuf request and returns a typed protobuf response. Pass per-call headers via the keyword-only headers= argument.

Health

from openstatus._gen.openstatus.health.v1.health_pb2 import CheckRequest

health = client.health.v1.HealthService.check(CheckRequest())

Monitor

from openstatus._gen.openstatus.monitor.v1.service_pb2 import (
    GetMonitorRequest,
    ListMonitorsRequest,
    TriggerMonitorRequest,
)

client.monitor.v1.MonitorService.list_monitors(ListMonitorsRequest())
client.monitor.v1.MonitorService.get_monitor(GetMonitorRequest(id="abc"))
client.monitor.v1.MonitorService.trigger_monitor(TriggerMonitorRequest(id="abc"))

Status report

from openstatus._gen.openstatus.status_report.v1.service_pb2 import ListStatusReportsRequest

client.status_report.v1.StatusReportService.list_status_reports(ListStatusReportsRequest())

Status page

from openstatus._gen.openstatus.status_page.v1.service_pb2 import ListStatusPagesRequest

client.status_page.v1.StatusPageService.list_status_pages(ListStatusPagesRequest())

Maintenance

from openstatus._gen.openstatus.maintenance.v1.service_pb2 import ListMaintenancesRequest

client.maintenance.v1.MaintenanceService.list_maintenances(ListMaintenancesRequest())

Notification

from openstatus._gen.openstatus.notification.v1.service_pb2 import ListNotificationsRequest

client.notification.v1.NotificationService.list_notifications(ListNotificationsRequest())

Reference

Regions

Region constants live in openstatus._gen.openstatus.monitor.v1.monitor_pb2 as Region. Use the descriptor API to enumerate them:

from openstatus._gen.openstatus.monitor.v1.monitor_pb2 import Region

print(list(Region.keys()))  # ["REGION_UNSPECIFIED", "REGION_FLY_AMS", ...]
print(Region.Name(1))       # "REGION_FLY_AMS"
print(Region.Value("REGION_FLY_AMS"))

Enums

Common enums:

  • HTTPMethod (openstatus.monitor.v1.http_monitor_pb2) — request method for HTTP monitors.
  • Periodicity (openstatus.monitor.v1.monitor_pb2) — check frequency.
  • MonitorStatus, Region (openstatus.monitor.v1.monitor_pb2).
  • NumberComparator, StringComparator, RecordComparator (openstatus.monitor.v1.assertions_pb2) — assertion operators.
  • HTTPResponseLogRequestStatus, HTTPResponseLogTrigger, TimeRange (openstatus.monitor.v1.service_pb2).

Error handling

All transport errors derive from OpenstatusError:

from openstatus import (
    AuthenticationError,
    NotFoundError,
    OpenstatusClient,
    OpenstatusError,
)
from openstatus._gen.openstatus.monitor.v1.service_pb2 import GetMonitorRequest

with OpenstatusClient() as client:
    try:
        client.monitor.v1.MonitorService.get_monitor(GetMonitorRequest(id="missing"))
    except NotFoundError as err:
        print("monitor not found:", err.connect_code, err.http_status)
    except AuthenticationError:
        print("check OPENSTATUS_API_KEY")
    except OpenstatusError as err:
        print("openstatus failed:", err.connect_code, err.details)

Each exception carries connect_code, http_status, details, and raw_body attributes for inspection.

Connect code Exception
unauthenticated AuthenticationError
not_found NotFoundError
invalid_argument InvalidArgumentError
permission_denied PermissionDeniedError
resource_exhausted RateLimitError
unavailable ServiceUnavailableError
anything else OpenstatusError

When the server response is not a Connect error envelope (e.g. a 502 HTML body from a proxy), ServiceUnavailableError is raised with the raw body preserved on .raw_body.

Recipes

FastAPI

from fastapi import Depends, FastAPI
from openstatus import OpenstatusClient

app = FastAPI()
_client = OpenstatusClient()

def get_client() -> OpenstatusClient:
    return _client

@app.on_event("shutdown")
def shutdown() -> None:
    _client.close()

@app.get("/monitors")
def monitors(client: OpenstatusClient = Depends(get_client)):
    from openstatus._gen.openstatus.monitor.v1.service_pb2 import ListMonitorsRequest
    res = client.monitor.v1.MonitorService.list_monitors(ListMonitorsRequest())
    return {"total": res.total_size}

Django

# myapp/openstatus.py
from django.conf import settings
from openstatus import ClientOptions, OpenstatusClient

_singleton: OpenstatusClient | None = None

def client() -> OpenstatusClient:
    global _singleton
    if _singleton is None:
        _singleton = OpenstatusClient(ClientOptions(api_key=settings.OPENSTATUS_API_KEY))
    return _singleton

Migration from the Node SDK

  • Method names: MonitorService.listMonitors(...) → MonitorService.list_monitors(...).
  • Message field access: monitor.fooBar → monitor.foo_bar.
  • Enum lookups: Region[value] (Node) → Region.Name(value) (Python).
  • Headers per call: pass as keyword argument headers={...}.
  • Authentication: same OPENSTATUS_API_KEY env var and ClientOptions(api_key=...) parameter.

Development

uv sync
uv run pytest tests/unit
uv run pyright
uv run ruff check .

Integration tests against the live API:

OPENSTATUS_API_KEY=... uv run pytest tests/integration

Regenerating the protobuf message classes:

bash scripts/regen.sh

See CONTRIBUTING.md for details.

For the design rationale (why JSON over HTTP, why a pinned Buf archive, why sync+async from day one), see docs/decisions.md.

License

MIT — see LICENSE.

Metadata

Release files for openstatus 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for openstatus 0.1.0
File Size Uploaded
openstatus-0.1.0.tar.gz 92.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for openstatus 0.1.0
File Interpreter ABI Platform
openstatus-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 224.5 kB

Release files / openstatus-0.1.0.tar.gz

Download URL openstatus-0.1.0.tar.gz
Size 92.5 kB
Tags Source
SHA-256 checksum
How to use checksums
84cfc6c8efa3a0713c0f2b168e0558a5a4e1d3efb1ee8db45c1b5581e89e105b
BLAKE2b-256 checksum
How to use checksums
03524e632260ed22177fc72402ccf82157fb726a6ea4338b0fea17c601ee40c0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 29, 2026.

Transparency log

Release files / openstatus-0.1.0-py3-none-any.whl

Download URL openstatus-0.1.0-py3-none-any.whl
Size 132.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e3de81ef0c9507d982f846464b6f47474e692133699bc303a354b6267342182c
BLAKE2b-256 checksum
How to use checksums
5370a9c10d1509f192a39725aad4cefe15da5e64dbb97cf5cbea23a37c90bd5d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 29, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page