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.
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
| Parameter | Type | Required | Description |
|---|---|---|---|
text | string | Yes | The text to decide about. Up to 32,000 characters. |
template | string | No | A template slug: moderation, spam, support_intent, routing, sentiment, priority or language. See Decision templates. |
type | string | Without template |
choice, yes_no or score. Ignored when you use a template. |
question | string | Without template |
The question to answer, up to 2,000 characters. With a template, replaces the template's question. |
options | array or object | For 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. |
lang | string | No | 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. |
model | string | No | laya-auto (default), laya-english or laya-multilingual. See Models. |
cache | boolean | No | 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:
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"
}
}'
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);
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"])
$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;
{
"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
| Field | Type | Description |
|---|---|---|
decision | string or boolean | The answer: the chosen option for choice, true or false for yes_no, and the level name for score. |
confidence | number | How sure the model is, from 0 to 1. See Reading confidence. |
probabilities | object | choice and score only. The probability of each option, keyed by option name. Sorted most likely first for choice, in level order for score. |
probability | number | yes_no only. The probability that the answer is yes. decision is true when it is 0.5 or more. |
score | number | score only. The expected level on a scale where 0 is the first level and n−1 the last. |
template | string or null | The template you used, or null. |
model | string | The model that answered: laya-english or laya-multilingual. The language template reports lingua, its dedicated language detector. |
usage.decisions | integer | Decisions billed. Always 1 on this endpoint. |
usage.input_tokens | integer | Tokens the model read (text plus question and options). |
usage.cost_micros | integer | What the request cost, in millionths of a US dollar: 5 is $0.000005. Use this for exact accounting. |
usage.cost_usd | number | The same cost in US dollars. A JSON number, which may be written in exponent form: 5.0e-6 is $0.000005. |
latency_ms | number | Server-side processing time in milliseconds. |
request_id | string | Unique 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:
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"
}'
{
"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:
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?"
}'
{
"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:
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"]
}'
{
"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":
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"]
}'
{
"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:
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"
}
}'
{
"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:
choiceandscore: 1 minus the normalised entropy ofprobabilities. 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 ofprobabilityand 1 −probability, so it ranges from 0.5 to 1.languagetemplate: 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
| Field | Limit |
|---|---|
text | 32,000 characters |
question | 2,000 characters |
options for choice | At 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 score | 2 to 10 levels |
| Each option description | 500 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:
{
"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:
{
"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:
{
"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.