Decisions API

DECISIONS API · REFERENCE

Decisions API reference

The Decisions API answers closed questions about a context. You list the allowed answers; each decision returns the chosen answer and a probability for every option. Create a key, send one POST, and read typed results.

Base URL https://decisionsapi.pro/api · Endpoint POST /v1/decisions

cURL
curl --fail-with-body https://decisionsapi.pro/api/v1/decisions \
  -H "Authorization: Bearer $DECISIONS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-6-luna","context":"I was charged twice for my Pro subscription this month. Please refund the duplicate payment before Friday.","questions":{"queue":{"type":"choice","instructions":"Which queue should handle this ticket?","options":{"billing":"Payments, refunds and invoices","technical_support":"Bugs and product problems","sales":"New purchases and upgrades"}},"urgent":{"type":"yes_no","instructions":"Does the customer mention a deadline?"}}}'

API keys

Create a key on the API keys page after signing in. Send it from your server as Authorization: Bearer <key>. Never ship a key in browser or mobile code, and revoke it from the same page when you no longer need it.

Models

ModelRuns onUse it for
gpt-6-lunaOfficial OpenAI Decisions API (POST /v1/decisions)Default and only model. Text and images, choice, yes/no and score questions.

The earlier names decisions-latest and decisions-mini are still accepted and run on gpt-6-luna.

GET /api/v1/models lists the models available to your key.

List models
curl https://decisionsapi.pro/api/v1/models -H "Authorization: Bearer $DECISIONS_API_KEY"

Request format

JSON body
{
  "model": "gpt-6-luna",
  "context": "I was charged twice for my Pro subscription this month. Please refund the duplicate payment before Friday.",
  "questions": {
    "queue": {
      "type": "choice",
      "instructions": "Which queue should handle this ticket?",
      "options": {
        "billing": "Payments, refunds and invoices",
        "technical_support": "Bugs and product problems",
        "sales": "New purchases and upgrades"
      }
    },
    "urgent": {
      "type": "yes_no",
      "instructions": "Does the customer mention a deadline?"
    }
  }
}
FieldRequiredFormat
modelNogpt-6-luna (default).
contextYesText, a JSON object or an array; up to 100,000 characters.
imagesNoUp to 4 images: https URLs or base64 data URLs (PNG, JPEG, WebP, GIF, up to 5 MB each). context may be empty when images are sent.
image_detailNoauto (default), low or high. Low detail uses fewer input tokens.
questionsYesObject keyed by question ID; 1–32 questions.

Question IDs use letters, digits, dot, dash or underscore (up to 64 characters). The request body is limited to 20 MB. All questions are answered in one model call over the same context and images. The context is treated as data: instructions inside it are judged, not followed.

Question types

All three types
{
  "sentiment": {
    "type": "score",
    "instructions": "How satisfied is the reviewer overall?",
    "levels": [
      "Very negative",
      "Negative",
      "Mixed",
      "Positive",
      "Very positive"
    ]
  },
  "refund_requested": {
    "type": "yes_no",
    "instructions": "Does the customer ask for a refund?",
    "criteria": {
      "yes": "Explicitly asks for money back",
      "no": "Anything else"
    }
  },
  "topic": {
    "type": "choice",
    "instructions": "What is the main topic?",
    "options": {
      "shipping": null,
      "product_quality": null,
      "billing": null,
      "other": null
    }
  }
}
TypeDefineReturns
choiceoptions: 2–50 names, each with an optional description (or null).answer, confidence, probabilities per option.
yes_noOptional criteria.yes / criteria.no descriptions.answer (boolean), probability of yes, confidence.
scorelevels: 2–10 labels, lowest to highest.answer (level label), level (0-based), score (expected level), probabilities.

Response format

A 200 response maps each question ID to its decision. Probabilities come from the OpenAI Decisions API; for a question they sum to 1. The values below are illustrative. If the model declines one question, that decision is {"type": "refusal"} and the others are still answered.

200 response
{
  "id": "4f3c1a2e-…",
  "object": "decision",
  "model": "gpt-6-luna",
  "decisions": {
    "queue": {
      "type": "choice",
      "answer": "billing",
      "confidence": 0.9998,
      "probabilities": {
        "billing": 0.9998,
        "technical_support": 0.0001,
        "sales": 0.0001
      }
    },
    "urgent": {
      "type": "yes_no",
      "answer": true,
      "probability": 0.9241,
      "confidence": 0.9241
    }
  },
  "usage": {
    "input_tokens": 214,
    "output_tokens": 0
  },
  "latency_ms": 1180
}

usage.input_tokens is the model input for the whole request, the number you are billed for. Output tokens are always 0.

Image input

Pass screenshots, receipts, product photos or scanned documents in images. The Decisions API reads them together with the text context for every question. OpenAI only accepts inline images, so https URLs are downloaded by our server first; they must be public and respond directly (no redirects) within 10 seconds.

