Errors & rate limits
Rate limits (per API key, sliding 1-second window)
| Tier | Requests / second |
|---|---|
| free | 10 |
| starter | 50 |
| pro | 200 |
| scale | 1,000 |
Every response includes:
X-RateLimit-Limit: 50
X-RateLimit-Remaining: 47
X-RateLimit-Window: 1s
When the limit is exceeded:
HTTP/1.1 429 Too Many Requests
Retry-After: 1
Content-Type: application/json
{ "ok":false, "error":"rate_limit_exceeded", "limit":50, "window_ms":1000, "retry_after_ms":318, "tier":"starter" }
Quota (monthly cap)
Each tier has a monthly check cap. When exhausted:
HTTP/1.1 402 Payment Required
{ "ok":false, "error":"quota_exceeded", "tier":"free", "used":1000, "cap":1000, "remaining":0, "upgrade_url":"/docs/pricing" }
The cap resets on the 1st of each calendar month (UTC). Upgrades take effect on the next request.
Idempotency
Pass Idempotency-Key: <any-string> to make retries safe. Replays return the original response with header Idempotent-Replay: true. Same key with a different body returns 409 idempotency_key_conflict.
Stored for 24 hours, then garbage-collected.
Check errors
These are returned in the issues array of a 200 response — not as HTTP errors. The check completed and was billed; the output failed your rule set.
All problems are reported, one entry per issue. Label prefixes:
blocked:<phrase>— a phrase from your ownmust_not_containappeared.filler:<phrase>— a built-in AI-slop phrase appeared.missing:<phrase>— a required phrase is absent.leftover:<phrase>— leftover AI text, such as “Here’s a more polished version…”, was left in the output.
Your blocked phrases previously appeared as filler:; they now appear as blocked:. Built-in slop remains filler:.
System errors
| Status | Error | Action |
|---|---|---|
| 500 | quota_check_failed | DB unreachable. Retry with backoff. |
| 500 | validator_error | Internal validator threw. Report to support; safe to retry. |
| 503 | db_not_configured | Service is bootstrapping. Retry after 30s. |
Reporting issues
Email support@nexxtool.ai with the validation_id when applicable.