Errors
The error shape, every error type, and which errors to retry.
A failed request returns an HTTP error status and a JSON body:
{
"error": {
"type": "invalid_request",
"message": "duplicate option text: ' Yes'",
"param": "questions.q.options"
}
}| Field | Description |
|---|---|
type | One of the types below. Branch on this |
message | A description for people. It can change, so don't parse it |
param | The dotted path to the field at fault, such as questions.risk.levels, or null |
Validation stops at the first problem, so a request with several problems reports one at a time.
Error types
| HTTP | type | When | Retry |
|---|---|---|---|
400 | invalid_request | Malformed JSON, or the request breaks a rule in Create a decision | No. Fix the request |
401 | authentication_error | Missing or invalid API key, including a revoked key | No. Check the key |
402 | insufficient_credit | The organization's credit balance is used up | No. An admin adds credit in the portal under Settings → Billing |
404 | model_not_found | Unknown model | No. Use grayson-1 |
404 | invalid_request | Any path or method other than POST /v1/decide | No. Fix the URL |
413 | request_too_large | Over 32,768 tokens, or a body over 2 MB | No. Shorten the state or ask fewer questions |
429 | rate_limited | Too many requests | Yes, with backoff |
500 | internal_error | Something failed on Finic's side | Yes |
503 | overloaded | Temporarily at capacity, or the decision didn't finish within 30 seconds | Yes, with backoff |
An organization that is out of credit gets 402 before its request is checked, so fix the credit first.
During a deployment or an outage you may also get a 502 or 504 from the network edge. These come without a JSON body or an X-Request-Id header; treat them like 503.
Invalid requests
Some invalid_request errors and the param they point to:
| Cause | param | message |
|---|---|---|
A state of only whitespace, such as " " | state | state must not be blank |
| Question name starts with a digit | questions.1st | invalid name '1st': must match ^[A-Za-z_][A-Za-z0-9_]{0,63}$ |
| Two options whose descriptions differ only in case or whitespace | questions.q.options | duplicate option text: ' Yes' |
Score values not strictly increasing | questions.risk.values | values must be strictly increasing (levels are lowest first) |
options on a noul | questions.q.options | Extra inputs are not permitted |
An unknown top-level field, such as temperature | null | Unknown field "temperature". |
| An unknown field inside a question | questions.q.temperature | Extra inputs are not permitted |
Retrying
A decision changes nothing on Finic's side except usage, so any request is safe to retry. Each successful response uses credit, so a retry after a timeout whose request did succeed is charged twice.
- Retry
429,500,502,503and504, and network errors and timeouts, with exponential backoff and jitter. - Don't retry other
4xxerrors without changing the request; they will fail the same way. - Set your client timeout above 30 seconds, the longest a decision can run.
import random
import time
import requests
RETRYABLE = {429, 500, 502, 503, 504}
def decide(body: dict, api_key: str, attempts: int = 5) -> dict:
for attempt in range(attempts):
last = attempt == attempts - 1
try:
response = requests.post(
"https://api.finic.ai/v1/decide",
headers={"Authorization": f"Bearer {api_key}"},
json=body,
timeout=60,
)
except (requests.ConnectionError, requests.Timeout):
if last:
raise
else:
if response.status_code not in RETRYABLE or last:
break
time.sleep(min(8.0, 0.5 * 2**attempt) * random.uniform(0.5, 1.0))
if not response.ok:
request_id = response.headers.get("X-Request-Id")
try:
error = response.json()["error"]
except ValueError: # an edge 502/504 has no JSON body
raise RuntimeError(f"{response.status_code} (request {request_id})")
raise RuntimeError(f"{response.status_code} {error['type']}: {error['message']} (request {request_id})")
return response.json()Contact support
Email support@finic.ai with the value of the X-Request-Id header. Every response from the API has one, errors included.
Finic records request metadata only, so a request id lets support see the time, key, model, status and error type of a request, but not its state, questions or answers. If a problem depends on the content, describe it or send a redacted example.