CoreDash Uptime API and MCP Tools: Monitors and Checks
List, add, change and pause uptime monitors with your CoreDash API key, and read their checks over REST or MCP.
Uptime monitors over the CoreDash API
Read and change the uptime monitors of your CoreDash projects over REST, with the API key you already use for your RUM data. An AI agent reads them over MCP.
Quick start
- Base URL
https://app.coredash.app/api/uptime/monitors, JSON in and JSON out. - Header
Authorization: Bearer cdk_your_key, with a project key or a master key. - First call:
GET /api/uptime/monitorslists your monitors with their state and the uptime of the last 7 days.
curl https://app.coredash.app/api/uptime/monitors \
-H "Authorization: Bearer cdk_your_key"
API keys for uptime monitors
The uptime endpoints take the keys of the CoreDash API and the Agency API.
| Key | Starts with | Sees | A new monitor goes into |
|---|---|---|---|
| Project key | cdk_ | The monitors of its own project | Its own project, always |
| Master key | cdk_master_ | The monitors of every project you own or were invited to | The project you name in project_id, one you own |
Make a project key on the Connect Your AI page in your project's sidebar: give it a name and click Generate API key. The same keys are in your project settings under API Keys (MCP). Only a project's owners can make them. A master key comes from the Agency API page in the sidebar, on agency accounts. Once a project has expired, its project key gets 401 on every call.
A guest on a project reads its monitors. Adding, changing, moving and deleting them needs a project you own.
The OAuth token of an AI connection such as Claude (mcp_at_) only reads. POST, PATCH and DELETE with it get 403.
Uptime endpoints
| Method and path | What it does | Returns |
|---|---|---|
GET /api/uptime/monitors | Lists every monitor the key can see, sorted by name. | 200, { "monitors": [...] }, each with a summary |
POST /api/uptime/monitors | Adds a monitor. The first check runs in the next round, at :00 or :30. | 201, { "monitor": {...} } |
GET /api/uptime/monitors/:id | One monitor with its checks, newest first. ?limit= sets the number of checks: default 300, at most 2100. | 200, { "monitor", "summary", "checks", "rum" } |
PATCH /api/uptime/monitors/:id | Changes the fields you send and leaves the rest. | 200, { "monitor": {...} } |
DELETE /api/uptime/monitors/:id | Deletes the monitor and all its checks. | 200, { "deleted": true } |
The origin IP and the header values are secrets. They come back from POST, PATCH and GET /api/uptime/monitors/:id. The list and the MCP tools leave origin_ip out and show every header value as ••••.
The monitor object
| Field | Meaning |
|---|---|
id | The monitor's id, for the :id in the paths. |
name, url | The name in the app and the URL that gets checked. |
project_id | The CoreDash project the monitor belongs to. |
paused | true while the monitor isn't checked. |
expect_status | The HTTP status that counts as up. Default 200. |
origin_check | true when an origin IP is set, so every round also checks the server itself. |
origin_ip | The server's IP. Only in the answers that carry secrets. |
headers | The extra request headers, [{ "name", "value" }]. |
state | pending, up, failing, down, warn, blocked or paused. See the states table below. |
last_check_at, last_up_at | The last round, and the last round that came back up. |
down_since | While down: the time of the first failed round. Otherwise null. |
last_down | The last outage that ended, { "from", "to" }, or null. |
check_requested_at | Set when you add the monitor. The next round clears it. |
last | The last check per kind: edge and origin, each a check object. origin_is_cdn is true when the origin check answered with Cloudflare headers, so the IP you entered isn't your server. |
cert_expires | When the HTTPS certificate your visitors get runs out. |
created_at | When the monitor was added. |
The summary and rum fields
The list and the single monitor both carry a summary: rounds_7d and down_rounds_7d count the rounds of the last 7 days, uptime_7d is the percentage of those rounds without a down check, and recent holds the last 48 rounds, oldest first, each with the worst outcome of that round. A monitor without checks in the last 7 days has summary: null.
The single monitor also carries rum: the TTFB at p75 your real visitors got in the last 7 days, from the project's RUM data, to compare with the checker's ttfb_ms. It is null while the project has no RUM data.
GET /api/uptime/monitors/:id
curl "https://app.coredash.app/api/uptime/monitors/6ad68c7a844fad80b752fd16?limit=2" \
-H "Authorization: Bearer cdk_your_key"
{
"monitor": {
"id": "6ad68c7a844fad80b752fd16",
"name": "Checkout",
"url": "https://www.example.com/checkout/",
"project_id": "655f1f77bcf86cd799439011",
"paused": false,
"expect_status": 200,
"origin_check": true,
"origin_ip": "203.0.113.10",
"headers": [{ "name": "X-Staging-Auth", "value": "k7Qp2vX9mR4tL8wZ" }],
"state": "up",
"last_check_at": "2026-10-20T08:00:09.000Z",
"last_up_at": "2026-10-20T08:00:09.000Z",
"down_since": null,
"last_down": { "from": "2026-10-18T19:00:11.000Z", "to": "2026-10-18T20:00:10.000Z" },
"check_requested_at": null,
"last": {
"edge": { "at": "2026-10-20T08:00:09.000Z", "server": "scan1", "mode": "edge", "outcome": "up", "status": 200, "ttfb_ms": 212, "total_ms": 388, "connect_ms": 14, "redirects": 0, "final_url": "https://www.example.com/checkout/", "error": null, "error_text": null, "cloudflare": true, "cache_status": "DYNAMIC" },
"origin": { "at": "2026-10-20T08:00:09.000Z", "server": "scan1", "mode": "origin", "outcome": "up", "status": 200, "ttfb_ms": 640, "total_ms": 702, "connect_ms": 9, "redirects": 0, "final_url": "https://www.example.com/checkout/", "error": null, "error_text": null, "cloudflare": false, "cache_status": null },
"origin_is_cdn": false
},
"cert_expires": "2027-01-02T23:59:59.000Z",
"created_at": "2026-10-06T09:12:41.000Z"
},
"summary": {
"rounds_7d": 336,
"down_rounds_7d": 2,
"uptime_7d": 99.4,
"recent": [
{ "at": "2026-10-20T07:30:10.000Z", "outcome": "up" },
{ "at": "2026-10-20T08:00:09.000Z", "outcome": "up" }
]
},
"checks": [
{ "at": "2026-10-20T08:00:09.000Z", "server": "scan1", "mode": "edge", "outcome": "up", "status": 200, "ttfb_ms": 212, "total_ms": 388, "connect_ms": 14, "redirects": 0, "final_url": "https://www.example.com/checkout/", "error": null, "error_text": null, "cloudflare": true, "cache_status": "DYNAMIC" },
{ "at": "2026-10-20T08:00:09.000Z", "server": "scan1", "mode": "origin", "outcome": "up", "status": 200, "ttfb_ms": 640, "total_ms": 702, "connect_ms": 9, "redirects": 0, "final_url": "https://www.example.com/checkout/", "error": null, "error_text": null, "cloudflare": false, "cache_status": null }
],
"rum": { "ttfb_p75": 1920, "rating": "poor", "period": "last 7 days" }
}
In the real answer, recent holds 48 rounds; this example shows the last two.
The check object and its outcomes
Every 30 minutes one round checks every monitor, from two servers in turn: scan1 at :00, scan2 at :30. A round always checks the URL the way visitors reach it, through DNS and your CDN (edge). With an origin IP it also checks your server directly (origin). The API has no call to check a monitor between rounds. Checks are kept for 30 days.
Every check sends the user agent CoreDash/1.0 (uptime; +https://www.coredash.app/bot). When the monitor's URL is on your project's own site (its host, with or without www, or a subdomain), the check also sends the header X-CoreDash-Bot with your project's secret value, from the CoreDash bot token tab in your project settings. A monitor on any other site gets no token. On a redirect the token follows the rule for the headers you set: it goes along only while the redirect stays on the monitor's host. A header of your own named X-CoreDash-Bot is dropped. The CoreDash bot page has more on both.
| Field | Meaning |
|---|---|
at, server | When the server reported the round, and which server ran it: scan1 or scan2. The checks of one round share the same at. |
mode | edge or origin. |
outcome | up, down, blocked or warn. |
status | The HTTP status of the last answer, after redirects. null when nothing answered. |
ttfb_ms, total_ms, connect_ms | Time to first byte and total time, both including redirects, and the time to connect on the first request. |
redirects, final_url | The number of redirects followed and the URL that answered last. |
error, error_text | Why the check failed, as a value from the table below and as text. |
cloudflare, cache_status | Whether the answer came through Cloudflare, and the CDN's cache header (cf-cache-status or x-cache). |
How a check gets its outcome
| Outcome | When |
|---|---|
up | The status equals expect_status, unless that status is a 403, a 429 or 500 or higher: those count as blocked or down first. |
down | A status of 500 or higher, or an error: dns, connect, connect_timeout (no connection within 10 seconds), timeout (no full answer within 30 seconds), tls, redirects (more than 5) or network. |
blocked | A 403, a 429 or a Cloudflare challenge: a firewall stopped the checker. Never counted as downtime. Let CoreDash through your firewall. |
warn | Any other status, such as a 404 on a checkout after a release. Also invalid_ip and invalid_url: the URL or a redirect leads to a private or reserved address, or a redirect points at something that isn't a URL. The checker doesn't request those. |
The worst outcome of a round's checks decides the monitor's state, from worst to best: down, blocked, warn, up.
Monitor states
state | In the app | Means |
|---|---|---|
pending | Waiting for first check | Added; the first round hasn't run yet. |
up | Up | The last round got the expected status. |
failing | Failing | One round failed. One more makes it down. |
down | Down | Two failed rounds in a row, so both servers saw it fail. |
warn | Unexpected status | The last round came back warn. |
blocked | Blocked | A firewall stopped the checker. |
paused | Paused | Not checked until you set paused to false. |
A monitor in a project whose subscription has ended keeps its settings and its last state. It isn't checked until the project is paid again.
Add, change and delete a monitor
POST /api/uptime/monitors
curl -X POST https://app.coredash.app/api/uptime/monitors \
-H "Authorization: Bearer cdk_master_your_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://www.example.com/checkout/",
"name": "Checkout",
"project_id": "655f1f77bcf86cd799439011",
"origin_ip": "203.0.113.10",
"headers": [{ "name": "X-Staging-Auth", "value": "k7Qp2vX9mR4tL8wZ" }],
"expect_status": 200
}'
| Field | Rules |
|---|---|
url | Required on POST. A full http or https URL, without a username or password. |
name | Up to 80 characters; longer names are cut off. Empty on POST: the host of the URL. Empty on PATCH: the old name stays, or the new host when the same PATCH sends a new url. |
project_id | Required with a master key: a project you own, with a paid subscription or a running trial. A project key ignores it and uses its own project. |
origin_ip | A public IPv4 or IPv6 address of your server. Adds the origin check: straight to this IP, past DNS and the CDN. "" or null removes it. |
headers | Up to 5 extra request headers, [{ "name", "value" }]. Names: letters, numbers and dashes, up to 64 characters. Values: up to 256 characters, longer ones are cut off. On a redirect they go along only while it stays on the monitor's host, with or without www. A redirect to any other host, a subdomain included, gets none of them. |
expect_status | The status that counts as up, 100 to 599. Default 200. A 403, a 429 or any status of 500 or higher never counts as up. |
paused | true stops the checks, false starts them again. |
The answer is 201 with the new monitor, origin IP and header values included:
{
"monitor": {
"id": "6ad68c7a844fad80b752fd16",
"name": "Checkout",
"url": "https://www.example.com/checkout/",
"project_id": "655f1f77bcf86cd799439011",
"paused": false,
"expect_status": 200,
"origin_check": true,
"origin_ip": "203.0.113.10",
"headers": [{ "name": "X-Staging-Auth", "value": "k7Qp2vX9mR4tL8wZ" }],
"state": "pending",
"last_check_at": null,
"last_up_at": null,
"down_since": null,
"last_down": null,
"check_requested_at": "2026-10-20T09:12:41.000Z",
"last": {},
"cert_expires": null,
"created_at": "2026-10-20T09:12:41.000Z"
}
}
PATCH /api/uptime/monitors/:id
Send only the fields you change. headers replaces the whole list, so send every header you keep. This pauses a monitor:
curl -X PATCH https://app.coredash.app/api/uptime/monitors/6ad68c7a844fad80b752fd16 \
-H "Authorization: Bearer cdk_your_key" \
-H "Content-Type: application/json" \
-d '{ "paused": true }'
With a master key, project_id moves the monitor, by the same rules as on POST.
DELETE /api/uptime/monitors/:id
curl -X DELETE https://app.coredash.app/api/uptime/monitors/6ad68c7a844fad80b752fd16 \
-H "Authorization: Bearer cdk_your_key"
There is no undo. To stop the checks and keep the history, send { "paused": true } with PATCH.
Uptime API errors and limits
Errors come back as { "error": "..." } with one of these statuses:
| Status | When |
|---|---|
400 | The body breaks a rule. The error says which, see below. |
401 | Unauthorized: no key, an unknown, revoked or expired key, or a key tied to an expired project. |
403 | This token can only read. Use a CoreDash API key to change monitors.: a POST, PATCH or DELETE with an OAuth token (mcp_at_). A PATCH or DELETE on a monitor in a project where you are a guest gets 403 with Only the project's owners can change its monitors. |
404 | Monitor not found: the id doesn't exist, or the key can't see that monitor. |
405 | Method not allowed. |
400 error | Fix |
|---|---|
Choose a project for this monitor | Send project_id with a master key. |
project not found | The project_id isn't a project you own. Guests can't add monitors or move them there. |
This project's subscription has ended | Adding or moving a monitor needs a paid project or a running trial. |
A project can have up to 25 monitors | Delete one first, or use another project. |
A monitor must belong to a project | Leave project_id out of the PATCH, or send a project you own. |
url can't contain a username or password | For basic auth, send an Authorization header in headers. |
origin_ip is not an IP address, origin_ip must be a public IP address | Use the public address of the server itself. |
url must be a full http or https URL, e.g. https://www.example.com/, url must start with http:// or https://, headers must be a list of {name, value}, at most 5 headers, "…" isn't a valid header name (letters, numbers and dashes only), expect_status must be an HTTP status code | Fix the field the message names. Its rules are in the field table under POST. |
Limits: 25 monitors per project, 5 extra headers per monitor, 2100 checks per GET of one monitor, and 30 days of check history.
Uptime MCP tools
The CoreDash MCP server at https://app.coredash.app/api/mcp has two uptime tools next to the RUM tools, plus list_projects for the projects your key reaches. All three only read. To add, change or delete a monitor, use the app or the REST endpoints above with a CoreDash API key. The tools need no project_id: a project key reads its own project, a master key or an OAuth connection such as Claude reads every project you own or were invited to.
| Tool | Ask your agent | Returns |
|---|---|---|
list_projects | "Which sites can you see?" | { "projects": [...] } with project_id, name, url and role (owner or guest). |
list_uptime_monitors | "Is everything up?" | { "monitors": [...] }, with origin IP and header values masked. |
get_uptime_monitor | "Was the checkout down this week, and since when?" | { "monitor", "summary", "checks" }. Takes monitor_id and limit (default 100, at most 1000); summary gives rounds, down_rounds and uptime_pct over those checks. |
curl -X POST https://app.coredash.app/api/mcp \
-H "Authorization: Bearer cdk_your_key" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_uptime_monitor",
"arguments": { "monitor_id": "6ad68c7a844fad80b752fd16", "limit": 48 }
}
}'
The answer is the JSON-RPC wrapper of the CoreDash API, with the result as a JSON string in result.content[0].text. An unknown monitor gives { "error": "Monitor not found" } there, and result.isError is true.
More on uptime and the CoreDash API
- Uptime monitoring: what CoreDash checks and what you see in the app.
- CoreDash API: project keys, the JSON-RPC format and the RUM tools.
- Agency API: master keys and projects over REST.
- CoreDash bot: the user agent, the
X-CoreDash-Botheader and the addresses. - Let CoreDash through your firewall: for a monitor that says Blocked.