REST API
The API manages one project's checks, incidents, and alert channels. The machine-readable description is the OpenAPI 3.1 document. AI agents can use the same operations over MCP.
Authentication
Create a key under Project settings → API keys and send it as a bearer token:
curl https://checkpulse.foo/api/v1 -H "Authorization: Bearer cpk_…"
X-Api-Key: cpk_… also works. Keys are read-only or read-write and belong to a single project. GET /api/v1 describes the project, the key's scope, limits, and usage, and is a good first call.
Requests
- Send JSON with
Content-Type: application/json. Unknown fields are rejected, so typos surface as errors. {check}in a path is a numeric ID or a slug.- Durations (
period,grace,duration) accept seconds or strings such as"90s","5m","1h","1d". tagsandfailure_keywordsaccept a string or an array of strings.channelsaccepts"*"(every channel) or an array of channel IDs.- Times are RFC 3339 in UTC.
Errors
Errors use RFC 9457 problem details with Content-Type: application/problem+json:
{
"type": "about:blank",
"title": "Bad Request",
"status": 400,
"code": "invalid_period",
"field": "period",
"detail": "Interval must be at least 1m on this account."
}
code is stable for programs; detail and, when present, hint explain what to do. Common codes:
| Code | Status | Meaning |
|---|---|---|
unauthorized | 401 | Missing, invalid, expired, or revoked key. |
read_only_key | 403 | The key cannot make changes. |
limit_reached | 403 | An account limit (checks, channels, keys) is reached. |
check_not_found, not_found | 404 | No such resource in this project. |
slug_taken | 409 | Another check uses that slug. |
invalid_<field>, invalid_json | 400 | The request is not valid; see field and detail. |
idempotency_key_reused | 422 | The Idempotency-Key was used for a different request. |
rate_limited | 429 | Too many requests; wait for Retry-After seconds. |
Idempotency
Send Idempotency-Key: <unique value> with any write. Retrying with the same key within 24 hours returns the stored response, including error responses with their application/problem+json type, marked Idempotent-Replayed: true instead of repeating the change. A retry that arrives while the first request is still running gets 409 request_in_progress; a request that never finished releases its key after two minutes. PUT /api/v1/checks/{slug} is idempotent by design.
Rate limits
Each key may make 60 requests a minute on free accounts. Responses include RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset; a 429 includes Retry-After.
Pagination
Lists of pings and audit entries return newest first. Pass the next_before value (pings) or the last entry's id (audit) as before to fetch older items.
Endpoints
| Method and path | Scope | Purpose |
|---|---|---|
GET /api/v1 | read | Project, key, counts, limits, usage, and links. |
GET /api/v1/checks | read | List checks. Filters: status, tag, slug, q. |
POST /api/v1/checks | write | Create a check. |
GET /api/v1/checks/{check} | read | Get a check. |
PUT /api/v1/checks/{slug} | write | Create or update by slug (201 created, 200 updated). |
PATCH /api/v1/checks/{check} | write | Change some fields. |
DELETE /api/v1/checks/{check} | write | Delete; restorable for 7 days. |
POST /api/v1/checks/{id}/restore | write | Restore a deleted check. |
POST /api/v1/checks/{check}/pause | write | Pause. |
POST /api/v1/checks/{check}/resume | write | Resume. |
POST /api/v1/checks/{check}/silence | write | Hold alerts: {"duration": "2h", "reason": "…"}. |
DELETE /api/v1/checks/{check}/silence | write | End a silence. |
POST /api/v1/checks/{check}/rotate-token | write | Issue a new ping URL. |
GET /api/v1/checks/{check}/pings | read | Recent pings. limit, before, include_system. |
GET /api/v1/incidents | read | Incidents. status (open, closed, all), check. |
GET /api/v1/incidents/{id} | read | One incident with notes. |
POST /api/v1/incidents/{id}/acknowledge | write | Acknowledge, optionally with {"note": "…"}. |
POST /api/v1/incidents/{id}/notes | write | Add {"note": "…"}. |
GET /api/v1/channels | read | Alert channels. |
POST /api/v1/channels | write | Add a channel (see Alert channels). |
PATCH /api/v1/channels/{id} | write | enabled, notify_down, notify_up, repeat_minutes. |
DELETE /api/v1/channels/{id} | write | Remove a channel. |
POST /api/v1/channels/{id}/test | write | Send a test alert. |
GET /api/v1/audit | read | Recent changes and who made them. |
GET /api/v1/badges | read | Status badge URLs. |
GET /api/v1/metrics | read | Prometheus metrics. |
GET /api/v1/openapi.json | none | The OpenAPI document. |
Check fields
| Field | Notes |
|---|---|
name, slug | The slug is unique in the project, uses lowercase letters, digits, and hyphens, and must contain a letter. |
description, runbook | The runbook is Markdown included in alerts; write it for whoever responds, people or agents. |
tags | Used for filtering, badges, and metrics. |
kind | interval (with period) or cron (with cron and timezone). |
grace | See Schedules. |
methods | any or post. |
manual_resume | When true, pings do not resume a paused check. |
failure_keywords | Output containing any of these fails a success ping. |
channels | Channels that receive this check's alerts. |
Responses add status, last_ping, next_due, started_at, last_duration_seconds, silenced_until, open_incident, and, for read-write keys only, the secret ping_url and slug_ping_url.
Examples
Create or update a cron check:
curl -X PUT https://checkpulse.foo/api/v1/checks/db-backup \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"name": "DB backup", "kind": "cron", "cron": "0 3 * * *", "timezone": "Europe/Paris", "grace": "30m", "runbook": "Check free disk space on db-1, then rerun."}'
List checks that are down:
curl "https://checkpulse.foo/api/v1/checks?status=down" -H "Authorization: Bearer $KEY"
Acknowledge an incident:
curl -X POST https://checkpulse.foo/api/v1/incidents/42/acknowledge \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"note": "Disk full on db-1; clearing old WAL files."}'