### GET /v1/usage Source: https://laya.studio/docs/api Get credit balance and 30-day usage. Requires authentication. ```APIDOC ## GET /v1/usage ### Description Credit balance and 30-day usage. Your token balance and the last 30 days of usage. ### Method GET ### Endpoint /v1/usage ### Authentication Required - Bearer token or x-api-key ### Response #### Success Response (200) - **balance** (number) - Credit balance. - **usage** (object) - Usage details for the last 30 days. #### Error Response (401) Missing or invalid API key. #### Response Example { "balance": 0, "usage": {} } ``` -------------------------------- ### GET /v1/models Source: https://laya.studio/docs/api List served checkpoints. Shows which models are live (English, multilingual, typed decisions). No API key needed. ```APIDOC ## GET /v1/models ### Description List served checkpoints. Which models are live (English, multilingual, typed decisions). No key needed. ### Method GET ### Endpoint /v1/models ### Response #### Success Response (200) - **models** (array) - List of available models. #### Response Example { "models": [] } ``` -------------------------------- ### decide tool response (structuredContent) Source: https://laya.studio/docs/mcp Example structuredContent response from the decide tool. Shows answers with probabilities and confidence, usage, routing, and credits charged. Every result also comes back as a text block holding the same JSON for clients that ignore structuredContent. ```json { "id": "dec_3f9c0a…", "model": "laya-rl-agent", "answers": { "intent": { "type": "choice", "choice": "refund", "probabilities": { "refund": 0.9466, "tracking": 0.0456, "other": 0.0078 }, "confidence": 0.7899 }, "urgent": { "type": "noul", "noul": 0.912, "confidence": 0.824 } }, "usage": { "input_tokens": 109, "output_tokens": 0 }, "routing": { "model": "english", "reason": "English Latin text" }, "credits_charged": 109 } ``` -------------------------------- ### Choice question reference (JSON) Source: https://laya.studio/docs/questions Reference example for a choice question. The 'criteria' may also be a plain list of labels. ```json "intent": { "type": "choice", "instructions": "What does the customer want?", "criteria": { "refund": "money back or a duplicate charge reversed", "tracking": "where is my parcel", "other": "anything else" } } // criteria may also be a plain list: ["refund", "tracking", "other"] ``` -------------------------------- ### Get credit balance and usage with curl Source: https://laya.studio/docs/api Use this curl command to check your credit balance and 30-day usage. Requires an API key in the Authorization header. ```shell curl https://api.laya.studio/v1/usage \ --header 'Authorization: Bearer YOUR_SECRET_TOKEN' ``` -------------------------------- ### decide tool request (tools/call) Source: https://laya.studio/docs/mcp Example tools/call request for the decide tool. It asks two questions (intent as choice, urgent as noul) about a customer message. The state is read once per question; only the first ~512 tokens (English) or ~1,024 (multilingual) are read per question. ```json { "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "decide", "arguments": { "state": "I was charged twice for order #4411 and I need the money back today.", "questions": { "intent": { "type": "choice", "instructions": "What does the customer want?", "criteria": { "refund": "money back or a duplicate charge reversed", "tracking": "where is my parcel", "other": "anything else" } }, "urgent": { "type": "noul", "instructions": "Does the message communicate time pressure?" } } } } } ``` -------------------------------- ### Noul question reference (JSON) Source: https://laya.studio/docs/questions Reference example for a noul question. The 'criteria' is optional; answer.noul is P(true). ```json "urgent": { "type": "noul", "instructions": "Does the message communicate time pressure?", "criteria": { "true": "a deadline or 'today/now' is stated", "false": "no time pressure" } } // criteria is optional; answer.noul is P(true) ``` -------------------------------- ### Choice question request (JSON) Source: https://laya.studio/docs/questions Example of a choice question definition sent in the 'questions' field. The 'criteria' object maps labels to short descriptions. Always include an 'other' option. ```json { "intent": { "type": "choice", "instructions": "What does the customer want?", "criteria": { "refund": "money back or a duplicate charge reversed", "technical_help": "a bug or integration problem", "cancellation": "wants to cancel", "other": "anything else" } } } ``` -------------------------------- ### Score question reference (JSON) Source: https://laya.studio/docs/questions Reference example for a score question. The answer.score is the expected level index (0-3 here) and answer.probabilities is the distribution. ```json "frustration": { "type": "score", "instructions": "How frustrated does the customer sound?", "criteria": ["calm", "concerned", "annoyed", "very angry"] } // answer.score is the expected level index (0-3 here), answer.probabilities the distribution ``` -------------------------------- ### cURL request to /v1/systemone Source: https://laya.studio/docs Authenticate with a bearer token and send a JSON payload with a state message and question definitions. The example includes choice, noul, and score question types. The response is a 200 OK JSON object. ```bash curl https://api.laya.studio/v1/systemone \ -H "Authorization: Bearer lsk_live_…" \ -H "Content-Type: application/json" \ -d '{"state":{"message":"I was charged twice this month. Refund me or I cancel."},"questions":{"intent":{"type":"choice","instructions":"What does the customer want?","criteria":{"refund":"money back or a duplicate charge reversed","technical_help":"a bug or integration problem","cancellation":"wants to cancel","other":"anything else"}},"urgent":{"type":"noul","instructions":"Does the message communicate time pressure?"},"frustration":{"type":"score","instructions":"How frustrated does the customer sound?","criteria":["calm","concerned","annoyed","very angry"]}}}' ``` -------------------------------- ### HTTP response headers showing x-laya-region Source: https://laya.studio/docs/data-residency Example response headers from the Laya Studio API. The x-laya-region: ch header indicates that the request was processed in Switzerland. ```http HTTP/2 200 content-type: application/json x-laya-region: ch ``` -------------------------------- ### Error body JSON example Source: https://laya.studio/docs/errors Shows the standard error response shape with code, message, balance, and needed fields. Failed requests are never billed. ```json { "error": { "code": "insufficient_credits", "message": "This request needs 5 credits; the workspace has 2.", "balance": 2, "needed": 5 } } ``` -------------------------------- ### Choice answer shape (JSON) Source: https://laya.studio/docs/questions Example of the answer object returned for a choice question. Shows the selected label, probabilities, confidence, and action. Confidence is 1 minus normalised entropy. ```json { "type": "choice", "choice": "refund", // the most probable label "probabilities": { "refund": 0.9466, "technical_help": 0.0071, ... }, "confidence": 0.7899, // 1 − normalised entropy "action": { "act_probability": 1.0 } } ``` -------------------------------- ### 402 Payment required error body JSON Source: https://laya.studio/docs/errors Example of a 402 error response indicating insufficient credits. Includes a link to billing and details about token needs. ```json { "error": { "code": "insufficient_credits", "message": "Not enough credits for this request: add credits or subscribe at https://laya.studio/dashboard/billing. It needs about 412 tokens (1 credit = 1 input token); the workspace has 20.", "balance": 20, "needed": 412, "free_runs_remaining": 0 } } ``` -------------------------------- ### Guard check 200 response Source: https://laya.studio/docs/guard Example JSON response from the Laya Guard API. It includes the verdict (block), reasons, and calibrated scores for safety, violation, severity, destructive, exfiltration, injected, approval policy, blast radius, and args grounded. ```json { "id": "dec_3f9c0a…", "verdict": "block", "p_unsafe": 0.9597, "reasons": [ "destructive", "arguments not supported by the request", "scope violation" ], "scores": { "safe": 0.0403, "violation": { "none": 0.0234, "policy_violation": 0.0768, "scope_violation": 0.383, "injection": 0.0552, "goal_drift": 0.3826, "corrigibility": 0.079 }, "severity": { "expected": 2.61, "level": "high", "probabilities": [ 0.03, 0.08, 0.14, 0.75 ] }, "destructive": 0.9987, "exfiltration": 0.0214, "injected": 0.0311, "approval_policy": { "auto_approve": 0.0122, "require_human": 0.1105, "reject": 0.8773 }, "blast_radius": { "expected": 1.93, "level": "production-mutating or external side effect", "probabilities": [ 0.01, 0.05, 0.94 ] }, "args_grounded": 0.2135 }, "model": "mcp-guard-deberta-v1", "latency_ms": 14.8 } ``` -------------------------------- ### JSON request body for Decision API Source: https://laya.studio/docs Example request body sent to the Decision API. It includes the state text and a questions object with typed questions: a choice question with criteria and a noul (yes/no) question. This is the exact JSON that the demo generates and that your code will send. ```json { "state": "I was charged twice for my order last week. I want my money back today.", "questions": { "intent": { "type": "choice", "instructions": "What does the customer want?", "criteria": [ "refund", "tracking", "other" ] }, "angry": { "type": "noul", "instructions": "Is the customer angry?" } } } ``` -------------------------------- ### POST /mcp - initialize Source: https://laya.studio/docs/mcp Initializes an MCP session with the Laya Studio server. Returns protocol version, server capabilities, and server info. ```APIDOC ## [POST] /mcp ### Description Initializes an MCP session with the Laya Studio server. Returns protocol version, server capabilities, and server info. ### Method POST ### Endpoint https://api.laya.studio/mcp ### Headers - **Authorization** (string) - Required - Bearer token (e.g., `Bearer lsk_live_…`) - **Content-Type** (string) - Required - `application/json` - **Accept** (string) - Required - `application/json, text/event-stream` ### Request Body - **jsonrpc** (string) - Required - Must be `"2.0"` - **id** (number) - Required - Request identifier - **method** (string) - Required - Must be `"initialize"` - **params** (object) - Required - Parameters for initialization - **protocolVersion** (string) - Required - Protocol version, e.g., `"2025-06-18"` - **capabilities** (object) - Required - Client capabilities - **clientInfo** (object) - Required - Client information - **name** (string) - Required - Client name - **version** (string) - Required - Client version ### Request Example { "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2025-06-18", "capabilities": {}, "clientInfo": { "name": "my-app", "version": "1.0" } } } ### Response #### Success Response (200) - **Mcp-Session-Id** (string) - Session identifier (e.g., `mcp_…`) - **jsonrpc** (string) - Must be `"2.0"` - **id** (number) - Request identifier - **result** (object) - Result object - **protocolVersion** (string) - Protocol version - **capabilities** (object) - Server capabilities - **serverInfo** (object) - Server information - **name** (string) - Server name - **title** (string) - Server title - **version** (string) - Server version - **instructions** (string) - Instructions for the client #### Response Example { "jsonrpc": "2.0", "id": 1, "result": { "protocolVersion": "2025-06-18", "capabilities": { "tools": {} }, "serverInfo": { "name": "laya-studio", "title": "Laya Studio", "version": "1.0.0" }, "instructions": "…" } } ### Error Handling - **400** - Invalid JSON, empty/oversized batch, or unsupported MCP-Protocol-Version. - **401** - Missing or invalid key. Includes `WWW-Authenticate: Bearer` and JSON-RPC error body. - **405** - GET or DELETE not allowed; use POST. - **429** - Rate limited per key or workspace. Honour `Retry-After`. - Unknown methods return JSON-RPC error `-32601`; unknown tool names return `-32602`. ``` -------------------------------- ### POST /v1/systemone Source: https://laya.studio/docs/api The main decision endpoint. Send text and up to 32 questions, and receive answers with probabilities and confidence for each. ```APIDOC ## POST /v1/systemone ### Description Answer typed questions about a state in one forward pass. Send text plus questions, get an answer and probabilities for each. Jev-compatible. ### Method POST ### Endpoint /v1/systemone ### Parameters #### Request Body - **state** (string) - Required - The input text or JSON state. - **questions** (array) - Required - Up to 32 questions to answer. ### Response #### Success Response (200) - **answers** (object) - Contains answers keyed by question ID, each with answer, probabilities, and confidence. #### Response Example { "answers": { "": { "answer": "...", "probabilities": {}, "confidence": 0.0 } } } ``` -------------------------------- ### POST /v1/systemone Source: https://laya.studio/docs Sends a customer message along with a set of questions to classify intent, urgency, and frustration. Returns structured answers with confidence scores and probabilities. ```APIDOC ## POST /v1/systemone ### Description Sends a customer message along with a set of questions to classify intent, urgency, and frustration. Returns structured answers with confidence scores and probabilities. ### Method POST ### Endpoint https://api.laya.studio/v1/systemone ### Authentication Bearer token (e.g., `Authorization: Bearer lsk_live_…`) ### Request Body - **state** (object) - Required - Contains the customer message. Field: `message` (string). - **questions** (object) - Required - A map of question IDs to question definitions. Each question has a `type` (choice, noul, score), `instructions` (string), and `criteria` (for choice: object mapping labels to descriptions; for score: array of labels). ### Request Example ```json { "state": { "message": "I was charged twice this month. Refund me or I cancel." }, "questions": { "intent": { "type": "choice", "instructions": "What does the customer want?", "criteria": { "refund": "money back or a duplicate charge reversed", "technical_help": "a bug or integration problem", "cancellation": "wants to cancel", "other": "anything else" } }, "urgent": { "type": "noul", "instructions": "Does the message communicate time pressure?" }, "frustration": { "type": "score", "instructions": "How frustrated does the customer sound?", "criteria": ["calm", "concerned", "annoyed", "very angry"] } } } ``` ### Response #### Success Response (200) - **id** (string) - Decision ID. - **model** (string) - Model used (e.g., "laya-rl-agent"). - **answers** (object) - Map of question IDs to answer objects. Each answer contains: - `type` (string) - Question type. - `choice` (string) - For choice questions: the most probable label. - `score` (number) - For score questions: expected level index. - `noul` (number) - For noul questions: probability that the statement is true. - `probabilities` (object) - Full distribution over options (choice, score). - `confidence` (number) - Confidence score. - `action` (object) - Contains `act_probability` (number). - **usage** (object) - Token usage: `input_tokens` (integer), `output_tokens` (integer, always 0). - **routing** (object) - Model routing info: `model`, `repo`, `reason`. #### Response Example ```json { "id": "dec_6f0c…", "model": "laya-rl-agent", "answers": { "intent": { "type": "choice", "choice": "refund", "probabilities": { "refund": 0.9466, "technical_help": 0.0071, "cancellation": 0.0385, "other": 0.0078 }, "confidence": 0.7899, "action": { "act_probability": 1.0 } }, "urgent": { "type": "noul", "noul": 0.81, "confidence": 0.81, "action": { "act_probability": 1.0 } }, "frustration": { "type": "score", "score": 2.31, "legend": { "0": "calm", "1": "concerned", "2": "annoyed", "3": "very angry" }, "probabilities": { "0": 0.03, "1": 0.12, "2": 0.36, "3": 0.49 }, "confidence": 0.34, "action": { "act_probability": 1.0 } } }, "usage": { "input_tokens": 212, "output_tokens": 0 }, "routing": { "model": "english", "repo": "convaiinnovations/laya", "reason": "English Latin text" } } ``` ### Field Reference - `answers..choice` (string) - choice questions: the most probable label. - `answers..score` (number) - score questions: expected level index, Σ i·p(i). - `answers..noul` (number) - noul questions: probability that the statement is true. - `answers..probabilities` (object) - The full distribution over options (choice, score). - `answers..confidence` (number) - choice/score: 1 − H(p)/log k. noul: max(p, 1 − p). Gate automation on this. - `answers..action.act_probability` (number) - Output of the act/escalate head. The model card reports it carries little signal today — prefer confidence. - `usage.input_tokens` (integer) - Tokens encoded across all questions. output_tokens is always 0. - `routing` (object) - Which checkpoint answered and why (english / multilingual / typed-decisions). ``` -------------------------------- ### 200 OK JSON response from /v1/systemone Source: https://laya.studio/docs The response contains an id, model, answers object with each question's result, usage tokens, and routing info. The answers include choice, noul, and score types with probabilities and confidence. Use the confidence field to decide what to automate. ```json { "id": "dec_6f0c…", "model": "laya-rl-agent", "answers": { "intent": { "type": "choice", "choice": "refund", "probabilities": { "refund": 0.9466, "technical_help": 0.0071, "cancellation": 0.0385, "other": 0.0078 }, "confidence": 0.7899, "action": { "act_probability": 1.0 } }, "urgent": { "type": "noul", "noul": 0.81, "confidence": 0.81, "action": { "act_probability": 1.0 } }, "frustration": { "type": "score", "score": 2.31, "legend": { "0": "calm", "1": "concerned", "2": "annoyed", "3": "very angry" }, "probabilities": { "0": 0.03, "1": 0.12, "2": 0.36, "3": 0.49 }, "confidence": 0.34, "action": { "act_probability": 1.0 } } }, "usage": { "input_tokens": 212, "output_tokens": 0 }, "routing": { "model": "english", "repo": "convaiinnovations/laya", "reason": "English Latin text" } } ``` -------------------------------- ### Diff: Change base URL and Authorization header Source: https://laya.studio/docs/jev-migration Shows the two lines that change when migrating: the base URL and the Authorization header. The path stays /v1/systemone. ```diff - base URL: https://api.typesafe.ai + base URL: https://api.laya.studio - Authorization: Bearer + Authorization: Bearer lsk_live_… # dashboard → API keys ``` -------------------------------- ### Add Laya MCP server to Claude Code Source: https://laya.studio/docs/mcp Run once in your terminal to connect Laya to Claude Code. Add --scope user to make Laya available in every project. Then type /mcp inside Claude Code to check that "laya" is connected. ```bash claude mcp add --transport http laya https://api.laya.studio/mcp --header "Authorization: Bearer lsk_live_…" ``` -------------------------------- ### Python guard function for pre-tool-call hook Source: https://laya.studio/docs/guard Sends a POST request to the Laya Studio guard API with the tool call, intent, and trigger. Returns the verdict ('allow', 'ask', or 'block'). Use this in your agent's pre-tool-call hook to decide whether to run a tool. Requires the LAYA_API_KEY environment variable. ```python import os, requests def guard(tool: str, args: dict, intent: str, trigger: str = "user_request") -> str: r = requests.post( "https://api.laya.studio/v1/guard", headers={"Authorization": f"Bearer {os.environ['LAYA_API_KEY']}"}, json={"action": {"tool": tool, "args": args}, "intent": intent, "trigger": trigger}, timeout=10, ) r.raise_for_status() return r.json()["verdict"] # "allow" | "ask" | "block" # In your agent's pre-tool-call hook: verdict = guard("send_email", {"to": "ops@acme.com", "body": "..."}, intent="Email the weekly report to ops") if verdict == "allow": ... # run the tool elif verdict == "ask": ... # show the call to the user and wait for a yes else: ... # never run it; tell the agent why ``` -------------------------------- ### curl request with x-laya-residency header Source: https://laya.studio/docs/data-residency Send a request to the Laya Studio API with the x-laya-residency: ch header to enforce Swiss-only processing for that request. The header can only make a request stricter; if the workspace already has Swiss-only mode on, every request is Swiss-only regardless of the header. ```bash curl -i https://api.laya.studio/v1/systemone \ -H "Authorization: Bearer $LAYA_API_KEY" \ -H "Content-Type: application/json" \ -H "x-laya-residency: ch" \ -d '{"state":"Patient reports chest pain since this morning.","questions":{"urgent":{"type":"noul","instructions":"Does this need same-day attention?"}}}' ``` -------------------------------- ### POST /v1/systemone/batch Source: https://laya.studio/docs/api Process up to 64 independent decisions in a single call, useful for backfills and bulk jobs. ```APIDOC ## POST /v1/systemone/batch ### Description Up to 64 decisions in one call. Many independent texts at once, for backfills and bulk jobs. ### Method POST ### Endpoint /v1/systemone/batch ### Parameters #### Request Body - **items** (array) - Required - Array of decision requests, each containing state and questions. ### Response #### Success Response (200) - **results** (array) - Array of decision results, each with answers. #### Response Example { "results": [ { "answers": {} } ] } ``` -------------------------------- ### List served checkpoints with curl Source: https://laya.studio/docs/api Use this curl command to list served checkpoints. No API key is required for this endpoint. ```shell curl https://api.laya.studio/v1/models ``` -------------------------------- ### POST /v1/systemone Source: https://laya.studio/docs/errors The main API endpoint for making decisions. This documentation covers error handling, status codes, limits, and retry policy. ```APIDOC ## POST /v1/systemone ### Description Sends a request to the Laya Studio API to get a decision. This endpoint is used for all API calls and is subject to the error handling and retry policy described below. ### Method POST ### Endpoint https://api.laya.studio/v1/systemone ### Parameters #### Request Body - **questions** (object) - Required - The questions to be answered. Must be an object, not an array. Maximum 32 questions. - **batch** (array) - Optional - A batch of requests. Maximum 64 requests per batch. ### Request Example ```json { "questions": { "question1": { "type": "decision", "instructions": "...", "criteria": "...", "options": ["..."] } } } ``` ### Response #### Success Response (200) - **x-credits-charged** (header) - The number of input tokens billed. - **x-free-runs-remaining** (header) - The number of legacy free runs remaining (0 for new workspaces). #### Response Example ```json { "error": { "code": "insufficient_credits", "message": "This request needs 5 credits; the workspace has 2.", "balance": 2, "needed": 5 } } ``` ### Error Handling All errors have the same shape: `{ "error": { "code": "...", "message": "..." } }`. Only 429 and 503 are worth retrying. Failed requests are never billed. #### Status Codes - **200** - OK. Answered. `x-credits-charged` tells what was billed (input tokens). `x-free-runs-remaining` reports legacy free runs (0 for new workspaces). - **400** - Bad request. Malformed body: invalid JSON, questions not an object, more than 32 questions, batch over 64. - **401** - Unauthorized. Missing, malformed or revoked key (revocation propagates within 30 s). - **402** - Payment required. The workspace’s token balance cannot cover this request’s estimated input tokens. Add credits or subscribe in the dashboard. No retry, no billing. - **413** - Payload too large. Body larger than 512 KB. - **422** - Invalid question. A question is invalid: unknown type, missing instructions, choice without criteria, too many options. - **429** - Rate limited. Per key, and per workspace across all its keys. Honour Retry-After. - **503** - Unavailable. Inference capacity is saturated or restarting. Retry with backoff; honour Retry-After. #### Error Body Example (402) ```json { "error": { "code": "insufficient_credits", "message": "Not enough credits for this request: add credits or subscribe at https://laya.studio/dashboard/billing. It needs about 412 tokens (1 credit = 1 input token); the workspace has 20.", "balance": 20, "needed": 412, "free_runs_remaining": 0 } } ``` ### Limits - **Questions per request**: 32 - **Options per question**: 64 (accuracy is best well below 20) - **Requests per batch**: 64 - **Body size**: 512 KB - **State read per question**: 512 tokens (english), 1,024 (multilingual, typed-decisions) - **Rate limit**: 3,000 requests per 10 s per key, and the same budget per workspace across all its keys (contact us to raise it) ### Retry Policy with Exponential Backoff Retry 429 and 503 (and network errors) with jittered exponential backoff; never retry other 4xx errors. The small random jitter stops many clients from retrying at the same instant. #### Python Example ```python import random, time, requests def decide(body, key, attempts=5): for i in range(attempts): r = requests.post("https://api.laya.studio/v1/systemone", json=body, headers={"Authorization": f"Bearer {key}"}, timeout=30) if r.status_code not in (429, 503): r.raise_for_status() return r.json() wait = float(r.headers.get("retry-after", 0)) or min(8, 0.25 * 2 ** i) time.sleep(wait + random.random() * 0.25) r.raise_for_status() ``` Using Swiss-only mode? A 503 can also mean the Swiss pool is unavailable; see data residency. ``` -------------------------------- ### Shadow traffic: compare Jev and Laya responses (TypeScript) Source: https://laya.studio/docs/jev-migration Sends the same request to both Jev and Laya Studio in parallel and logs the answers for each question. Use this to compare answers and confidence before switching. ```TypeScript const body = { state, questions, model: "jev-latest" }; const [jev, laya] = await Promise.all([ fetch("https://api.typesafe.ai/v1/systemone", { method: "POST", headers: { Authorization: `Bearer ${JEV_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify(body) }).then(r => r.json()), fetch("https://api.laya.studio/v1/systemone", { method: "POST", headers: { Authorization: `Bearer ${LAYA_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify(body) }).then(r => r.json()), ]); for (const id of Object.keys(questions)) log(id, jev.answers[id], laya.answers[id]); ``` -------------------------------- ### Before: Jev client (TypeScript) Source: https://laya.studio/docs/jev-migration Original Jev client code using the TypeSafe API endpoint and Jev key. The request body, question types, and answer fields remain unchanged when migrating. ```TypeScript const BASE = "https://api.laya.studio"; const KEY = process.env.LAYA_API_KEY; // lsk_live_… const res = await fetch(`${BASE}/v1/systemone`, { method: "POST", headers: { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ state, questions, model: "jev-latest" }), }); const { answers } = await res.json(); route(answers.intent.choice, answers.intent.confidence); ``` -------------------------------- ### guard_batch Source: https://laya.studio/docs/guard Performs a batch guard check. Requires the same API key as the decision tools. Billing is per check, with credits charged as indicated in the response headers. ```APIDOC ## guard_batch ### Description Performs a batch guard check. Requires the same API key as the decision tools. Billing is per check, with credits charged as indicated in the response headers. ### Method POST ### Endpoint https://api.laya.studio/mcp ### Parameters #### Headers - **x-laya-residency** (string) - Optional - Set to `ch` for Swiss-only processing, which costs 15% more and never leaves Switzerland. ### Response #### Success Response (200) - **x-credits-charged** (string) - Credits billed for the check. - **x-request-id** (string) - Request identifier. #### Error Responses - **400** - Malformed body: no action, a bad trigger, constraints not strings, a batch over 64. - **401** - Missing, malformed or revoked key. - **402** - The balance cannot cover the check (5,602 credits each). Add credits or subscribe. - **413** - A field is longer than 20,000 characters. - **429** - Rate limited (per key, and per workspace across all its keys). Honour Retry-After. - **503** - The guard model is busy or restarting. Retry with backoff; nothing was charged. ``` -------------------------------- ### Send a guard check with curl Source: https://laya.studio/docs/guard Use this curl command to send a tool call to the Laya Guard API. Replace $LAYA_API_KEY with your API key. The request includes the action, user intent, and context. The response will be a JSON object with a verdict and scores. ```bash curl https://api.laya.studio/v1/guard \ -H "Authorization: Bearer $LAYA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "action": { "tool": "db.drop_table", "args": { "table": "users" } }, "intent": "List the tables in the staging database", "context": "Database agent. Environment: production." }' ``` -------------------------------- ### POST /v1/guard Source: https://laya.studio/docs/guard Sends a tool call along with the user's intent and context to receive a safety verdict. Returns allow, ask, or block with reasons and calibrated scores. ```APIDOC ## POST /v1/guard ### Description Checks a proposed tool call against the user's intent and context to determine if it should be allowed, require human approval, or be blocked. Returns a verdict, reasons, and calibrated scores for nine safety questions. ### Method POST ### Endpoint https://api.laya.studio/v1/guard ### Parameters #### Request Body - **action** (object) - Required - The tool call to be evaluated, containing `tool` (string) and `args` (object). - **intent** (string) - Required - What the user asked for. - **context** (string) - Required - Additional context about the environment or agent. ### Request Example ```json { "action": { "tool": "db.drop_table", "args": { "table": "users" } }, "intent": "List the tables in the staging database", "context": "Database agent. Environment: production." } ``` ### Response #### Success Response (200) - **id** (string) - Unique identifier for the check. - **verdict** (string) - One of `allow`, `ask`, or `block`. - **p_unsafe** (number) - Probability that the action is unsafe. - **reasons** (array of strings) - Human-readable reasons for the verdict. - **scores** (object) - Calibrated scores for nine safety questions, including `safe`, `violation`, `severity`, `destructive`, `exfiltration`, `injected`, `approval_policy`, `blast_radius`, and `args_grounded`. - **model** (string) - Model used for the check. - **latency_ms** (number) - Latency of the check in milliseconds. #### Response Example ```json { "id": "dec_3f9c0a…", "verdict": "block", "p_unsafe": 0.9597, "reasons": [ "destructive", "arguments not supported by the request", "scope violation" ], "scores": { "safe": 0.0403, "violation": { "none": 0.0234, "policy_violation": 0.0768, "scope_violation": 0.383, "injection": 0.0552, "goal_drift": 0.3826, "corrigibility": 0.079 }, "severity": { "expected": 2.61, "level": "high", "probabilities": [0.03, 0.08, 0.14, 0.75] }, "destructive": 0.9987, "exfiltration": 0.0214, "injected": 0.0311, "approval_policy": { "auto_approve": 0.0122, "require_human": 0.1105, "reject": 0.8773 }, "blast_radius": { "expected": 1.93, "level": "production-mutating or external side effect", "probabilities": [0.01, 0.05, 0.94] }, "args_grounded": 0.2135 }, "model": "mcp-guard-deberta-v1", "latency_ms": 14.8 } ``` ``` -------------------------------- ### guard_check Source: https://laya.studio/docs/guard Performs a single guard check. Requires the same API key as the decision tools. Billing is per check, with credits charged as indicated in the response headers. ```APIDOC ## guard_check ### Description Performs a single guard check. Requires the same API key as the decision tools. Billing is per check, with credits charged as indicated in the response headers. ### Method POST ### Endpoint https://api.laya.studio/mcp ### Parameters #### Headers - **x-laya-residency** (string) - Optional - Set to `ch` for Swiss-only processing, which costs 15% more and never leaves Switzerland. ### Response #### Success Response (200) - **x-credits-charged** (string) - Credits billed for the check. - **x-request-id** (string) - Request identifier. #### Error Responses - **400** - Malformed body: no action, a bad trigger, constraints not strings, a batch over 64. - **401** - Missing, malformed or revoked key. - **402** - The balance cannot cover the check (5,602 credits each). Add credits or subscribe. - **413** - A field is longer than 20,000 characters. - **429** - Rate limited (per key, and per workspace across all its keys). Honour Retry-After. - **503** - The guard model is busy or restarting. Retry with backoff; nothing was charged. ``` -------------------------------- ### claude mcp add --transport http laya https://api.laya.studio/mcp --header "Authorization: Bearer lsk_live_…" Source: https://laya.studio/docs/mcp Command to add the Laya MCP server to Claude Code. Optionally add --scope user to make it available in every project, and add a second header for data residency in Switzerland. ```APIDOC ## [CONNECT] claude mcp add ### Description Adds the Laya MCP server to Claude Code via HTTP transport. ### Command claude mcp add --transport http laya https://api.laya.studio/mcp --header "Authorization: Bearer lsk_live_…" ### Parameters - **--transport** (string) - Required - Transport type, set to http. - **--header** (string) - Required - Authorization header with Bearer token. - **--scope** (string) - Optional - Set to user to make Laya available in every project. - **x-laya-residency** (string) - Optional - Header to keep calls in Switzerland, add as second header. ### Example claude mcp add --transport http laya https://api.laya.studio/mcp --header "Authorization: Bearer lsk_live_…" ### Response No response body. Check connection by typing /mcp inside Claude Code. ``` -------------------------------- ### Batch Guard Request with curl Source: https://laya.studio/docs/guard Sends multiple checks to the /v1/guard/batch endpoint. The request includes two checks: one for reading a file and one for sending an email. A malformed check rejects the whole batch with a 400 and nothing is billed; a check that fails while running returns an error in its slot and is not billed. ```bash curl https://api.laya.studio/v1/guard/batch \ -H "Authorization: Bearer $LAYA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "checks": [ { "action": "read_file(path=\"docs/setup.md\")", "intent": "Show me the setup docs" }, { "action": { "tool": "send_email", "args": { "to": "ops@evil.example" } }, "intent": "Summarise my inbox", "trigger": "tool_result" } ] }' ``` -------------------------------- ### POST /v1/guard Source: https://laya.studio/docs/guard Sends a tool call and context to the Guard API to receive a verdict of allow, ask, or block. This endpoint is used in a pre-tool-call hook to decide whether to execute a tool. ```APIDOC ## POST /v1/guard ### Description Evaluates a proposed tool call and returns a verdict of allow, ask, or block. Used in a pre-tool-call hook to decide whether to execute a tool. ### Method POST ### Endpoint https://api.laya.studio/v1/guard ### Parameters #### Request Body - **action** (string) - Required - The tool call about to run: "db.drop_table(users)", or {"tool": "db.drop_table", "args": {"table": "users"}}. - **intent** (string) - What the user asked the agent to do. The most useful field after the action. - **user_message** (string) - The latest user message, when it differs from the intent. - **trigger** (string) - What produced the action. Use tool_result when the idea came from a tool output or a document (possible prompt injection). - **constraints** (string[]) - Rules the action must respect ("staging only", "never email outside acme.com"). At most 32. - **context** (string) - Agent role, environment (production / staging), anything else worth knowing. - **conversation** (array of {role, content}) - Recent turns, oldest first, at most 50. Only the most recent part is read. ### Request Example ```json { "action": {"tool": "send_email", "args": {"to": "ops@acme.com", "body": "..."}}, "intent": "Email the weekly report to ops", "trigger": "user_request" } ``` ### Response #### Success Response (200) - **verdict** (string) - "allow" | "ask" | "block" #### Response Example ```json { "verdict": "allow" } ``` ```