IronWatchDocs
Dashboard
synced 2026-05-29·/api/v1 + ping routes@live
PingWatch · API reference

API reference

Two surfaces: the authenticated /api/v1/monitorsREST API for managing monitors, and the unauthenticated ping & badge endpoints your jobs hit by UUID or slug. New to PingWatch? Start with the quickstart.

Base URL & authentication

The base URL is https://pingwatch.dev. The /api/v1 management routes require a Bearer token (pw_live_…) created in Settings → API keys. A missing, placeholder, invalid, or revoked key returns 401. Create / update / delete also require a key with the write scope; read-only keys get 403.

Header
Authorization: Bearer pw_live_a1b2c3d4e5f6...

Monitors

A monitor is one heartbeat expectation. Full CRUD lives under /api/v1/monitors (GET, POST, GET /:id, PATCH /:id, DELETE /:id).

POST/api/v1/monitors
Bearertier monitor cap

Create a monitor. Returns the full monitor object in status 'new'.

Request body
name
string·REQUIRED
Human-readable label for the monitor. Max 100 characters.
schedule
string·REQUIRED
Expected interval between heartbeats. A number plus a unit: s, m, h, or d.
"30s""5m""1h""24h"
gracePeriodSeconds
integer·OPTIONAL
Slack allowed past the interval before the monitor is considered late. 60–86400 seconds.
default·300
slug
string·OPTIONAL
Optional custom ping slug (lowercase letters, numbers, single dashes; 2–64 chars). Globally unique. Send null or "" to leave unset.
Responses
201Created
Monitor created. The body is the full monitor object, starting in status "new" with no pings yet.
400Bad Request
Validation failed — missing/oversized name, unparseable schedule, grace period out of range, or an invalid slug.
error.codeName is required (max 100 chars)Invalid schedule. Use format like 5m, 1h, 24hGrace period must be between 60 and 86400 secondsslug must be lowercase letters, numbers, and single dashes …
401Unauthorized
Missing, placeholder, invalid, or revoked API key.
403Forbidden
Read-only key (no write scope), or your tier's monitor limit has been reached.
error.codeThis API key is read-only …Monitor limit reached (N). Upgrade your plan for more.
409Conflict
The requested slug is already in use by another monitor.
error.codeSlug "…" is already in use by another monitor.
Request
POST /api/v1/monitors
curl -X POST "https://pingwatch.dev/api/v1/monitors" \
  -H "Authorization: Bearer <PINGWATCH_API_KEY>" \
  -H "Content-Type: application/json" \
  -d {
       "name": "Nightly DB backup",
       "schedule": "24h",
       "gracePeriodSeconds": 600
     }'
Response201Created
application/json
{
"id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"userId": "8RXc1Pm9-2b3c-4d5e-6f70-8192a3b4c5d6",
"name": "Nightly DB backup",
"slug": null,
"schedule": "24h",
"scheduleType": "interval",
"gracePeriodSeconds": 600,
"status": "new",
"lastPingAt": null,
"lastPingType": null,
"nextExpectedAt": null,
"alertSentAt": null,
"consecutiveMisses": 0,
"isPaused": false,
"createdAt": "2026-05-29T17:55:00.000Z",
"updatedAt": "2026-05-29T17:55:00.000Z"
}
GET/api/v1/monitors
Bearerread

List every monitor owned by the key's user, oldest first.

Responses
200OK
Body is { monitors: [...] } — every monitor owned by the key's user, oldest first.
401Unauthorized
Bad or missing API key.
Request
GET /api/v1/monitors
curl -X GET "https://pingwatch.dev/api/v1/monitors" \
  -H "Authorization: Bearer <PINGWATCH_API_KEY>" \
Response200OK
application/json
{
"monitors": [
{16 fields}
]
}
GET/api/v1/monitors/{id}
Bearerread

Fetch a single monitor plus its 50 most recent ping events.

