Skip to content

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" }
        ]
      }
    ]
  }'
FieldRequiredTypeNotes
modelYesstringA model id from the Decisions models.
inputYesstring or arrayText evidence, or an array of user messages. See Send an image.
questionsYesarray1 to 200 questions. Answers come back in this order.
input_audioNoobjectAn audio clip as {"data": "<base64>", "format": "wav"}. See Send audio.
safety_identifierNostringAn 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.

FieldRequiredTypeNotes
choicesYesarray2 to 255 options. Each value is a string or a boolean, and values are distinct.
choices[].descriptionNostringWhen 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.

FieldRequiredTypeNotes
levelsYesarray2 to 10 levels in ascending order. The first level has the value 0.
levels[].labelYesstringThe level's name.
levels[].descriptionNostringThe 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?"
    }
  ]
}
FieldRequiredTypeNotes
roleYesstringuser.
contentYesstring or arrayText, or an array of parts.
input_image.image_urlYesstringA data: URL or a public HTTPS URL.
input_image.detailNostringlow, 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

FieldTypeNotes
modelstringThe model id from the request.
answersarrayOne answer per question, in question order.
usage.input_tokensintegerInput tokens across text, audio, and image evidence.
usage.input_tokens_details.multimodal_tokensobject or nullInput tokens by modality, such as {"audio": 67}. null for text-only evidence.
usage.output_tokensintegerOutput tokens.
usage.total_tokensintegerInput and output tokens together.

Decisions has no streaming mode. The response arrives once every question has an answer.

Errors

StatusMeaning
400Validation error, such as a duplicate question name, duplicate choice values, or fewer than two levels.
401Missing, invalid, or expired credentials.
402No payment method on the account.
403Not a member of the requested organization.
404Unknown model id.
413Request too large.
429Rate limit exceeded.
502The model returned an error. Also sent when the model's answers do not match the questions. Retry the request.
503Temporarily 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.