layahost
Menu · POST /v1/decide

POST /v1/decide

One text in, one decision out. Use a ready-made template or ask your own question, and get a flat response with the decision, its probabilities and the cost.

Endpoint
POST https://layahost.com/v1/decide

For several questions about the same text in one request, use the Jev-compatible POST /v1/systemone instead. For many texts at once, see Batch requests.

Request body

ParameterTypeRequiredDescription
textstringYes The text to decide about. Up to 32,000 characters.
templatestringNo A template slug: moderation, spam, support_intent, routing, sentiment, priority or language. See Decision templates.
typestringWithout template choice, yes_no or score. Ignored when you use a template.
questionstringWithout template The question to answer, up to 2,000 characters. With a template, replaces the template's question.
optionsarray or objectFor your own choice and score The possible answers, either as a list of names (["billing", "sales"]) or as an object that maps each name to a short description ({"billing": "invoices, payments"}). choice takes 2 or more options, within the option budget; score takes 2 to 10 levels, lowest first. Names can be numbers, such as ["1", "2", "3"]. Descriptions can be up to 500 characters. With a template, replaces the template's options. Ignored for yes_no.
langstringNo A language hint such as en or de. With laya-auto, en sends the text to the English checkpoint and any other value to the multilingual one, instead of detecting the language.
modelstringNo laya-auto (default), laya-english or laya-multilingual. See Models.
cachebooleanNo Default true. Set false to skip the response cache: the answer is computed fresh and not stored.

Example

A choice question with a short description for each option:

POST /v1/decide
curl https://layahost.com/v1/decide \
  -H "Authorization: Bearer $LAYAHOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Can I get an invoice with my VAT number on it?",
    "type": "choice",
    "question": "Which team should answer this email?",
    "options": {
      "billing": "invoices, payments, refunds",
      "technical": "bugs, errors, API",
      "sales": "pricing, plans, quotes"
    }
  }'
POST /v1/decide
const res = await fetch("https://layahost.com/v1/decide", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.LAYAHOST_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    text: "Can I get an invoice with my VAT number on it?",
    type: "choice",
    question: "Which team should answer this email?",
    options: {
      billing: "invoices, payments, refunds",
      technical: "bugs, errors, API",
      sales: "pricing, plans, quotes",
    },
  }),
});

if (!res.ok) throw new Error(`layahost ${res.status}: ${await res.text()}`);
const result = await res.json();
console.log(result.decision, result.probabilities);
POST /v1/decide
import os
import requests

res = requests.post(
    "https://layahost.com/v1/decide",
    headers={"Authorization": f"Bearer {os.environ['LAYAHOST_API_KEY']}"},
    json={
        "text": "Can I get an invoice with my VAT number on it?",
        "type": "choice",
        "question": "Which team should answer this email?",
        "options": {
            "billing": "invoices, payments, refunds",
            "technical": "bugs, errors, API",
            "sales": "pricing, plans, quotes",
        },
    },
    timeout=10,
)
res.raise_for_status()
result = res.json()
print(result["decision"], result["probabilities"])
POST /v1/decide
$client = new GuzzleHttp\Client(['base_uri' => 'https://layahost.com']);

$res = $client->post('/v1/decide', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('LAYAHOST_API_KEY')],
    'json' => [
        'text' => 'Can I get an invoice with my VAT number on it?',
        'type' => 'choice',
        'question' => 'Which team should answer this email?',
        'options' => [
            'billing' => 'invoices, payments, refunds',
            'technical' => 'bugs, errors, API',
            'sales' => 'pricing, plans, quotes',
        ],
    ],
]);

$result = json_decode($res->getBody(), true);
echo $result['decision'], PHP_EOL;
Response · 200
{
  "decision": "billing",
  "confidence": 0.6506,
  "probabilities": {
    "billing": 0.9036,
    "technical": 0.0506,
    "sales": 0.0458
  },
  "template": null,
  "model": "laya-english",
  "usage": {
    "decisions": 1,
    "input_tokens": 52,
    "cost_micros": 5,
    "cost_usd": 5.0e-6
  },
  "latency_ms": 169.63,
  "request_id": "req_iazyijj7zo5nmmoxzhnivu9d"
}

