Errors & Rate Limits
All errors return JSON with an error field. HTTP status codes follow REST conventions. Rate limits are enforced per API key per calendar month.
HTTP status codes
| Status | Meaning | Action |
|---|---|---|
200 | Success | Read verdict, score, signals |
400 | Bad request | Check your JSON body — missing required field |
401 | Unauthorized | API key missing, invalid, or revoked |
429 | Quota exceeded | Upgrade plan or wait for monthly reset |
500 | Server error | Retry with exponential backoff — we're paged immediately |
Error response format
{
"error": "Monthly quota exceeded. Resets on 2026-06-01.",
"quota_per_month": 5000,
"used": 5000,
"reset_at": "2026-06-01T00:00:00.000Z"
}
Rate limits
| Plan | Monthly quota | Overage |
|---|---|---|
| Free | 50 checks | No overage — blocked at limit |
| Starter | 5,000 checks | €0.01/check (coming soon) |
| Pro | 25,000 checks | €0.008/check (coming soon) |
| Scale | Unlimited | — |
Quota headers
Every response includes quota information:
X-Quota-Limit: 5000
X-Quota-Used: 1247
X-Quota-Remaining: 3753
X-Quota-Reset: 2026-06-01T00:00:00.000Z
Handling 429 gracefully
const res = await fetch('https://kairoscheck.net/api/check', { ... });
if (res.status === 429) {
const { reset_at } = await res.json();
console.warn('Quota exceeded. Resets at:', reset_at);
// Allow the user through (fail open) or show a friction step
return { verdict: 'ALLOW', score: 0, note: 'quota_exceeded' };
}
Fail-open vs fail-closed: When quota is exceeded, we recommend failing open (allowing users through) rather than blocking everyone. Blocking all signups because of a quota is worse than missing a few fraudsters. Monitor your usage in the dashboard.