Decisions API documentation

Everything you need to make your first Decisions API call: one endpoint, three question types, and a response your code can use without parsing.

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
FieldTypeDescription
contextstring | object | string[]What the decision is about. Required.
questionsobject1 or more questions, keyed by a name you choose. Required.
questions.*.typestringchoice, score or yes_no.
questions.*.optionsobject | string[]choice: option → description. score: ordered list, low to high.
questions.*.questionstringRequired for yes_no, optional framing for choice and score.
instructionsstringOptional 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

FieldTypeDescription
idstringUnique id for the decision, useful for logs and support.
answers.*.choicestringSelected option (choice and score).
answers.*.confidencenumberProbability of the selected option, 0–1.
answers.*.probabilitiesobjectProbability for every option you defined.
answers.*.answerbooleanyes_no only.
answers.*.probabilitynumberyes_no only: probability of “yes”.
usage.input_tokensnumberBillable 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"
  }
}
StatusTypeMeaning
400invalid_requestThe body failed validation. The message names the field.
401unauthorizedMissing or invalid API key.
402insufficient_balanceThe free allowance or prepaid balance is used up.
413context_too_largeThe context exceeds the per-request token limit.
429rate_limitedToo many requests. Retry after the Retry-After header.
5xxserver_errorSomething 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.