layahost
Menu · POST /v1/systemone

POST /v1/systemone

The Jev-compatible endpoint. Ask up to 32 typed questions about the same state in one request. The request, response and error formats match TypeSafe AI's Jev System One API, so the official Jev SDKs work unchanged.

To send many requests in one call, use POST /v1/systemone/batch.

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

Coming from Jev? Start with Migrate from Jev. For a single question with a flat response, POST /v1/decide is simpler.

Request body

ParameterTypeRequiredDescription
statestring, object or arrayYes The text or structured data to evaluate. Objects and arrays are sent to the model as JSON. Up to 32,000 characters.
modelstringYes laya-auto, laya-english or laya-multilingual. Any jev-* name, such as jev-latest, is answered by laya-auto. The SDKs send jev-latest unless you set a model. See Models.
questionsobjectYes 1 to 32 questions, keyed by names you choose. Each answer comes back under the same name.
langstringNo layahost extension. A language hint such as en or de. With laya-auto, en sends the state to the English checkpoint and any other value to the multilingual one, instead of detecting the language. Ignored by other models.
cachebooleanNo layahost extension. Default true. Set false to skip the response cache.

Questions

Every question has a type, the question itself in instructions, and for most types a set of possible answers in criteria. Instructions and criteria can be plain strings or JSON objects and arrays. instructions is optional, as in Jev, but a short question tells the model what you are asking, so write one.

typecriteriaAnswer
noul Optional. {"true": "...", "false": "..."} describing what counts as yes and as no. Yes/no. noul is the probability of yes.
choice Required. An object that maps each label to a description, or to null. At least 2 labels, within the option budget. One of the labels, with a probability for each.
score Required. An array of levels, lowest first. 2 to 10 levels. The expected level, with a probability for each level.

Example

Three questions about one customer message: a choice, a noul and a score.

POST /v1/systemone
curl https://layahost.com/v1/systemone \
  -H "Authorization: Bearer $LAYAHOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "state": "Hi, I ordered a blue jacket two weeks ago and it still has not arrived. This is the second time this happens. If it is not here by Friday I want a full refund.",
    "model": "laya-auto",
    "questions": {
      "intent": {
        "type": "choice",
        "instructions": "What does the customer want?",
        "criteria": {
          "refund": "wants money back",
          "delivery_status": "asks where the order is",
          "product_question": "asks about a product",
          "other": null
        }
      },
      "is_complaint": {
        "type": "noul",
        "instructions": "Is the customer complaining?"
      },
      "anger": {
        "type": "score",
        "instructions": "How angry is the customer?",
        "criteria": ["calm", "annoyed", "angry", "furious"]
      }
    }
  }'
POST /v1/systemone
// npm install @typesafe-ai/sdk
import { choice, noul, score, TypeSafeClient } from "@typesafe-ai/sdk";

const client = new TypeSafeClient({
  baseURL: "https://layahost.com",
  apiKey: process.env.LAYAHOST_API_KEY,
});

const result = await client.systemOne({
  model: "laya-auto",
  state:
    "Hi, I ordered a blue jacket two weeks ago and it still has not arrived. This is the second time this happens. If it is not here by Friday I want a full refund.",
  questions: {
    intent: choice("What does the customer want?", {
      refund: "wants money back",
      delivery_status: "asks where the order is",
      product_question: "asks about a product",
      other: null,
    }),
    is_complaint: noul("Is the customer complaining?"),
    anger: score("How angry is the customer?", ["calm", "annoyed", "angry", "furious"]),
  },
});

console.log(result.answers.intent.choice); // "refund"
console.log(result.answers.is_complaint.noul); // probability of yes
console.log(result.answers.anger.score); // 0 = calm ... 3 = furious
POST /v1/systemone
# pip install typesafe-sdk
import os
from typesafe_sdk import Choice, Noul, Score, TypeSafeClient

with TypeSafeClient(
    base_url="https://layahost.com",
    api_key=os.environ["LAYAHOST_API_KEY"],
) as client:
    result = client.system_one(
        model="laya-auto",
        state=(
            "Hi, I ordered a blue jacket two weeks ago and it still has not arrived. "
            "This is the second time this happens. If it is not here by Friday I want a full refund."
        ),
        questions={
            "intent": Choice(
                instructions="What does the customer want?",
                criteria={
                    "refund": "wants money back",
                    "delivery_status": "asks where the order is",
                    "product_question": "asks about a product",
                    "other": None,
                },
            ),
            "is_complaint": Noul(instructions="Is the customer complaining?"),
            "anger": Score(
                instructions="How angry is the customer?",
                criteria=["calm", "annoyed", "angry", "furious"],
            ),
        },
    )

