Skip to main content

/v1/decisions and /v1/systemone

Decision models answer typed questions about an input and return probabilities instead of text: a yes/no probability, a pick from a fixed list, a score on a scale, or on TypeSafe Jev 1.14 a box around something in an image. LiteLLM serves them on two routes that share one provider list, so any decision model in your model_list works on either route

RouteAliasRequest formatUse it when
POST /v1/decisions/decisionsOpenAI Decisions: input plus a list of predicate, choice, score and box questionsYou write against OpenAI's format
POST /v1/systemone/systemoneSystem One: state plus a map of noul, choice, score and box questionsYou already have TypeSafe Jev request bodies

Available in v1.104.2 and later on the 1.104.x line and in v1.105.0-rc.3 and later. v1.106.0-dev.1 served the System One format at /v1/decisions, so on that build send those bodies to /v1/systemone. Databricks and Microsoft Foundry landed on main after v1.106.0-dev.3 and ship in the next build. Image input on Cloudflare Clef ships in v1.107.0-rc.1 and later. TypeSafe images, box questions and the TypeSafe-Danger-Zone-* headers ship in the next build.

FeatureSupportedNotes
Cost trackingYesReturned in the x-litellm-response-cost header and written to spend logs
LoggingYesWorks across all integrations
Virtual keys, budgets, rate limitsYesNormal proxy key auth
Load balancing, fallbacksYesGoes through the router like /chat/completions
Image inputOpenAI, Cloudflare Clef and TypeSafeTypeSafe needs the TypeSafe-Danger-Zone-Images: true header. Other providers return a 400, or drop the images under drop_params
StreamingNo

Supported providers​

ProviderExample modelCredentialsLiteLLM endpointImages
OpenAIopenai/gpt-6-lunaOPENAI_API_KEY, optional OPENAI_BASE_URL/v1/decisionsYes
TypeSafe Jevtypesafe/jev-latestTYPESAFE_API_KEY, optional TYPESAFE_API_BASE/v1/systemoneWith the images header
Fireworks AI (private preview)fireworks_ai/accounts/fireworks/routers/runeFIREWORKS_AI_API_KEY or FIREWORKS_API_KEY, optional FIREWORKS_API_BASE/v1/systemoneNo
Perplexityperplexity/pplx-decider-v1-27bPERPLEXITYAI_API_KEY or PERPLEXITY_API_KEY, optional PERPLEXITY_API_BASE/v1/systemoneNo
Cloudflare Clefcloudflare/clef or cloudflare/clef-flashCLOUDFLARE_API_KEY and CLOUDFLARE_ACCOUNT_ID, or api_base/v1/systemoneYes
Databricksdatabricks/databricks-openjev-qwen35-4bDATABRICKS_API_KEY or DATABRICKS_TOKEN, DATABRICKS_API_BASE required/v1/systemoneNo
Databricks ai_decidedatabricks/ai_decideDATABRICKS_API_KEY or DATABRICKS_TOKEN, DATABRICKS_API_BASE required/v1/systemoneNo
Microsoft Foundryazure_ai/<deployment> with base_model: azure_ai/Microsoft-Decision-1AZURE_AI_API_KEY, AZURE_AI_API_BASE required/v1/systemoneNo
Strands Decider (self-hosted)strands_decider/strands-decider-2B-hobson-v19STRANDS_DECIDER_API_BASE required, STRANDS_DECIDER_API_KEY optional/v1/systemoneNo
vLLM (self-hosted)hosted_vllm/Qwen/Qwen3-0.6BHOSTED_VLLM_API_BASE or api_base required, HOSTED_VLLM_API_KEY optional/v1/systemoneNo
Laya (self-hosted)laya/english, laya/multilingual or laya/typed-decisionsapi_base or LAYA_API_BASE required, LAYA_API_KEY optional/v1/systemoneNo
Bespoke Nimble (self-hosted)bespoke/nimble on Ollama, else bespoke/nimble-latest or bespoke/bespokelabs/Bespoke-Nimble-9Bapi_base or BESPOKE_API_BASE required, BESPOKE_API_KEY optional/v1/systemoneNo

LiteLLM translates between the two formats, so the route you call does not limit which provider you can use. OpenAI receives OpenAI-format bodies and every other provider receives System One bodies, and the answers come back in the format of the route you called. Text parts of an OpenAI input are joined into the System One state, and System One questions are named by their keys when they go to OpenAI

