Documentation
HyperMonitors is API-first: everything you can do in the dashboard, you can do over a JSON REST API or expose to an AI agent via the Model Context Protocol. Create a free account to mint an API key.
Let AI agents (Claude Code, Cursor, VS Code, …) inspect and manage your monitors over the Model Context Protocol. Enable it in Settings → MCP and connect with an API key. Read-only keys can use the read tools; creating, updating, or pausing monitors needs a read-write key.
https://api.hypermonitors.com/v1/mcp{
"mcpServers": {
"hypermonitor": {
"type": "http",
"url": "https://api.hypermonitors.com/v1/mcp",
"headers": {
"Authorization": "Bearer hm_live_YOUR_KEY"
}
}
}
}Or with Claude Code: claude mcp add --transport http hypermonitor https://api.hypermonitors.com/v1/mcp--header "Authorization: Bearer hm_live_…"
list_monitorsget_monitorget_monitor_uptimeget_monitor_checkslist_incidentslist_alert_channelsget_usagecreate_monitorupdate_monitorpause_monitorresume_monitorset_monitor_channelsDeleting monitors is intentionally not exposed over MCP.
All endpoints live under the base URL and speak JSON. Authenticate by passing your key as a bearer token:
curl -H "Authorization: Bearer hm_live_…" \ https://api.hypermonitors.com/v1/monitors
- Key scopes. read-only keys may only make GET requests — anything else returns 403. read-write keys can use every method. Routes marked owner · read-write additionally require your org role to be owner, and dashboard only routes only work from the web app — keys can't mint or revoke keys.
- Organizations. Requests act on your default organization. To target another org you belong to, send its id in an
x-org-idheader. - Conventions. List responses are shaped
{ items: [...] }; timestamps are ISO 8601 UTC; ids are UUIDs. Only/v1/notificationspaginates (viacursor/nextCursor). - OpenAPI. A machine-readable spec is served at https://api.hypermonitors.com/docs/json.
Monitors
/v1/monitorsany keyList every monitor in the organization, newest first.
{ items: Monitor[], nextCursor: null }/v1/monitorsread-write keyCreate a monitor. The body is discriminated on type — see the field reference below.
typehttp | port | ping | heartbeat | dns | ssl | domain (required)namestring, 1–100 chars (required)intervalSecondsint 30–86400, must be ≥ your plan's minimum (required; ignored for domain, which is daily)timeoutMsint 1000–60000, default 30000confirmationThresholdconsecutive failures before an incident opens, int 1–10, default 2regionsregion ids to check from; capped to your plan. Omit to use the plan defaulthomeRegionAutobool, default false — check from every region your plan allows and order them by response timetagsstring[], max 20 — free-form labels for grouping/filtering…plus the type-specific fields listed in the monitor type reference
201 MonitorPlan gates: tier_type_not_allowed if the type isn't on your plan, tier_interval_too_low if the interval is below the plan minimum, tier_limit_exceeded when the monitor limit is reached.
New monitors are automatically routed to every enabled alert channel (opt-out) — narrow it with PUT /v1/monitors/:id/channels.
/v1/monitors/:idany keyFetch one monitor.
Monitor/v1/monitors/:idread-write keyPartially update a monitor. Accepts any create field for the monitor's type except type itself (immutable). The merged result is re-validated in full.
Monitor/v1/monitors/:idread-write keyDelete a monitor and its history.
{ deleted: boolean }/v1/monitors/:id/pauseread-write keyPause checking. Status becomes paused.
Monitor/v1/monitors/:id/resumeread-write keyResume a paused monitor. 409 conflict if it isn't paused.
Monitor/v1/monitors/:id/check-nowread-write keyRun an on-demand check now in every selected region. Rate-limited; not available for heartbeat monitors.
{ enqueued: number }/v1/monitors/:id/checksany keyRaw check results, newest first.
hoursint 1–17520, default 24limitint 1–1000, default 500
{ items: [{ id, monitorId, checkedAt, ok, responseTimeMs, statusCode, error }] }/v1/monitors/:id/checks/seriesany keyChecks aggregated into time buckets — ideal for charts and uptime bars.
hoursint 1–17520, default 24bucketMinutesint 1–1440, default 5
{ items: [{ bucketStart, avgResponseTimeMs, upCount, downCount }] }/v1/monitors/:id/checks/region-statusany keyCurrent up/down and latest latency per region — for multi-region monitors.
{ items: [{ region, status: "up"|"down"|"pending", latestResponseMs, lastCheckAt }] }/v1/monitors/:id/checks.csvany keyExport raw checks as CSV (attachment).
hoursint 1–17520, default 720
text/csv/v1/monitors/:id/uptimeany keyUptime percentage over fixed windows. Always returns all four windows.
{ windows: [{ window: "1d"|"7d"|"30d"|"365d", uptimePct: number|null, totalChecks }] }/v1/monitors/:id/incidentsany keyIncidents for this monitor, newest first (up to 200).
{ items: [{ id, monitorId, kind, startedAt, resolvedAt, cause }] }/v1/monitors/:id/channelsany keyThe alert channels currently assigned to this monitor.
{ channelIds: uuid[] }/v1/monitors/:id/channelsread-write keyReplace the monitor's alert-channel assignment wholesale.
channelIdsuuid[], max 100 — every id must be a channel in your org
{ channelIds: uuid[] }Fields accepted by POST /v1/monitors in addition to the common ones, per type. Types marked “paid plans” aren't available on Free.
httpurlhttp(s) URL (required)httpMethodGET | HEAD | POST | PUT, default GEThttpBodyrequest body sent with POST/PUT (max 10000 chars)expectedStatusCodesint[] (100–599, max 50) — default: any 2xx/3xx is upkeywordType"exists" | "absent" — pair with keywordValuekeywordValuestring 1–500 — pair with keywordTypefollowRedirectsboolean, default truecustomHeadersobject of header name → value (max 20) sent with every check, e.g. { "Authorization": "Bearer …" } — request-framing headers (host, content-length, connection, …) can't be setsslCheckEnabledboolean, default true — capture HTTPS cert stats + expiry reminderssslAlertDaysint 1–90, default 14
porthosthostname or IPv4 (required)portint 1–65535 (required)
pinghosthostname or IPv4 (required)
heartbeatpaid plansheartbeatGraceSecondsint 0–86400, default 300 — how long a ping may be overdue before the monitor goes down
dnspaid planshosthostname (required)dnsRecordTypeA | AAAA | CNAME | MX | TXT | NS (required)dnsExpectedValuestring 1–255 — resolved records must include it
sslpaid planshosthostname (required)portint 1–65535, default 443sslAlertDaysint 1–90, default 14sslWatchChangesboolean, default false — alert when the certificate fingerprint changes
domainpaid planshostregistrable domain, e.g. example.com (required) — expiry resolved via RDAPdomainAlertDaysint 1–90, default 30 — remind this many days before the registration expires
Incidents
/v1/incidentsany keyIncidents across all monitors in the organization, newest first.
status"open" | "resolved" — open means resolvedAt is null (optional)limitint 1–200, default 50
{ items: [{ id, monitorId, monitorName, kind: "down"|"ssl_expiring"|"ssl_changed", startedAt, resolvedAt, cause }] }/v1/incidents/acknowledgeread-write keyAcknowledge an open incident to stop repeat/escalation notifications.
incidentIduuid of an open incident
Incident/v1/incidents.csvany keyExport incidents as CSV (attachment).
text/csvAlert channels
/v1/alert-channelsany keyList the organization's alert channels.
{ items: [{ id, type, name, enabled, verified, config, createdAt, … }] }/v1/alert-channelsread-write keyCreate an alert channel. It is automatically assigned to every existing monitor (opt-out). tier_limit_exceeded when the plan's channel limit is reached.
typein_app | telegram | email | slack | discord | sms (required)namestring, 1–100 chars (required)configemail → { address }; slack/discord → { webhookUrl } (https); sms → { phone } in international format (e.g. +41791234567 — stored digits-only). in_app and telegram need none — telegram starts unverified until linked
201 AlertChannel/v1/alert-channels/:idread-write keyRename or enable/disable a channel.
namestring, 1–100 chars (optional)enabledboolean (optional)
AlertChannel/v1/alert-channels/:idread-write keyDelete a channel.
{ deleted: boolean }/v1/alert-channels/:id/testread-write keySend a test alert through the channel. 409 if the channel is disabled or Telegram isn't linked yet.
{ delivered: boolean, message: string|null }/v1/alert-channels/telegram/link-coderead-write keyMint a one-time code that binds a Telegram chat to a channel. Send /start <code> to the bot, or open the returned deep link. Codes expire after 10 minutes.
channelIduuid of a telegram channel (required)
{ code, deepLink, expiresAt }Notifications
/v1/notificationsany keyYour in-app notifications (per user, not per org). The only cursor-paginated endpoint.
unreadOnlyboolean, default falselimitint 1–200, default 50cursorid from a previous page's nextCursor (optional)
{ items: [{ id, incidentId, title, body, readAt, createdAt }], nextCursor: string|null }/v1/notifications/readread-write keyMark notifications as read.
idsnumber[], 1–500 entries (required)
{ updated: number }Account & usage
/v1/meany keyThe authenticated user and their active organization's tier.
{ id, email, tier, telegramLinked, createdAt }/v1/medashboard onlyUpdate account settings: the per-account MCP toggle and/or the active organization. Only available with a browser session. 404 if you are not a member of the given organization.
mcpEnabledboolean (optional)activeOrganizationIduuid of an organization you belong to (optional) — switches the active org
MeResponse (tier reflects the new active organization)/v1/usageany keyCurrent usage against plan limits.
{ tier, monitors: {used, limit}, alertChannels: {used, limit}, minIntervalSeconds, logRetentionDays, allowedMonitorTypes }/v1/analyticsany keyOrg-wide analytics for a trailing window, compared with the window before it: time-weighted uptime, down-incident count/downtime/avg/longest/MTBF, response-time stats with >1s peaks, and every monitor sorted by lowest uptime.
days7 or 30, default 7
{ windowDays, since, until, uptimePct, prevUptimePct, incidents, prevIncidents, downtimeMs, avgIncidentMs, longestIncidentMs, mtbfMs, avgResponseMs, prevAvgResponseMs, minResponseMs, maxResponseMs, peaksAbove1s, monitors: [{ id, name, uptimePct, incidents, avgResponseMs }] }/v1/analytics/sla.csvany keyExport the per-monitor SLA/uptime breakdown as CSV (attachment).
days7 or 30, default 7
text/csvMCP server
A Model Context Protocol server for AI agents (Claude Code, Cursor, …). Enable it per account in Settings → MCP, then point your client at the endpoint with an API key in the Authorization header.
/v1/mcpany keyMCP Streamable HTTP endpoint (stateless JSON-RPC 2.0). Tools: list_monitors, get_monitor, get_monitor_uptime, get_monitor_checks, list_incidents, list_alert_channels, get_usage, create_monitor, update_monitor, pause_monitor, resume_monitor, set_monitor_channels. Read tools work with read-only keys; write tools need a read-write key. 403 until the account enables MCP in Settings.
JSON-RPC 2.0 responsesOrganization & team
/v1/organizationsany keyEvery organization the authenticated user belongs to (drives the org switcher).
{ items: [{ id, name, tier, role: "owner"|"member" }] }/v1/organizationsread-write keyCreate a new organization (the caller becomes its owner and it becomes active).
namestring, 1–100 chars (required)
201 Organization/v1/organizationany keyThe active organization.
{ id, name, tier, timezone, createdAt }/v1/organizationowner · read-writeUpdate the organization's name and/or timezone.
namestring, 1–100 chars (optional)timezoneIANA timezone, e.g. Europe/Vienna (optional)
Organization/v1/organization/transferowner · read-writeTransfer ownership to an existing member (the caller becomes a member).
userIduuid of a current member (required)
{ transferred: boolean }/v1/organization/leaveread-write keyLeave the active organization. Owners must transfer ownership (or delete the org) first.
{ organizationId: uuid } — the org you're switched to after leaving/v1/organization/membersany keyList members.
{ items: [{ userId, email, role: "owner"|"member", joinedAt }] }/v1/organization/members/:idowner · read-writeRemove a member. 409 when trying to remove yourself.
{ removed: boolean }/v1/organization/invitesany keyList pending invites.
{ items: [{ id, email, role, expiresAt, createdAt }] }/v1/organization/invitesowner · read-writeInvite a teammate. Invites expire after 7 days. 409 if they're already a member.
emailemail, max 255 (required)role"owner" | "member", default "member"
201 { id, token, email, role, acceptUrl, expiresAt }/v1/organization/invites/:idowner · read-writeRevoke a pending invite.
{ revoked: boolean }/v1/organization/invites/acceptread-write keyAccept an invite as the calling user. 404 if the token is invalid or expired.
tokeninvite token, min 8 chars (required)
{ organizationId: uuid }Maintenance windows
Planned windows during which alerts are suppressed (checks still run and data is recorded). A window covers the whole org (empty monitorIds) or a specific set, with optional weekly recurrence.
/v1/maintenance-windowsany keyList the org's maintenance windows.
{ items: [{ id, name, monitorIds, startsAt, endsAt, recurrence, note }] }/v1/maintenance-windowsread-write keyCreate a maintenance window.
namestring, 1–100 (required)monitorIdsuuid[], max 500 — empty = whole orgstartsAtISO datetime (required)endsAtISO datetime, after startsAt (required)recurrencenull (one-off) or weekly recurrence objectnotestring, max 500 (optional)
201 MaintenanceWindow/v1/maintenance-windows/:idread-write keyUpdate a maintenance window.
MaintenanceWindow/v1/maintenance-windows/:idread-write keyDelete a maintenance window.
{ deleted: boolean }On-call schedules
Team+ feature. Who's on call is derived deterministically from the anchor, rotation length, and ordered member list — escalations route to the current member's own channels.
/v1/on-callany keyList on-call schedules with the member currently on call.
{ items: [{ id, name, rotationDays, anchorAt, memberIds, currentOnCallId }] }/v1/on-callread-write keyCreate an on-call schedule.
namestring, 1–100 (required)rotationDaysint 1–90, default 7memberIdsordered uuid[] of org members, max 50anchorAtISO datetime; defaults to now
201 OnCallSchedule/v1/on-call/:idread-write keyUpdate a schedule (name, rotation, members, anchor).
OnCallSchedule/v1/on-call/:idread-write keyDelete an on-call schedule.
{ deleted: boolean }Audit log
Team+ feature. An append-only record of who changed what in the organization.
/v1/auditany keyRead the org audit log, newest first (cursor-paginated). Team+ tier.
limitint 1–200, default 50cursorcreatedAt ISO of the previous page's last row
{ items: [{ id, actorEmail, actorKind, method, path, status, targetType, targetId, createdAt }], nextCursor }Status pages
/v1/status-pagesany keyList the organization's status pages.
{ items: StatusPage[] }/v1/status-pages/:idany keyFetch one status page.
{ id, slug, title, branding: { logoUrl, accentColor, headerText }, isPublic, hasPassword, customDomain, monitorIds, createdAt }/v1/status-pages/by-slug/:slug/previewany keyTeam preview: the same payload as the public status endpoint, for members of the owning org. Works for hidden pages and bypasses the password gate. 403 when the page belongs to another organization.
PublicStatusPage/v1/status-pagesread-write keyCreate a status page. Slugs are global — 409 if taken; tier_limit_exceeded at the plan's page limit.
slug3–40 chars, lowercase letters/digits/hyphens (required)titlestring, 1–100 chars (required)
201 StatusPage/v1/status-pages/:idread-write keyUpdate settings, branding, monitors, visibility, custom domain, or password.
titlestring, 1–100 charsslugnew slug (409 if taken)brandingpartial { logoUrl, accentColor, headerText }isPublicbooleancustomDomainhostname (max 253) or null to clearmonitorIdsuuid[], max 200 — all must be org monitorspasswordstring 4–200 to set, null to remove, omit to keep
StatusPage/v1/status-pages/:idread-write keyDelete a status page.
{ deleted: boolean }API keys
/v1/api-keysany keyList your active (non-revoked) keys. The secret is never returned.
{ items: [{ id, name, access, prefix, lastUsedAt, createdAt }] }/v1/api-keysdashboard onlyMint a key. Only available with a browser session — keys can't create keys. The secret is returned once; up to 25 active keys per user.
namestring, 1–100 chars (required)access"read_only" | "read_write", default "read_write"
201 ApiKey & { secret }/v1/api-keys/:iddashboard onlyRevoke a key. Only available with a browser session.
{ revoked: boolean }Billing
/v1/billing/statusany keyWhether billing is configured, the org's plan, and its purchased extra seats.
{ tier, billingEnabled, hasCustomer, hasSubscription, monitorCap, extraSeats }/v1/billing/checkoutowner · read-writeCreate a Stripe Checkout session for a paid tier. 409 if billing isn't configured or the org already has a subscription (plan changes go through the portal).
tiera paid tier (not free) (required)cycle"monthly" | "annual", default "monthly"currency"usd" | "eur" | "chf" — currency to charge, default "usd" (falls back to USD if the price doesn't support it)
{ url: string }/v1/billing/seatsowner · read-writeSet the org's purchased extra seats (absolute count, in the tier's block size — 1 for Team, 5 for Enterprise). Requires an active subscription; 409 on tiers without extra seats.
extraSeatstotal extra seats beyond the plan's included ones (0 removes the add-on) (required)
{ extraSeats }/v1/billing/portalowner · read-writeOpen the Stripe customer portal. Pass an optional target to deep-link straight to a plan switch or seat change; omit it for the portal landing page. 409 if the org has no Stripe customer yet.
{ url: string }Public endpoints
No Authorization header. Each is rate-limited to 120 requests per minute.
/v1/heartbeat/:tokenpublicHeartbeat ping for cron-style monitors — also accepts POST. Call it from your job on every run; the monitor goes down when pings stop for longer than the grace period.
{ ok: true }/v1/public/status/:slugpublicThe JSON behind a public status page, including daily uptime per monitor over the page's configured history window (7/30/90/365 days, default 90).
passwordrequired only for password-protected pages
{ title, branding, overall, historyDays, monitors: [{ id, name, status, uptime, dailyUptime[historyDays] }], incidents, updatedAt } — or { passwordRequired: true, title }/v1/public/resolve-domainpublicResolve a status-page custom domain to its slug.
hosthostname, max 253 chars (required)
{ slug: string|null }/healthzpublicLiveness probe (note: no /v1 prefix).
{ status, service, uptimeSeconds }/readyzpublicReadiness probe — 503 until the database and scheduler are up (no /v1 prefix).
{ status, checks }Errors
Every error is JSON with a stable code:
{ "error": { "code": "conflict", "message": "…", "details": … } }| Code | Status | Meaning |
|---|---|---|
validation_error | 400 | Request body or query failed validation — details carries the issues |
unauthorized | 401 | Missing, invalid, or revoked credentials |
forbidden | 403 | Read-only key on a write, non-member org, missing owner role, or a dashboard-only route |
not_found | 404 | Resource (or route) doesn't exist in your org |
conflict | 409 | State conflict — slug taken, monitor not paused, channel disabled, billing unconfigured… |
tier_limit_exceeded | 403 | A plan count limit was reached (monitors, channels, status pages, 25 API keys) |
tier_interval_too_low | 403 | Check interval below your plan's minimum |
tier_type_not_allowed | 403 | Monitor type not available on your plan |
rate_limited | 429 | Too many requests (public endpoints: 120/min) |
internal | 500 | Unexpected server error |