API examples
Everything in the console is also available over the API. See the
API reference. This page has two complete Python examples. They use
the requests library (pip install requests). You need an API token first. See
API tokens.
Sync your checks declaratively
PUT /v1/tenants/{org}/checks reconciles your complete set of checks against
the request body, in one transaction. ZeroDrop creates or updates checks by name,
and deletes every check that the body does not contain. It validates the whole
set and applies the quota before it commits anything. A bad request therefore
changes nothing.
Use this endpoint for checks as code. Keep the desired state in your script or in a settings file under version control. Then run the script from a scheduled job or from a CI pipeline.
#!/usr/bin/env python3
"""Reconcile ZeroDrop's checks for this org against CHECKS below."""
import os
import requests
API_BASE = "https://zerodrop.app/api"
session = requests.Session()
session.headers["Authorization"] = "Bearer " + os.environ["ZERODROP_API_TOKEN"]
# The full desired state. Anything not listed here is deleted.
CHECKS = {
"http": [
{
"name": "marketing site",
"url": "https://example.com",
"expected_status": 200,
},
{
"name": "api",
"url": "https://api.example.com/healthz",
"expected_status": 401,
},
],
"smtp": [
{"name": "mail", "host": "mx.example.com", "port": 25},
],
}
def main():
me = session.get(f"{API_BASE}/v1/me")
me.raise_for_status()
org_id = me.json()["org_id"]
resp = session.put(f"{API_BASE}/v1/tenants/{org_id}/checks", json=CHECKS)
resp.raise_for_status()
result = resp.json()
print(f"created={result['created']} updated={result['updated']} deleted={result['deleted']}")
if __name__ == "__main__":
main()
Run the script with ZERODROP_API_TOKEN=zd_... python3 sync_checks.py. Every
field has the same name and meaning as on the check form. For the full list, see
Checks.
A second run with the same CHECKS value changes nothing. The sync replaces the
complete desired state and is not an incremental change. The result therefore
converges instead of a growing set of duplicate checks.
raise_for_status() turns a rejected request into a
requests.exceptions.HTTPError. The body stays available on
resp.json()["error"]. Use it to show the real reason instead of a generic
traceback.
Render a private dashboard
Status pages publish a set of checks on a public link with no sign-in. Sometimes that is not what you want. For example, the dashboard can be for your own team only, on an internal tool or on a screen in an ops room.
GET /v1/checks returns every check in your org with its current status. It uses
your API token like any other management call, so nothing is public unless you
publish it.
ZeroDrop does not cache this endpoint on the server the way it caches a status page, and reads have no rate limit. You can therefore call it as often as you want. The cache in the example only prevents a new request for each page view when several people watch your dashboard at the same time.
#!/usr/bin/env python3
"""Render a private check dashboard as HTML, with a small in-process cache."""
import html
import os
import time
import requests
API_BASE = "https://zerodrop.app/api"
CACHE_TTL_SECONDS = 15
session = requests.Session()
session.headers["Authorization"] = "Bearer " + os.environ["ZERODROP_API_TOKEN"]
_cache = {"checks": None, "expires_at": 0.0}
def fetch_checks():
if _cache["checks"] is not None and _cache["expires_at"] > time.monotonic():
return _cache["checks"]
resp = session.get(f"{API_BASE}/v1/checks")
resp.raise_for_status()
checks = resp.json()["checks"]
_cache["checks"] = checks
_cache["expires_at"] = time.monotonic() + CACHE_TTL_SECONDS
return checks
STATUS_ICON = {"ok": "🟢", "firing": "🔴", "unknown": "⚪"}
def render_dashboard():
rows = "".join(
f"<tr><td>{STATUS_ICON.get(c['status'], '⚪')} {html.escape(c['name'])}</td>"
f"<td>{html.escape(c['target'])}</td></tr>"
for c in fetch_checks()
)
return f"<!doctype html>\n<title>Status</title>\n<h1>Status</h1>\n<table>{rows}</table>\n"
if __name__ == "__main__":
print(render_dashboard())
render_dashboard returns a plain HTML string. It fits into whatever already
serves your internal tool: a route handler in your web framework, a Slack app, or
a scheduled job that posts the HTML somewhere.
The cache in the example is a module-level dict. It is correct for a single process. Behind more than one worker, use a shared cache such as Redis, so the workers do not all call the API on their own.
CAUTION:
session.headers["Authorization"]carries your API token. Treat this script, and the machine that runs it, like the token itself. Never run the script in a browser or anywhere that a visitor can read its source. Send its output only to people that you trust with the token.
The status of each check is ok, firing, or unknown. These are the three
states in Consensus & status. To also show recent
downtime, add a call to GET /v1/checks/{id}/incidents. The
API reference has the full response shape.
The example escapes every field from the response with html.escape before it
puts the field in HTML. Your check names are text that you entered, so they are
trusted from your side. A page that another person renders must never make this
assumption.