Download the OpenAPI 3.1 specification for request fields, response schemas, authentication, and error codes. This is the same queue and scanner used by the website.
1. Queue a scan
For local development, start the website and worker, replace the example repository, and use your running port. Loopback SQLite needs no API key unless you configure one.
curl --fail-with-body --silent --show-error \
http://127.0.0.1:3100/api/v1/scans \
-H 'Content-Type: application/json' \
-d '{"source":"https://github.com/owner/repository","intent":false}'For a hosted integration, ask the site operator for a scanner API key. Set SCANNER_ORIGIN to the HTTPS scanner origin and provide the key through your server’s secret manager. Do not put it in browser code, source control, or a URL.
curl --fail-with-body --silent --show-error \
"$SCANNER_ORIGIN/api/v1/scans" \
-H "Authorization: Bearer $SCANNER_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"source":"https://github.com/owner/repository","intent":false}'Add ref to pin a commit, branch, or tag, and skillPath to select a skill folder or its SKILL.md. Set intent: true only when you want optional AI assessment. It may incur provider charges; failed requested analysis is reported as incomplete.
2. Keep the returned links
A successful request returns 202 Accepted, a Location header pointing to the status endpoint, and this response shape. The token below is a placeholder, not a real report.
{
"reportUrl": "/reports/<report-token>",
"statusUrl": "/api/v1/scans/<report-token>"
}Both paths are relative to your scanner origin. The token is a read credential: anyone holding either link can read that report. There is no public listing, and a lost link cannot be recovered by repository or API key.
3. Poll for the result
Use the returned statusUrl, without an API key. Poll every three seconds or slower and stop when status is complete or incomplete. Nonterminal responses include Retry-After: 3.
curl --fail-with-body --silent --show-error \
"$SCANNER_ORIGIN$STATUS_URL"The JSON includes status, target, timestamps, report, and error. While running, report is null. A completed report includes the immutable commit, GitHub source URL, coverage, findings, optional intent, and bounded raw matches. An incomplete scan may have a partial report or only an error. Complete does not mean safe.
Small API, explicit limits
POST /api/v1/scansaccepts JSON up to 8 KiB. Public GitHub repositories only; no uploads or private repositories.- Five submissions per integration key in ten minutes, with 100 across the hosted website and API per hour. Local anonymous calls share the local website limit.
429includes a conservativeRetry-Afterdelay. Other errors use{ "error": "…" }. See OpenAPI for each status.- Submission is not idempotent. Retrying an accepted POST creates another scan; save the returned URLs and poll instead.
- A worker must be running to process queued scans. There are no webhooks, cancellation, public search, or self-service API keys yet.
- Hosted submission keys are operator-managed and server-only. The browser form remains account-free with its existing challenge; cross-origin browser calls are not enabled.
Operator setup
Configure a dedicated SCANNER_API_KEY with 32–256 random URL-safe characters on the scanner web server. Generate 32 random bytes as hex, distribute through a secret manager, and rotate by replacing the setting. This is separate from the Supabase service key. The hosted API also needs the dedicated database, HTTPS public origin, rate-limit secret, and worker described in the README. Browser submissions still require Turnstile.
Keep Authorization headers and report capability paths out of access logs and analytics. Read docs/API.md in the project for integration and deployment details.