Image request
{
  "model": "gpt-6-luna",
  "context": "Employee note: client dinner after the Milan workshop. Alcohol needs manager approval.",
  "images": [
    "https://decisionsapi.pro/examples/receipt.jpg"
  ],
  "questions": {
    "category": {
      "type": "choice",
      "instructions": "Which expense category is this receipt?",
      "options": {
        "meals": null,
        "travel": null,
        "software": null,
        "office": null
      }
    },
    "needs_approval": {
      "type": "yes_no",
      "instructions": "Does the receipt include alcohol?"
    }
  }
}

OpenAI request format

The same endpoint also accepts the request body of the OpenAI Decisions API: input (text, or user messages with input_text and input_image parts) and a questions array of predicate, choice and score questions. Code written for https://api.openai.com/v1/decisions only needs a new base URL and a Decisions API key. The response keeps OpenAI's answers array, in question order.

OpenAI-format request
{
  "model": "gpt-6-luna",
  "input": "I was charged twice for my order.",
  "questions": [
    {
      "type": "choice",
      "name": "department",
      "instructions": "Which department should handle this complaint?",
      "choices": [
        {
          "value": "billing",
          "description": "Payments, invoices, and refunds."
        },
        {
          "value": "technical"
        },
        {
          "value": "shipping"
        },
        {
          "value": "other"
        }
      ]
    },
    {
      "type": "predicate",
      "name": "refund",
      "instructions": "Does the customer ask for money back?"
    },
    {
      "type": "score",
      "name": "severity",
      "instructions": "How severe is this issue?",
      "levels": [
        {
          "label": "Low"
        },
        {
          "label": "Medium"
        },
        {
          "label": "High"
        }
      ]
    }
  ]
}
200 response
{
  "id": "9b1e…",
  "object": "decision",
  "model": "gpt-6-luna",
  "answers": [
    {
      "type": "choice",
      "name": "department",
      "choice": "billing",
      "probabilities": [
        {
          "value": "billing",
          "probability": 1
        },
        {
          "value": "technical",
          "probability": 0
        },
        {
          "value": "shipping",
          "probability": 0
        },
        {
          "value": "other",
          "probability": 0
        }
      ],
      "confidence": 1
    },
    {
      "type": "predicate",
      "name": "refund",
      "probability": 0.02
    },
    {
      "type": "score",
      "name": "severity",
      "score": 0.75,
      "probabilities": [
        {
          "value": 0,
          "label": "Low",
          "probability": 0.26
        },
        {
          "value": 1,
          "label": "Medium",
          "probability": 0.73
        },
        {
          "value": 2,
          "label": "High",
          "probability": 0.01
        }
      ],
      "confidence": 0.6
    }
  ],
  "usage": {
    "input_tokens": 387,
    "output_tokens": 0
  },
  "latency_ms": 2100
}

Unnamed questions are named question_1, question_2 and so on. Image parts may be data URLs or public https URLs. The same limits, billing and errors apply.

Python example

Standard library only. Use the confidence to decide when a person should review.

Python
import json, os, urllib.request

body = {
    "model": "gpt-6-luna",
    "context": "Nobody wants your garbage opinions here. Log off.",
    "questions": {
        "label": {"type": "choice", "instructions": "Which policy label fits best?",
                  "options": {"safe": None, "harassment": None, "threat": None, "spam": None}},
        "hide": {"type": "yes_no", "instructions": "Should this be hidden until reviewed?"},
    },
}
req = urllib.request.Request(
    "https://decisionsapi.pro/api/v1/decisions",
    data=json.dumps(body).encode(),
    headers={"Authorization": f"Bearer {os.environ['DECISIONS_API_KEY']}",
             "Content-Type": "application/json"},
)
with urllib.request.urlopen(req, timeout=30) as resp:
    result = json.load(resp)

label = result["decisions"]["label"]
if label["confidence"] < 0.8:
    print("send to a human reviewer", label["probabilities"])
else:
    print("label:", label["answer"])

Billing headers

API calls use purchased input tokens first; if the token balance is insufficient, one credit covers the whole request. A request never charges both balances, output tokens are free, and failed requests are not charged.

HeaderMeaning
X-Decisions-BillingBalance used: tokens or credits-fallback.
X-Decisions-Paid-Input-Tokens-UsedInput tokens charged.
X-Decisions-Credits-UsedCredits charged.
X-Decisions-Tokens-RemainingToken balance after the call.
X-Decisions-Credits-RemainingCredit balance after the call.

See pricing for token plans.

Errors and limits

HTTPMeaningWhat to do
401Missing, invalid or revoked key.Use a valid key; do not retry.
402No balance or spending paused.Add tokens on the pricing page.
422Invalid model, context or question.Fix the request body.
429Rate limit (600 requests per minute per account) or model busy.Wait for Retry-After, then retry.
502 / 503 / 504Model unavailable or timed out.Retry with backoff; nothing was charged.

Readiness check

A public check that returns ready and a reason. It does not run a decision or use a key.

Readiness
curl https://decisionsapi.pro/api/decisions/status