/v1/decisions API reference
Our public decisions endpoint, running on TypeSafe's Jev 1.13 (System One) today. POST https://opendecisionsapi.com/v1/decisions — also served at /v1/systemone as a drop-in alias for existing Jev SDK users. This is not OpenAI's endpoint; when OpenAI publishes one we will link it.
Authentication
Create a key on the dashboard (requires a free account) and send it as a bearer token. Keys start with sk- and share your account's input-token balance. Guest sessions cannot create keys.
Authorization: Bearer sk-…Request body
JSON object with three fields:
model—"jev-latest"(default; resolves tojev-1.13.0upstream)."openai-decisions-luna"is rejected with 422 — OpenAI's API is preview-only.state— string or JSON object, the context to judge. Serialized form ≤ 8,000 chars.questions— object keyed by a question id (letters, digits,_; max 8 questions). Each value:
| type | instructions | criteria |
|---|---|---|
choice | required — the question to answer | object mapping 2–20 answer labels to short descriptions |
noul | required — a yes/no question | not used — response is P(yes) |
score | required — what to measure | ordered array of 2–10 level labels, lowest → highest |
Instructions ≤ ~1,800 chars; serialized criteria ≤ 2,000 chars.
Response
200 JSON, passed through from the model. Shape:
{
"model": "jev-latest",
"answers": {
"route": {
"type": "choice",
"choice": "Technical",
"probabilities": { "Billing": 0.11, "Technical": 0.71, "Account": 0.18 },
"confidence": 0.71
},
"urgent_today": {
"type": "noul",
"noul": 0.84
},
"frustration": {
"type": "score",
"score": 1.4,
"probabilities": { "0": 0.1, "1": 0.62, "2": 0.28 },
"legend": { "0": "0: Calm", "1": "1: Frustrated but polite", "2": "2: Very frustrated" }
}
},
"usage": { "input_tokens": 214 }
}choice→choice(the picked label),probabilitiesfor every option,confidence0–1.noul→noul, the probability of “Yes” 0–1.score→ weightedscore, per-levelprobabilities, and alegendmapping keys back to your labels.
Successful responses include x-tokens-remaining with your post-call balance.
Errors
401 | authentication_error — missing, malformed, disabled, or wrong-app key. |
402 | insufficient_credits — input-token balance too low. Top up at /pricing. |
422 | invalid_request_error — failed validation (bad model, missing state, malformed questions), or the model rejected the payload. Message says which. |
429 | rate_limit_error — over 120 requests/minute per key. |
502 | upstream_error — the model could not complete the call. Reserved tokens are refunded. |
Error bodies are { "error": { "type", "message" } }. Upstream 429/529 pass through with the same status.
Idempotency
Send Idempotency-Key (≤ 100 chars) on retries. Retried calls with the same key reuse the same billing record instead of double-charging. We recommend one key per logical decision (e.g. ticket-4821-route).
Limits & rate limits
/v1/* | 120 requests/minute per API key (when KV rate limiting is enabled). |
| playground | 60 runs/hour per IP signed in, 10/hour as a guest. |
| request | state ≤ 8,000 chars · ≤ 8 questions · choice ≤ 20 options · score 2–10 levels. |
Billing: input tokens only, estimated at enqueue then settled to actual usage; overage is refunded automatically. Output is never billed.
Code samples
curl https://opendecisionsapi.com/v1/decisions \
-H "Authorization: Bearer $OPENDECISIONS_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: ticket-4821-route" \
-d '{
"model": "jev-latest",
"state": "Since yesterday, every CSV export from our dashboard stops halfway through...",
"questions": {
"route": {
"type": "choice",
"instructions": "Which team should handle this support ticket?",
"criteria": {
"Billing": "Invoices, payments, subscriptions, or refunds.",
"Technical": "Errors or product features that are not working.",
"Account": "Login, access, or account settings."
}
},
"urgent_today": {
"type": "noul",
"instructions": "Does this need attention today?"
}
}
}'