Skip to main content

The audit, from your code or your agent

One key, three shapes: the full evidence JSON, a verdict-only call, and batch scans. Plus an MCP server so Claude Code, Cursor and other agents can ask "is this site AI slop?" themselves. A free account comes with one key and 30 scans a month.

Get a key

Authentication

Every call carries your key as a bearer token. Keys start with ca_live_, are shown once when created, and can be revoked on your account page. They are for servers and tools, not for browsers: there is no CORS on the API.

Authorization: Bearer ca_live_…

Endpoints

CallWhat it does
POST /api/v1/scanStarts an audit of one URL. Body: url, optional mode (standard or deeper), provenance (default true), webhook_url (https), lang (en or ro: the language of the PDF, the ready email and the webhook). Answers 202 with an id, or 200 when the same site was audited in the last 10 minutes. Counts one scan. On a paid plan, mode deeper with provenance also runs the AI slop check on 5, 10 or 20 crawled pages (Solo, Team, Partner), returned under provenance.sitewide; still one scan. Inner pages carry a band with confidence null, because the error rates were measured on homepages.
GET /api/v1/scan/{id}The evidence JSON: status and progress (while waiting, queue.position and queue.est_wait_s in seconds), scores, the provenance block (band, confidence, the two axes, tells and authored signals, lineage, coverage, the legal line), built_with (the platform, its theme or template, with version and author when the theme names them, and the page builders next to it), every finding with its evidence and recommendation, report and PDF links. Add ?lang=ro for the findings in Romanian; English otherwise.
GET /api/v1/verdict?url=Verdict only. A provenance result younger than 7 days (max_age_days to change it) comes back at once; otherwise a scan is queued, one scan is counted, and you get 202 with an id to poll.
POST /api/v1/batchUp to your plan's batch size of URLs in one call. The whole batch is checked against your quota first. Answers 202 with a batch_id and the accepted and rejected URLs.
GET /api/v1/batch/{batch_id}Counts of done, failed and pending, and one row per URL with status, overall score, band and report link.
GET /api/v1/meYour plan, usage this month, limits and number of active keys.

Example

curl -X POST https://audit.crocky.host/api/v1/scan \
  -H "Authorization: Bearer ca_live_…" -H "Content-Type: application/json" \
  -d '{"url":"https://example.com"}'
# {"id":"3cfd…","status":"pending","cached":false,"result_url":"…/api/v1/scan/3cfd…","report_url":"…/report/3cfd…"}

curl -H "Authorization: Bearer ca_live_…" https://audit.crocky.host/api/v1/scan/3cfd…
# {"id":"3cfd…","status":"done","scores":{"performance":62,"seo":88,"security":74,"hosting":91,"accessibility":95,"overall":79},
#  "provenance":{"band":"LIKELY","probability":81,"tools":[],"tells":["E36","E03","E17"],"anti_tells":[],
#                "axes":{"discipline":54,"provenance":71},"lineage":{"tier_a":[],"tier_b":["…"]},
#                "legal":"Automated estimate from public signals - not a statement of fact about a site or its authors."},
#  "findings":[{"category":"security","severity":"high","title":"No Content-Security-Policy header", …}],
#  "checks":{"total":{"ran":310,"hit":29,"pass":281,"review":0,"na":75,"skip":0},"by_category":{"security":{…}, …},
#            "rows":[{"id":"chk:hdr_hsts","category":"security","name":"Strict-Transport-Security (HSTS) header","state":"found","severity":"high"},
#                    {"id":"path:/.env","category":"security","name":"/.env","state":"passed"}, …]}, …}

Verdict bands

CONFIRMED (a build artefact names the tool), LIKELY (with a confidence number), POSSIBLE (capped, no number: designers use the same kits), NONE (no evidence found; wrong about one time in twelve), UNMEASURED (could not fetch or render). The API never says a site is human-made. Error rates and what each band means are on the AI slop page.

How the check works

Every check, not only the findings

Each result also carries checks: every test the audit ran, with its state (passed, found, needs_review, not_applicable, not_run), a severity where it found something, and the reason where it did not apply or did not run. Findings list only what a check found; checks also list what came back clean, so you can tell "checked and fine" from "never checked". Counts per category come with every result, the rows with the full one.

MCP server

The same key works on an MCP server at /api/mcp (Streamable HTTP, stateless JSON, no SSE). Two tools: check_site with a URL returns the verdict with evidence when a result younger than 7 days exists, otherwise it queues a scan and tells the model to call get_result with the id after 20 seconds.

claude mcp add --transport http crocky-audit https://audit.crocky.host/api/mcp \
  --header "Authorization: Bearer ca_live_…"
{ "mcpServers": { "crocky-audit": {
    "url": "https://audit.crocky.host/api/mcp",
    "headers": { "Authorization": "Bearer ca_live_…" } } } }

Webhooks

Pass webhook_url on a scan and we POST the evidence JSON once when it finishes, with X-Crocky-Event: scan.completed and X-Crocky-Signature: sha256=… (HMAC-SHA256 of the body with the signing secret shown on your account page). Three-second budget, no retries.

Plans

PlanScans a monthBatchKeysMonitorsSite-wide pages
Free30510-
Solo30020255
Team2000100105010
Partner100005002550020

Every key is limited to 60 requests a minute. To move to a paid plan, write to audit@crocky.host; self-service billing comes later.

Errors

401 bad_keyMissing, revoked or unknown key.
402 quotaMonthly scans used up; the body says used and limit.
429 rateMore than 60 requests in a minute on one key.
400 validationBad URL, unknown mode, batch too large, webhook not https.
404 not_foundNo scan or batch with that id on your account.

Automated estimate from public signals, not a statement of fact about a site or its authors.