idcheck.now API Docs

Rate limits

What you can send, how fast, and how long things live. Only the free tier is hard-capped today; everything else runs on fair use.

Free tier limits

The keyless endpoints under /v1/free/* are limited to 30 requests per hour per client IP (rolling 3600-second window, X-Forwarded-For aware).

HeaderMeaning
X-RateLimit-LimitWindow allowance — always 30.
X-RateLimit-RemainingRequests left in the current window.
Retry-AfterOn 429 only: seconds until the window reopens.
JSON429 response
{
  "detail": "free tier rate limit exceeded — 30 lookups per hour"
}

Keyed endpoint policy

Merchant endpoints (/v1/verifications, /v1/screen/*, /v1/keys, /v1/webhooks) currently have no hard request-rate limit — usage is metered per completed verification for billing, and abusive patterns may be throttled. If you expect bursts (batch re-screening, backfills), contact api@idcheck.now first. The unauthenticated POST /v1/signals/collect endpoint is body-capped (64 KB) rather than rate-capped.

TTLs, caps and timeouts

ResourceLimit
Client token TTL (X-Client-Token)1800 seconds (30 minutes)
Verification lifetime (expires_at)24 hours from creation
Presigned media URL lifetime3600 seconds (1 hour); re-fetch via GET /v1/verifications/{id}/media
List page size (GET /v1/verifications)limit 1–200, default 50
Signals collect body (/v1/signals/collect)64 KB hard cap; ≤ 50 component keys; values truncated at 500 chars
Stored selfie framesFirst 8 frames
Webhook delivery3 attempts; backoff 0.5s / 1.0s / 2.0s; 10s per-attempt timeout; success = status < 300
Name screening inputname 2–255 chars (keyed) / 2–200 (free); wallet address 8–255 chars

Handling 429s

Only the free tier returns 429 today. Read Retry-After, sleep that long, then retry — do not hammer the window boundary. If you need more than 30 lookups/hour, that is exactly what the keyed POST /v1/screen/ofac endpoint is for.

JavaScript
async function freeOfacLookup(name, dob) {
  const res = await fetch("https://idcheck.now/v1/free/ofac", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ name, dob }),
  });
  if (res.status === 429) {
    const wait = Number(res.headers.get("Retry-After") || 60);
    await new Promise(r => setTimeout(r, wait * 1000));
    return freeOfacLookup(name, dob); // retry after the window reopens
  }
  return res.json();
}
Python
import time, requests

def free_ofac_lookup(name, dob=None):
    res = requests.post("https://idcheck.now/v1/free/ofac", json={"name": name, "dob": dob})
    if res.status_code == 429:
        time.sleep(int(res.headers.get("Retry-After", 60)))
        return free_ofac_lookup(name, dob)  # retry after the window reopens
    return res.json()