API and feeds
Official AI changes and incidents, ready for your app.
Read public JSON from ClaudeMon, or subscribe with your feed reader. Every change retains its original source.
Your first request
Public reads work without an API key.
const response = await fetch("https://claudemon.com/api/v1/changes?limit=3");
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const { data } = await response.json();
console.log(data);import requests
response = requests.get("https://claudemon.com/api/v1/changes?limit=3", timeout=30)
response.raise_for_status()
print(response.json()["data"])curl "https://claudemon.com/api/v1/changes?limit=3"fetch. Python uses requests (pip install requests).Explore the API
/api/v1/changesOfficial changes, newest firstGET /api/v1/changes/{id}One change by IDGET /api/v1/incidentsActive and recently resolved incidentsGET /api/v1/sourcesSources and their freshnessGET /api/v1/statusA freshness summaryGET /api/v1/healthA liveness probeGET /feeds/changes.atomAtom, RSS and JSON FeedGET /status.jsonThe status page and its filesAll routes and methods
| Endpoint | What it returns |
|---|---|
GET /api/v1/changes | Official changes, newest first |
GET /api/v1/changes/{id} | One change by ID |
GET /api/v1/incidents | Active and recently resolved incidents |
GET /api/v1/sources | Sources and their freshness |
GET /api/v1/status | A freshness summary |
GET /api/v1/health | A liveness probe |
GET /feeds/changes.atom | Atom, RSS and JSON Feed |
GET /status.json | The status page and its files |
POST /api/v1/keys | Request an email verification link |
GET / DELETE /api/v1/keys/me | Inspect or revoke the calling key |
GET / POST /api/v1/subscriptions | List or create email subscriptions |
DELETE /api/v1/subscriptions/{id} | Disable an owned subscription |
GET / POST /keys/verify | Confirm the email link and show a key once |
GET / POST /alerts/unsubscribe | Confirm or perform signed unsubscribe |
Base URL
Every path is relative to https://claudemon.com. Responses are JSON (application/json) unless a page says otherwise. Times are ISO 8601 in UTC.
Authentication
Change, source, status and health reads are public and need no key. Send an optional Authorization: Bearer cm_live_... API key for a higher rate limit. Key management and subscriptions require a valid key; an invalid or revoked key returns 401. Request a single-use sign-in link with POST /api/v1/keys and a JSON email field.
Rate limits
On /api/v1/*, each client IP has a shared allowance of 600 units per minute. Anonymous and invalid-key requests use two units (up to 300 requests); a valid key uses one IP unit and one unit from its own 600-per-minute allowance. Exhausted limits return 429 with Retry-After: 60. Sign-in links have additional limits of 3 per address and 10 per IP per hour. Please poll at most once a minute and send conditional requests. Feeds do not use this API limiter.
Caching and ETags
Changes, single changes, incidents and feeds send a strong ETag; sources, status and health do not. Send it back as If-None-Match and an unchanged response answers 304 with no body. Feeds also send Last-Modified when the deploy time is known, and honor If-Modified-Since.
Cache-Control differs by endpoint and is listed on each page. Health is no-store and status is no-cache.
curl -H 'If-None-Match: "<etag>"' -G \
"https://claudemon.com/api/v1/changes" \
--data-urlencode "limit=1"
Pagination
Lists return data, next_cursor and has_more. Pass next_cursor back as cursor for the next page; the same URL is also in the Link header with rel="next".
A cursor is tied to the filters it came from. With other filters it answers 400 invalid_cursor. Change pages are a live view: a change revised between two requests can move between pages.
Views for people
The bare URL always serves compact JSON. Two parameters change only the presentation, on any /api/v1 endpoint:
prettybooleanOptional1ortrueindents the JSON.0andfalseare accepted and change nothing.formatstringOptionalhtmlshows the JSON on a readable page.jsonis the default.
Errors
Errors are application/problem+json (RFC 9457) with code, request_id and, for a bad parameter, param. Unknown query parameters are refused rather than ignored, except on sources, status and health.
{
"type": "https://claudemon.com/problems/invalid_parameter",
"title": "Invalid parameter",
"status": 400,
"detail": "limit must be an integer from 1 to 100",
"instance": "urn:request:8d2f3c1b7a9e4b21",
"code": "invalid_parameter",
"param": "limit",
"request_id": "8d2f3c1b7a9e4b21"
}
GET /api/v1/changes?limit=0. The request ID differs on every request.invalid_parameter400. A parameter is unknown or has a bad value.since,prettyandformatalso refuse a second value; other single-value parameters read the first.invalid_cursor400. The cursor is malformed or from other filters.not_found404. No route or no change with that ID.method_not_allowed405. OnlyGET,HEADandOPTIONSare served.internal_error500. The request failed on our side. Retry later.
CORS
/api/v1 and /feeds answer any origin (Access-Control-Allow-Origin: *) and expose ETag, Link and X-Request-Id to browser code.
Feeds
Subscribe in any reader with Atom, RSS or JSON Feed, filtered like the changes API.