Authenticate every request with your API key in the X-API-Key header. Responses carry an X-API-Version: 1 header and a per-request X-Request-Id for support correlation.
curl "https://headershield.dev/api/v1/scan?url=https://example.com" -H "X-API-Key: hsh_your_key_here"{
"url": "https://example.com",
"fetchedStatus": 200,
"score": 62,
"grade": "C",
"findings": [
{
"header": "Content-Security-Policy",
"status": "fail",
"points": 0,
"maxPoints": 25,
"advice": "No CSP. Without it, any injected script runs with full page privileges.",
"explanation": "Content-Security-Policy is an allowlist that tells the browser which sources may load. It is the strongest defence against XSS.",
"fixSnippet": {
"nextConfig": "{ key: \"Content-Security-Policy\", value: \"default-src 'self'; frame-ancestors 'self'\" }",
"vercelJson": "{ \"key\": \"Content-Security-Policy\", \"value\": \"default-src 'self'; frame-ancestors 'self'\" }",
"nginx": "add_header Content-Security-Policy \"default-src 'self'; frame-ancestors 'self'\" always;",
"apache": "Header always set Content-Security-Policy \"default-src 'self'; frame-ancestors 'self'\"",
"cloudflare": "# Transform Rule → Set static → Content-Security-Policy"
}
},
{
"header": "Strict-Transport-Security",
"status": "pass",
"points": 20,
"maxPoints": 20,
"advice": "HSTS enforced with a long max-age and includeSubDomains.",
"explanation": "Strict-Transport-Security (HSTS) tells the browser to only ever contact the site over HTTPS, blocking SSL-stripping attacks."
}
],
"tls": {
"validTo": "2026-09-14T23:59:59.000Z",
"daysRemaining": 95,
"issuer": "Let's Encrypt"
},
"httpsRedirect": {
"redirectsToHttps": true,
"status": 301,
"location": "https://example.com/"
},
"cookies": [
{ "name": "session", "secure": true, "httpOnly": true, "sameSite": "Lax" }
]
}Every finding carries a status-independent explanation of what the header does, plus a fixSnippet with copy-paste directives for Nginx, Apache, Cloudflare, Next.js and vercel.json. httpsRedirect reports whether the plain-HTTP origin upgrades to HTTPS.
The API is plain REST — call it from any language. Pass your key in the X-API-Key header.
curl "https://headershield.dev/api/v1/scan?url=https://example.com" \
-H "X-API-Key: hsh_your_key_here"const res = await fetch(
"https://headershield.dev/api/v1/scan?url=https://example.com",
{ headers: { "X-API-Key": process.env.HEADERSHIELD_KEY } }
);
const data = await res.json();
console.log(data.grade, data.score);import os, requests
res = requests.get(
"https://headershield.dev/api/v1/scan",
params={"url": "https://example.com"},
headers={"X-API-Key": os.environ["HEADERSHIELD_KEY"]},
timeout=30,
)
data = res.json()
print(data["grade"], data["score"])Drop this workflow into your repo (.github/workflows/headershield.yml). It scans your production URL on every push and fails the build if the security-headers grade falls below your threshold. Add your key as a repo secret named HEADERSHIELD_KEY — the scan runs against your quota, so it costs you nothing extra and us nothing.
name: HeaderShield
on: [push]
jobs:
security-headers:
runs-on: ubuntu-latest
steps:
- name: Check security headers grade
env:
HEADERSHIELD_KEY: ${{ secrets.HEADERSHIELD_KEY }}
run: |
TARGET="https://example.com" # your production URL
MIN_GRADE="B" # fail below this grade
RESP=$(curl -sf "https://headershield.dev/api/v1/scan?url=$TARGET" \
-H "X-API-Key: $HEADERSHIELD_KEY")
GRADE=$(echo "$RESP" | grep -o '"grade":"[^"]*"' | cut -d'"' -f4)
echo "Security headers grade: $GRADE"
ORDER="F E D C B A A+"
rank() { case "$1" in A+) echo 6;; A) echo 5;; B) echo 4;; C) echo 3;; D) echo 2;; E) echo 1;; *) echo 0;; esac; }
if [ "$(rank "$GRADE")" -lt "$(rank "$MIN_GRADE")" ]; then
echo "::error::Grade $GRADE is below the required $MIN_GRADE"
exit 1
fiA public, key-less SVG badge you can drop straight into a README or page. It shows the live A+→F grade and is cached for an hour, so it never hammers your site.
<img
src="https://headershield.dev/api/badge?url=example.com"
alt="Security headers grade"
/>On paid plans you can register sites to be re-scanned automatically. If a grade drops, HeaderShield emails you and POSTs a signed payload to your callback URL.
curl -X POST "https://headershield.dev/api/v1/monitors" \
-H "X-API-Key: hsh_your_key_here" \
-H "content-type: application/json" \
-d '{ "url": "https://example.com" }'curl -X PUT "https://headershield.dev/api/v1/webhooks" \
-H "X-API-Key: hsh_your_key_here" \
-H "content-type: application/json" \
-d '{ "url": "https://your-app.com/hooks/headershield" }'Each delivery is signed: verify the X-HeaderShield-Signature: sha256=<hex> header by computing HMAC-SHA256(rawBody, yourSecret) and comparing in constant time.
Pull your recent API calls as CSV (for a spreadsheet) or JSON.
curl "https://headershield.dev/api/dashboard/requests?format=csv" \
-H "X-API-Key: hsh_your_key_here" -o requests.csvInvalid or unreachable targets return 400 with { "error": { "code": "SCAN_FAILED", "message": "..." } }. Private and internal addresses are always rejected. Quota and burst limits return 429.