Response

FieldTypeDescription
decisionstring or booleanThe answer: the chosen option for choice, true or false for yes_no, and the level name for score.
confidencenumberHow sure the model is, from 0 to 1. See Reading confidence.
probabilitiesobjectchoice and score only. The probability of each option, keyed by option name. Sorted most likely first for choice, in level order for score.
probabilitynumberyes_no only. The probability that the answer is yes. decision is true when it is 0.5 or more.
scorenumberscore only. The expected level on a scale where 0 is the first level and n−1 the last.
templatestring or nullThe template you used, or null.
modelstringThe model that answered: laya-english or laya-multilingual. The language template reports lingua, its dedicated language detector.
usage.decisionsintegerDecisions billed. Always 1 on this endpoint.
usage.input_tokensintegerTokens the model read (text plus question and options).
usage.cost_microsintegerWhat the request cost, in millionths of a US dollar: 5 is $0.000005. Use this for exact accounting.
usage.cost_usdnumberThe same cost in US dollars. A JSON number, which may be written in exponent form: 5.0e-6 is $0.000005.
latency_msnumberServer-side processing time in milliseconds.
request_idstringUnique ID of the request, also sent in the x-request-id and x-typesafe-request-id headers and shown in Logs.

Use a template

Templates bundle a tested question and options. Send only the text and the template slug. This one is a score template, so the response also has score:

POST /v1/decide
curl https://layahost.com/v1/decide \
  -H "Authorization: Bearer $LAYAHOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Our whole checkout is down and we are losing orders right now!",
    "template": "priority"
  }'
Response · 200
{
  "decision": "urgent",
  "score": 2.9086,
  "confidence": 0.8195,
  "probabilities": {
    "low": 0.0133,
    "normal": 0.0154,
    "high": 0.0207,
    "urgent": 0.9506
  },
  "template": "priority",
  "model": "laya-english",
  "usage": {
    "decisions": 1,
    "input_tokens": 46,
    "cost_micros": 5,
    "cost_usd": 5.0e-6
  },
  "latency_ms": 101.57,
  "request_id": "req_fhmwim3yoqgdfdxf4mzsfp7l"
}

See Decision templates for the full list.

Ask a yes/no question

Set type to yes_no. No options are needed. The response has probability instead of probabilities:

POST /v1/decide
curl https://layahost.com/v1/decide \
  -H "Authorization: Bearer $LAYAHOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "The delivery was two weeks late and nobody answered my emails.",
    "type": "yes_no",
    "question": "Is the customer complaining?"
  }'
Response · 200
{
  "decision": true,
  "probability": 0.8481,
  "confidence": 0.8481,
  "template": null,
  "model": "laya-english",
  "usage": {
    "decisions": 1,
    "input_tokens": 43,
    "cost_micros": 5,
    "cost_usd": 5.0e-6
  },
  "latency_ms": 96.41,
  "request_id": "req_7oymodjner418isoiy49zsjs"
}

When accuracy matters, a choice question with two described options is often more reliable than a bare yes/no question. Try both on your data.

Score on a scale

Set type to score and list the levels from lowest to highest:

POST /v1/decide
curl https://layahost.com/v1/decide \
  -H "Authorization: Bearer $LAYAHOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "The delivery was two weeks late and nobody answered my emails.",
    "type": "score",
    "question": "How angry is the customer?",
    "options": ["calm", "annoyed", "angry", "furious"]
  }'
Response · 200
{
  "decision": "angry",
  "score": 1.5788,
  "confidence": 0.2046,
  "probabilities": {
    "calm": 0.0319,
    "annoyed": 0.5244,
    "angry": 0.2768,
    "furious": 0.1669
  },
  "template": null,
  "model": "laya-english",
  "usage": {
    "decisions": 1,
    "input_tokens": 45,
    "cost_micros": 5,
    "cost_usd": 5.0e-6
  },
  "latency_ms": 97.47,
  "request_id": "req_7hwhzpjgkpibhof91s7x7wmc"
}

score is the expected level: the sum of each level's position (0 for calm up to 3 for furious) times its probability. decision is the level nearest to it. That is not always the single most likely level: here annoyed has the highest probability, but the expected score of 1.58 is closest to level 2, angry. If you need the most likely level, take the largest value in probabilities.