Cloudflare model names without an @cf/ prefix are expanded to @cf/cloudflare/<model>, and the {"result": ...} envelope Cloudflare returns is unwrapped so the response has the same shape as the other providers. On Databricks the model is the bare serving endpoint name and DATABRICKS_API_BASE points at https://<workspace-host>/serving-endpoints, so the request goes to that endpoint's /invocations route. databricks/ai_decide instead calls the ai_decide AI Function at /api/2.0/ai-functions/ai-decide on the same workspace, which needs the ai_decide preview turned on and reports no token usage. On Microsoft Foundry the model is your deployment name and AZURE_AI_API_BASE is the resource host, https://<resource>.services.ai.azure.com. A project-scoped base such as https://<resource>.services.ai.azure.com/api/projects/<project>/openai/v1 is trimmed back to the host. Azure does not let you name a deployment Microsoft-Decision-1, so deploy it under another name and set base_model so cost tracking finds the price

model_list:
- model_name: decision-1
litellm_params:
model: azure_ai/decision-1
api_base: https://<resource>.services.ai.azure.com
api_key: os.environ/AZURE_AI_API_KEY
model_info:
base_model: azure_ai/Microsoft-Decision-1

Strands Decider has no default host, so set STRANDS_DECIDER_API_BASE or pass api_base. vLLM answers only choice questions, serves Qwen3 and Qwen3.5 models, and needs a vLLM build that includes vllm-project/vllm#59299, which landed after v0.31.0

Self-hosted Laya and Nimble​

Laya and Bespoke Nimble are decision models that you host yourself. From a build containing LiteLLM #45260 they are providers for /v1/decisions and /v1/systemone, and you can add them from the Admin UI under Models + Endpoints, Add Model, with Mode set to Decisions - /v1/decisions. Earlier builds serve them only on their own gateway routes

ModelGateway routeServer settings
Laya/laya/v1/systemoneLAYA_API_BASE, optional LAYA_API_KEY
Bespoke Nimble/bespoke/v1/systemoneBESPOKE_API_BASE, optional BESPOKE_API_KEY

