API, tokens and webhooks
Read status, events and reports with scoped, read-only tokens, browse the OpenAPI reference, and receive signed webhooks for every event.
5 min read · For admins and integrators
Other systems can work with a collector in two ways. They can ask, by calling the API with a read-only token, or be told, by webhooks that send each event as it happens. These webhooks are for systems; the alert webhooks in Settings › Alerts post a short message for people.
1. Create an API token
- Open Settings › API tokens.
- Under Create a token, enter a Name (what will use it) and choose Expires after: 30 days, 90 days or 1 year.
- To limit what it sees, tick device types under Limit to device types and sites under Limit to sites. Leave both empty for every device.
- Choose Create token and copy the token now. It isn't shown again: only a hash of it is stored.
curl -H "Authorization: Bearer mtr_…" https://monitoring.example.com/api/v1/status
curl -H "Authorization: Bearer mtr_…" "https://monitoring.example.com/api/v1/reports/availability?hours=720&format=csv"- GET /api/v1/status: every sensor in scope with its status, value and message.
- GET /api/v1/events?limit=100: recent status changes.
- GET /api/v1/availability?hours=24: for each sensor, how often it was checked in that time and how often it wasn't Down.
- GET /api/v1/reports/availability?hours=168&group=device&format=csv|json: the availability report.
- Tokens can also read sensor history, the Windows health and health review reports, traffic and the map. Settings › API lists them all.
Tokens are read-only: they can't change anything, sign in to the collector's pages or see users. A token sees only its device types and sites; anything else answers 404, as if it didn't exist. Revoke a token at any time; the list shows its last four characters, what it sees and when it was last used. AI assistants connect with a token too: see the AI assistant guide.
The API reference
The collector describes its whole API, including the routes its features add, as OpenAPI 3.1 at /api/v1/openapi.json. Settings › API shows it as a searchable page; set Who to API tokens to see what a token can read, or choose Download openapi.json for an API client or code generator. Every /api/ route also answers under /api/v1/, which scripts should use: endpoints marked stable keep working within version 1 and only gain additions, so ignore fields you don't know. A breaking change would come as /api/v2/, with /api/v1/ kept for at least 12 months; endpoints marked internal or experimental can change sooner.
2. Send events with webhooks
- Open Settings › Webhooks and choose + Add endpoint.
- Enter a Name and the receiver's Address, such as https://psa.example.com/hooks/monitaria.
- Under Events to send, keep All events, including kinds added later, or choose Only these and tick kinds such as sensor.status or incident.*. Optionally tick the sites and device types the events must be about.
- Choose Add endpoint, then copy the signing secret (whsec_…) into the receiver. It isn't shown again.
- Choose Send test. A webhook.test event goes out at once, and the result shows next to the endpoint.
- Under Settings, tick Send webhooks and choose Save settings. Events are only delivered from then on.
Each delivery is a POST with a JSON body (id, kind, ts, summary, collector, data and version) and an X-Monitaria-Signature header: t=<unix seconds>,v1=<hex>. The v1 value is the HMAC-SHA256 of the timestamp, a full stop and the raw body, keyed with the whole signing secret; check it against the raw bytes before parsing, and refuse timestamps more than five minutes old. Answer with any 2xx within 10 seconds; anything else is retried with growing pauses for up to 24 hours. A delivery can arrive more than once or out of order, so skip duplicates by the event id and order by ts.
import hashlib, hmac, time
def verify(secret: str, header: str, body: bytes, tolerance: int = 300) -> bool:
"""True when X-Monitaria-Signature matches the raw request body and is recent."""
parts = [p.split("=", 1) for p in (header or "").split(",") if "=" in p]
stamps = [v.strip() for k, v in parts if k.strip() == "t"]
signatures = [v.strip() for k, v in parts if k.strip() == "v1"]
if not stamps or not stamps[0].isdigit() or abs(time.time() - int(stamps[0])) > tolerance:
return False
expected = hmac.new(secret.encode(), stamps[0].encode() + b"." + body, hashlib.sha256).hexdigest()
return any(hmac.compare_digest(expected, s) for s in signatures)Good to know
- Webhooks go to https:// addresses. A receiver on your own network (a private address, or plain http:// to one) needs Allow addresses on your own network. Link-local and cloud metadata addresses are always refused, and every address is checked again before each delivery.
- New secret makes another signing secret. For 24 hours deliveries carry signatures made with both, so the receiver can switch over without missing anything.
- After 20 failed attempts in a row (about 13 hours; you can change the number in the settings), or a 410 Gone answer, an endpoint is paused and Settings › Webhooks shows a notice. Fix the receiver and choose Resume: deliveries less than 24 hours old go out then.
- sensor.status is sent for every status change, including ones the alert rules don't notify about; data.wanted is false for those.
- Each delivery also carries X-Monitaria-Event (the kind), X-Monitaria-Delivery (the same id on every retry) and X-Monitaria-Attempt. The Checking the signature panel on Settings › Webhooks shows how to check it in Python and Node.js.
- There can be up to 50 endpoints, and the delivery log keeps 7 days. Deliveries go straight to the receiver, without an HTTP proxy.
- The collector's clock signs each delivery, so keep the collector and the receiver on NTP.