Levels can be named with numbers, for a star rating for example. score still counts positions from 0, so a score of 1.31 is nearest the second level, "2":

POST /v1/decide
curl https://layahost.com/v1/decide \
  -H "Authorization: Bearer $LAYAHOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "The product is fine but shipping took forever.",
    "type": "score",
    "question": "Rate the review from 1 to 5 stars.",
    "options": ["1", "2", "3", "4", "5"]
  }'
Response · 200
{
  "decision": "2",
  "score": 1.3059,
  "confidence": 0.3685,
  "probabilities": {
    "1": 0.0701,
    "2": 0.679,
    "3": 0.1651,
    "4": 0.0466,
    "5": 0.0392
  },
  "template": null,
  "model": "laya-english",
  "usage": {
    "decisions": 1,
    "input_tokens": 50,
    "cost_micros": 5,
    "cost_usd": 5.0e-6
  },
  "latency_ms": 120.5,
  "request_id": "req_uzivv1hv24gdcyf2bidnyilj"
}

Send numeric names as strings. JSON numbers such as [1, 2, 3] are not accepted for score levels.

Override a template

With a template, question and options replace the template's own. This is how you route to your own teams with the routing template:

POST /v1/decide
curl https://layahost.com/v1/decide \
  -H "Authorization: Bearer $LAYAHOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "My order arrived broken, I want my money back.",
    "template": "routing",
    "options": {
      "logistics": "shipping, delivery, damaged parcels",
      "finance": "refunds, invoices, payments",
      "product": "product questions and feedback"
    }
  }'
Response · 200
{
  "decision": "finance",
  "confidence": 0.108,
  "probabilities": {
    "finance": 0.568,
    "logistics": 0.243,
    "product": 0.189
  },
  "template": "routing",
  "model": "laya-english",
  "usage": {
    "decisions": 1,
    "input_tokens": 52,
    "cost_micros": 5,
    "cost_usd": 5.0e-6
  },
  "latency_ms": 96.03,
  "request_id": "req_rzgml9eicffev62s1ogyfgpm"
}

The message fits two teams, and the low confidence says so. That is a good case to send to a person.

Reading confidence

confidence runs from 0 to 1, but it is computed differently per question type:

  • choice and score: 1 minus the normalised entropy of probabilities. It is 0 when every option is equally likely and 1 when one option has all of the probability. It is usually well below the top probability: 0.108 for a 0.568 favourite in the example above.
  • yes_no: the larger of probability and 1 − probability, so it ranges from 0.5 to 1.
  • language template: the probability of the detected language.

Choose a threshold per question on your own data. A common pattern is to act automatically above the threshold and send everything else to a person.

Limits

FieldLimit
text32,000 characters
question2,000 characters
options for choiceAt least 2. All option names and descriptions of one question must fit in the model's option budget of 192 tokens, roughly 100 to 150 short options. Longer lists get 422.
options for score2 to 10 levels
Each option description500 characters

Identical requests may be answered from a short-lived cache unless you send "cache": false. The answer is the same and is billed as usual. See Data & privacy.

Errors

An invalid body gets 422 with one entry per problem. It is not billed. Here the request had neither a template nor a type and question:

Response · 422
{
  "detail": [
    {
      "loc": ["body", "type"],
      "msg": "The type field is required when template is not present.",
      "type": "value_error"
    },
    {
      "loc": ["body", "question"],
      "msg": "The question field is required when template is not present.",
      "type": "value_error"
    }
  ]
}

A choice or score question without options:

Response · 422
{
  "detail": [
    {
      "loc": ["body", "options"],
      "msg": "The options field is required.",
      "type": "value_error"
    }
  ]
}

A score question with fewer than 2 or more than 10 levels:

Response · 422
{
  "detail": [
    {
      "loc": ["body", "options"],
      "msg": "A score needs 2 to 10 levels.",
      "type": "value_error"
    }
  ]
}

Options that don't fit the option budget get 422 on ["body", "options"] with a message that says so. See Errors for authentication, balance, rate-limit and capacity errors.