simodocs

HTTP API

Errors

Every error returns JSON with a stable code and a human-readable message:

JSON
{"error": {"code": "insufficient_balance", "message": "Your balance is $0. Contact us to add funds."}}

Branch on code, not on message; messages may change.

Status codes

Status Code Meaning Charged What to do
400 invalid_json The body isn't a JSON object No Fix the body
400 unknown_model model isn't a Simo model No Use simo-1-pro
400 / 422 varies A question, media or option is invalid. The body names the bad field No Read the error detail
401 unauthorized No Authorization header No Send Bearer <key>
401 invalid_api_key The key is wrong or revoked No Check the key in the console
402 insufficient_balance Your balance is $0 No Add credit
403 account_suspended The account is suspended No Contact support
403 model_not_available The model isn't open yet No Use simo-1-pro
413 payload_too_large The body is over 25 MB No Send smaller or fewer images
429 Too many requests No Retry with backoff
502 upstream_unavailable The model is briefly unavailable No Retry with backoff
503 / 504 The service is briefly unavailable No Retry with backoff

Validation errors from the model (400 / 422) pass through with details naming the field, for example:

JSON
{"detail": [{"loc": ["body", "questions", "team", "criteria"], "msg": "...", "type": "..."}]}

Retrying

Retry 429, 502, 503 and 504 with exponential backoff, honoring Retry-After when present. Don't retry 4xx errors other than 429: the same request will fail again. The Python SDK does this for you (3 retries by default).

JavaScript
async function ask(body, attempt = 0) {
  const res = await fetch("https://api.temprl.org/v1/ask", {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.SIMO_API_KEY}`, "Content-Type": "application/json" },
    body: JSON.stringify(body),
  });
  if ([429, 502, 503, 504].includes(res.status) && attempt < 3) {
    const wait = Number(res.headers.get("retry-after")) * 1000 || 500 * 2 ** attempt;
    await new Promise((r) => setTimeout(r, wait));
    return ask(body, attempt + 1);
  }
  const data = await res.json();
  if (!res.ok) throw Object.assign(new Error(data.error?.message ?? res.statusText), { status: res.status, data });
  return data;
}

SDK exceptions

Every failure raises a SimoError subclass. Each carries status, code, detail and request_id.

Exception When
AuthError 401: missing, wrong or revoked key
InsufficientBalance 402: no balance left (not charged)
PermissionDenied 403: account suspended, or the model isn't open to you
InvalidRequest 400 / 413 / 422: bad JSON or question, media not matching the state, over 25 MB
ModelNotFound Unknown model
QueueFull 429, after the automatic retries
Unavailable 502 / 503 / 504, after the automatic retries (not charged)
ServerError Any other 5xx
ConnectionFailed The API is unreachable
SimoTimeout No answer within timeout
Python
from simoai import InsufficientBalance, InvalidRequest, SimoError

try:
    r = c.ask(state, questions)
except InsufficientBalance:
    top_up()                              # 402: not charged
except InvalidRequest as e:
    print(e.code, e.detail)               # names the bad field
except SimoError as e:
    print(e.status, e.code, e, e.request_id)