print(result.choices["intent"].choice)  # "refund"
print(result.nouls["is_complaint"].noul)  # probability of yes
print(result.scores["anger"].score)  # 0 = calm ... 3 = furious
POST /v1/systemone
$client = new GuzzleHttp\Client(['base_uri' => 'https://layahost.com']);

$res = $client->post('/v1/systemone', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('LAYAHOST_API_KEY')],
    'json' => [
        'model' => 'laya-auto',
        'state' => 'Hi, I ordered a blue jacket two weeks ago and it still has not arrived. '
            . 'This is the second time this happens. If it is not here by Friday I want a full refund.',
        'questions' => [
            'intent' => [
                'type' => 'choice',
                'instructions' => 'What does the customer want?',
                'criteria' => [
                    'refund' => 'wants money back',
                    'delivery_status' => 'asks where the order is',
                    'product_question' => 'asks about a product',
                    'other' => null,
                ],
            ],
            'is_complaint' => ['type' => 'noul', 'instructions' => 'Is the customer complaining?'],
            'anger' => [
                'type' => 'score',
                'instructions' => 'How angry is the customer?',
                'criteria' => ['calm', 'annoyed', 'angry', 'furious'],
            ],
        ],
    ],
]);

$result = json_decode($res->getBody(), true);
echo $result['answers']['intent']['choice'], PHP_EOL;
echo $result['answers']['is_complaint']['noul'], PHP_EOL;
echo $result['answers']['anger']['score'], PHP_EOL;
Response · 200
{
  "model": "laya-english",
  "answers": {
    "intent": {
      "type": "choice",
      "choice": "refund",
      "probabilities": {
        "refund": 0.8808,
        "delivery_status": 0.0788,
        "product_question": 0.0268,
        "other": 0.0136
      },
      "confidence": 0.6627
    },
    "is_complaint": {
      "type": "noul",
      "noul": 0.7899,
      "confidence": 0.7899
    },
    "anger": {
      "type": "score",
      "score": 1.5154,
      "legend": {
        "0": "calm",
        "1": "annoyed",
        "2": "angry",
        "3": "furious"
      },
      "probabilities": {
        "0": 0.0229,
        "1": 0.5684,
        "2": 0.279,
        "3": 0.1297
      },
      "confidence": 0.2579
    }
  },
  "usage": {
    "input_tokens": 218,
    "output_tokens": 0
  },
  "meta": {
    "checkpoint": "english",
    "cached": false,
    "latency_ms": 307.75,
    "request_id": "req_wxxjgdeytykryrijxucxwmq3",
    "decisions": 3,
    "cost_micros": 15,
    "cost_usd": 1.5e-5
  }
}

Response

FieldTypeDescription
modelstringThe model that answered: laya-english or laya-multilingual. With laya-auto or a jev-* name, this is the checkpoint it chose.
answersobjectOne answer per question, under the question's name. Fields depend on the type (below).
usage.input_tokensintegerTokens the model read, over all questions.
usage.output_tokensintegerAlways 0. Laya generates no text.
metaobjectlayahost extension, ignored by the Jev SDKs. See meta.

Answer fields

TypeFieldDescription
choicechoiceThe most likely label.
probabilitiesProbability per label, in the order you sent them.
confidence1 minus the normalised entropy of probabilities: 0 when all labels are equally likely, 1 when one label has all of the probability.
noulnoulProbability that the answer is yes, from 0 to 1.
confidencelayahost extension: the larger of noul and 1 − noul.
scorescoreThe expected level: each level's index (0 for the first) times its probability, summed. Ranges from 0 to n−1 and can fall between levels.
legendYour levels keyed by index: "0" is the first.
probabilitiesProbability per level, keyed by index.
confidenceSame measure as for choice.

meta

FieldTypeDescription
checkpointstringenglish or multilingual.
cachedbooleanWhether the answers came from the response cache.
latency_msnumberServer-side processing time in milliseconds.
request_idstringUnique ID of the request, also in the x-request-id and x-typesafe-request-id headers and in Logs.
decisionsintegerDecisions billed: one per question.
cost_microsintegerWhat the request cost, in millionths of a US dollar: 15 is $0.000015. Use this for exact accounting.
cost_usdnumberThe same cost in US dollars, as a JSON number that may be written in exponent form: 1.5e-5 is $0.000015.

Structured state

state can be a JSON object or array, for example a ticket with its metadata. The model sees it as JSON text:

POST /v1/systemone
curl https://layahost.com/v1/systemone \
  -H "Authorization: Bearer $LAYAHOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "state": {
      "subject": "Refund",
      "body": "Please refund my last order.",
      "customer_tier": "gold"
    },
    "model": "laya-english",
    "cache": false,
    "questions": {
      "refund": {
        "type": "noul",
        "instructions": "Does the customer ask for a refund?"
      }
    }
  }'
Response · 200
{
  "model": "laya-english",
  "answers": {
    "refund": {
      "type": "noul",
      "noul": 0.7831,
      "confidence": 0.7831
    }
  },
  "usage": {
    "input_tokens": 59,
    "output_tokens": 0
  },
  "meta": {
    "checkpoint": "english",
    "cached": false,
    "latency_ms": 96.18,
    "request_id": "req_zpkrvcyzsmdkqqpsuxy1dte6",
    "decisions": 1,
    "cost_micros": 5,
    "cost_usd": 5.0e-6
  }
}

Language hint

With laya-auto, each request goes to the English checkpoint only when the state is detected as English, and to the multilingual checkpoint otherwise. If you already know the language, pass lang to skip detection:

POST /v1/systemone
curl https://layahost.com/v1/systemone \
  -H "Authorization: Bearer $LAYAHOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "state": "Ich möchte mein Abo kündigen.",
    "model": "laya-auto",
    "lang": "de",
    "cache": false,
    "questions": {
      "cancel": {
        "type": "noul",
        "instructions": "Does the customer want to cancel?"
      }
    }
  }'
Response · 200
{
  "model": "laya-multilingual",
  "answers": {
    "cancel": {
      "type": "noul",
      "noul": 0.9885,
      "confidence": 0.9885
    }
  },
  "usage": {
    "input_tokens": 40,
    "output_tokens": 0
  },
  "meta": {
    "checkpoint": "multilingual",
    "cached": false,
    "latency_ms": 31.08,
    "request_id": "req_5saxpesxm6qwhrssxrha8tjv",
    "decisions": 1,
    "cost_micros": 5,
    "cost_usd": 5.0e-6
  }
}

Caching

Identical requests (same checkpoint, state and questions) may be answered from an in-memory cache for up to an hour. A cached response has the same answers, meta.cached set to true and a very low latency_ms. Repeating the three-question example above returns:

meta · cached response
{
  "checkpoint": "english",
  "cached": true,
  "latency_ms": 0.37,
  "request_id": "req_cvwvpdksqcrakbv1cuzmr0mg",
  "decisions": 3,
  "cost_micros": 15,
  "cost_usd": 1.5e-5
}

Cached answers are billed like any other. Laya gives the same answer for the same input either way, so the cache only saves time. Set "cache": false to skip the cache completely: the answer is neither read from it nor stored in it. That is useful when you measure latency.

Billing

Each question is one decision, at $0.000005. The example above has three questions, so it costs $0.000015, as meta.decisions and meta.cost_micros show. Requests that fail are not billed. See Pricing & billing.

Limits

WhatLimit
Questions per request1 to 32
state32,000 characters (objects and arrays count as JSON text)
choice labelsAt least 2. Jev allows up to 255, but on layahost all labels and descriptions of one question must fit in the model's option budget of 192 tokens, roughly 100 to 150 short labels. Longer lists get 422.
score levels2 to 10

Errors

Invalid requests get 422 in the FastAPI format that Jev uses, and are not billed. An unknown model:

Response · 422
{
  "detail": [
    {
      "loc": ["body", "model"],
      "msg": "Model 'gpt-4o' is not available. Use GET /v1/models.",
      "type": "value_error"
    }
  ]
}

Errors in a question's shape point to the question by name, and include the offending input and a ctx object. Here the choice question q had a single label:

Response · 422
{
  "detail": [
    {
      "type": "too_short",
      "loc": ["body", "questions", "q", "choice", "criteria"],
      "msg": "Dictionary should have at least 2 items after validation, not 1",
      "input": {"yes": null},
      "ctx": {
        "field_type": "Dictionary",
        "min_length": 2,
        "actual_length": 1
      }
    }
  ]
}

A question whose labels and descriptions don't fit the option budget:

Response · 422
{
  "detail": [
    {
      "loc": ["body", "questions", "category", "criteria"],
      "msg": "The options of this question are too long for the model: all option names and descriptions together must fit in 192 tokens (roughly 100-150 short options). Shorten descriptions or split the question.",
      "type": "value_error"
    }
  ]
}

Too many questions:

Response · 422
{
  "detail": [
    {
      "loc": ["body", "questions"],
      "msg": "At most 32 questions per request.",
      "type": "value_error"
    }
  ]
}

See Errors for authentication, balance, rate-limit and capacity errors.