The scan API
One endpoint. No account, no key, no signup. Send a URL, get back the same JSON security report the website produces. It is read-only and free, because understanding your own app is never the thing we gate.
Endpoint
POST https://xlogs.com/api/v1/scan { "url": "<your-url>" }GET https://xlogs.com/api/v1/scan?url=<your-url> with the header x-xlogs-scan: 1Both forms run the same scan. A GET runs only when it carries the header x-xlogs-scan: 1; without it the response is a 400 that says so and nothing is scanned. That header is the whole difference between a request you sent and a link somebody pasted: a chat preview, a crawler or an image tag cannot add it, so no one can make xlogs scan a site by posting a URL somewhere. The same rule holds everywhere on this site: a GET never scans on its own.
Example
curl -X POST https://xlogs.com/api/v1/scan -H "content-type: application/json" -d '{"url":"https://your-app.com"}'
curl -H "x-xlogs-scan: 1" "https://xlogs.com/api/v1/scan?url=https://your-app.com"Returns a JSON object with the scan result: findings (each with severity, a confidence label, CWE and OWASP tags, and a copy-paste fix), a coverage receipt, a plain verdict, the platform fingerprint, the shipped-library list, and the measured scan time. It is the exact shape the website renders.
Response shape
{
"ok": true,
"apiVersion": "1",
"scannedAt": "2026-08-13T00:00:00.000Z",
"url": "https://your-app.com",
"reachable": true,
"counts": { "critical": 0, "high": 0, "medium": 1, "low": 0 },
"verdict": { "level": "issues", "headline": "1 table anyone can read: review", "review": 1 },
"findings": [
{
"vulnId": "supabase-rls",
"severity": "medium",
"confidence": "confirmed",
"observationConfidence": "confirmed",
"interpretationConfidence": "potential",
"interpretationBasis": "intent-unknown",
"reviewPriority": "elevated",
"reviewReasons": ["email is named like private personal data", "the values were not inspected"],
"cwe": "CWE-284",
"owasp": "A01:2021 Broken Access Control",
"title": "Anyone can read this table; confirm that is deliberate",
"statements": { "observed": "...", "notTested": "Not tested: ...", "recommended": "..." },
"fixSteps": ["..."],
"verify": "..."
}
],
"receipt": [ { "id": "database", "status": "found" } ],
"sbom": { "libraries": [ { "name": "react", "version": "18.2.0" } ] }
}Rules
- Free and unauthenticated. No key, no account. Every field is returned; nothing is gated.
- Read-only. The API runs the same checks as the site: ordinary GET requests, no writes, no login, no exploitation.
- Public URLs only. Private, loopback, and cloud-metadata addresses are refused, the same as the website scanner.
- Rate limited to 60 scans per IP per hour, so it cannot be used as a scanning amplifier. Over that returns HTTP 429.
- CORS open. You can call it from a browser tool or a dashboard.
- Not a compliance product. The CWE and OWASP tags are for matching against other tools, not evidence for SOC 2 or PCI.
- Two confidences, from rules 1.9.
observationConfidencesays how sure the scan is of what it saw;interpretationConfidencesays how sure it is of what that means, withinterpretationBasisnaming what it rests on. A table anyone can read is a review item:severitymedium, basisintent-unknown, and areviewPrioritywith its reasons.verdict.levelkeeps its values (a result with review items readsissues), andverdict.reviewcounts the review items beside it.
Prefer the command line?
The live-site checks also run from a zero-dependency CLI you can drop into CI, with a deploy gate and SARIF output. The command line tool is released on its own: the release these pages run is v0.2.4 (2026-10-06), and the copy on npm, xlogs-scanner 0.1.0 (2026-08-13), is older still, so either can report differently from a scan on this site. See the methodology for the full list of requests either path sends.
