Skip to content

Structured Decisions (System One)

When you ask a language model for a decision your code will branch on, you are doing two jobs at once: telling the model to produce the answer, then parsing the text it produced back into your own types. The parsing step is the fragile one — the model changes format, adds a preamble, truncates the JSON.

System One models remove that step. They take a state (the content to judge) and the typed questions you define, and return a structured answer for each question. No free text is generated, so there is nothing to parse. Every answer arrives with its probability distribution, which means the threshold is yours to set in code.

Model Context Input / Output ($/1M tokens)
typesafe/jev 32,000 0.042 / 0
upstage/solar-decide 524,288 0.10 / 0
fastino/glide 40,000 0.15 / 0
greenpt/metis 32,768 0.147783 / 0
perplexity/pplx-decider-v1.1-27b 262,144 0.02 / 0
perplexity/pplx-decider-v1-27b 262,144 0.02 / 0
llmtr/leyla 1,024 0.03 / 0
llmtr/leyla-english 512 0.03 / 0
llmtr/leyla-typed-decisions 1,024 0.03 / 0
nace/drex-v2.0 131,072 0.06 / 0
scaledown/classify-free 131,072 0 / 0

The Leyla models are hosted in Turkey; request content does not leave Turkey. llmtr/leyla works in more than 100 languages including Turkish. llmtr/leyla-english is for English text only. llmtr/leyla-typed-decisions is for English decisions on invoices, security incidents, customer-service records and agent traces.

fastino/glide retains the requests and responses you send and may use them to improve its models; for states that contain personal data, prefer the Leyla models.

greenpt/metis is a general-purpose decision model; according to the provider, requests are processed in the European Union. Your account must have given the GreenPT data transfer consent before you can call it; without it the request returns 403 provider_consent_required (Data transfer consent).

The Perplexity Decider models evaluate images as well as text (Image input). perplexity/pplx-decider-v1-27b is the first version and is for integrations pinned to it; a new integration can start on perplexity/pplx-decider-v1.1-27b.

nace/drex-v2.0 is the newest version of Nace's decision model. It reads text only; an image, audio or PDF in the state returns 422 provider_error. The free offer on nace/drex-v1.5-free and nace/drex-v1.0-free ended on 13 October 2026; those ids return 410 model_retired and name nace/drex-v2.0 instead. Drex 2.0 is a different version, so the probabilities it returns can differ from the earlier versions'; check your thresholds when you move.

scaledown/classify-free is free until 20 October 2026, 23:59 (TRT); it closes earlier if the quota set aside for free use runs out, and free use is limited per account per day. It reads text only; an image or PDF in the state returns 400 invalid_request. A state object with only a text key ({ "text": "..." }) is given to the model as that text; any other object or array as its JSON text. Once the free offer ends, the model's page lists paid System One models that take the same request. See ScaleDown task models for details.

To list the System One models in the catalog:

Terminal window
curl -s "$LLMTR_BASE_URL/v1/models" \
| jq -r '.data[] | select(.supported_operations[] == "SYSTEM_ONE").id'
Terminal window
curl "$LLMTR_BASE_URL/v1/systemone" \
-H "Authorization: Bearer llmtr-your_key" \
-H "Content-Type: application/json" \
-d '{
"model": "typesafe/jev",
"state": "I was charged twice on my card and I want the duplicate refunded.",
"questions": {
"refund_requested": {
"type": "noul",
"instructions": "Is the customer requesting a refund?"
},
"department": {
"type": "choice",
"instructions": "Which team should handle this request?",
"criteria": {
"billing": "Payments, invoicing, refunds",
"technical": "Bugs, outages, integrations",
"sales": "Pricing, new accounts"
}
}
}
}'
Field Required Description
model Yes The System One model id.
state Yes The content to evaluate. Plain text or structured data (an object or an array). On the Perplexity Decider models the array can also carry images.
questions Yes A map of questions whose keys you choose. Answers come back under the same keys.
max_budget_usd No A pre-flight estimated-cost check. See the note below.

Question keys are not sent to the model; they only match answers back to questions. Write the complete question in instructions, however self-explanatory the key looks — the key is not text the model sees.

