DOCS

The public API.

What is documented here is the unauthenticated scan surface: the one behind the free scorecard. It is the part that is stable enough to build against.

Response envelope

Every response uses the same wrapper, success or failure.

{
  "success": true,
  "message": "Scan",
  "data": { … },
  "error": null,
  "timestamp": "2026-08-12T06:00:00Z",
  "requestId": "req_…"
}

On failure, success is false, data is null, and error carries { code, details }. The one exception is rate limiting, which is returned by the limiter ahead of the application and does not use the envelope: worth handling explicitly.

Endpoints

POST /api/v1/public/scans

Queue a scan. Returns 202 with a scan id: the result is not ready yet.

Request

{ "url": "https://example.com", "captchaToken": "…" }

Response

{ "scanId": "scan_…", "status": "queued", "reused": false }

Worth knowing

  • Rate limited to 3 submissions an hour per caller.
  • One real crawl per domain per day; inside that window reused comes back true and you get that day’s scan.
  • CAPTCHA is verified before anything else, before URL validation, before any DNS lookup, and fails closed in production.
  • The URL is checked against an SSRF guard. Addresses that resolve into private space are rejected.

GET /api/v1/public/scans/{scanId}

Read a scan. Poll until status leaves queued or running.

Response

{ "status": "done", "score": 71, "grade": "C+",
  "categories": [{ "name": "…", "score": 62 }],
  "findingsCount": 12, "pagesScanned": 10, "pagesTotal": 47,
  "remainingPages": 37, "unlocked": false,
  "advisory": "Advisory scan of public HTML only." }

Worth knowing

  • findings is omitted entirely until an email is verified: omitted, not blanked, because a locked field still present in the payload is one devtools tab away from unlocked.
  • A scan that never ran has no grade at all rather than a default one.
  • No traffic metrics are returned. There are no clicks, impressions, positions or citation counts in this payload.

GET /api/v1/public/scorecards/{slug}

Read a shared scorecard by its share slug.

Response

Same shape as a scan, always with `unlocked: false`.

Worth knowing

  • Always locked, even if the owner has verified their email: otherwise one verified address would publish the findings to anyone holding the link.
  • Expires 30 days after the scan.

POST /api/v1/public/scans/{scanId}/claim

Trade an email address for the findings. Sends a verification link.

Request

{ "email": "you@example.com" }

Response

202 accepted

Worth knowing

  • Rate limited separately from scan submission, because it sends mail rather than starting a crawl.

Error codes

CodeMeaning
CAPTCHA_REQUIRED The verification challenge was not solved. Fails closed in production.
VALIDATION_FAILED The URL was rejected: malformed, or resolving somewhere it should not.
SERVICE_UNAVAILABLE The scanning engine is not available. No grade is invented in its absence.
RESOURCE_NOT_FOUND Unknown scan id, or a scorecard slug that has expired.
429 Rate limited. Handled outside the envelope, so parse defensively.

A worked example

# queue
curl -sX POST https://api.crawld.co/api/v1/public/scans \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://example.com"}'

# poll until status is done or failed
curl -s https://api.crawld.co/api/v1/public/scans/scan_abc123

The authenticated API Not documented yet

The brand-scoped surface: fix queue, audits, watchdog, citations: exists but is not publicly documented, which means it is not stable enough to build against and should not be treated as though it were. When it is documented it will be here.

Webhooks and the platform integrations are described on the integrations pages, including which of them are built.

Try it on your own site Crawler behaviour