Skip to content

Repository files navigation

hyperping

PyPI versionPython versionsCIRuffChecked with mypyLicense: MIT

Python SDK for the Hyperping uptime monitoring and incident management API.

Installation

Requires Python 3.11+.

pip install hyperping
# or
uv add hyperping

Quick Start

fromhyperpingimportHyperpingClient, IncidentCreate, LocalizedTextwithHyperpingClient(api_key="sk_...") asclient:
# List all monitorsmonitors=client.list_monitors()
forminmonitors:
print(f"{m.name}: {'down'ifm.downelse'up'}")
# Open an incidentincident=client.create_incident(
IncidentCreate(
title=LocalizedText(en="Service degradation"),
text=LocalizedText(en="Investigating elevated error rates"),
statuspages=["sp_your_uuid"],
)
)
# Resolve itclient.resolve_incident(incident.uuid, "All systems operational")

Async Client

An async-first client is available for use with asyncio and anyio-based frameworks:

fromhyperpingimportAsyncHyperpingClientasyncdefmain():
asyncwithAsyncHyperpingClient(api_key="sk_...") asclient:
monitors=awaitclient.list_monitors()
forminmonitors:
print(f"{m.name}: {'down'ifm.downelse'up'}")
outage=awaitclient.acknowledge_outage("out_uuid", message="On it")

The async client supports all the same resources, retry behaviour, and circuit breaker as the sync client. Use RetryConfig and CircuitBreakerConfig in exactly the same way.

An async MCP client is also available:

fromhyperpingimportAsyncHyperpingMcpClientasyncdefmain():
asyncwithAsyncHyperpingMcpClient(api_key="sk_...") asmcp:
summary=awaitmcp.get_status_summary()
members=awaitmcp.list_team_members()
anomalies=awaitmcp.get_monitor_anomalies("mon_uuid")

Authentication

Pass your API key directly or via environment variable:

importosfromhyperpingimportHyperpingClient# Constructor paramclient=HyperpingClient(api_key="sk_...")
# From environmentclient=HyperpingClient(api_key=os.environ["HYPERPING_API_KEY"])

Resources

Monitors

monitors=client.list_monitors()
monitor=client.get_monitor("mon_uuid")
created=client.create_monitor(MonitorCreate(name="API", url="https://api.example.com"))
client.pause_monitor("mon_uuid")
client.resume_monitor("mon_uuid")
client.delete_monitor("mon_uuid")
# Reportsreports=client.get_all_reports(period="30d")
report=client.get_monitor_report("mon_uuid", period="7d")

Incidents

incidents=client.list_incidents()
incident=client.get_incident("inci_uuid")
created=client.create_incident(IncidentCreate(...))
client.add_incident_update("inci_uuid", AddIncidentUpdateRequest(...))
client.resolve_incident("inci_uuid", "Fixed")
client.delete_incident("inci_uuid")

Maintenance Windows

windows=client.list_maintenance()
window=client.get_maintenance("mw_uuid")
created=client.create_maintenance(MaintenanceCreate(...))
client.update_maintenance("mw_uuid", MaintenanceUpdate(name="New name"))
client.delete_maintenance("mw_uuid")
# Helpersactive=client.get_active_maintenance()
in_maint=client.is_monitor_in_maintenance("mon_uuid")

Outages

outages=client.list_outages() # auto-fetches all pagesoutages=client.list_outages(page=0) # single pageclient.acknowledge_outage("out_uuid", message="On it")
client.resolve_outage("out_uuid", message="Fixed")
client.escalate_outage("out_uuid")

Status Pages

pages=client.list_status_pages(search="prod") # auto-fetches all pagespages=client.list_status_pages(page=0) # single pagepage=client.get_status_page("sp_uuid")
created=client.create_status_page(StatusPageCreate(name="Prod", subdomain="prod-status"))
client.update_status_page("sp_uuid", StatusPageUpdate(name="Production Status"))
client.delete_status_page("sp_uuid")
# Subscriberssubs=client.list_subscribers("sp_uuid") # auto-fetches all pagessub=client.add_subscriber("sp_uuid", "user@example.com")
client.remove_subscriber("sp_uuid", sub.id)