max_budget_usd is a pre-flight check: the request is refused before it reaches the upstream when the cost estimated from the body exceeds this value. The final charge is computed from the token count the upstream reports and is not re-checked against this ceiling, so input that produces more tokens per character than expected can be billed above the estimate. Use the per-API-key spending limit when you need a hard cap.

Questions in one request are evaluated independently; one answer never becomes context for another.

All three share type and instructions; criteria differs by type.

A yes/no question. Returns the probability that the answer is yes, between 0 and 1. criteria is optional and only clarifies what each end means.

{
"is_urgent": {
"type": "noul",
"instructions": "Does this message convey urgency?",
"criteria": {
"true": "Explicitly time-sensitive",
"false": "No urgency expressed"
}
}
}

Picks one of the options you define. Returns the selected option, the probability distribution across every option, and a confidence value. criteria maps each option name to a description; use null when an option needs no further detail.

Add an option such as other when your inputs might not fit the list; otherwise the model always returns the closest option in it.

{
"department": {
"type": "choice",
"instructions": "Which team should handle this request?",
"criteria": {
"billing": "Payments, invoicing, refunds",
"technical": "Bugs, outages, integrations",
"other": null
}
}
}

Returns a position along ordered levels. criteria is an ordered array of at least two levels. The returned score can fall between two of them. fastino/glide differs: score is the index of the most probable level (an integer from 0), and expected_level is the probability-weighted position between levels.

{
"frustration": {
"type": "score",
"instructions": "How frustrated does the customer appear?",
"criteria": ["Calm", "Frustrated but civil", "Very angry"]
}
}

Do not confuse a yes/no judgment with measuring a level. For "is this candidate strong in Python?", a value of 0.5 does not mean the candidate is mid-level; it means the model gives yes and no equal probability. Use Score to measure a level, and a Noul with a clearly defined condition when you need a decision.

{
"model": "typesafe/jev",
"answers": {
"refund_requested": {
"type": "noul",
"noul": 0.94
},
"department": {
"type": "choice",
"choice": "billing",
"probabilities": { "billing": 0.88, "technical": 0.07, "sales": 0.05 },
"confidence": 0.85
}
},
"usage": { "input_tokens": 312, "output_tokens": 61 }
}

Every key in answers is a question key you supplied. Each answer carries its own type, so which fields to read is unambiguous: noul for a Noul, choice + probabilities + confidence for a Choice, score + legend + probabilities + confidence for a Score (plus expected_level on fastino/glide).

The model field returns the LLMTR catalog id. The token counts above are illustrative; output_tokens normally comes back greater than zero — what is free is the price of output, not the count. Do not assume this field is zero when building your own token accounting.

confidence summarizes how peaked the probability distribution is; where to act automatically is your decision. If you only need the most likely option, you do not need a threshold at all — reading choice is enough. Thresholds earn their place where you separate acting automatically from handing a case to a person.

Keep thresholds and question text together in one file in your code. Those are what a reviewer needs to look at; threshold constants scattered across a codebase are not found again later.

perplexity/pplx-decider-v1.1-27b and perplexity/pplx-decider-v1-27b evaluate images too. Send state as an array and add each image as an image_url part carrying a base64 data URL; text parts can sit in the same array:

{
"model": "perplexity/pplx-decider-v1.1-27b",
"state": [
"Product photo for listing #881.",
{ "type": "image_url", "image_url": { "url": "data:image/png;base64,iVBORw0KGgo..." } }
],
"questions": {
"color": {
"type": "choice",
"instructions": "What color is the shirt the person is wearing?",
"criteria": { "navy": null, "white": null, "red": null }
}
}
}
  • PNG, JPEG and WebP data URLs are accepted. The model does not download images from an address; an http or https URL returns 400 provider_error.
  • An image counts as input tokens and is counted again for every question. A single image comes to at most about 2,050 tokens per question.
  • An image is read at up to 2,048 squares of 32 × 32 pixels (for example 1440 × 1440 or 2048 × 1024). Resize a larger image to that size before sending it; how an image over the limit is read is not guaranteed. The request body is limited to 24 MB in total, and base64 encoding makes a file about a third larger.

