API
CertWatch's dashboard is a client of its own /v1 HTTP/JSON API. There's no separate public
API key today — authenticated routes use the same session cookie the dashboard sets on login, and one
route (the certificate checker) is intentionally open with no account required.
Authentication
POST /v1/login and POST /v1/signup set an HttpOnly,
SameSite=Lax session cookie good for 30 days from creation (not a sliding window).
POST /v1/logout clears it and works even against an already-expired or missing cookie.
Forgotten-password flows (/v1/password-reset/request, /v1/password-reset/confirm)
don't require a session, for the obvious reason, and never reveal whether a given email has an account.
Endpoints and domains
Session-gated. The shapes mirror what the dashboard shows:
| Method | Path | What it does |
|---|---|---|
| GET | /v1/endpoints | List TLS endpoints, newest first. |
| POST | /v1/endpoints | Add one — {hostname, port, label}, port defaults to 443. |
| PATCH | /v1/endpoints/{id} | Partial update — label, hostname/port, active state, or mute. |
| DELETE | /v1/endpoints/{id} | Remove one. |
| GET | /v1/endpoints/{id}/checks | Check history, most recent first. |
| GET | /v1/domains | List monitored domains. |
| POST | /v1/domains | Add one — {name}, a registrable domain like example.com. |
| GET | /v1/account | Plan, limits, and current usage. |
| PATCH | /v1/account | Update notification email, Slack/webhook URLs (Pro), or display name. |
Adding an endpoint or domain past your plan's limit returns 403 endpoint_limit_reached /
403 domain_limit_reached; a literal duplicate returns 409. Every mutating route
is scoped strictly to the caller's own account — another account's resource id 404s rather than 403ing, so
a guessed id can't be used to confirm it exists.
Public certificate check
POST /v1/check — {host} (a hostname[:port] string, port defaults to
443). No authentication, nothing persisted: runs one TLS check and returns the result plus a computed
status (healthy / warning / critical / expired /
error), the same thresholds the dashboard uses. Rate-limited per client IP
(429 rate_limited, with Retry-After) since it requires no account to attribute
requests to.
Billing
POST /v1/billing/checkout and POST /v1/billing/portal return hosted Stripe
links for upgrading and for managing an existing subscription (plan changes, cancellation, payment
methods) respectively — see Billing for what each plan includes.
Validation and abuse controls
Hostnames and webhook URLs are checked against internal/private address ranges both when you save them and again at dial time (so a hostname that later resolves somewhere internal via DNS rebinding still gets caught) — CertWatch never dials loopback, link-local, RFC 1918/IPv6 unique-local, CGNAT, multicast, or unspecified addresses on your behalf.