Decision flows
A flow chains decisions: each answer of a question leads to the next question or to an outcome. You draw it in the console and call it with one request. Only the questions on the path the text takes are asked, so a run costs one decision per question it passes.
POST https://layahost.com/v1/flows/{flow}/run
GET https://layahost.com/v1/flows
GET https://layahost.com/v1/flows/{flow}
Why a flow instead of one big question
Laya works best on narrow questions with a few well-described options: all options of a question share one small token budget, so long label lists leave little room for their descriptions (see models). A flow asks “Is this spam?”, then “What does the customer want?”, then “How urgent is the bug?”, skips the questions that do not apply (no urgency check for spam), and lets you change the routing in the editor without redeploying your code.
Building a flow
- Start: every run begins here with the text you send.
- Question: a template or your own choice, yes/no or score question. Each possible answer is an output you connect to the next step.
- Outcome: where a run ends. Its value (for example
billing-queue) is returned asoutcome, and your code branches on it.
An answer with no connection also ends the run; the answer itself becomes the outcome. Open Flows to start from a template (support inbox triage, comment moderation, lead qualification) or from scratch, and use the Test tab to run texts through the canvas before you save.
Yes/no thresholds
A yes/no question answers yes when p(yes) is at least 0.5. Set a different threshold on the step when a wrong yes costs more than a missed one, or the other way round.
Unsure branches
Turn on the unsure branch of a question and set a minimum probability. When the probability of the chosen answer is below it, the run follows the _unsure output instead, for example to a human review queue. The step still reports the answer the model chose.
Running a flow
Send the text; {flow} is the endpoint name shown in the editor (you can change it there). lang is optional, as in /v1/decide. Runs use the last saved version.
curl https://layahost.com/v1/flows/support-inbox/run \
-H "Authorization: Bearer $LAYAHOST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"text": "Hi, I was charged twice this month, please refund one payment."}'
import os
import requests
res = requests.post(
"https://layahost.com/v1/flows/support-inbox/run",
headers={"Authorization": f"Bearer {os.environ['LAYAHOST_API_KEY']}"},
json={"text": ticket_body},
timeout=30,
)
res.raise_for_status()
run = res.json()
if run["outcome"] == "page-on-call":
page_on_call(ticket_id)
else:
move_to_queue(ticket_id, run["outcome"])
const res = await fetch("https://layahost.com/v1/flows/support-inbox/run", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.LAYAHOST_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ text: ticketBody }),
});
const run = await res.json();
console.log(run.outcome, run.steps.map((s) => `${s.label}: ${s.answer}`));
{
"flow": "support-inbox",
"version": 1,
"outcome": "billing-queue",
"ended_at": "billing",
"steps": [
{
"step": "spam",
"label": "Spam?",
"answer": "legit",
"probability": 0.8049,
"probabilities": { "legit": 0.8049, "spam": 0.1951 },
"confidence": 0.288,
"followed": "legit",
"latency_ms": 148.95
},
{
"step": "intent",
"label": "What do they want?",
"answer": "refund",
"probability": 0.9977,
"probabilities": { "refund": 0.9977, "other": 0.0006, "bug_report": 0.0005, "cancellation": 0.0004, "question": 0.0003, "feature_request": 0.0003, "praise": 0.0003 },
"confidence": 0.9895,
"followed": "refund",
"latency_ms": 97.66
}
],
"usage": { "decisions": 2, "cost_micros": 10, "cost_usd": 1.0e-5 },
"latency_ms": 275,
"request_id": "req_pebc6fszrqvqwhetxbxruttk"
}
| Field | Meaning |
|---|---|
outcome | The value of the outcome the run reached, or the last answer when that answer has no connection. |
ended_at | The id of the step where the run stopped. |
steps[].answer | The answer of each question on the path: an option, a level name, or yes/no. |
steps[].probability | The probability of that answer. probabilities has every option; confidence is the model's own entropy-based confidence, as in /v1/decide. |
steps[].followed | The output the run took: the answer, or _unsure when the unsure branch was used. |
usage | Decisions asked on this run and their cost. Also in the x-layahost-cost-micros header. |
Billing and logs
Each question on the path is billed and logged as one decision (see pricing). The request ID of a run is shared by its steps, with _1, _2… appended in Logs, where each step shows the flow it belongs to. Test runs in the editor are billed like the playground.
Errors
A run stops at the first step that fails and returns that step's error with the steps completed so far in steps. The questions already asked stay billed; the failed one is not.
| Status | When |
|---|---|
402 | The balance ran out before or during the run. |
404 | No flow with that endpoint name in the account of the API key. |
422 | No text, or the flow's start is not connected (error_type: invalid_flow). |
503 / 529 | The model is unavailable or overloaded; retry. See errors. |
Reading flows
GET /v1/flows lists your flows with their endpoint names, number of questions and possible outcomes. GET /v1/flows/{flow} returns the graph: its nodes, edges, and the answers each question can give.