Everything you can do with monitors in the dashboard, you can do over REST. Base URL: https://tracewarrior.com/api/v1. All requests and responses are JSON.
Authentication
API access is included in the Professional and Enterprise plans. Create a key in Dashboard → Profile → API keys. The full key (starting tw_) is shown once at creation; we store only a hash. Send it on every request:
curl https://tracewarrior.com/api/v1/monitors \ -H "Authorization: Bearer tw_your_key_here"
Requests without a valid key get 401. A valid key on a plan without API access gets 402.
Finding a monitor ID
Every monitor has a UUID. You can copy it from the monitor's page in the dashboard (next to the target, under the title), read it from the dashboard URL, or list your monitors with the API below: each monitor object includes its id.
Endpoints
GET /api/v1/monitors
List every monitor on your account.
curl https://tracewarrior.com/api/v1/monitors \
-H "Authorization: Bearer tw_your_key_here"
{
"monitors": [
{
"id": "45aee0f7-fab1-4471-9731-aaaa86c2cdd9",
"name": "Packet Collection",
"type": "ssl-expiry",
"target_host": "packetcollection.com",
"target_port": 443,
"target_path": null,
"interval_seconds": 900,
"state": "warning",
"state_since": "2026-06-12T20:00:41.000Z",
"last_check_at": "2026-06-12T20:15:41.000Z",
"next_check_at": "2026-06-12T20:30:41.000Z",
"paused": false,
"email_alerts": true,
"webhook_url": null,
"public_status_page": null,
"created_at": "2026-06-12T19:55:02.000Z",
"updated_at": "2026-06-12T20:00:41.000Z"
}
]
}GET /api/v1/monitors/:id
Fetch one monitor. Returns { "monitor": { … } } with the same shape as above, or 404 if the ID doesn't exist on your account.
POST /api/v1/monitors
Create a monitor. Plan limits apply exactly as in the dashboard (monitor count and minimum interval). Required fields: name, type, target_host, interval_seconds. target_host accepts a bare hostname or a full URL; we normalize it to a hostname.
curl -X POST https://tracewarrior.com/api/v1/monitors \
-H "Authorization: Bearer tw_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"name": "API SSL watch",
"type": "ssl-expiry",
"target_host": "api.example.com",
"target_port": 443,
"interval_seconds": 900,
"config": { "alertWarningDays": 30, "alertCriticalDays": 7 },
"email_alerts": true,
"webhook_url": "https://hooks.example.com/tw-alerts"
}'Returns 201 with the created monitor. If you supplied a webhook_url, the response also includes webhook_secret, shown once only: store it to verify alert signatures (see Webhooks below).
PATCH /api/v1/monitors/:id
Update a monitor. All fields optional: name, target_host, target_port, interval_seconds, config, email_alerts, recovery_alerts, webhook_url, paused. Adding a webhook_url to a monitor that never had one generates its webhook secret, returned once in the response.
curl -X PATCH https://tracewarrior.com/api/v1/monitors/45aee0f7-… \
-H "Authorization: Bearer tw_your_key_here" \
-H "Content-Type: application/json" \
-d '{ "paused": true }'DELETE /api/v1/monitors/:id
Permanently delete a monitor and its entire check and alert history. Returns { "deleted": true }.
Monitor types and config
The type field selects what gets checked; config carries type-specific settings.
ssl-expiry: certificate expiry ontarget_host:target_port(port required, usually 443). Config:{ "alertWarningDays": 30, "alertCriticalDays": 7 }http-status: HTTP(S) reachability and response checks. Config:{ "expectedStatus": [200, 204], "bodyMatch": "OK", "followRedirects": true }(bodyMatchoptional)dns-record: watches records for drift against a baseline. Config:{ "recordTypes": ["A", "MX"], "resolver": "cloudflare" }(resolvers:cloudflare,google,quad9,opendns)port-tcp: TCP connect check ontarget_host:target_port(port required). No config.whois-expiry: domain registration expiry. Config same asssl-expiry.
interval_seconds minimums by plan: 60 on Professional and Enterprise (the plans with API access). Private and internal hosts (RFC1918, loopback, .local and similar) are rejected at create time.
Webhooks
When a monitor with a webhook_url fires an alert, we POST a JSON payload to it and sign the raw body. Verify the X-TraceWarrior-Signature header before trusting it: the value is sha256=<hex>, an HMAC-SHA256 of the request body using your monitor's webhook secret as the key.
// Node.js verification
const crypto = require("node:crypto");
const expected = "sha256=" + crypto
.createHmac("sha256", WEBHOOK_SECRET)
.update(rawBody)
.digest("hex");
const valid = crypto.timingSafeEqual(
Buffer.from(signatureHeader), Buffer.from(expected));Errors
Errors return { "error": "…" } with a meaningful status: 400 invalid input, 401 missing or invalid key, 402 plan doesn't include the feature or you're at a plan limit, 404 monitor not found on your account.
Questions? Email support@tracewarrior.com.