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_01J9X4M2Q8",
"answers": {
"team": {
"choice": "billing",
"confidence": 0.97,
"probabilities": { "billing": 0.97, "technical": 0.02, "sales": 0.01 }
}
},
"usage": { "input_tokens": 41 }
}
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 are issued from the waitlist, in batches. Keep your key on the server: never ship it in a browser bundle or a mobile app.
Don’t have a key yet? Join the Decisions API waitlist and we’ll email you when yours is ready.
Endpoint
The Decisions API has a single endpoint:
POST https://api.decisionsapi.cc/v1/decisions
| 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. |
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. Tell us on the waitlist if your use case needs it.
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
}
}
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. |
answers.*.choice | string | Selected option (choice and score). |
answers.*.confidence | number | Probability of the selected option, 0–1. |
answers.*.probabilities | object | Probability for every option you defined. |
answers.*.answer | boolean | yes_no only. |
answers.*.probability | number | yes_no only: probability of “yes”. |
usage.input_tokens | number | Billable input tokens. See Decisions API pricing. |
Decisions API in Python and Node.js
The Decisions API is a single JSON endpoint, so any HTTP client works. Typed Python and TypeScript helpers will ship with the first keys.
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 | The free allowance or prepaid balance is used up. |
| 413 | context_too_large | The context exceeds the per-request token limit. |
| 429 | rate_limited | Too many requests. 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.