Path parameters
id
string·REQUIRED
The monitor UUID.
Responses
200OK
Body is { monitor, events } — the monitor object plus its 50 most recent ping events (newest first).
401Unauthorized
Bad or missing API key.
404Not Found
No monitor with that id belongs to the key's owner.
Request
GET /api/v1/monitors/{id}
curl -X GET "https://pingwatch.dev/api/v1/monitors/:id" \
  -H "Authorization: Bearer <PINGWATCH_API_KEY>" \
Response200OK
application/json
{
"monitor": {
"id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"userId": "8RXc1Pm9-2b3c-4d5e-6f70-8192a3b4c5d6",
"name": "Nightly DB backup",
"slug": null,
"schedule": "24h",
"scheduleType": "interval",
"gracePeriodSeconds": 600,
"status": "healthy",
"lastPingAt": null,
"lastPingType": "success",
"nextExpectedAt": null,
"alertSentAt": null,
"consecutiveMisses": 0,
"isPaused": false,
"createdAt": "2026-05-29T17:55:00.000Z",
"updatedAt": "2026-05-29T17:55:00.000Z"
},
"events": [
{8 fields},
{8 fields}
]
}
PATCH/api/v1/monitors/{id}
Bearertier monitor cap

Partially update a monitor — name, schedule, grace period, pause state, or slug. Only the fields you send change.

Path parameters
id
string·REQUIRED
The monitor UUID.
Request body
name
string·OPTIONAL
New label. Max 100 characters.
schedule
string·OPTIONAL
New expected interval (e.g. 5m, 1h, 24h).
gracePeriodSeconds
integer·OPTIONAL
New grace period. 60–86400 seconds.
isPaused
boolean·OPTIONAL
Pause or resume the monitor. While paused, pings are logged but never trigger or clear alerts.
slug
string·OPTIONAL
Set, change, or clear the custom slug. Send null or "" to clear. Globally unique.
Responses
200OK
The full updated monitor object. Only the fields you sent change.
400Bad Request
A supplied field failed validation (name, schedule, grace, or slug).
401Unauthorized
Bad or missing API key.
403Forbidden
The key is read-only (no write scope).
404Not Found
No monitor with that id belongs to the key's owner.
409Conflict
The requested slug is already in use by another monitor.
Request
PATCH /api/v1/monitors/{id}
curl -X PATCH "https://pingwatch.dev/api/v1/monitors/:id" \
  -H "Authorization: Bearer <PINGWATCH_API_KEY>" \
  -H "Content-Type: application/json" \
  -d {
       "slug": "nightly-backup",
       "gracePeriodSeconds": 900
     }'
Response200OK
application/json
{
"id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"userId": "8RXc1Pm9-2b3c-4d5e-6f70-8192a3b4c5d6",
"name": "Nightly DB backup",
"slug": "nightly-backup",
"schedule": "24h",
"scheduleType": "interval",
"gracePeriodSeconds": 900,
"status": "new",
"lastPingAt": null,
"lastPingType": null,
"nextExpectedAt": null,
"alertSentAt": null,
"consecutiveMisses": 0,
"isPaused": false,
"createdAt": "2026-05-29T17:55:00.000Z",
"updatedAt": "2026-05-29T17:55:00.000Z"
}
DELETE/api/v1/monitors/{id}
Bearerwrite

Delete a monitor and its ping history. Returns { deleted: true }.

Path parameters
id
string·REQUIRED
The monitor UUID.
Responses
200OK
Body is { deleted: true }. The monitor and its ping history are removed.
401Unauthorized
Bad or missing API key.
403Forbidden
The key is read-only (no write scope).
404Not Found
No monitor with that id belongs to the key's owner.
Request
DELETE /api/v1/monitors/{id}
curl -X DELETE "https://pingwatch.dev/api/v1/monitors/:id" \
  -H "Authorization: Bearer <PINGWATCH_API_KEY>" \
Response200OK
application/json
{
"deleted": true
}

Ping endpoints

These are the URLs your job actually calls. No auth — the monitor's UUID (or slug) is the secret. Each accepts GET or POST; a POSTbody is captured with the event, subject to your tier's body cap. The HTTP response is always the plain text OK (200) or Not found (404); the monitor state is updated asynchronously after the response is returned.

GET/api/ping/{id}
Bearerunauthenticated

