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).
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Window allowance — always 30. |
X-RateLimit-Remaining | Requests left in the current window. |
Retry-After | On 429 only: seconds until the window reopens. |
{
"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
| Resource | Limit |
|---|---|
Client token TTL (X-Client-Token) | 1800 seconds (30 minutes) |
Verification lifetime (expires_at) | 24 hours from creation |
| Presigned media URL lifetime | 3600 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 frames | First 8 frames |
| Webhook delivery | 3 attempts; backoff 0.5s / 1.0s / 2.0s; 10s per-attempt timeout; success = status < 300 |
| Name screening input | name 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.
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();
}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()