When you send a Turkish state to llmtr/leyla, this way of writing the request gives the best results:

  • Noul and Score: write instructions and the Score level names in English ("Does the customer ask for a refund?"). The text itself can stay in Turkish.
  • Choice: write the option descriptions (the criteria values) in Turkish, as short keywords ("fatura, ödeme, iade"). Longer descriptions do not improve the result.
  • Catch-all option: do not rely on an option such as other being picked. If the highest probability is low (for example below 0.6), treat the result as undecided and route it to a person.
  • Before going live: measure multi-option classification on your own real examples (at least 50-100) and set your thresholds from that.

Keep the text short: the model works with a 1,024-token context (512 on llmtr/leyla-english). Text past the context returns no error; it is cut and the cut part is not evaluated, so choose the part the decision needs.

Only input tokens are billed; output tokens are free. The usage field in the response carries both counts.

typesafe/jev, greenpt/metis and the Drex models count the state once; combine the questions about one state into one request. upstage/solar-decide, fastino/glide, Perplexity Decider and the Leyla models count the state for every question; send only the questions you will use. scaledown/classify-free counts the state for every question too.

Platform margin is not added to model prices; the margin applies to credit top-ups only. Because the provider publishes its price in euros, the greenpt/metis price in the table is the euro price converted to USD at the European Central Bank rate plus an 8% exchange-rate allowance, so it is not the provider's published figure as is. See Billing for details.

LLMTR accepts at most 1,000 questions per request; more are refused with 400 invalid_request. When a model's own limit is lower, the value in the table below applies: on the Leyla models a request over 64 returns 413 provider_error, on the Perplexity Decider models a request over 128 returns 400 provider_error, on greenpt/metis a request over 32 returns 422 provider_error, on the Drex models a request over 512 returns 400 invalid_request.

Limit typesafe/jev upstage/solar-decide fastino/glide greenpt/metis Perplexity Decider Leyla models Drex models scaledown/classify-free
Request size state and questions together, 32,000 tokens state at most 1 MiB each question together with state, 40,000 tokens state, questions and the model's fixed prompt together, 32,768 tokens each question together with state, under 262,144 tokens state at most 50,000 characters state at most 131,072 tokens, each question together with state at most 262,144 tokens; state and questions together at most 4 MiB state at most 131,072 tokens
Questions per request 1,000 1,000 1,000 32 128 64 512 1,000
Choice options no documented limit 2-26 at most 255 2-255 per question, at most 2,048 per request in all (each noul question counts as 2) at most 255 at most 100; up to 20 recommended when options carry descriptions no documented limit no documented limit
Score levels at least 2 2-10 2-255 2-10 2-10 at most 32 at least 2 2-10

fastino/glide accepts only text in instructions; an object or array returns 422 provider_error.

On the Perplexity Decider models response time grows with the input; a request near the context limit can take close to a minute. Set your client timeout to at least 90 seconds.

This endpoint does not support streaming. The response arrives in one piece; there is no generated text to stream.

System One models do not appear in the Playground and cannot be called on chat endpoints; they answer on /v1/systemone only.

Status Meaning
400 invalid_request The request body does not match the schema. The message names the offending field.
403 provider_consent_required Your account has not given the data transfer consent for the model's provider (greenpt/metis). Consent is given in the Settings tab.
404 model_not_found The model id is not in the catalog.
410 model_retired The model was retired; the message gives the date. On the free Drex models and scaledown/classify-free it means the free offer has ended.
400 unsupported_operation The model does not support this endpoint. The response lists the endpoints it does support.
400 provider_error The model did not accept the request. On fastino/glide, if the message says the context window was exceeded, one of the questions does not fit together with the state; shorten the state or that question. On Perplexity Decider the message names the limit that was exceeded or the unsupported image address.
413 provider_error The request exceeds the model's limit on questions, options or text length. Make the request smaller.
422 provider_error A question definition or the state is in a shape the model does not accept, or exceeds that model's limit. The message carries which field is at fault.
429 rate_limit_error The API key's request limit was exceeded.
502 provider_error The model could not complete the request. On Perplexity Decider, if a question together with the state goes over 262,144 tokens, the request returns this error after about a minute; shorten the state.
503 model_unavailable The model is temporarily unable to answer. If the response carries a Retry-After header, wait that long.

See Errors for the error format.