API
REST API for certificate monitoring: add, delete and re-check domains, read health scores and history. Token auth, JSON in and out, from Starter up.
The REST API lets you script what you would otherwise do in the browser: add and remove domains,
trigger checks, and read health scores. It is available on Starter and Pro at /api/v1/....
Everything is JSON, in and out.
Getting a token
- Go to Settings → API token.
- Copy the token and send it in the
Authentication-Tokenheader on every request:
curl https://certwatchr.com/api/v1/domains \
-H 'Authentication-Token: <YOUR-TOKEN>'
Treat the token like a password: anyone holding it can add, remove and inspect your domains. If it appears in a shared log, a CI job output or a screenshot, rotate it.
Rotate token on the same page issues a new token and invalidates the old one immediately, so update your scripts straight after. Rotating does not sign you out of the web app, and changing your password does not change your token.
Domains
GET /api/v1/domains # list your domains
POST /api/v1/domains # add a domain
DELETE /api/v1/domains/<id> # remove a domain
POST /api/v1/domains/<id>/check # run a certificate check now
Adding a domain
curl -X POST https://certwatchr.com/api/v1/domains \
-H 'Authentication-Token: <YOUR-TOKEN>' \
-H 'Content-Type: application/json' \
-d '{"hostname":"example.com","port":443,"alert_at_days":30,"tags":["prod","web"]}'
| Field | Required | Notes |
|---|---|---|
hostname |
yes | Lowercased and trimmed for you. Up to 255 characters. |
port |
no | 1–65535. Defaults to 443. |
label |
no | Up to 128 characters. |
alert_at_days |
no | 1–365 (Free accounts: up to 30). Defaults to 30. |
tags |
no | A list (["prod","web"]) or a comma-separated string ("prod,web"). Stored the same way the web form stores them. |
Adding a hostname and port you already monitor returns 409 Conflict and leaves the existing domain untouched, so re-running a script is safe. Your plan's domain limit applies exactly as it does in the browser.
Domain objects
Every domain is returned in this shape:
{
"id": 42,
"hostname": "example.com",
"port": 443,
"label": "Main site",
"tags": ["prod", "web"],
"alert_at_days": 30,
"status": "ok",
"days_remaining": 67,
"cert_expiry": "2026-11-28T09:14:00",
"cert_issuer": "Let's Encrypt",
"cert_subject": "example.com",
"last_checked_at": "2026-09-22T06:00:12",
"alerts_snoozed_until": null
}
status is untested, ok, warning, critical or error. POST .../check answers
202 {"queued": true}; the result appears on the domain a few seconds later.
Health score
GET /api/v1/domains/<id>/health # latest score, breakdown, suggestions
POST /api/v1/domains/<id>/health/check # run a health check now
GET /api/v1/domains/<id>/health/history?limit=90 # score over time, oldest first
GET /health returns the stored result without running a new check:
{
"health_score": 90,
"breakdown": {
"chain_trusted": 20,
"hostname_match": 15,
"not_yet_valid": 5,
"expiry_proximity": 20,
"revocation": 10,
"chain_complete": 0,
"tls_version": 10,
"weak_algorithms": 10
},
"certificate": {
"subject": "example.com",
"issuer": "Let's Encrypt",
"days_remaining": 67
},
"errors": ["Incomplete chain: server did not send its intermediate certificate"],
"suggestions": [
{
"category": "chain_complete",
"points": 10,
"severity": "critical",
"title": "Send the intermediate certificates too",
"why": "..."
}
],
"last_health_checked_at": "2026-09-22T06:30:00"
}
The categories and points are the ones on the Health score page.
suggestions is the same "what to fix" list the domain page shows, most urgent first.
history returns one entry per past check with health_score, breakdown, tls_version,
signature_algorithm, errors and checked_at. limit defaults to 90 and goes up to 365.
Errors
Every error is JSON with a matching HTTP status, including authentication failures — you never get an HTML page or a redirect to the login form:
{"error": "Conflict", "message": "example.com:443 is already being monitored."}
| Status | Meaning |
|---|---|
400 |
The body is not valid JSON, or a field failed validation. The message says which. |
401 |
Missing or invalid Authentication-Token. |
403 |
Your plan does not include this endpoint, the domain is not yours, or you are at your domain limit. |
404 |
No such domain. |
409 |
That hostname and port are already monitored on your account. |
5xx responses are safe to retry with a short delay. 4xx responses will not change until you
change the request.