Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: UptimeMonitoring.com Public API
version: 0.1.0
description: 'API-first uptime monitoring for developers, deploy pipelines, and AI agents.
## Authentication
All `/api/v1` endpoints require a Bearer token — either an API key (`umk_live_*`)
or a session token obtained via GitHub OAuth. The `/mcp` endpoint additionally
accepts OAuth 2.1 JWT access tokens (`eyJ...`) issued via the self-hosted
authorization server documented under the `OAuth` tag.
```
Authorization: Bearer umk_live_abc123...
```
## Rate limits
200 requests/minute per account. Exceeding the limit returns `429` with a
`Retry-After` header.
Responses that pass through the per-account rate-limiter carry the
`X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset`
headers (decimal integers; `Reset` is a Unix epoch second at which
the bucket would be full again). In practice this is every
authenticated response under `/api/v1/*` whose request reached the
handler — earlier failures from the auth middleware (e.g. 401 missing
credentials, 403 suspended account) return before the limiter runs
and do NOT carry the trio. Routes mounted outside `/api/v1`
(notably `GET /api/v1/events/stream`, which has its own SSE
middleware stack) are not subject to this limiter and likewise do
not emit these headers. Successful responses on
`POST /api/v1/monitors` reflect the **global** 200/min bucket; the
per-route 20/min creation limit only surfaces its own headers when
it 429s. The trio is documented once here rather than referenced
into every individual response — see `components.headers` for the
schemas.
One exception: once a request presenting an API key enters an
authenticated route group through a registered route or mounted
subtree, while that key remains in the bounded pre-auth cache
(entries expire after 5 minutes, but may be evicted sooner once the
cache is at capacity), the global bucket is charged BEFORE
authentication and authorization run (issue #47) — so for that
cached key only, a `401` (key revoked while still cached), `403`,
`500`, or a `404` for an unmatched path inside a mounted subtree
also carries the `X-RateLimit-*` trio and spends one token. `429`
still comes first whenever the bucket is already empty. An uncached
key (first seen, expired, or evicted early at capacity), a session
token, an OAuth JWT, and any path outside every authenticated group
are all unaffected.
## Browser push notifications
Subscriptions registered via `POST /api/v1/push/subscribe` receive
fire-and-forget Web Push notifications on monitor state transitions
(down/up/flapping); per-monitor 5-minute throttle. No public API change
in this release — dispatch is internal to `internal/push.Dispatcher`.'
contact:
name: UptimeMonitoring.com
url: https://uptimemonitoring.com
license:
name: Proprietary
identifier: LicenseRef-Proprietary
servers:
- url: https://api.uptimemonitoring.com
description: Production
tags:
- name: Public
paths:
/:
get:
operationId: getServiceInfo
summary: Service info
description: Returns the service name and docs URL.
tags:
- Public
security: []
responses:
'200':
description: Service info.
content:
application/json:
schema:
type: object
properties:
service:
type: string
example: uptimemonitoring-dispatcher
docs:
type: string
example: https://uptimemonitoring.com/docs
'405':
$ref: '#/components/responses/MethodNotAllowed'
'500':
$ref: '#/components/responses/InternalError'
/healthz:
get:
operationId: healthCheck
summary: Health check
description: Returns 200 if the service is running. Used by load balancers and by the post-deploy smoke check, which also asserts `commit` against the commit it just deployed.
tags:
- Public
security: []
responses:
'200':
description: Healthy.
content:
application/json:
schema:
type: object
properties:
status:
type: string
example: ok
commit:
type: string
description: The 40-char git commit this binary was built from, or "dev" for a build with no -X main.commitSHA stamp.
example: 8bade47d6d9db61a607781f04aefb9349f01d28d
'405':
$ref: '#/components/responses/MethodNotAllowed'
'500':
$ref: '#/components/responses/InternalError'
/{token}:
servers:
- url: https://status.uptimemonitoring.com
description: Free status page host (STATUS_PAGE_URL)
get:
operationId: getStatusPageHTML
summary: Public status page (issue
description: 'Unauthenticated — the token is the only credential, same shape as
`/feed/{token}`. Served on its own host (`STATUS_PAGE_URL`), not
under `/api/v1`; a request to this path on the API host 404s. Any
method other than `GET` on this path (`HEAD`/`POST`/`PUT`/`DELETE`)
also 404s, never 405. A token that doesn''t match the pattern below
gets the same 404 without a database lookup. Carries `Age` (seconds
the served copy has aged at the origin) and `Cache-Control: public,
max-age=`, where `N` is the full freshness lifetime the view was
cached under — 60 for a settled view, 5 for one where the live
status currently disagrees with the open incident rows — never
reduced by `Age`, since a cache already subtracts `Age` from
`max-age` itself; both headers are computed the same way on the
RSS/Atom/JSON/badge siblings below.'
tags:
- Public
security: []
parameters:
- name: token
in: path
required: true
schema:
type: string
pattern: ^sp_[0-9a-f]{32}$
responses:
'200':
description: HTML status page.
headers:
Age:
$ref: '#/components/headers/StatusPageAge'
Cache-Control:
$ref: '#/components/headers/StatusPageCacheControl'
content:
text/html: {}
'404':
$ref: '#/components/responses/StatusPageNotFound'
'500':
$ref: '#/components/responses/StatusPageInternalError'
'503':
$ref: '#/components/responses/StatusPageUnavailable'
/{token}/feed.rss:
servers:
- url: https://status.uptimemonitoring.com
description: Free status page host (STATUS_PAGE_URL)
get:
operationId: getStatusPageRSS
summary: Public status page, RSS 2.0 (issue
tags:
- Public
security: []
parameters:
- name: token
in: path
required: true
schema:
type: string
pattern: ^sp_[0-9a-f]{32}$
responses:
'200':
description: RSS 2.0 feed of down/up events, capped at 50, newest-first.
headers:
Age:
$ref: '#/components/headers/StatusPageAge'
Cache-Control:
$ref: '#/components/headers/StatusPageCacheControl'
content:
application/rss+xml: {}
'404':
$ref: '#/components/responses/StatusPageNotFound'
'500':
$ref: '#/components/responses/StatusPageInternalError'
'503':
$ref: '#/components/responses/StatusPageUnavailable'
/{token}/feed.atom:
servers:
- url: https://status.uptimemonitoring.com
description: Free status page host (STATUS_PAGE_URL)
get:
operationId: getStatusPageAtom
summary: Public status page, Atom (issue
tags:
- Public
security: []
parameters:
- name: token
in: path
required: true
schema:
type: string
pattern: ^sp_[0-9a-f]{32}$
responses:
'200':
description: Atom feed of down/up events, capped at 50, newest-first.
headers:
Age:
$ref: '#/components/headers/StatusPageAge'
Cache-Control:
$ref: '#/components/headers/StatusPageCacheControl'
content:
application/atom+xml: {}
'404':
$ref: '#/components/responses/StatusPageNotFound'
'500':
$ref: '#/components/responses/StatusPageInternalError'
'503':
$ref: '#/components/responses/StatusPageUnavailable'
/{token}/status.json:
servers:
- url: https://status.uptimemonitoring.com
description: Free status page host (STATUS_PAGE_URL)
get:
operationId: getStatusPageJSON
summary: Public status page, JSON (issue
tags:
- Public
security: []
parameters:
- name: token
in: path
required: true
schema:
type: string
pattern: ^sp_[0-9a-f]{32}$
responses:
'200':
description: JSON status page.
headers:
Age:
$ref: '#/components/headers/StatusPageAge'
Cache-Control:
$ref: '#/components/headers/StatusPageCacheControl'
content:
application/json:
schema:
$ref: '#/components/schemas/StatusPageJSON'
'404':
$ref: '#/components/responses/StatusPageNotFound'
'500':
$ref: '#/components/responses/StatusPageInternalError'
'503':
$ref: '#/components/responses/StatusPageUnavailable'
/{token}/badge.svg:
servers:
- url: https://status.uptimemonitoring.com
description: Free status page host (STATUS_PAGE_URL)
get:
operationId: getStatusPageBadge
summary: Public status page, SVG uptime badge (issue
description: 'A static, namespaced SVG — a fixed "uptime" label plus a
status-colored message, `% · ` (or `no data ·
` when the 30-day average has no data yet) — rendered
from the same cached `View` the HTML page, RSS, Atom, and JSON
siblings share — requests landing on the same cache entry always
render identical state, but a rebuild after the entry''s TTL
expires (or a downstream cache holding the two URLs
independently) can leave the badge and page briefly disagreeing
across that boundary. Resolved, cached, and error-handled
identically to those four siblings (same token-shape check, same
`GetStatusPageByToken` lookup folding an unknown/off/deleted/
suspended token into one 404, same view cache and
`Age`/`Cache-Control` computation, recomputed from the live clock
on every response). No
style element, no inline style attribute, no script element, and
no external reference — presentation attributes only, so the
document stays inside the status host''s Content-Security-Policy
and renders safely through an image proxy such as GitHub''s camo.'
tags:
- Public
security: []
parameters:
- name: token
in: path
required: true
schema:
type: string
pattern: ^sp_[0-9a-f]{32}$
responses:
'200':
description: SVG uptime badge.
headers:
Age:
$ref: '#/components/headers/StatusPageAge'
Cache-Control:
$ref: '#/components/headers/StatusPageCacheControl'
content:
image/svg+xml: {}
'404':
$ref: '#/components/responses/StatusPageNotFound'
'500':
$ref: '#/components/responses/StatusPageInternalError'
'503':
$ref: '#/components/responses/StatusPageUnavailable'
components:
responses:
InternalError:
description: Internal server error.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
StatusPageNotFound:
description: 'Unknown or malformed token, a page that is off, a deleted
monitor, or a suspended account — all indistinguishable, and all
five status-host formats (`/{token}`, `/{token}/feed.rss`,
`/{token}/feed.atom`, `/{token}/status.json`,
`/{token}/badge.svg`) return this identical shape. A malformed
token (wrong length, prefix, or a non-hex/uppercase character)
never reaches the database lookup the other cases do.
'
StatusPageUnavailable:
description: 'The shared view-build deadline (`StatusPageBuildTimeout`, 10s)
was exceeded while this request was still live — e.g. database
slowness. Distinct from a client disconnecting mid-build, which
writes no response at all. Every one of the five status-host
formats returns this identical shape, including the
`Retry-After` header.
'
headers:
Retry-After:
$ref: '#/components/headers/StatusPageRetryAfter'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
MethodNotAllowed:
description: 'The HTTP method is not supported for this path. The `Allow`
response header lists the methods this endpoint accepts.
'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: method not allowed
StatusPageInternalError:
description: 'The token lookup, the view build, or the format''s own render
step failed for a reason other than the deliberately
indistinguishable 404 cases above — a connection failure, query
timeout, or scan error. Distinct from `503` below, which is
specifically the shared view-build deadline expiring.
'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
headers:
StatusPageAge:
schema:
type: integer
description: 'Seconds since the origin built the `View` currently being served —
`0` on the request that populated the cache, growing on every
subsequent request served from that same entry. Computed the same
way (live clock minus the cache entry''s insertion time) for all
five status-host formats (issue #368, badge added by #383), so two
requests served from one cache entry at the same instant carry
identical `Age` — this is not a promise that `Age` itself stays
constant across requests over time.
'
StatusPageCacheControl:
schema:
type: string
description: '`public, max-age=<N>`, where `N` is the serving cache entry''s full
freshness lifetime as cached — `60` for a settled view (the live
status agrees with the open incident rows), `5` for an unsettled
one — never reduced by `Age`: an HTTP cache already subtracts
`Age` from `max-age` itself to get the remaining lifetime, so an
already-reduced `max-age` would double-subtract. Identical across
all five formats for one cache entry.
'
StatusPageRetryAfter:
schema:
type: integer
description: 'Fixed at `5` — the shared view-build deadline
(`StatusPageBuildTimeout`) that expired while this request was
still live.
'
schemas:
Error:
type: object
required:
- error
properties:
error:
type: string
example:
error: something went wrong
StatusPageDay:
type: object
description: One day of the public status page's 30-day grid.
required:
- date
- uptime_pct
- not_monitored_yet
properties:
date:
type: string
format: date
uptime_pct:
type:
- number
- 'null'
format: float
not_monitored_yet:
type: boolean
description: True for a day before the monitor existed — rendered grey, never a fabricated 0% or 100%.
StatusPageIncident:
type: object
description: One entry of the public downtime history, newest-first, capped at 50.
required:
- id
- started_at
- clipped_start
- ongoing_over_30_days
properties:
id:
type: integer
format: int64
started_at:
type: string
format: date-time
clipped_start:
type: boolean
description: True when the incident actually began before the 30-day window.
resolved_at:
type: string
format: date-time
ongoing_over_30_days:
type: boolean
description: True for a still-open incident older than 30 days — rendered as "Down for more than 30 days".
StatusPageJSON:
type: object
description: 'The public `GET /{token}/status.json` response (issue #368). Served
from the status host (`STATUS_PAGE_URL`), unauthenticated — the
token is the only credential.
'
required:
- monitor_name
- monitor_host
- status
- headline
- days
- uptime_pct_30d
- avg_response_ms
- history
- claimed
- generated_at
properties:
monitor_name:
type: string
monitor_host:
type: string
status:
type: string
enum:
- up
- down
- flapping
- paused
- unknown
headline:
type: string
example: example.com is up
last_checked_at:
type: string
format: date-time
down_since:
type: string
format: date-time
region_clause:
type: string
example: confirmed from 2 of 3 regions
description: Present only when status is down and the open incident carries a region tally.
days:
type: array
minItems: 30
maxItems: 30
items:
$ref: '#/components/schemas/StatusPageDay'
uptime_pct_30d:
type:
- number
- 'null'
format: float
description: Plain average of the days whose uptime_pct is not null.
avg_response_ms:
type:
- number
- 'null'
format: float
history:
type: array
maxItems: 50
items:
$ref: '#/components/schemas/StatusPageIncident'
claimed:
type: boolean
generated_at:
type: string
format: date-time
securitySchemes:
bearerAuth:
type: http
scheme: bearer
description: 'API key (`umk_live_*`) or session token from OAuth exchange.
'