Developer API
One endpoint, one dimension: the security result of a scan as JSON, without walking the full report schema. Built for CI pipelines, dashboards and agency tooling that check response headers on a schedule.
01 Authentication
Every request carries an API token as a bearer token in the Authorization header. Tokens are created and revoked on the API tokens page of your account, and a token only ever sees the scans of the account it belongs to. API access is part of the Agency plan; whether a lighter, registration-free tier follows is an open product question and not decided here.
02 The endpoint
The endpoint returns the security dimension of a finished scan and nothing else. It reads what the scan stored and measures nothing of its own, so the same scan token answers the same way from the full report endpoint.
GET /api/v1/scans/{token}/security JSON curl -H "Authorization: Bearer $SCAN_API_TOKEN" \ "https://scan.erseni.com/api/v1/scans/8f14e45fceea167a5a36dedd4bea2543/security?locale=en-gb" { "schemaVersion": 6, "token": "8f14e45fceea167a5a36dedd4bea2543", "url": "https://example.com/", "status": "finished", "resultAvailable": true, "scanErrorMessage": null, "progressStage": null, "progressPercent": 100, "security": { "dimension": "security", "measured": true, "score": 62, "band": "warn", "rank": "needs_work", "checkSummary": { "passed": 21, "violated": 9, "notChecked": 18, "ran": 30, "total": 48 }, "checks": [ { "key": "strict-transport-security", "state": "passed", "label": "Strict-Transport-Security", "reason": "Enforces HTTPS for every later request." } ], "findings": [ { "code": "security.missing-header.content-security-policy", "severity": "high", "riskLevel": "high", "effort": "medium", "title": "Content-Security-Policy header missing", "detail": "...", "riskStatement": "...", "remediation": "..." } ] } } 03 Starting a scan
A scan runs a real browser against the page, so it is asynchronous. The first call queues it and hands back a token, the second reads the result once the status is finished. Poll the security endpoint: while the scan is still running it answers with the status and progress and a null security block.
POST /api/v1/scans curl -X POST \ -H "Authorization: Bearer $SCAN_API_TOKEN" \ -H "Content-Type: application/json" \ -d '{"url": "https://example.com/"}' \ "https://scan.erseni.com/api/v1/scans" { "token": "8f14e45fceea167a5a36dedd4bea2543", "id": 4711, "status": "queued", "statusUrl": "/api/v1/scans/8f14e45fceea167a5a36dedd4bea2543" } 04 Reading the answer
Nothing in the answer is a legal statement, and nothing is filled in for the sake of a tidy shape. A dimension that was never measured comes back as measured false with a null score rather than a zero.
score The security score of the scan from 0 to 100, or null when the dimension was not measured. band is good, warn, poor or unknown; rank is the finer seven-step scale used in the report.
measured False when the scan carries no security score. Everything else in the block may still be present, but no score stands behind it.
checkSummary How many of the declared security checks passed, were violated and could not be run. ran is passed plus violated, total counts all three. Null for a scan taken before the check ledger existed.
checks One entry per check with its key, its state, a label and the reason it is checked. The list is either complete for the dimension or null: a partial list would present the checks that happen to be named as the full scope of what was tested.
findings The public security findings of the scan. code is a stable fingerprint you can key on; the four texts are rendered in the requested locale.
locale Optional query parameter, en-gb by default, de-de also supported. It selects the language of the labels, reasons and finding texts. Keys, codes and states never change with the locale.
05 Errors
Every error carries the HTTP status and a JSON body with errorMessage. Branch on the status code, not on the text: the wording may change, the codes do not.
06 Migration
Snyk is retiring the securityheaders.com API in April 2026. The mapping below is deliberately literal: where we mean something different, it says so instead of bending our answer into a shape that would read as compatible and quietly report something else.
07 Beyond the headers
The security dimension is wider than a header list. These checks come with the same call and appear in checks and findings alongside the header ones.
08 Limits
The honest half of the comparison. None of these is an oversight, and each one is a decision we would rather state than have you discover in production.
Create a token in your account, run one scan by hand to see the shape of the answer, then point your pipeline at it.