Errors

Every status code the API returns, what it means, and how to react to it.

The error envelope

Errors share one shape. code is -1, message is human-readable, and error repeats the message so the body reads like a normal REST error. Some errors add extra fields that tell you what to do next.

{
  "code": -1,
  "message": "\"input\" is required",
  "error": "\"input\" is required"
}

Status codes

400 Bad Request

The request never reached the model. Nothing was billed.

MessageCause
Request body must be JSONThe body could not be parsed.
Request body must be a JSON objectThe body was valid JSON but not an object.
"input" is requiredinput (or state) was missing or empty.
At least one question is requiredquestions was missing or empty.
Question "<key>" requires a "prompt" (or "instructions") stringA question had no prompt.
Question "<key>" of type "choice" requires a "criteria" object, ...A choice question had no criteria.
Question "<key>" of type "score" requires a "criteria" array, ...A score question had no criteria.
Question "<key>" has an unsupported type. Use one of: choice, score, noulThe type was not recognised.

401 Unauthorized

MessageCause
Missing API key. Pass it as "Authorization: Bearer sk-..."No bearer token on the request.
Invalid API keyThe key does not exist, was deleted, or is disabled.

402 Payment Required

The account has no usable credits.

{
  "code": -1,
  "message": "Insufficient credits",
  "error": "Insufficient credits",
  "remaining_credits": 0
}

Buy a credit pack to continue. See Limits & credits.

429 Too Many Requests

The daily allowance is used up. See Limits & credits for the full rules.

{
  "code": -1,
  "message": "You have reached the daily free limit of 100 decisions. Buy credits to lift it.",
  "error": "You have reached the daily free limit of 100 decisions. Buy credits to lift it.",
  "daily_limit": 100,
  "reset_at": "2026-11-01T09:14:22.000Z",
  "remaining_credits": 812,
  "upgrade_path": "/settings/credits"
}

500 Internal Server Error

The service could not complete the call — for example Jev decision failed unexpectedly, or Jev upstream is not configured. Nothing was billed. Retry after a short delay; if it persists, contact support with the request id.

502 Bad Gateway

The upstream model rejected the request, or answered in a way the API could not turn into a decision. The message carries the upstream status and body so you can see what the provider said. Nothing was billed.

Handling errors in code

const response = await fetch('https://jevmodel.io/api/v1/decisions', options);
const payload = await response.json();

if (!response.ok) {
  switch (response.status) {
    case 400:
      throw new Error(`Bad request: ${payload.message}`);
    case 401:
      throw new Error('The API key is missing or invalid.');
    case 402:
      throw new Error('Out of credits.');
    case 429:
      throw new Error(`Rate limited until ${payload.reset_at}.`);
    default:
      throw new Error(`Jev API error ${response.status}: ${payload.message}`);
  }
}

Retrying

  • 400, 401, and 402 will not succeed on a retry. Fix the request, the key, or the balance first.
  • 429 succeeds after reset_at.
  • 500 and 502 are worth retrying with exponential backoff. Since a failed call is not billed, a retry costs you nothing beyond the upstream call.