A laya/* or bespoke/* deployment takes only the model names in the provider table above, and any other name answers 400 before a request leaves the proxy. Ollama serves Nimble as bespoke/nimble. The API base must be an HTTP or HTTPS URL without credentials, a query, or a fragment. LAYA_API_KEY and BESPOKE_API_KEY go only to a deployment whose api_base is LAYA_API_BASE or BESPOKE_API_BASE, ignoring a trailing / or /v1, and an api_key set on the deployment always wins. Both are priced at $0 because you pay for the hardware, so set Custom Pricing on the deployment to track spend

Laya, Nimble and Jev can also pick the model tier for Auto Router. For request examples and the classifier setup, see Call a native decision API

Proxy setup​

  1. Add decision models to config.yaml
model_list:
- model_name: luna
litellm_params:
model: openai/gpt-6-luna
api_key: os.environ/OPENAI_API_KEY
- model_name: jev
litellm_params:
model: typesafe/jev-latest
api_key: os.environ/TYPESAFE_API_KEY
  1. Start the proxy
litellm --config config.yaml

# RUNNING on http://0.0.0.0:4000

/v1/decisions​

Ask one question of each type in the OpenAI format

curl -X POST 'http://0.0.0.0:4000/v1/decisions' \
-H "Authorization: Bearer $LITELLM_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"model": "luna",
"input": [
{
"type": "message",
"role": "user",
"content": [
{"type": "input_text", "text": "Customer wrote: I was charged twice for my order #4411 and want one of the charges refunded today."}
]
}
],
"questions": [
{"type": "predicate", "name": "is_refund_request", "instructions": "Is the customer asking for a refund?"},
{
"type": "choice",
"name": "needs_human",
"instructions": "Should a human agent take over?",
"choices": [{"value": true, "description": "billing dispute that needs a person"}, {"value": false}]
},
{
"type": "score",
"name": "frustration",
"instructions": "How frustrated is the customer?",
"levels": [{"label": "calm"}, {"label": "mildly annoyed"}, {"label": "angry", "description": "uses hostile language"}]
}
]
}'

Response

{
"model": "gpt-6-luna",
"answers": [
{"type": "predicate", "name": "is_refund_request", "probability": 1.0},
{
"type": "choice",
"name": "needs_human",
"choice": true,
"probabilities": [{"value": true, "probability": 0.99}, {"value": false, "probability": 0.01}],
"confidence": 0.98
},
{
"type": "score",
"name": "frustration",
"score": 0.74,
"probabilities": [
{"value": 0, "label": "calm", "probability": 0.26},
{"value": 1, "label": "mildly annoyed", "probability": 0.74},
{"value": 2, "label": "angry", "probability": 0.0}
],
"confidence": 0.61
}
],
"usage": {
"input_tokens": 401,
"input_tokens_details": {"cached_tokens": 0, "cache_write_tokens": 0},
"output_tokens": 0,
"output_tokens_details": {"reasoning_tokens": 0},
"total_tokens": 401
}
}

Changing "model" to "jev" sends the same questions to TypeSafe and returns the same shape

FieldTypeDescription
modelstringA proxy model name, or <provider>/<model> in the SDK
inputstring or arrayA string, or messages shaped like {"type": "message", "role": "user", "content": ...}. content is a string or a list of input_text and input_image parts
questionsarray1 to 128 questions. Answers come back in the same order
safety_identifierstring, optionalA stable ID for your end user. Sent to OpenAI. Other providers return a 400, or drop it under drop_params

Every question takes instructions and an optional name that is echoed in its answer

typeExtra fieldsAnswer fields
predicateNoneprobability that the answer is yes
choicechoices: 2 to 255 entries of {"value": string or boolean, "description": optional}choice, probabilities per value, confidence
scorelevels: 2 to 10 entries of {"label": ..., "description": optional}, lowest firstscore (the probability-weighted level index), probabilities per level, confidence
boxNone. TypeSafe jev-1.14.0 and jev-preview only, with the images headerbox with top, bottom, left and right, confidence

A question the model will not answer comes back as {"type": "refusal", "name": ...}

Image input​

OpenAI, Cloudflare Clef and TypeSafe models take input_image parts, TypeSafe only with the images header. image_url is an image URL or a data URL, and detail is optional and only used by OpenAI.

curl -X POST 'http://0.0.0.0:4000/v1/decisions' \
-H "Authorization: Bearer $LITELLM_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"model": "luna",
"input": [
{
"type": "message",
"role": "user",
"content": [
{"type": "input_text", "text": "Here is the swatch the customer uploaded."},
{"type": "input_image", "image_url": "data:image/png;base64,<BASE64_PNG>", "detail": "low"}
]
}
],
"questions": [
{"type": "predicate", "name": "is_red", "instructions": "Is the swatch mostly red?"},
{
"type": "choice",
"name": "color",
"instructions": "Which color dominates the swatch?",
"choices": [{"value": "red"}, {"value": "green"}, {"value": "blue"}]
}
],
"safety_identifier": "user-1234"
}'

Response for a solid red square

{
"model": "gpt-6-luna",
"answers": [
{"type": "predicate", "name": "is_red", "probability": 1.0},
{
"type": "choice",
"name": "color",
"choice": "red",
"probabilities": [
{"value": "red", "probability": 1.0},
{"value": "green", "probability": 0.0},
{"value": "blue", "probability": 0.0}
],
"confidence": 1.0
}
],
"usage": {
"input_tokens": 277,
"input_tokens_details": {"cached_tokens": 0, "cache_write_tokens": 0},
"output_tokens": 0,
"output_tokens_details": {"reasoning_tokens": 0},
"total_tokens": 277
}
}

Changing "model" to "clef" sends the image to Cloudflare. Cloudflare does not take safety_identifier, so remove that field or turn on drop_params. The same swatch then returns

{
"model": "clef",
"answers": [
{"type": "predicate", "name": "is_red", "probability": 0.995},
{
"type": "choice",
"name": "color",
"choice": "red",
"probabilities": [
{"value": "red", "probability": 0.9908},
{"value": "green", "probability": 0.0043},
{"value": "blue", "probability": 0.0049}
],
"confidence": 0.9727
}
],
"usage": {
"input_tokens": 289,
"input_tokens_details": {"cached_tokens": 0, "cache_write_tokens": 0},
"output_tokens": 0,
"output_tokens_details": {"reasoning_tokens": 0},
"total_tokens": 289
}
}

Before calling Cloudflare, LiteLLM downloads image URLs into data URLs and checks Clef's limits: at most 4 images per request, each a PNG, JPEG or WebP of at most 4 MiB, and 8 MiB in total. A request over a limit gets a 400 before Cloudflare is called. With drop_params on, images of another type are dropped instead, and the 4-image limit counts only the images that are left. Cloudflare receives the text parts joined into state and the images as a separate list, so the model does not see which text sat next to which image.

Other providers do not take images, and TypeSafe takes them only with the images header. So the same request with "model": "jev", no safety_identifier and no images header is rejected before TypeSafe is called.

{
"error": {
"message": "litellm.UnsupportedParamsError: typesafe does not support parameters: ['input_image'], for model=typesafe/jev-latest. To drop these, set `litellm.drop_params=True` or for proxy:\n\n`litellm_settings:\n drop_params: true`\n\n\nLiteLLM: model group 'jev' failed with the error above. No fallback was attempted.",
"type": "invalid_request_error",
"param": null,
"code": "400"
}
}

With drop_params: true in litellm_settings or on the deployment, LiteLLM drops the images and sends only the text. A request that has no text left after the drop still gets a 400.

/v1/systemone​

The same kind of request in the System One format

curl -X POST 'http://0.0.0.0:4000/v1/systemone' \
-H "Authorization: Bearer $LITELLM_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"model": "jev",
"state": "Customer wrote: I was charged twice for my order #4411 and want one of the charges refunded today.",
"questions": {
"is_refund_request": {"type": "noul", "instructions": "Is the customer asking for a refund?"},
"urgency": {
"type": "choice",
"instructions": "How urgent is this?",
"criteria": {"low": "can wait a week", "high": "needs action today"}
},
"frustration": {
"type": "score",
"instructions": "How frustrated is the customer?",
"criteria": ["calm", "mildly annoyed", "angry"]
}
}
}'

Response

{
"model": "jev-1.13.0",
"answers": {
"is_refund_request": {"type": "noul", "noul": 0.99},
"urgency": {
"type": "choice",
"choice": "high",
"confidence": 1.0,
"probabilities": {"low": 0.0, "high": 1.0}
},
"frustration": {
"type": "score",
"score": 0.95,
"confidence": 0.86,
"legend": {"0": "calm", "1": "mildly annoyed", "2": "angry"},
"probabilities": {"0": 0.07, "1": 0.91, "2": 0.02}
}
},
"usage": {"input_tokens": 391, "output_tokens": 67}
}

Changing "model" to "luna" asks OpenAI instead and still returns System One answers keyed by question name

FieldTypeDescription
modelstringA proxy model name, or <provider>/<model> in the SDK
statestring, object or arrayThe thing being judged, such as a support ticket, a document or a chat transcript
questionsobject1 to 128 named questions. Each key becomes a key in answers
imagesarray, optionalImage URLs or data URLs. OpenAI and Cloudflare Clef only, with the rules in Image input
assetsobject, optionalImages keyed by a name you use in state, each {"type": "image", "format": "png", "jpg" or "jpeg", "data_base64": ...}. TypeSafe only, with the images header

Every question has a type and an optional instructions field. Extra fields on a question are forwarded to System One providers unchanged

typecriteriaAnswer fields
noulOptional object with true and false descriptions. A noul question needs instructions or criterianoul: probability that the answer is true
choiceRequired object mapping 1 to 255 labels to descriptionschoice, confidence, probabilities per label
scoreRequired array of 1 to 10 levels, lowest firstscore (0 to levels - 1), confidence, legend, probabilities per level
boxNone. TypeSafe jev-1.14.0 and jev-preview only, with the images headerbox with top, bottom, left and right, confidence

On both routes, requests that break these rules, such as no questions at all, duplicate choice values or a score question with 11 levels, are rejected by LiteLLM with a 400 before any provider is called

TypeSafe images, box questions and long context​

TypeSafe Jev 1.14 reads images and answers box questions, and TypeSafe keeps both behind opt-in request headers. The proxy forwards any client header that starts with TypeSafe-Danger-Zone- to TypeSafe deployments and to no other provider.

HeaderWhat it turns on
TypeSafe-Danger-Zone-Images: trueImages in assets on /v1/systemone, input_image parts on /v1/decisions, and box questions on both
TypeSafe-Danger-Zone-Long-Context: trueRequests over TypeSafe's default limit of 64k tokens per request and 32k per question

Name each image in assets and use that name in state, since TypeSafe rejects an asset the state never mentions. This request asks whether a photo shows a red square and where it is

curl -X POST 'http://0.0.0.0:4000/v1/systemone' \
-H "Authorization: Bearer $LITELLM_API_KEY" \
-H 'Content-Type: application/json' \
-H 'TypeSafe-Danger-Zone-Images: true' \
-d '{
"model": "jev-1.14.0",
"state": {"photo": "photo-7f3a9c"},
"assets": {
"photo-7f3a9c": {"type": "image", "format": "png", "data_base64": "<BASE64_PNG>"}
},
"questions": {
"has_red_square": {"type": "noul", "instructions": "Is there a red square in `photo`?"},
"red_square": {"type": "box", "instructions": "the red square in `photo`"}
}
}'

The box edges are fractions of the image height and width, measured from the top left corner

{
"model": "jev-1.14.0",
"answers": {
"has_red_square": {"type": "noul", "noul": 0.99},
"red_square": {"type": "box", "box": {"top": 0.11, "bottom": 0.51, "left": 0.49, "right": 0.83}, "confidence": 0.94}
},
"usage": {"input_tokens": 756, "output_tokens": 39}
}

On /v1/decisions, send the images as input_image parts with the same header. LiteLLM turns each PNG or JPEG into an asset, puts the asset's name where the image was in the text, and downloads image URLs first. A box question comes back as {"type": "box", "name": ..., "box": {...}, "confidence": ...} in its place in answers.

box works on jev-1.14.0 and jev-preview, and only with the images header, even when the request has no image. A box question to another model, jev-1.13.0 and jev-latest included, or without the header gets a 400 before the provider is called, or with drop_params on, LiteLLM drops the question. A dropped question comes back as {"type": "refusal"} on /v1/decisions and is left out of answers on /v1/systemone. Without the images header, assets and input_image parts get the same 400 or drop on TypeSafe that they get on providers without image input, and with drop_params on, LiteLLM also drops any assets entry it cannot read and keeps the rest.

In the SDK, pass the headers in extra_headers

import litellm

response = litellm.systemone(
model="typesafe/jev-1.14.0",
state={"photo": "photo-7f3a9c"},
assets={"photo-7f3a9c": {"type": "image", "format": "png", "data_base64": "<BASE64_PNG>"}},
questions={"red_square": {"type": "box", "instructions": "the red square in `photo`"}},
extra_headers={"TypeSafe-Danger-Zone-Images": "true"},
)
print(response.answers["red_square"].box)

SDK usage​

The SDK has one function per request format. litellm.decisions takes the OpenAI Decisions shape (input, a questions list and an optional safety_identifier) and returns the OpenAI response, with answers as a list. litellm.systemone takes the System One shape (state and a questions mapping keyed by question name) and returns the System One response, with answers keyed by question name. Both work with every supported provider, so you pick the function by the request shape you write, not by the provider you call.

OpenAI Decisions format
import os
import litellm

os.environ["OPENAI_API_KEY"] = ""

response = litellm.decisions(
model="openai/gpt-6-luna",
input="Customer wrote: I was charged twice for my order #4411 and want one of the charges refunded today.",
questions=[
{"type": "predicate", "name": "is_refund_request", "instructions": "Is the customer asking for a refund?"},
],
)
print(response.answers[0].probability)
print(response.usage)
System One format
import os
import litellm

os.environ["TYPESAFE_API_KEY"] = ""

response = litellm.systemone(
model="typesafe/jev-latest",
state="Customer wrote: I was charged twice for my order #4411 and want one of the charges refunded today.",
questions={
"is_refund_request": {"type": "noul", "instructions": "Is the customer asking for a refund?"},
},
)
print(response.answers["is_refund_request"].noul)

The async versions are litellm.adecisions and litellm.asystemone and take the same arguments.

import asyncio
import os
import litellm

os.environ["TYPESAFE_API_KEY"] = ""

async def main():
response = await litellm.asystemone(
model="typesafe/jev-latest",
state="Customer wrote: I was charged twice for my order #4411 and want one of the charges refunded today.",
questions={
"is_refund_request": {"type": "noul", "instructions": "Is the customer asking for a refund?"},
},
)
print(response.answers["is_refund_request"].noul)

asyncio.run(main())

All four functions also accept safety_identifier, api_key, api_base, timeout, custom_llm_provider and extra_headers. litellm.systemone and litellm.asystemone also take images, a list of image URLs or data URLs, and assets, the TypeSafe image map described in TypeSafe images, box questions and long context. Passing images to litellm.decisions raises a BadRequestError unless drop_params is on, since the OpenAI format carries images as input_image parts. Passing input to litellm.systemone raises a BadRequestError that points at litellm.decisions. Passing state to litellm.decisions still works for existing callers, it sends the System One format and emits a UserWarning that points at litellm.systemone. A model whose prefix is not one of the supported providers fails with a BadRequestError that lists the supported ones.

Through the Router the same split applies: router.decisions and router.adecisions take the OpenAI shape, router.systemone and router.asystemone take the System One shape. On the proxy, /v1/systemone requests are logged with call type asystemone and /v1/decisions requests with adecisions.

Upgrading from v1.104.x

In v1.104.2 through v1.104.x, litellm.decisions accepted both shapes and picked the format from whether you passed input or state. Those calls keep working unchanged, with a UserWarning. Rename litellm.decisions(state=...) to litellm.systemone(state=...) when convenient, the arguments stay the same.

Limits​

OpenAI requires instructions on every question and at least 2 choices or score levels. When a System One question without instructions goes to an OpenAI model, LiteLLM fills in a generic one such as "Which choice best fits the input?", and a noul question's criteria are folded into the instructions OpenAI sees. A choice with one label or a score with one level has no OpenAI equivalent, so LiteLLM rejects it with a 400 before OpenAI is called

A choice question cannot have both a boolean value and a string with the same text, such as true and "true", because System One providers key choices by their text. LiteLLM rejects that request with a 400

Try it in the Admin UI​

Add a decision model​

Go to Models + Endpoints, open the Add Model tab and pick the provider, for example OpenAI. Pick the decision model under LiteLLM Model Name(s), for example gpt-6-luna, and a Decision model note confirms the pick and links to the Decisions playground. Enter the provider credentials as you would for any other model, then click Add Model. The model then answers on /v1/decisions and /v1/systemone under its public model name. Providers that need an endpoint URL, such as Databricks and Microsoft Foundry, take it in the API Base field, matching the api_base in the proxy setup above. The optional Mode dropdown has an Evaluation - /v1/decisions entry for health checking the model over /v1/decisions.

Add Model with OpenAI and gpt-6-luna picked, showing the Decision model note

Decisions playground​

The Playground Decisions tab sends requests to both routes. Open it at LITELLM_PROXY_BASE_URL/ui/?page=llm-playground&tab=system-one, or go to Playground and pick Decisions. The Endpoint selector picks /v1/decisions (OpenAI Decisions format) or /v1/systemone (System One format), and the Model selector lists the decision models in your model_list, such as jev or luna from the config above; a proxy with no decision models shows an Add a decision model link instead. Both endpoints have a Form tab for building the request without JSON and a JSON tab for the raw request. Image input on /v1/decisions is edited in JSON, since the form keeps messages and image parts as they are. Virtual Key Source picks the key: Current UI Session uses your dashboard login and Virtual Key attributes the call to a key you paste. Once the call returns, each question shows its answer and probabilities, with the model the provider reported, token usage, latency and the raw JSON response under them.

Decisions playground with /v1/systemone picked, the jev model, the Form tab and the answers for the issue triage example Decisions playground with /v1/decisions picked, showing the OpenAI Decisions form with predicate, choice and score questions

The tab is not in v1.104.2 or v1.105.0. Releases before this UI change label it System One and only send the System One format, so use curl or the SDK for /v1/decisions there. The TypeSafe page walks through the System One form, validation and answer view.

Use a decision model as a guardrail​

The Decision Model guardrail asks any model on this page yes/no questions you write about each request or response, and blocks or logs the call when a probability reaches its threshold

Decision routes vs TypeSafe pass-through​

The TypeSafe pass-through at /typesafe/v1/systemone forwards raw requests to TypeSafe only and reads the key from the proxy environment. /v1/decisions and /v1/systemone use the models in your model_list, so you can switch providers, load balance and set per-deployment keys without changing the request body