layahost
Menu · Decision flows

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.

Endpoints
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 as outcome, 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.

POST /v1/flows/{flow}/run
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."}'
POST /v1/flows/{flow}/run
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"])
POST /v1/flows/{flow}/run
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}`));
Response · 200
{
  "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"
}
FieldMeaning
outcomeThe value of the outcome the run reached, or the last answer when that answer has no connection.
ended_atThe id of the step where the run stopped.
steps[].answerThe answer of each question on the path: an option, a level name, or yes/no.
steps[].probabilityThe probability of that answer. probabilities has every option; confidence is the model's own entropy-based confidence, as in /v1/decide.
steps[].followedThe output the run took: the answer, or _unsure when the unsure branch was used.
usageDecisions 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.

StatusWhen
402The balance ran out before or during the run.
404No flow with that endpoint name in the account of the API key.
422No text, or the flow's start is not connected (error_type: invalid_flow).
503 / 529The 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.