Decisions API
Send evidence and an ordered list of predicate, choice, and score questions, and read back one typed answer per question.
POST /v1/decisions takes evidence and a list of questions and returns one
answer per question, in question order. Evidence is text, a list of messages
with text and image parts, or an audio clip.
Request
curl https://api.sprag.ai/v1/decisions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SPRAG_API_KEY" \
-d '{
"model": "spev",
"input": "The agent was polite but could not answer my question about the invoice.",
"questions": [
{
"name": "resolution",
"type": "score",
"instructions": "How well was the issue resolved?",
"levels": [
{ "label": "unresolved", "description": "The question was not answered." },
{ "label": "partial" },
{ "label": "resolved" }
]
}
]
}'| Field | Required | Type | Notes |
|---|---|---|---|
model | Yes | string | A model id from the Decisions models. |
input | Yes | string or array | Text evidence, or an array of user messages. See Send an image. |
questions | Yes | array | 1 to 200 questions. Answers come back in this order. |
input_audio | No | object | An audio clip as {"data": "<base64>", "format": "wav"}. See Send audio. |
safety_identifier | No | string | An opaque id for your end user, up to 128 characters. |
Ask a question
Every question has a type and instructions. name is optional. If you set
name, the answer carries the same name; otherwise its name is null.
Names are unique within a request.
Predicate
A predicate asks whether a condition holds.
{ "name": "refund", "type": "predicate", "instructions": "Is the customer asking for a refund?" }The answer's probability is the probability that the condition holds, from 0
to 1.
{ "type": "predicate", "name": "refund", "probability": 0.9997 }Choice
A choice picks one value from a list you supply.
| Field | Required | Type | Notes |
|---|---|---|---|
choices | Yes | array | 2 to 255 options. Each value is a string or a boolean, and values are distinct. |
choices[].description | No | string | When this option applies. |
The answer's choice is the selected value, with the same type you sent.
probabilities holds one entry per option in the order you supplied them, and
confidence runs from 0 to 1.
{
"type": "choice",
"name": "department",
"choice": "billing",
"probabilities": [
{ "value": "billing", "probability": 0.981 },
{ "value": "technical", "probability": 0.019 }
],
"confidence": 0.962
}Score
A score rates the evidence on a scale of levels you define, lowest first.
| Field | Required | Type | Notes |
|---|---|---|---|
levels | Yes | array | 2 to 10 levels in ascending order. The first level has the value 0. |
levels[].label | Yes | string | The level's name. |
levels[].description | No | string | The criteria for this level. |
probabilities holds one entry per level, with its value and label.
score is the expected level value: each level's value weighted by its
probability. A score of 1.5 on a three-level scale sits halfway between the
second and third levels. confidence runs from 0 to 1.
{
"type": "score",
"name": "resolution",
"score": 0.007,
"probabilities": [
{ "value": 0, "label": "unresolved", "probability": 0.993 },
{ "value": 1, "label": "partial", "probability": 0.007 },
{ "value": 2, "label": "resolved", "probability": 0.0003 }
],
"confidence": 0.989
}Refusal
An answer of type refusal can replace the answer to any question. It carries
the question's name and no probabilities.
{ "type": "refusal", "name": "resolution" }Send an image
To attach an image, send input as an array of user messages. Each message's
content is a string or an array of input_text and input_image parts.
{
"model": "spev",
"input": [
{
"role": "user",
"content": [
{ "type": "input_text", "text": "Photo from the delivery driver." },
{ "type": "input_image", "image_url": "data:image/png;base64,iVBORw0KGgo..." }
]
}
],
"questions": [
{
"type": "predicate",
"instructions": "Does the photo show a package at a door?"
}
]
}| Field | Required | Type | Notes |
|---|---|---|---|
role | Yes | string | user. |
content | Yes | string or array | Text, or an array of parts. |
input_image.image_url | Yes | string | A data: URL or a public HTTPS URL. |
input_image.detail | No | string | low, high, auto, or original. |
The number of images a request can carry depends on the model. See Models.
Send audio
To attach audio, send the clip as input_audio next to input.
{
"model": "spev",
"input": "Call recording attached.",
"input_audio": { "data": "UklGRiQAAABXQVZF...", "format": "wav" },
"questions": [
{ "type": "predicate", "instructions": "Does the caller ask to cancel?" }
]
}input_audio.data is the base64-encoded file, not a data: URL.
input_audio.format names the container, such as wav or mp3.
input_audio is a Sprag extension to the request shape.
Response
| Field | Type | Notes |
|---|---|---|
model | string | The model id from the request. |
answers | array | One answer per question, in question order. |
usage.input_tokens | integer | Input tokens across text, audio, and image evidence. |
usage.input_tokens_details.multimodal_tokens | object or null | Input tokens by modality, such as {"audio": 67}. null for text-only evidence. |
usage.output_tokens | integer | Output tokens. |
usage.total_tokens | integer | Input and output tokens together. |
Decisions has no streaming mode. The response arrives once every question has an answer.
Errors
| Status | Meaning |
|---|---|
400 | Validation error, such as a duplicate question name, duplicate choice values, or fewer than two levels. |
401 | Missing, invalid, or expired credentials. |
402 | No payment method on the account. |
403 | Not a member of the requested organization. |
404 | Unknown model id. |
413 | Request too large. |
429 | Rate limit exceeded. |
502 | The model returned an error. Also sent when the model's answers do not match the questions. Retry the request. |
503 | Temporarily unavailable. Retry after Retry-After when it is set. |
POST /v1/systemone is retired. A request to it returns HTTP 410 with the
error code endpoint_removed.
See the errors reference for the full error shape and retry guidance.