Browse API docsOverview

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.

TypeScript
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);
TypeScript and JavaScript use native fetch. Python uses requests (pip install requests).

JSON responses include an opaque cursor for the next page.

Explore the API

All routes and methods
EndpointWhat it returns
GET /api/v1/changesOfficial changes, newest first
GET /api/v1/changes/{id}One change by ID
GET /api/v1/incidentsActive and recently resolved incidents
GET /api/v1/sourcesSources and their freshness
GET /api/v1/statusA freshness summary
GET /api/v1/healthA liveness probe
GET /feeds/changes.atomAtom, RSS and JSON Feed
GET /status.jsonThe status page and its files
POST /api/v1/keysRequest an email verification link
GET / DELETE /api/v1/keys/meInspect or revoke the calling key
GET / POST /api/v1/subscriptionsList or create email subscriptions
DELETE /api/v1/subscriptions/{id}Disable an owned subscription
GET / POST /keys/verifyConfirm the email link and show a key once
GET / POST /alerts/unsubscribeConfirm 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.

Request
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:

prettybooleanOptional
1 or true indents the JSON. 0 and false are accepted and change nothing.
formatstringOptional
html shows the JSON on a readable page. json is the default.

Each view has its own ETag. Feeds and /status.json do not take these parameters.

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.

Error400 application/problem+json
{
  "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"
}
The body of GET /api/v1/changes?limit=0. The request ID differs on every request.
invalid_parameter
400. A parameter is unknown or has a bad value. since, pretty and format also refuse a second value; other single-value parameters read the first.
invalid_cursor
400. The cursor is malformed or from other filters.
not_found
404. No route or no change with that ID.
method_not_allowed
405. Only GET, HEAD and OPTIONS are served.
internal_error
500. 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.