Record a SUCCESS beat: monitor → healthy, stale timer reset, consecutive misses cleared, and a recovery alert fired if it had been down or late.

Path parameters
id
string·REQUIRED
The monitor's UUID or its custom slug. Anything matching the UUID shape resolves by id; otherwise it resolves by slug.
Responses
200OK
Beat accepted. The response body is the literal text OK; the monitor is updated asynchronously. A paused monitor still returns 200 but records the ping without changing state or alerting.
404Not Found
No monitor matched the id or slug. Body is the literal text Not found.
Request
GET /api/ping/{id}
curl -fsS "https://pingwatch.dev/api/ping/d290f1ee-6c54-4b01-90e6-d701748f0851"
Response200OK
application/json
"OK"
GET/api/ping/{id}/start
Bearerunauthenticated

Record a START: stamps the run-start so a later success can be timed (start → success duration). Does not reset the stale timer on its own.

Path parameters
id
string·REQUIRED
The monitor's UUID or its custom slug. Anything matching the UUID shape resolves by id; otherwise it resolves by slug.
Responses
200OK
Beat accepted. The response body is the literal text OK; the monitor is updated asynchronously. A paused monitor still returns 200 but records the ping without changing state or alerting.
404Not Found
No monitor matched the id or slug. Body is the literal text Not found.
Request
GET /api/ping/{id}/start
curl -fsS "https://pingwatch.dev/api/ping/d290f1ee-6c54-4b01-90e6-d701748f0851/start"
Response200OK
application/json
"OK"
GET/api/ping/{id}/fail
Bearerunauthenticated

Record a FAIL: monitor → down immediately and an alert fires (deduplicated — one per outage). Use this when the job itself errored.

Path parameters
id
string·REQUIRED
The monitor's UUID or its custom slug. Anything matching the UUID shape resolves by id; otherwise it resolves by slug.
Responses
200OK
Beat accepted. The response body is the literal text OK; the monitor is updated asynchronously. A paused monitor still returns 200 but records the ping without changing state or alerting.
404Not Found
No monitor matched the id or slug. Body is the literal text Not found.
Request
GET /api/ping/{id}/fail
curl -fsS "https://pingwatch.dev/api/ping/d290f1ee-6c54-4b01-90e6-d701748f0851/fail"
Response200OK
application/json
"OK"

Status badge

A live SVG badge for any monitor, by UUID or slug. No auth. Embed it in a README, wiki, or status page. The badge shows the monitor name and its current state; a paused monitor reads paused, and an unknown id renders a not found badge with a 404 status.

GET/api/badge/{id}
Bearerunauthenticated

Render the monitor's status as an SVG (image/svg+xml). Cached 30s for a real monitor, 60s for a miss.

Path parameters
id
string·REQUIRED
The monitor's UUID or its custom slug. Anything matching the UUID shape resolves by id; otherwise it resolves by slug.
Responses
200OK
An SVG badge labelled with the monitor name and its state (healthy / new / late / down / paused). Content-Type: image/svg+xml.
404Not Found
No monitor matched. Still returns an SVG — a grey "not found" badge — with a 404 status.
Request
GET /api/badge/{id}
synced
![backup status](https://pingwatch.dev/api/badge/nightly-backup)

Errors

The /api/v1 routes return JSON with an error string. The ping and badge routes are plain-text / SVG instead (they aren't meant to be parsed by a client).

StatusMeaning
200Beat accepted, or monitor read/updated
400Invalid body, missing/oversized name, bad schedule, grace out of range, or invalid slug
401Missing, placeholder, invalid, or revoked API key (v1 routes)
403Read-only key (no write scope), or tier monitor limit reached
404Monitor not found (v1 by owned id; ping/badge by id or slug)
409Slug already in use by another monitor

Tier limits

TierMax monitorsHistoryBody captureAlert channels
Free57 daysnoneemail
Starter2030 days10 KBemail · slack · webhook
Pro10090 days100 KB+ pagerduty
Business500365 days512 KB+ discord

tip Custom slugs are available on every tier. See live numbers and upgrade on the pricing page.