MCP Client (on-call, alerts, anomalies, integrations)

Some Hyperping features are only available via the MCP server (JSON-RPC 2.0), not the REST API. Use HyperpingMcpClient for these:

fromhyperpingimportHyperpingMcpClientwithHyperpingMcpClient(api_key="sk_...") asmcp:
# Status & reportingsummary=mcp.get_status_summary()
mtta=mcp.get_monitor_mtta("mon_uuid")
mttr=mcp.get_monitor_mttr("mon_uuid")
response_time=mcp.get_monitor_response_time("mon_uuid")
# On-call & escalationschedules=mcp.list_on_call_schedules()
policies=mcp.list_escalation_policies()
members=mcp.list_team_members()
# Observabilityanomalies=mcp.get_monitor_anomalies("mon_uuid")
logs=mcp.get_monitor_http_logs("mon_uuid")
alerts=mcp.list_recent_alerts()
# Integrationsintegrations=mcp.list_integrations()
# Outage timeline & monitor searchtimeline=mcp.get_outage_timeline("out_uuid")
results=mcp.search_monitors_by_name("api")

The MCP client uses the same API key as HyperpingClient. All methods return plain dicts/lists; use the exported Pydantic models (e.g., OnCallSchedule, EscalationPolicy) for validation if needed.

MCP rate limits and connection lifecycle

