Gates
Errors
Errors returned by the Gates v1 API use the same JSON body: a stable, machine-readable error code and a human-readable message.
{
"error": "gate_not_found",
"message": "Gate not found."
}
Match on error, not the wording of message, which can change.
Handling failures
Read the HTTP status first. Parse JSON defensively: an empty, invalid, or non-object body means no error code is available. For Gates v1, use this policy:
| Response | What to do |
|---|---|
429 with quota_exceeded |
Check your credits or enable overage. Repeated retries will not restore the quota |
Any other 429 |
Pause requests. Honor Retry-After when present; otherwise use exponential backoff with jitter. If it arrives on your very first requests, check your API key |
500, 502, 503, 504 |
Retry with backoff, even if the body is empty or has no error code |
Other 4xx |
Fix the request or access problem before retrying |
Limit retry attempts. Only automatically retry requests that are safe to repeat: a failed response does not prove that a write was never applied. A missing Retry-After header alone does not mean credits are exhausted.
In a signup or other request a user is waiting on, don't retry a decision. Fall back and log it, as described in Timeouts and failures.
Errors before the API
Infrastructure failures can return 502, 503, or 504 with JSON, text, HTML, or no body. The handling policy above works without a JSON error code. Temporary IP blocks return 429 rate_limit_exceeded in the Gates v1 format and follow the same retry policy; see Rate Limits.
Cloudflare security rejections can return a non-JSON 403, such as error code: 1010. This does not indicate an invalid API key; 403 pro_only specifically means the account needs a plan that includes Gates. For an unexplained security rejection, contact us with the request URL (without credentials), timestamp, user-agent, and CF-Ray header if present. Do not include your API key.
Field validation
When individual fields are at fault, the body carries an errors object naming each one:
{
"error": "validation_failed",
"message": "Some input fields are invalid.",
"errors": {
"name": ["The name field is required."]
}
}
Codes on every endpoint
| Status | Code | Meaning |
|---|---|---|
400 |
invalid_json |
A non-empty request body could not be parsed as JSON. Set Content-Type: application/json and check the body syntax |
401 |
unauthorized |
The API key is missing, mistyped, or revoked. After 5 such requests per hour from one IP, the API answers 429 rate_limit_exceeded instead, with a Retry-After of up to an hour |
403 |
pro_only |
The account is not on a plan that includes Gates |
404 |
not_found |
No Gates endpoint at that path |
405 |
method_not_allowed |
The path exists, but not for that HTTP method. The response carries an Allow header listing the methods it does accept |
422 |
validation_failed |
One or more fields are invalid, see Field validation |
429 |
rate_limit_exceeded |
Throughput limit exceeded, a temporary IP block, or too many requests without a valid API key. See Rate Limits |
429 |
quota_exceeded |
Decision Endpoint only. Monthly credits are used up until the billing cycle resets or overage is enabled. Management requests use no credits and never return it |
500 |
server_error |
The request failed on our side |
502, 503, 504 |
Not guaranteed | Infrastructure failure; the body may be empty or outside the JSON envelope. See Errors before the API |
Codes on specific endpoints
The Decision Endpoint and the Management API each list the codes only they return, such as invalid_email or rule_limit_reached.
The /v0 endpoint
POST /v0/gates/{gate_id}/decisions predates this contract and keeps its own:
- Input errors, including
invalid_ip, return400where/v1returns422. Theerrorcodes are the same on both. - An
emailordomainthat isnull, empty, not a string, or longer than 255 characters returns422withmessageanderrors, but noerrorcode. - There is no
invalid_json./v0accepts form-encoded and multipart bodies, and a malformed JSON body returns400 missing_input. - Exceeding the per-second rate limit returns
429with{"status": 429, "error": "Too many requests"}. - Used-up monthly credits return
429 rate_limit_exceededwhere/v1returns429 quota_exceeded. - Some error bodies include a
metaobject; do not require it on every failure. - A wrong path or HTTP method returns a generic
404or405response without anerrorcode.
On both versions, ip: null is treated as absent and adds no IP signals or credits.
Migrate from v0 to v1 covers the move.