undownable

Using the REST API

Everything the MCP server can do is a plain HTTP endpoint too, so a cron job, a deploy script, or a status board can drive your monitoring without speaking MCP. Same tokens, same rules, same answers: both surfaces run the same code underneath.

Base URL

https://undownable.com/api/v1

JSON in, JSON out, authenticated with an Authorization: Bearer <token> header. Versioned, so a script written today keeps working: a breaking change ships as /api/v2.

1. Create a token

  1. Log in and open API tokens in the dashboard sidebar.
  2. Pick the abilities the script actually needs. A status board wants monitors:read and nothing else.
  3. If you belong to more than one team, pin the token to one of them so it can never touch the others.
  4. Copy the token immediately: it is shown exactly once.
curl -H "Authorization: Bearer $UNDOWNABLE_TOKEN" \
  https://undownable.com/api/v1/monitors

2. Two rules worth knowing up front

Anything that writes must name its team

Pass team on every create, update, or delete. Reads may omit it, in which case they span every team the token can see. We refuse to guess on a write on purpose: the alternative is following whichever team you last clicked in the dashboard, which would one day point a nightly script at the wrong systems without anything having changed on its side. A token pinned to one team may omit it, because there is nothing to guess.

config replaces, it does not merge

Sending config on an update overwrites the stored settings wholesale, so include every key the monitor still needs. Drop the keyword from a keyword monitor and it quietly becomes a plain reachability check that passes against an error page.

3. Endpoints

Every response is shaped {"data": ..., "meta": ...}. Monitor and window IDs are the ULIDs the list endpoints return.

Endpoint Ability What it does
GET /teamsteams:readTeams this token can reach, and the identifiers every other endpoint accepts as team
GET /monitorsmonitors:readEvery monitor with status, interval, and ID. Filter with ?tag=
GET /monitors/{id}monitors:readOne monitor in detail: config (secrets masked), 24h, 7d, and 30d uptime, recent incidents
POST /monitorsmonitors:writeCreate an HTTP, keyword, JSON, SSL, TCP, DNS, ping, or heartbeat monitor
PATCH /monitors/{id}monitors:writeEdit in place, keeping check history. The type cannot change
DELETE /monitors/{id}monitors:writeRemove a monitor and stop collecting its history
POST /monitors/{id}/pause
POST /monitors/{id}/resume
monitors:writeStop and restart checking. A pause never expires: for planned work use a maintenance window instead
GET /incidentsincidents:readRecent outages, newest first. Filter with ?monitor_id=, ?ongoing_only=, ?limit=
GET /status-pages
POST /status-pages
status-pages:read
status-pages:write
List your status pages, or publish one with chosen monitors in display order
GET /maintenance-windows
POST /maintenance-windows
maintenance-windows:read
maintenance-windows:write
List windows (filter with ?state=), or schedule downtime for chosen monitors, a tag, or the whole team
POST /maintenance-windows/{id}/end
DELETE /maintenance-windows/{id}
maintenance-windows:writeEnd an active window early, or cancel one entirely
GET /fleet-statusfleet-status:readOne compact health rollup per team, built for dashboards

4. A worked example

Open a maintenance window before you take something down, and close it when you are finished. This is the pattern worth copying into a deploy script: a window ends itself, so forgetting to close it leaves you monitored rather than blind.

WINDOW=$(curl -sS -X POST https://undownable.com/api/v1/maintenance-windows \
  -H "Authorization: Bearer $UNDOWNABLE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"team": "acme", "name": "Rack move", "tag": "homelab", "duration_minutes": 90}' \
  | jq -r .data.id)

# ... do the work ...

curl -sS -X POST https://undownable.com/api/v1/maintenance-windows/$WINDOW/end \
  -H "Authorization: Bearer $UNDOWNABLE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"team": "acme"}'

Good to know

Errors say what to do

Failures return a message, and validation failures an errors object. 422 means fix the request, 403 means the token lacks the ability, 404 means the token cannot see it, 409 means the resource is in the wrong state.

Plan limits apply

Monitor count, fastest check interval, and status page count follow your plan, and the error names the limit you hit.

Rate limited

120 requests per minute per token. The MCP server has its own limit of 60 per minute.

Secrets stay masked

Request headers you store on a monitor, and anything else that looks like a credential, come back redacted. Lists return config key names only.

Put it in your pipeline

Free includes 10 monitors, every alert channel, and a public status page. No card required.

Start monitoring free