The Hyperping MCP server (https://api.hyperping.io/v1/mcp) is documented by Hyperping as stateless over HTTP and rate-limits per API key. The publicly documented limit is 300 requests per minute shared with the REST API (rate-limit docs), but the server also enforces a separate, undocumented cap on the initialize handshake (observed around 5/minute). Because every new HyperpingMcpClient instance must perform the MCP initialize handshake on its first call, instantiating the client in a hot path or running several short-lived processes against one key will trip this cap.

Operational guidance:

  • Create one HyperpingMcpClient per process and reuse it. Do not instantiate it inside a loop. The first call performs the handshake; subsequent calls reuse it for the life of the client.
  • Catch HyperpingRateLimitError and honour retry_after. Rate-limit signals arrive two ways: as HTTP 429 (with a standard Retry-After header) and as a JSON-RPC server error (code: -32000, HTTP 200) on initialize. Both surface as HyperpingRateLimitError with retry_after parsed from whichever signal was used. The status_code attribute is 429 or 200, matching the underlying signal; cool-off short-circuits preserve the originating status code so callers can disambiguate the two buckets.
  • Use ensure_initialized() for startup health checks. Calling it once on service boot lets you fail fast if the key is already at the initialize cap, instead of failing on the first business call.
  • Several workloads on one key collide on the initialize cap. A weekly cron, a watchdog daemon, and a developer running the CLI cannot all warm up the same API key inside one minute. Use one long-lived process per workload, or separate API keys per workload if your plan allows.
  • After a rate-limit on initialize, the SDK latches a cool-off so that subsequent call_tool invocations on the same client fail fast with HyperpingRateLimitError (no extra HTTP traffic) until retry_after elapses. This prevents accidentally burning more slots from the bucket. The latch is per-HyperpingMcpClient instance and per-process; it does not coordinate across separate Python processes sharing the same API key, so multi-process setups still need the workload-separation advice above.
fromhyperpingimportHyperpingMcpClient, HyperpingRateLimitErrormcp=HyperpingMcpClient(api_key="sk_...")
try:
mcp.ensure_initialized()
exceptHyperpingRateLimitErrorase:
print(f"MCP cold-start rate-limited; retry in {e.retry_after}s")
raisesummary=mcp.get_status_summary()

Healthchecks

checks=client.list_healthchecks()
check=client.get_healthcheck("hc_uuid")
created=client.create_healthcheck(HealthcheckCreate(name="Nightly Job", period=86400, grace=3600))
client.update_healthcheck("hc_uuid", HealthcheckUpdate(grace=7200))
client.pause_healthcheck("hc_uuid")
client.resume_healthcheck("hc_uuid")
client.delete_healthcheck("hc_uuid")

Error Handling

fromhyperpingimport (
HyperpingAPIError,
HyperpingAuthError,
HyperpingNotFoundError,
HyperpingRateLimitError,
HyperpingValidationError,
)
try:
monitor=client.get_monitor("mon_uuid")
exceptHyperpingNotFoundError:
print("Monitor not found")
exceptHyperpingRateLimitErrorase:
print(f"Rate limited. Retry after {e.retry_after}s")
exceptHyperpingAuthError:
print("Invalid API key")
exceptHyperpingAPIErrorase:
print(f"API error [{e.status_code}]: {e.message}")
print(f"Request ID: {e.request_id}")

Retries and Circuit Breaker

The SDK retries automatically on transient errors (5xx, 429) with exponential backoff and jitter. A circuit breaker prevents cascading failures.

fromhyperpingimportHyperpingClientfromhyperping.clientimportRetryConfig, CircuitBreakerConfigclient=HyperpingClient(
api_key="sk_...",
retry_config=RetryConfig(
max_retries=3,
initial_delay=1.0,
max_delay=30.0,
backoff_factor=2.0,
),
circuit_breaker_config=CircuitBreakerConfig(
failure_threshold=5,
recovery_timeout=60.0,
),
)

Per-endpoint circuit breaker

By default a single shared circuit breaker covers every request. If one endpoint flakes, every other endpoint is also blocked. Enable per_endpoint_circuit_breaker=True to keep one breaker per endpoint so a failing endpoint does not punish healthy ones:

client=HyperpingClient(
api_key="sk_...",
per_endpoint_circuit_breaker=True,
)
# Inspect state for an endpoint. The breaker key is canonicalised to the# matching `Endpoint` prefix, so all sub-resource paths share a bucket:fromhyperpingimportCircuitState, Endpointstate=client.circuit_breaker_state_for(str(Endpoint.MONITORS))
# /v1/monitors, /v1/monitors/mon_abc and /v1/monitors/mon_abc/reports all# report the same state — they share the `/v1/monitors` breaker.assertclient.circuit_breaker_state_for(f"{Endpoint.MONITORS}/mon_abc") ==stateassertstatein {CircuitState.CLOSED, CircuitState.HALF_OPEN, CircuitState.OPEN}

If you need different bucketing (e.g. one breaker per resource UUID, or a single breaker per HTTP verb), pass a breaker_key_fn:

defper_resource(path: str) ->str:
# one breaker per literal request pathreturnpath.split("?", 1)[0]
client=HyperpingClient(
api_key="sk_...",
per_endpoint_circuit_breaker=True,
breaker_key_fn=per_resource,
)
OptionTypeDefaultDescription
per_endpoint_circuit_breakerboolFalseWhen True, maintain a separate circuit breaker keyed by request endpoint instead of using one shared breaker. The same circuit_breaker_config applies to every per-endpoint breaker. The shared breaker remains accessible via client.circuit_breaker.
breaker_key_fnCallable[[str], str] | NoneNoneOverride the default endpoint-prefix bucketing. Receives the request path and returns the breaker key. Default behaviour collapses every path under the matching Endpoint prefix so the breaker set stays bounded (one per Endpoint); a custom function takes responsibility for keeping the key set bounded. Ignored unless per_endpoint_circuit_breaker=True.

State for any path is readable via client.circuit_breaker_state_for(path). In the default (single-breaker) mode this returns the shared breaker's state for any path, so the call is always safe regardless of the flag. The same options and method are available on AsyncHyperpingClient.

Type Safety

This package ships a py.typed marker (PEP 561) and is fully typed. Works out of the box with mypy and pyright.

Contributing

See CONTRIBUTING.md.

License

MIT — see LICENSE.

Maintained by

Develeap

About

Python SDK for the Hyperping uptime monitoring and incident management API

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages