Diffmonitors API
A small REST API for creating monitors and a streaming API for consuming their diffs. Base URL https://api.diffmonitors.com/v1.
Quickstart
Authenticate with a bearer token, create a monitor, and you’ll receive a baseline event followed by one event per detected change.
export DIFFMONITORS_API_KEY="dm_live_…"
curl https://api.diffmonitors.com/v1/monitors \
-H "Authorization: Bearer $DIFFMONITORS_API_KEY" \
-d url="https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_day.geojson" \
-d interval="1m" \
-d ignore="metadata.generated,bbox"Monitors
A monitor is a URL plus a cadence and optional request settings.
POST/v1/monitorsCreate a monitorGET/v1/monitorsList monitorsPATCH/v1/monitors/:idUpdate cadence, rules or deliveryDELETE/v1/monitors/:idDelete a monitorPOST/v1/monitors/bulkCreate up to 10,000 monitors (Enterprise)1{2 "url": "https://example.com/pricing",3 "interval": "1h | 1m | 1s | 100ms (Enterprise: rate agreed per target)",4 "method": "GET",5 "headers": {6 "x-api-key": "{{secret:vendor_key}}"7 },8 "selector": "main .pricing",9 "ignore": [10 "updated_at",11 "features.*.properties.updated"12 ],13 "when": "plans[0].price < 49",14 "notify": [15 {16 "type": "webhook",17 "url": "https://example.com/hooks/diff"18 },19 {20 "type": "slack",21 "channel": "#pricing-intel"22 }23 ]24}
Events
Every check that produces a difference emits a monitor.changed event. Events contain a summary and an RFC 6902 JSON Patch from the previous snapshot.
GET/v1/monitors/:id/eventsPaginated event historyGET/v1/snapshots/:etagFetch a stored snapshotGET/v1/monitors/:id/diff?from=…&to=…Diff any two points in timeWebhooks
Webhooks are POSTed as JSON and signed with HMAC-SHA256 in the x-diffmonitors-signature header (t=timestamp,v1=signature). Failed deliveries retry with exponential backoff for 24 hours.
import { createHmac, timingSafeEqual } from "node:crypto"
export function verify(body: string, header: string, secret: string) {
const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")))
const expected = createHmac("sha256", secret).update(`${t}.${body}`).digest("hex")
return timingSafeEqual(Buffer.from(v1), Buffer.from(expected))
}Streaming
Pro plans can subscribe to a monitor’s events over Server-Sent Events. Enterprise plans add a multiplexed WebSocket firehose across all monitors.
const es = new EventSource("https://stream.diffmonitors.com/v1/monitors/mon_8f2c1a/events?token=" + token)
es.addEventListener("monitor.changed", (e) => console.log(JSON.parse(e.data).patch))Ignore rules
Rules are applied before diffing. A bare key such as time matches that key at any depth. A dotted path such as metadata.generated matches exactly, and * matches any key or array element. Arrays of objects are matched by id, uuid, key, slug, code or name when present.
Rate limits
| Free | 1 check / hour / endpoint | No API access |
| Pro | 1 check / minute / endpoint | 600 API requests / min |
| Enterprise | Custom per target, up to 100 checks / second | Custom |