All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Corrective minor release. It renames the bundled console script (breaking) and
retroactively documents breaking changes that shipped mislabeled in 1.8.0/1.8.1
(see Upgrade Notes). If you pinned ~=1.8.0 or ~=1.8.1 you already received
those breaking changes silently; this entry explains them.
- The bundled console script is renamed
hyp→hyperping. 1.8.1 introduced ahypentry point for the SDK's CLI.hypis the long-standing command of the separatehyperping-automationtool; when both are installed the SDK's script silently shadowed it (last-writer-wins onbin/hyp), breaking that tool's commands and exposing the SDK's unguarded write commands under a familiar name. Invoke the SDK CLI ashyperping …now. (Removing/renaming a console script is a breaking change; it is the reason this is 1.9.0, not 1.8.2.)
create_maintenance_windows/create_incidentsnow surface partial failures. If a later chunk fails after earlier objects were created, they raiseHyperpingPartialBatchErrorcarrying the already-created objects (.created,.completed,.total) instead of discarding them, so callers can record or clean up rather than orphaning windows/incidents silently.
create_incidents()(sync + async): splits a broadcast incident's status pages into chunks of at mostMAX_STATUSPAGES_PER_INCIDENT(51), mirroringcreate_maintenance_windows.create_incident()now raisesHyperpingValidationErrorabove the cap instead of silently failing to persist. NOTE: the 51 cap for incidents is assumed identical to maintenance (same status-page attachment path) and has not been independently measured against the live API.HyperpingPartialBatchErrorandMAX_STATUSPAGES_PER_INCIDENTexported from the package root.
These are not new in 1.9.0; they are documented here because 1.8.0/1.8.1 changed them without an upgrade note, which is why consumers were caught out:
- 1.8.0 reconciled the
Integration,EscalationPolicy, andTeamMembermodels against the production API:Integration.activewas removed and the integration-type field key is nowchannel(wastype); a newEscalationStepshape was introduced. Any code readingIntegration.activeor sendingtype=breaks. - 1.8.1 added the
hypconsole script (renamed here) and the status-page / maintenance fixes; it was released as a patch despite the CLI addition.
Guidance: pin hyperping>=1.9.0,<2 and, if you consume the CLI, use hyperping.
list_status_pages()returned an empty list against the live v2 API. TheStatusPagemodel required asubdomainfield, but the API returns the hosted subdomain under the keyhostedsubdomain(and omits it entirely for custom-domain pages). Every record failed validation and was silently skipped.subdomainis now optional and aliased tohostedsubdomain;hostnameandurlare also parsed.
create_maintenance()now guards against the silent status-page overflow. Hyperping's v1 maintenance-windows API accepts a create with more than 51 status pages (returns a uuid) but never persists the window.create_maintenancenow raisesHyperpingValidationErrorwhenstatuspagesexceedsMAX_STATUSPAGES_PER_MAINTENANCE(51), instead of returning a phantom window. Split larger sets across multiple windows.create_maintenance_windows()(sync + async): convenience helper that splits a largestatuspageslist into consecutive windows of at most 51 pages, so callers can cover more pages than one window allows. Each window carries the full monitor set (the API requires at least one monitor per window).MAX_STATUSPAGES_PER_MAINTENANCEis exported for callers that chunk themselves (e.g. a broadcast-to-all-tenants command).
This is a security-focused release. It closes several credential-leak and validation gaps surfaced by an independent audit. One change is breaking for local-development workflows; see Upgrade Notes below.
validate_base_urlis now applied at every constructor that accepts abase_urlormcp_url: both the sync and async REST clients, both MCP transports, and the high-level MCP clients. The validator rejects non-httpsURLs by default, rejects URLs that carry userinfo (user:pass@hostor bareuser@host), and rejects URLs with a query string or fragment. TheAuthorization: Bearerheader therefore cannot reach an attacker-controlled host through a misconfigured base URL.HyperpingAPIError.response_bodyis now recursively redacted at construction time. Sensitive keys (authorization, tokens, cookies, set-cookie, request headers, request body, emails, webhooks) are replaced with[REDACTED]. Free-form string values are scrubbed forBearer <token>andsk_<token>shapes. The recursion is bounded to preventRecursionErrorfrom pathological payloads. Applies to all subclasses, includingHyperpingRateLimitError.HyperpingAPIErrorformatted messages now strip C0 control bytes (preserving\tand\n) and cap at 256 characters, so a server-supplied error string carrying ANSI escapes or a 1 KB blob cannot poison terminal output or downstream log pipelines.- The MCP transport no longer captures the first 500 bytes of server response as
response_body["raw"]on rate-limit (429), generic HTTP error, or JSON-parse failure paths. Subscriber emails or webhook URLs that the server may echo cannot leak through that channel. _utils.parse_listno longer logs the fullpydantic.ValidationErrorstring on per-item parse failures (Pydantic v2 includes the offending input by default). It now logs only the exception class and field locations.- The
breaker_key_fncallback is now used through an LRU-bounded map. A custom callback that returns unbounded unique strings can no longer leak memory in long-running processes: the per-endpoint breaker map is capped at 1024 entries and evicts oldest on overflow. Applies to both sync and async clients.
allow_insecure: bool = Falsekeyword argument on every constructor that accepts abase_urlormcp_url. When set toTrue,http://URLs are permitted and anInsecureTransportWarningis emitted. Provided for local-development workflows; not recommended for production.InsecureTransportWarningwarning class exported fromhyperping.
_parse_retry_afterdocuments that it intentionally supports only the delta-seconds form of theRetry-Afterheader. HTTP-date values fall through to exponential backoff rather than raising. Trade-off is documented in the docstring; no behavioral change for callers passing the integer form.
If your code instantiates HyperpingClient (or any MCP client) against a http://localhost URL for local development or against a mock server, the constructor will now raise ValueError. Pass allow_insecure=True to opt in, and expect an InsecureTransportWarning at runtime:
from hyperping import HyperpingClient
client = HyperpingClient(
api_key="sk_test_xxx",
base_url="http://localhost:8000",
allow_insecure=True,
)Production callers using https://api.hyperping.io are unaffected.
URLs that previously carried embedded credentials (https://user:pass@api.example.com) or a trailing query string / fragment will now also raise at construction time. Refactor to pass credentials through api_key and to keep query strings out of the base URL.
ensure_initialized()onHyperpingMcpClientandAsyncHyperpingMcpClientfor startup health checks. Performs the MCP handshake now if it hasn't happened yet and raisesHyperpingRateLimitErrorif the server'sinitializecap is hit.- New "MCP rate limits and connection lifecycle" section in README documenting
Hyperping's stateless MCP server, the undocumented
initializecap, and the recommended client lifetime per process.
- MCP rate-limit errors that the server returns as HTTP 200 with JSON-RPC
error.code = -32000(notably theinitializeper-minute cap) are now classified asHyperpingRateLimitErrorwithretry_afterparsed from the message, instead of a genericHyperpingAPIError. Existing HTTP 429 handling is unchanged. - After a rate-limit on
initialize, the MCP transport latches a cool-off so subsequentcall_toolinvocations short-circuit withHyperpingRateLimitErroruntil the advertisedretry_afterelapses, instead of issuing further HTTP requests that would burn more slots from the bucket. - TOCTOU race in lazy
initializewhere two concurrent first calls on the sameHyperpingMcpClientcould each POSTinitialize. The handshake is now performed under a dedicated lock with a double-checked flag, including a lockless fast path so post-handshakecall_tooldoes not contend on it. - Cool-off short-circuit now preserves the originating status code (200 for
JSON-RPC
-32000, 429 for HTTP 429) so callers can distinguish buckets, andretry_afterusesmath.ceilto avoid over-reporting by one second. - JSON-RPC rate-limit signals returned on the
notifications/initializedleg are now classified asHyperpingRateLimitError(previously they were silently treated as a successful notification). - Rate-limit detection requires the message to contain
"rate limit exceeded"(the observed phrasing) to avoid false positives on unrelated server messages that happen to mention"rate limit". TheRetry-Afterparser now also acceptsRetry-After:andretry after N secondsvariants.
- Per-endpoint circuit breaker option (
per_endpoint_circuit_breaker: bool = False) onHyperpingClientandAsyncHyperpingClient. When enabled, eachEndpointgets its own breaker state so a single flaky endpoint no longer blocks traffic to healthy ones. Sub-resource paths (e.g./v1/monitors/{uuid},/v1/monitors/{uuid}/reports) are bucketed under their parentEndpointprefix so the breaker set stays bounded; pass a custombreaker_key_fnto change that. The OPEN-state error message now identifies which endpoint tripped. State for a given path is readable viaclient.circuit_breaker_state_for(path)in either mode. Default behaviour is unchanged. See README for details.
AsyncHyperpingMcpClient-- full async counterpart toHyperpingMcpClient. All 16 MCP methods available viaawait. Useshttpx.AsyncClient,asyncio.Lock, and async retry withasyncio.sleep. Exported fromhyperpingtop-level.- Typed MCP returns -- all 16 MCP client methods now return Pydantic models instead of
raw
dict[str, Any]. Models verified against the live API. - New models:
TimeGroup,ResponseTimeReport,AlertHistory,MonitorMetricsSummary,MttrReport,MttaReport,ProbeLogResponse,TeamMember,OutageMonitorSummary. - MCP error handling parity -- both sync and async transports now map HTTP 404, 429,
400/422 to the same exception types as the REST client (
HyperpingNotFoundError,HyperpingRateLimitError,HyperpingValidationError). - MCP retry logic -- automatic retry with exponential backoff on transient server
errors (500, 502, 503, 504) up to
max_retriestimes (default 2). - Thread safety --
threading.Lock(sync) andasyncio.Lock(async) protect the request ID counter and initialization flag. - 83 new tests covering async MCP transport, client coverage, sync transport error paths, async maintenance/outages, and protocol base classes. Overall coverage: 96%.
- Forward-compatible models -- all 28 response models changed from
extra="ignore"toextra="allow". New API fields are preserved instead of silently dropped. - Typed sub-objects --
OutageTimeline.outageis now typedOutage(wasdict),.monitorisOutageMonitorSummary(wasdict).
- HTTP 403 from MCP server now correctly raises
HyperpingAuthError(wasHyperpingAPIError). The Hyperping MCP server returns 403 for invalid API keys; the transport only handled 401. Now matches REST client behavior. MCP_URLdefined in single location (endpoints.py); removed duplicate in_mcp_transport.py.- MCP handshake version string uses
__version__instead of hardcoded"1.4.0".
HyperpingMcpClient-- new client for Hyperping MCP server features not available via the REST API. Uses JSON-RPC 2.0 over HTTP at/v1/mcpwith the same Bearer token API key. Provides 16 typed methods:get_status_summary,get_monitor_response_time,get_monitor_mtta,get_monitor_mttr,get_monitor_anomalies,get_monitor_http_logs,list_recent_alerts,list_on_call_schedules,get_on_call_schedule,list_escalation_policies,get_escalation_policy,list_team_members,list_integrations,get_integration,get_outage_timeline,search_monitors_by_name.McpTransport-- low-level JSON-RPC 2.0 transport with auto-initialization handshake, double-parse response extraction, and error mapping to existing SDK exception types.MCP_URLconstant exported fromhyperpingtop-level.- Sync outage methods --
create_outage,delete_outage,get_outage,unacknowledge_outageadded toOutagesMixin(were only in async client). - Verification script --
scripts/verify_endpoints.pyfor testing endpoints against the live API.
- Maintenance update uses
model_dump(include=...)instead of hard-coded field list. - Incident update error handling --
add_incident_updatenow provides context when the POST succeeds but the follow-up GET fails.
- Speculative REST methods -- 12 methods that called nonexistent REST endpoints
(on-call, alerts, anomalies, integrations, probe logs, response time, MTTA, status
summary, outage timeline, monitor search) removed from
HyperpingClientandAsyncHyperpingClient. These features are MCP-only; useHyperpingMcpClientinstead. - 8 speculative mixin files (sync + async) deleted.
- 8 speculative Endpoint enum entries removed from
endpoints.py.
- HTTP 403 from MCP server now correctly raises
HyperpingAuthError(wasHyperpingAPIError). Matches REST client behavior. MCP_URLdefined in single location (endpoints.py), not duplicated.- MCP handshake version uses
__version__instead of hardcoded string. pytestbumped to 9.0.3 (CVE-2025-71176).
v1.3.0 added 18 speculative REST methods for MCP-discovered features (reporting,
observability, on-call, integrations). All 12 endpoint paths were guessed from MCP
tool names and none of them work via the REST API (verified: 10x 404, 2x 401).
These features are only accessible through the MCP server (JSON-RPC 2.0). Superseded
by v1.4.0 which replaces the broken REST methods with a proper HyperpingMcpClient.
- Bump
pytestto 9.0.3 (CVE-2025-71176).
- Sync outage methods --
create_outage,delete_outage,get_outage,unacknowledge_outageadded toOutagesMixinfor feature parity with async client.
- Maintenance update uses
model_dump(include=...)instead of hard-coded field enumeration for robustness. - Incident update error handling --
add_incident_updatenow provides context when the POST succeeds but the follow-up GET fails.
AsyncHyperpingClient— full async counterpart toHyperpingClient. All resources (monitors, incidents, maintenance, outages, status pages, healthchecks) are available viaawait. Retry logic usesasyncio.sleep; circuit breaker andRetryConfigare shared with the sync client. Exported fromhyperpingtop-level.HealthchecksMixin— full CRUD for push-based cron/heartbeat monitoring:list_healthchecks,get_healthcheck,create_healthcheck,update_healthcheck,delete_healthcheck,pause_healthcheck,resume_healthcheck.Healthcheck,HealthcheckCreate,HealthcheckUpdatemodels exported fromhyperping.- Pagination on
list_outages,list_status_pages,list_subscribers. Passpage=None(default) to auto-fetch all pages viahasNextPage; pass an explicitintto retrieve a single page.statusandoutage_typefilter params added tolist_outages. - Typed
OutageActionreturn type foracknowledge_outage,resolve_outage,escalate_outage,unacknowledge_outage(wasdict[str, Any]). _internals.py— sharedRETRY_AFTER_MAX,DEFAULT_USER_AGENT,sanitize_for_logused by both sync and async clients (eliminates private cross-module imports)._monitor_constants.py— sharedVALID_PERIODS,MONITOR_WRITABLE_FIELDSconstants used by both sync and async monitor mixins.collect_all_pages/collect_all_pages_asynchelpers in_utils.pyfor transparent multi-page result aggregation.
- Fix version string in
pyproject.toml(was out of sync with_version.py). - Fix package metadata: incorrect email address in project config.
First stable release. The public API is production-ready and covered by semver guarantees going forward.
- Typed
Outagemodel withextra="ignore",frozen=True.list_outages()now returnslist[Outage]instead of raw dicts. _validate_id()guard on all resource ID parameters before URL interpolation, preventing path-traversal attacks._parse_list()/_unwrap_list()helpers in_utils.py, eliminating ~65 lines of duplicated parse-and-skip logic across all five mixins._ClientProtocolbase class in_protocols.py, replacing 5 duplicate_requeststubs with a single source of truth.expect_dict()helper for safe response type narrowing (replaces bareassertcalls that would vanish underpython -O).LocalizedText.get(lang, default)accessor method.- DNS cross-field validation on
MonitorCreatevia@model_validator(mode="after"). periodparameter typed asLiteral["1h","24h","7d","30d","90d"]withValueErrorguard onget_all_reports()/get_monitor_report().- Client-side email validation in
add_subscriber(). - API key validation at
HyperpingClientinit (rejects empty/whitespace keys). DeprecationWarningfor legacy aliasesIncidentStatus,IncidentUpdateCreate,HYPERPING_API_BASE,API_PATHS(removal planned for v2.0.0).- SLSA build provenance attestation in the publish workflow.
- Dependabot configuration for weekly GitHub Actions and pip dependency updates.
pip-auditadded to dev dependencies for reproducible vulnerability scanning..env/.env.*/.env.localadded to.gitignore.- Missing test coverage:
update_incident,update_monitor,pause_monitor,resume_monitor,get_all_reports,get_monitor_report.
models.pysplit intomodels/subpackage (_monitor_models.py,_incident_models.py,_maintenance_models.py,_statuspage_models.py,_outage_models.py). All imports fromhyperping.modelsremain unchanged.CircuitBreakerextracted to_circuit_breaker.py; re-exported fromclient.pyfor backward compatibility._request()return type corrected todict[str, Any] | list[dict[str, Any]]._request()helpers extracted:_compute_sleep_time(),_should_retry(),_parse_error_body(),_parse_retry_after().CircuitBreaker.statereturn type changed fromstrtoCircuitState.CircuitBreaker.state/failure_countreads now acquire the lock (thread safety)._remap_legacy_fields/Monitor.__init__no longer mutate input dicts._MONITOR_WRITABLE_FIELDSmoved from class variable to module-levelfrozenset._incidents_mixin.pyuses canonicalIncidentUpdateType/AddIncidentUpdateRequestinstead of legacy aliases.- All mixin list methods use
_parse_list()/_unwrap_list()with%-style logging (no f-strings in logger calls). conftest.pyfixture converted toyield-based to close the HTTP client after each test.- All test files migrated from
HYPERPING_API_BASE + API_PATHS[...]toAPI_BASE + Endpoint.*. - Dependency bounds narrowed:
httpx>=0.27,<1.0,pydantic>=2.0,<3.0. - All GitHub Actions pinned to full 40-char commit SHAs.
- Sdist trimmed: excludes
.github/,uv.lock,BACKLOG.md.
- Bare
except Exceptionin_parse_error_bodynarrowed to(ValueError, httpx.DecodingError). HyperpingAuthErrornow omitsresponse_bodyto prevent credential leakage through observability stacks.- Circuit breaker error message references
recovery_timeout(was incorrectly usingretry_config.initial_delay). Retry-Afterheader parsing guarded withtry/exceptto handle RFC 7231 HTTP-date values without crashing the retry loop.- Debug logs sanitize sensitive fields (
request_headers,request_body) via_sanitize_for_log(). - Parse failure logs no longer include raw API response data (could contain subscriber emails or custom auth headers).
- Shadow
from datetime import datetime as dtinsideMaintenance.is_active()removed; uses module-level import. params if params else Nonesimplified toparams or None.- Internal symbols (
EndpointConfig,ENDPOINTS,get_endpoint_url,get_version_for_endpoint,API_PATHS,HYPERPING_API_BASE) removed from__all__; still accessible via__getattr__for backward compatibility. APIErrorResponseremoved from__all__(intentionally internal).- Publish workflow audit step is now blocking (no
continue-on-error). - CI permissions set to
contents: read(least privilege).
- All resource IDs validated against
^[a-zA-Z0-9_-]+$before URL interpolation. - Auth error responses omit
response_bodyto prevent token leakage. - Debug logs redact sensitive field values.
- GitHub Actions pinned to commit SHAs (supply chain hardening).
- SLSA provenance attestation on all published artifacts.
- Dependency vulnerability audit gates the publish pipeline.
- OIDC trusted publishing (no stored PyPI tokens).
- Initial release of the
hyperpingPython SDK. HyperpingClientwith full support for Monitors, Incidents, Maintenance Windows, Outages, and Status Pages.- Automatic retry with exponential backoff and jitter on transient errors (5xx, 429).
- Circuit breaker pattern to prevent cascading failures.
- Typed Pydantic v2 models for all API resources.
py.typedmarker for PEP 561 compliance.- CI matrix across Python 3.11, 3.12, 3.13.
- OIDC trusted publisher workflow for PyPI releases (no stored secrets).