Crovly

API Reference

Complete Crovly API endpoint documentation.

Base URL: https://api.crovly.com

For interactive API documentation with request builder, visit the Scalar API Reference.


GET /challenge

Request a new PoW challenge. The widget calls this automatically.

IP Binding: The challenge is bound to the requesting IP. The subsequent /verify call must come from the same IP address.

Headers

HeaderRequiredDescription
X-Site-KeyYesYour public site key

Response

{
  "nonce": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
  "difficulty": 18,
  "algorithm": "sha256",
  "expiresAt": 1709251200000
}
FieldTypeDescription
noncestring32-char hex nonce to solve
difficultyintegerLeading zero bits required (16–28, adaptive)
algorithmstringAlways sha256
expiresAtnumberExpiry timestamp (Unix ms)

Rate Limits

  • 60 requests/min per IP (global)
  • 30 requests/min per IP per site key

Errors

CodeDescription
400Invalid or missing X-Site-Key header
403Site key invalid, site inactive, or origin not allowed
429Rate limit exceeded
503Service temporarily unavailable

POST /verify

Submit the PoW solution with browser signals. Returns a verification token if the challenge passes.

IP Binding: Must be called from the same IP that requested the challenge. Mismatched IPs return 403.

Headers

HeaderRequiredDescription
X-Site-KeyYesYour public site key
Content-TypeYesapplication/json

Body

{
  "nonce": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
  "counter": 182637,
  "solveTimeMs": 245,
  "fingerprintHash": "e3b0c44298fc1c149afbf4c8996fb924...",
  "environment": {
    "webdriver": false,
    "chromeAbsent": false,
    "swiftShader": false,
    "noPlugins": false,
    "notificationDenied": false,
    "zeroScreen": false,
    "noLanguages": false
  }
}
FieldTypeRequiredDescription
noncestringYes32-char hex nonce from /challenge
counterintegerYesCounter value that solves the PoW
solveTimeMsnumberNoClient-reported solve time (ms)
fingerprintHashstringYesSHA-256 of browser signals
environmentobjectNoHeadless detection signals

Response (passed)

{
  "token": "1709424000|a1b2c3d4...|182637|e3b0c442...|hmac...",
  "passed": true,
  "expiresAt": 1709424300000
}

Response (failed)

{
  "token": null,
  "passed": false,
  "expiresAt": null
}

Note: If the site has IP rules configured (Pro plan), blocked IPs or IPs not on the allowlist receive an immediate passed: false response without going through the full scoring pipeline.

FieldTypeDescription
tokenstring | nullVerification token for your backend. Null if failed.
passedbooleanWhether verification passed the site threshold
expiresAtnumber | nullToken expiry (Unix ms, 5 min TTL). Null if failed.

Rate Limits

  • 30 requests/min per IP (global)
  • 20 requests/min per IP per site key

Errors

CodeDescription
400Invalid body, expired nonce, or missing fields
403IP mismatch, invalid site key, or origin not allowed
429Rate limit exceeded
503Service temporarily unavailable

POST /verify-token

Server-side token verification. Call this from your backend only — this endpoint does not support CORS.

Tokens are single-use and expire after 5 minutes.

Headers

HeaderRequiredDescription
AuthorizationYesBearer YOUR_API_KEY
Content-TypeYesapplication/json

Body

{
  "token": "1709424000|a1b2c3d4...|182637|e3b0c442...|hmac...",
  "expectedIp": "203.0.113.42"
}
FieldTypeRequiredDescription
tokenstringYesToken from /verify
expectedIpstringNoIP to match against. Recommended for security.

Response (success)

{
  "success": true,
  "score": 0.85,
  "ip": "203.0.113.42",
  "solvedAt": 1709424000000
}

Response (failure)

{
  "success": false,
  "error": "Token already used"
}
FieldTypeDescription
successbooleanWhether the token is valid
scorenumberConfidence score (0.0 = bot, 1.0 = human)
ipstringIP that solved the challenge
solvedAtnumberWhen the challenge was solved (Unix ms)
errorstringError message (only when success: false)

Rate Limits

  • 100 requests/min per IP (global, fail-closed)
  • 200 requests/min per API key (fail-closed)

Errors

CodeDescription
400Invalid token, expired, site mismatch, or already used
401Missing or invalid Authorization header
429Rate limit exceeded
503Service temporarily unavailable (fail-closed)

CORS

EndpointCORS
GET /challengeYes (*)
POST /verifyYes (*)
POST /verify-tokenNo — backend only

The /challenge and /verify endpoints accept requests from any origin. The /verify-token endpoint is server-to-server only and does not include CORS headers.

On this page