HeaderTest API
A free, open API for scanning a site's HTTP security headers and Content Security Policy. No sign-up, no API key — built to be called by scripts and AI agents.
For AI agents
Base URL https://headertest.com/api. No authentication and no rate limiting. Scanning is asynchronous:
POST /api/analyze→ returns ajob_idimmediately.- Poll
GET /api/jobs/{job_id}every ~2s untilstatusiscompletedorfailed(usually a few seconds).
Machine-readable summary for agents: /llms.txt.
POST/api/analyze
Start a scan. Body: { "url": "https://example.com", "timeout"?: 60 } (timeout in seconds, 10–120, default 60; scheme is added if omitted).
curl -s -X POST https://headertest.com/api/analyze \
-H 'Content-Type: application/json' \
-d '{"url":"https://example.com"}'{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "accepted",
"message": "Analysis started. Check job status for results."
}GET/api/jobs/{job_id}
Poll a job. status ∈ pending | running | completed | failed. When complete, results holds the full report.
curl -s https://headertest.com/api/jobs/550e8400-e29b-41d4-a716-446655440000{
"status": "completed",
"completed_at": "2026-07-18T18:00:05+00:00",
"results": {
"url": "https://example.com",
"risk_score": 35,
"letter_grade": "B",
"has_csp": true,
"security_headers": { /* per-header checks */ },
"issues": [ /* findings */ ],
"recommendations": [ /* fixes */ ],
"headers_present": 6,
"headers_missing": 3
}
}GET/api/domains/{domain}/history
Up to the 30 most recent scans for a domain, with the risk-score change vs. the previous scan. 404 if the domain has never been scanned.
curl -s https://headertest.com/api/domains/example.com/historyGET/api/stats
Totals: { "total_scans": int, "total_domains": int }.
curl -s https://headertest.com/api/statsGrade
security_score = 100 - risk_score, then banded: 90+ A+, 80–89 A, 70–79 B, 60–69 C, 50–59 D, 40–49 D-, else F. Lower risk_score is better.
End-to-end example
JOB=$(curl -s -X POST https://headertest.com/api/analyze \
-H 'Content-Type: application/json' \
-d '{"url":"https://example.com"}' | jq -r .job_id)
for i in $(seq 1 60); do
RESP=$(curl -s "https://headertest.com/api/jobs/$JOB")
STATUS=$(echo "$RESP" | jq -r .status)
[ "$STATUS" = completed ] || [ "$STATUS" = failed ] && break
sleep 2
done
echo "$RESP" | jq '{grade:.results.letter_grade, risk:.results.risk_score}'Errors
| Code | Meaning |
|---|---|
| 400 | Missing/invalid url, bad job UUID, or bad domain |
| 404 | Domain/job not found |
| 500 | Backend error |
| 503 | Too many pending scans queued — retry shortly |
Embeddable badge
Every domain has a live SVG grade badge at https://headertest.com/api/badge/{domain}. Link it back to the domain's report:
<a href="https://headertest.com/results/example.com">
<img src="https://headertest.com/api/badge/example.com" alt="HeaderTest security grade" />
</a>Infrastructure & exposure data
HeaderTest covers HTTP response headers. For the layer underneath — IPs, open ports, known CVEs, hosting network, DNS and WHOIS — use our sister project OSN, a free internet exposure search. Same deal: no key required.
# Open ports, CVEs, hosting, DNS and WHOIS for a domain (OSN, no key)
curl -s https://beta.osn.lt/api/v1/domain/example.com | jq '{hosts, whois}'Try it now
No key required — scan any site from the homepage or straight from the API.
Scan Now - Free