Console coming soon
Browse documentation

Developer docs

Start from a live reference page.

Phone layout stays search-first: pick a page here, then read it in a full single-column view.

Getting Started

Models

API Reference

Operations

Enterprise

Console

Policies

Errors

Errors raised by the API return a consistent envelope and an HTTP status code suitable for automated handling. Two documented exceptions bypass the envelope.

The shape of an error

Every error comes back the same way, so you can handle them with one branch rather than a special case per endpoint.

{
  "error": {
    "code": "INVALID_API_KEY",
    "message": "API key not found or has been revoked."
  }
}

Two cases do not return this envelope: (a) request-body parsing failures, malformed JSON, a missing required field, or a missing Content-Type: application/json header, are rejected by the HTTP layer before the handler runs and return a plain-text body with a 400, 415, or 422 status (a missing prompt is a 422 here, not EMPTY_PROMPT); (b) an unrecognised /api/v1/* path returns 404 with a welcome JSON object rather than the error envelope. Always guard response.json() and check for the error key before indexing it.

Every code

The full list. Most integrations only ever meet a handful of these, and the ones worth handling deliberately are 401, 429 and 402.

HTTPCodeDescription
401MISSING_API_KEYMissing bearer header.
401INVALID_API_KEYInvalid, expired, or revoked key.
400API_KEY_ERROROther API-key validation failure.
403INSUFFICIENT_SCOPEKey scope does not allow the route.
403INSUFFICIENT_TIERSubscription tier too low.
429RATE_LIMITEDMinute request envelope or per-day rung ceiling exceeded (the two are indistinguishable by code).
503BUDGET_UNAVAILABLEBudget enforcement could not be verified; the hard cap fails closed. Retry.
400EMPTY_PROMPTPrompt missing.
400PROMPT_TOO_LARGEPrompt exceeds 100,000 bytes.
400INVALID_MODELUnknown model identifier.
400MODEL_UNAVAILABLEKnown model ID, but not currently available.
400EMPTY_BATCHBatch request contained no items.
400BATCH_TOO_LARGEBatch exceeded the 100-request limit.
400INVALID_REQUESTInvalid request contract, includes a max_output_rungs of 0 or above the selected model's output limit, and malformed requests rejected by the inference gateway.
402BUDGET_EXCEEDEDProject hard cap would be exceeded by the request.
404NOT_FOUNDRequested upstream object was not found.
404SOURCES_NOT_FOUNDNo live sources retained for that request ID.
413PAYLOAD_TOO_LARGEUpstream payload exceeded the accepted size limit.
422SAFETY_BLOCKEDGateway safety pre-screen blocked the request.
429INFERENCE_RATE_LIMITEDUpstream inference service throttled the request.
503EVA_UNAVAILABLEInference service unavailable.
401INFERENCE_UNAUTHORIZEDGateway credentials were rejected upstream.
503INFERENCE_BUSYInference backend reported temporary saturation.
500DB_ERRORUsage or billing query failed.
500SERVER_MISCONFIGUREDAPI key verification is not configured correctly.
502INFERENCE_ERRORGateway or upstream dispatch failure on non-streaming requests. Also emitted in-band as a response.error SSE event on streaming requests, where the HTTP status is 200.
503DB_UNAVAILABLERequired database services are unavailable.

What to retry

The short version: retry when the platform is having a problem, and do not retry when your request is the problem. Retrying a rejected payload just spends your rate limit arriving at the same answer.

429 Rate Limited

When request limits are exceeded, the API returns retry-after (seconds, always at least 1, the exact value depends on which limiter tripped), x-ratelimit-reset (same value), x-ratelimit-limit, and x-ratelimit-remaining. Read retry-after from the response rather than assuming a fixed window.

Rate-limit headers are attached to successful (2xx) responses and to 429 responses only. Other 4xx/5xx responses carry none, so do not rely on them for backoff on those paths.

400 and 402 Contract or Budget Errors

Do not retry unchanged requests that fail with validation, model-selection, or budget-cap errors. Fix the payload, switch model, lower max_output_rungs, or adjust the project budget first.

500, 502 and 503 Service Errors

Retry with bounded exponential backoff. If the failure persists, stop retrying and inspect upstream availability, database health, workspace budget state, and current platform status.

Handling this in practice

import requests
import time

def call_eva(prompt, retries=3):
    for attempt in range(retries):
        response = requests.post(
            "https://evaesi.dev/api/v1/responses",
            headers={"Authorization": "Bearer esi_dev_YOUR_KEY"},
            json={"prompt": prompt, "model": "instant"},
        )

        if response.status_code == 200:
            return response.json()

        if response.status_code == 429:
            wait = int(response.headers.get("retry-after", 60))
            time.sleep(wait)
            continue

        if response.status_code >= 500:
            time.sleep(2 ** attempt)
            continue

        # Body-parse rejections (400/415/422) return plain text, not the
        # error envelope - guard the JSON decode before indexing it.
        try:
            error = response.json()["error"]["message"]
        except (ValueError, KeyError):
            error = response.text
        raise Exception(f"{response.status_code}: {error}")

    raise Exception("Max retries exceeded")