Barrion Docs
Public API

Passive scans

Start a passive scan, wait for it, and read its failing checks.

A passive scan runs Barrion's 35+ checks against a site without attacking it: TLS, security headers, cookies, CORS, email records and more. Scans are free and take a few minutes, which makes them a good gate on every deploy. They follow your plan's scan limits, the same as in the dashboard.

Types

type ScanStatus =
  | "STARTED" | "COMPLETED" | "FAILED"
  | "SCHEDULED"; // waiting to (re)start, e.g. a monitoring scan or one picked up again after an interruption; keep polling

type Scan = {
  id: string;
  domain: string;
  status: ScanStatus;
  securityScore: number | null;   // null until COMPLETED
  riskLevel: string | null;       // null until COMPLETED
  findings: { critical: number; high: number; medium: number; low: number } | null;
  startedAt: string;              // ISO 8601
  completedAt: string | null;
};

type ScanFinding = {
  checkKey: string;
  name: string;
  category: string;
  severity: "critical" | "high" | "medium" | "low";
  detectedValue: string | null;
  affectedUrlCount: number;
};

Start a scan

POST /v1/scans · permission scans:write · requires an Idempotency-Key header

Prop

Type

curl -X POST https://api.barrion.io/v1/scans \
  -H "Authorization: Bearer $BARRION_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: deploy-$CI_RUN_ID-$CI_RUN_ATTEMPT" \
  -d '{"url": "https://staging.example.com"}'
const res = await fetch("https://api.barrion.io/v1/scans", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.BARRION_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": `deploy-${runId}-${attempt}`,
  },
  body: JSON.stringify({ url: "https://staging.example.com" }),
});
const { id: scanId } = await res.json();
res = requests.post(
    "https://api.barrion.io/v1/scans",
    headers={
        "Authorization": f"Bearer {os.environ['BARRION_API_KEY']}",
        "Idempotency-Key": f"deploy-{run_id}-{attempt}",
    },
    json={"url": "https://staging.example.com"},
)
scan_id = res.json()["id"]

Response 202

The scan has been queued.

type StartScanResponse = { id: string; domain: string; status: "STARTED" };
{ "id": "5b1c7e2a-9d3f-4a1b-8c2e-7f6a5b4c3d2e", "domain": "staging.example.com", "status": "STARTED" }

Errors

StatusCodeWhy
400VALIDATION_ERRORurl is missing or not a valid URL
403PLAN_LIMIT_EXCEEDEDYour plan's scan limit is reached, or the same site was scanned too recently
403TARGET_NOT_ASSIGNEDIn an organization, this domain is not one of the domains assigned to you. Ask an organization admin for access
409IDEMPOTENCY_IN_PROGRESSThe first request with this key is still running
422IDEMPOTENCY_KEY_REUSEDThis key was already used with a different body
429RATE_LIMITEDToo many starts in a minute

The message on a limit error says which limit was hit.

Get a scan

GET /v1/scans/{id} · permission scans:read

Poll every 15 to 30 seconds until status is COMPLETED or FAILED.

curl https://api.barrion.io/v1/scans/5b1c7e2a-9d3f-4a1b-8c2e-7f6a5b4c3d2e \
  -H "Authorization: Bearer $BARRION_API_KEY"
const res = await fetch(`https://api.barrion.io/v1/scans/${scanId}`, {
  headers: { Authorization: `Bearer ${process.env.BARRION_API_KEY}` },
});
const scan = (await res.json()) as Scan;
scan = requests.get(
    f"https://api.barrion.io/v1/scans/{scan_id}",
    headers={"Authorization": f"Bearer {os.environ['BARRION_API_KEY']}"},
).json()

Response 200: Scan

{
  "id": "5b1c7e2a-9d3f-4a1b-8c2e-7f6a5b4c3d2e",
  "domain": "staging.example.com",
  "status": "COMPLETED",
  "securityScore": 82,
  "riskLevel": "Medium",
  "findings": { "critical": 0, "high": 1, "medium": 3, "low": 5 },
  "startedAt": "2026-09-28T10:02:11.000Z",
  "completedAt": "2026-09-28T10:05:47.000Z"
}

Findings you have ignored in the dashboard are left out of the counts. An unknown id is 404 NOT_FOUND.

Read the failing checks

GET /v1/scans/{id}/findings · permission scans:read

Prop

Type

curl "https://api.barrion.io/v1/scans/5b1c7e2a-9d3f-4a1b-8c2e-7f6a5b4c3d2e/findings?severity=critical,high" \
  -H "Authorization: Bearer $BARRION_API_KEY"

Response 200

type ScanFindingsResponse = {
  id: string;
  domain: string;
  status: ScanStatus;
  total: number | null;             // null until the scan has completed
  returned: number;
  hasMore: boolean;
  more: string | null;              // e.g. "4 further findings. Call again with offset 10."
  findings: ScanFinding[];          // worst first
};
{
  "id": "5b1c7e2a-9d3f-4a1b-8c2e-7f6a5b4c3d2e",
  "domain": "staging.example.com",
  "status": "COMPLETED",
  "total": 1,
  "returned": 1,
  "hasMore": false,
  "more": null,
  "findings": [
    {
      "checkKey": "hsts",
      "name": "Strict-Transport-Security header",
      "category": "Headers",
      "severity": "high",
      "detectedValue": null,
      "affectedUrlCount": 1
    }
  ]
}