Decisions API quickstart
A Decisions API call takes two things: the context you want a decision about, and the questions to answer, each with its allowed answers. This request routes a support ticket to one of three teams:
curl https://api.decisionsapi.cc/v1/decisions \
-H "Authorization: Bearer $DECISIONS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"context": "Charged twice for my March invoice, please refund one.",
"questions": {
"team": {
"type": "choice",
"options": {
"billing": "Payments, invoices, refunds",
"technical": "Bugs, errors, integrations",
"sales": "Plans, pricing, upgrades"
}
}
}
}'
The response contains one answer per question, keyed by the name you chose:
{
"id": "dec_01J9X4M2Q8a7c3e5b1d0",
"model": "decisions",
"answers": {
"team": {
"choice": "billing",
"confidence": 0.97,
"probabilities": { "billing": 0.97, "technical": 0.02, "sales": 0.01 }
}
},
"usage": { "input_tokens": 41, "credits": 1 }
}
choice is always one of the options you sent. probabilities covers every option and
sums to 1, so you can apply your own threshold.
Authentication
Every Decisions API request is authenticated with a secret key in the Authorization header:
Authorization: Bearer $DECISIONS_API_KEY
Keys start with dk_live_. Keep your key on the server: never ship it in a browser bundle or
a mobile app.
Don’t have a key yet? Buy credits and get one instantly. Check your remaining credits with GET /v1/balance.
Endpoint
The Decisions API has one endpoint for decisions, and one to check your balance:
POST https://api.decisionsapi.cc/v1/decisions
GET https://api.decisionsapi.cc/v1/balance
| Field | Type | Description |
|---|---|---|
context | string | object | string[] | What the decision is about. Required. |
questions | object | 1 or more questions, keyed by a name you choose. Required. |
questions.*.type | string | choice, score or yes_no. |
questions.*.options | object | string[] | choice: option → description. score: ordered list, low to high. |
questions.*.question | string | Required for yes_no, optional framing for choice and score. |
instructions | string | Optional policy text that applies to every question. |
model | string | Optional. decisions (the default) or decisions-latest. |
Context
The Decisions API accepts context in the form you already have it. You don’t need to extract features or summarize first.
- Text: a ticket, an email, a chat transcript, a product description.
- JSON: an event, a database row, an agent’s state.
- A list of strings: messages in a thread, lines in a log.
{
"context": {
"event": "checkout_failed",
"plan": "team",
"error": "card_declined",
"attempts": 3,
"last_message": "tried two cards, neither works"
},
"questions": { ... }
}
Image input is on the Decisions API roadmap.
Decisions API question types
You can mix all three types in one request. Each question is answered independently against the same context.
choice
Pick exactly one option. Describe each option in plain words, as you would brief a colleague. Good descriptions are the biggest lever on accuracy.
"team": {
"type": "choice",
"options": {
"billing": "Payments, invoices, refunds",
"technical": "Bugs, errors, integrations",
"sales": "Plans, pricing, upgrades"
}
}
"team": {
"choice": "billing",
"confidence": 0.97,
"probabilities": { "billing": 0.97, "technical": 0.02, "sales": 0.01 }
}
score
Place the context on an ordered scale. List options from lowest to highest. The Decisions API returns the most likely point and a probability for each, so you can also read the expected value.
"priority": {
"type": "score",
"question": "How soon does this need a human reply?",
"options": ["whenever", "today", "within the hour", "right now"]
}
"priority": {
"choice": "today",
"confidence": 0.64,
"probabilities": {
"whenever": 0.08, "today": 0.64, "within the hour": 0.23, "right now": 0.05
},
"score": 1.25
}
yes_no
Answer one yes-or-no question with a boolean and the probability of “yes”.
"refund_requested": {
"type": "yes_no",
"question": "Is the customer asking for money back?"
}
"refund_requested": { "answer": true, "probability": 0.93 }
Response
| Field | Type | Description |
|---|---|---|
id | string | Unique id for the decision, useful for logs and support. |
model | string | The model that answered. |
answers.*.choice | string | Selected option (choice and score). |
answers.*.confidence | number | How certain the model is, 0–1. Derived from the probabilities; use it for thresholds. |
answers.*.probabilities | object | Probability for every option you defined. |
answers.*.score | number | score only: expected position on the scale, 0 = first option. |
answers.*.answer | boolean | yes_no only. |
answers.*.probability | number | yes_no only: probability of “yes”. |
usage.input_tokens | number | Input tokens in the request. |
usage.credits | number | Credits charged: 1 per started 4,000 input tokens. See pricing. |
Decisions API in Python and Node.js
The Decisions API is a single JSON endpoint, so any HTTP client works and no SDK is needed. Copy one of these helpers, or give your coding agent the markdown reference.
Python: route a ticket, send unsure cases to a person
import os
import requests
DECISIONS_URL = "https://api.decisionsapi.cc/v1/decisions"
HEADERS = {"Authorization": f"Bearer {os.environ['DECISIONS_API_KEY']}"}
def decide(context, questions):
res = requests.post(DECISIONS_URL, headers=HEADERS, json={
"context": context,
"questions": questions,
}, timeout=10)
res.raise_for_status()
return res.json()["answers"]
answers = decide(ticket.body, {
"team": {"type": "choice", "options": {
"billing": "Payments, invoices, refunds",
"technical": "Bugs, errors, integrations",
}},
"urgent": {"type": "yes_no", "question": "Does the customer need action today?"},
})
if answers["team"]["confidence"] < 0.7:
send_to_human(ticket)
else:
route_to(answers["team"]["choice"], urgent=answers["urgent"]["answer"])
Node.js: choose an agent’s next action
const DECISIONS_URL = "https://api.decisionsapi.cc/v1/decisions";
export async function decide(context, questions) {
const res = await fetch(DECISIONS_URL, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.DECISIONS_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ context, questions }),
});
if (!res.ok) throw new Error(`Decisions API error ${res.status}`);
return (await res.json()).answers;
}
// Let an agent pick its next tool from a closed list
const { next_action } = await decide(agentState, {
next_action: {
type: "choice",
options: {
search_docs: "The answer is probably in the product docs",
ask_user: "Required information is missing",
create_ticket: "This needs a human on the support team",
finish: "The user's request is fully handled",
},
},
});
Errors
Errors use standard HTTP status codes and a consistent body:
{
"error": {
"type": "invalid_request",
"message": "questions.team.options must have at least 2 entries",
"param": "questions.team.options"
}
}
| Status | Type | Meaning |
|---|---|---|
| 400 | invalid_request | The body failed validation. The message names the field. |
| 401 | unauthorized | Missing or invalid API key. |
| 402 | insufficient_balance | This key has no credits left. Top up on the pricing page. |
| 413 | context_too_large | The context exceeds the per-request token limit. |
| 429 | rate_limited | Too many requests. Retry after the Retry-After header. |
| 503 | overloaded | Temporarily over capacity. Retry after the Retry-After header. |
| 5xx | server_error | Something failed on our side. Safe to retry with backoff. |
Best practices
- Make options mutually exclusive. If two options could both be right, merge them or add a third that covers the overlap.
- Add an escape hatch. An option like
"none": "None of the above apply"keeps the Decisions API from forcing a bad fit. - Use probabilities, not just the choice. Pick a confidence threshold per question and route everything below it to a human.
- Ask small questions. Three narrow questions in one request beat one broad question with twelve options.
- Evaluate on your own data. Run 100 labeled examples before you switch traffic, and re-run them whenever you edit option descriptions.