Skip to content

Scan API

The scanner,
without the browser.

Two calls: start a scan, then poll it until it is done. No key and no account — these are the same public endpoints this site's own front page uses, under the same five-scans-an-hour limit.

Start a scan

Returns 201 with a scan id, immediately. The scan itself runs in the background, so this call does not wait for it.

curl -s -X POST https://scs-health.onrender.com/api/scans \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://example.com"}'

{"id":"5f3c…","url":"https://example.com","status":"running","score":null, … }

Read the report

Poll until status is completed or failed. The site polls every two seconds; a scan usually finishes inside forty.

curl -s https://scs-health.onrender.com/api/scans/5f3c…

{
  "status": "completed",
  "score": 72,
  "unreachable": false,
  "summary": { "checksRun": 71, "passed": 62, "failed": 9 },
  "cappedBy": "critical",
  "categories": [
    { "category": "security", "score": 40, "checksRun": 12, "passed": 9, "failed": 3,
      "findings": [
        { "severity": "critical", "title": "SSL certificate has expired",
          "detail": "Expired 2026-07-02", "remediation": { … } }
      ] }
  ],
  "aiReadiness": { … },
  "crawl": { "status": "not_requested", "pagesScanned": null }
}

Three things worth knowing before you build on it

once

A report is delivered exactly once

The server erases a report the moment it answers with it, so the second GET for the same id returns 410 Gone. Keep the first response — this is the same deliver-once behaviour the browser gets, not an API restriction. Responses are sent no-store for the same reason.
null

No score is different from a low score

When the entered page never loaded, score is null and unreachable is true. Nothing about the site was measured, so treating a missing score as zero would be wrong — a site behind a bot wall is not a site that failed.
limits

Five scans an hour, per IP

Over that you get 429 with a Retry-After. If the service has been idle the first call can take up to a minute to answer; later ones are immediate.

Using it in CI

There is no official action or CLI yet. The shape below is what people write by hand — fail the build when the score drops under a threshold you pick.

id=$(curl -s -X POST https://scs-health.onrender.com/api/scans \
  -H 'Content-Type: application/json' \
  -d "{\"url\":\"$SITE_URL\"}" | jq -r .id)

# poll until it settles
until [ "$(curl -s $BASE/api/scans/$id | jq -r .status)" != "running" ]; do sleep 2; done

# NOTE: the report is erased once read, so capture it in one call
report=$(curl -s https://scs-health.onrender.com/api/scans/$id)
echo "$report" | jq '.summary, .score'
test "$(echo "$report" | jq -r '.score // 0')" -ge 80

Scheduled re-scans, alerting and a stable versioned API are what the paid tiers on pricing are being built around. If you are considering it for a pipeline, say so — that is the feedback that decides what gets built first.

Try it against your own site first.

The browser version runs the same scan and shows the same findings.

Run a scan