Reference
Errors & Rate Limits

Errors, Rate Limits & Quotas

Every API has failure modes. This page covers how the AIOZ AI API tells you something went wrong, which errors are worth retrying and which aren't, and the rate limits and quotas you'll bump into at scale.

The error response shape

When a request fails, the API returns a non-2xx HTTP status code and a JSON body of the shape:

{
  "status": "fail",
  "message": "human-readable error description"
}

The status field is "fail" and the message field is intended to be safe to surface to your own users or to log. The HTTP status code carries the category of failure; the message carries the specifics.

HTTP status code reference

The codes you'll commonly see, with their general meaning across endpoints. Endpoint-specific failures use the same codes; the message field tells you what specifically went wrong.

StatusCategoryWhen you'll see it
200 OKSuccessThe request succeeded; the response body's data field has your payload.
400 Bad RequestMalformed requestThe request itself is malformed, e.g. invalid JSON the server can't parse. Check message, fix the request before retrying.
401 UnauthorizedAuthenticationYour x-api-key header is missing, malformed, or no longer valid (e.g. the key was revoked).
403 ForbiddenAuthorizationThe authenticated identity doesn't have permission to perform the action.
404 Not FoundMissing resourceThe requested resource doesn't exist or isn't accessible to this key.
409 ConflictState conflictThe request can't be applied because of the resource's current state.
422 Unprocessable EntityValidationA body or query field is missing, has the wrong type, or fails an allowed-values (enum) check — e.g. an unknown sort or type value, a missing required field on a presigned-upload request, or size ≤ 0. The message names the offending field. Fix the request before retrying.
429 Too Many RequestsRate limitYou've exceeded a rate limit. Wait before retrying. See Rate limits below.
500 Internal Server ErrorServer-sideSomething went wrong on our side. The request itself was well-formed; retrying after a short delay will often succeed.

Rate limits

The API applies rate limits per API key to protect the platform from accidental overload and to keep latency predictable across all callers. When you exceed a limit, requests are rejected with a 429 Too Many Requests until the limit window resets.

Limits: the rate depends on the kind of endpoint you're calling, applied per API key:

  • Public endpoints: 5 requests per second.
  • Auth endpoints: 15 requests per second.

Response headers. Rate-limited responses, and successful responses on rate-limited endpoints, include the following headers so you can track your status without guessing:

HeaderMeaning
RateLimit-LimitThe maximum number of requests allowed in the current window.
RateLimit-RemainingThe number of requests left in the current window.
RateLimit-ResetSeconds until the current window resets and RateLimit-Remaining refills.
X-Rate-Limit-LimitThe same limit, expressed as a decimal (e.g. 5.00).
X-Rate-Limit-DurationThe length of the rate-limit window, in seconds.

Design your client to handle 429 gracefully: back off and retry after the window resets (wait RateLimit-Reset seconds), and don't burst all your requests at once.

Quotas

In addition to per-window rate limits, your account has a balance-based quota: you can only run tasks until you've used your available credits. See How Billing Works for how credits are consumed and how to check your balance. There is no separate API call that "reserves" credits; creating a task that would push you past your balance fails at the time of creation.

Retry guidance

Some errors are worth retrying and some aren't. As a rule:

  • 400, 401, 403, 404, 409, 422: don't retry. These are deterministic failures; the same request will keep failing until you fix it.
  • 429: retry, but only after a delay. Wait RateLimit-Reset seconds; otherwise back off exponentially.
  • 500, 502, 503, 504: retry with exponential backoff, capped at a small number of attempts. These are usually transient.

A reasonable pattern for retryable errors:

attempt = 0
max_attempts = 5
while attempt < max_attempts:
    response = call()
    if response is successful:
        return response
    if response status is non-retryable:
        raise
    wait = min(60, 2 ** attempt) seconds, with a little jitter
    sleep(wait)
    attempt += 1
raise last error

The SDKs handle automatic retries for transient transport-level failures (connection resets, brief network blips) at the HTTP layer. Application-level retry decisions (whether to retry a 429, a 500, or a timeout) are left to your code, since the right strategy depends on what the request was doing.