{"openapi":"3.1.0","info":{"title":"Canonopy Decisions API","description":"Your own decision model behind TypeSafe's System One (Jev) request format. Learned from your cases, your rules enforced, tested on rare situations. One flat price per workspace: unlimited decision models, decisions and retraining. A 5-day free trial starts when you first use it (your first trained model or first decision), no card needed. The models are yours to keep.\n\n**Words.** A *decision model* is called a **domain** in this API (`/v1/domains`). Its name is what you pass as `model` when you ask for a decision: `refunds@latest` (the version it serves now) or `refunds@3` (a fixed version). Every path that takes `{domain}` accepts the domain's `name` or its `id`.\n\n**Auth.** `Authorization: Bearer <key>` (or `X-API-Key: <key>`) on every call except `/health`, `/v1/health`, `/v1/plans`, sign-up, sign-in and `/v1/demo/*`. Keys come from the console (https://canonopylabs.com/console/keys).\n\n## Start here\n\n1. `POST /v1/domains` with `{\"name\": \"refunds\"}`: create the decision model.\n2. `POST /v1/domains/{domain}/agent`: describe the decision in plain words (what you decide, the actions, the fields that matter, the rules that must never be broken). Send more messages to refine it until `next_step` is `train`.\n3. Optional, any time: `GET /v1/domains/{domain}/examples` shows how it decides on about 20 example cases; correct any with `POST /v1/domains/{domain}/signoff` (they're learned at the next training run). Nothing waits for it.\n4. Optional, and the biggest lever for decisions on text: `POST /v1/domains/{domain}/data` with past cases and how each was resolved. No labelling: the outcome you already record is enough.\n5. `POST /v1/domains/{domain}/train`: a new version in about a minute, with a report (`GET /v1/domains/{domain}/versions/{version}/report`). To improve the same model later, replace its cases (`POST /v1/domains/{domain}/data?mode=replace`) or delete an upload (`GET /v1/domains/{domain}/uploads`, `DELETE /v1/domains/{domain}/uploads/{upload_id}`) and train again: `refunds@2`, `refunds@3`, under the same name.\n6. `POST /v1/decide` with `{\"model\": \"refunds@latest\", \"state\": {...}}`: answers in Jev's format plus a `decision` block (the action with your rules applied, and `route`: `act`, `review` or `ask`).\n7. Keep improving: answer the unsure queue (`GET /v1/domains/{domain}/unsure`, `POST /v1/domains/{domain}/answers`), report outcomes (`POST /v1/outcomes`), add options (`POST /v1/domains/{domain}/options`), and promote or roll back (`POST /v1/domains/{domain}/promote`).\n\nComing from Jev? Change the base URL and `model`: the request and answer shapes are the same, and `/v1/systemone` is an alias of `/v1/decide`.\n\n**Or build from the JSON you send Jev.** `POST /v1/build` with one real example `state` and your `questions` (optionally 5-20 more real states in `examples`, notes on fields in `fields` and `rules` in plain words): your own model in minutes. No past decisions or answers needed; a few examples of what you send Jev make it better. Poll `GET /v1/build/{build_id}` until it's `ready`, then keep sending the same JSON to `/v1/decide` with `\"model\": \"<name>@latest\"`. Nothing waits for you in between. Review how it decides any time (optional): `GET /v1/domains/{domain}/examples`, and correct any with `POST /v1/domains/{domain}/signoff` and `\"retrain\": true`.\n\n**Errors** are always `{\"error\": {\"type\": \"...\", \"message\": \"...\"}}` with a short message that says what to fix: `400 invalid_request`, `401 authentication_error`, `402 payment_required`, `404 not_found`, `409 conflict`, `413 too_large`, `429 rate_limited` (wait `Retry-After` seconds and send it again), `500 server_error`, `503 unavailable`. Every response carries `X-Request-Id`; quote it when you contact us.\n\n**Docs** for people and coding agents: https://canonopylabs.com/docs, https://canonopylabs.com/llms.txt (an index of every docs page as Markdown) and https://canonopylabs.com/llms-full.txt (all of it in one file).\n","version":"0.1.0"},"paths":{"/health":{"get":{"tags":["meta"],"summary":"Liveness check","description":"Answers `{\"ok\": true, \"version\": ...}` when the service is up. No key needed.\n\nUse `GET /v1/health` for a check that includes each dependency.","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"}}}}},"security":[]}},"/v1/health":{"get":{"tags":["meta"],"summary":"Service health with dependency checks","description":"Without a key: `ok` and `status` (`ok`, `degraded` or `down`). With the operators' admin key: also the version and each dependency it relies on (`database`, `queue`, `reader`, `translator`, `backup`, `email`), each `ok`, `degraded` or `down`.\n\n**Errors:** `503` with `ok: false` only when the database is down (the service can't work).","operationId":"health_v1_v1_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthDetail"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthDetail"}}}}},"security":[]}},"/v1/decide":{"post":{"tags":["decide"],"summary":"Ask for a decision (Jev's System One format)","description":"The call your application makes in production. Send the case as `state` and name the decision model as `model` (`refunds@latest`, or a fixed version like `refunds@3`). Leave out `questions` to ask every question the domain knows, or send questions in Jev's format (Choice, Score, Noul).\n\nEach answer keeps Jev's fields and meanings and adds `source` (who answered: `trained`, `translated`, `fallback`, `rule` or `backup`) and `route` (`act`: automatic; `review`: held for a person). The `decision` block (when the domain has a decision question) gives the final action with your rules applied, the rules that blocked something, and `route`: `act` (go ahead), `review` (held for a person, in the unsure queue) or `ask` (your rules allow no action; hand it over).\n\n**Before:** a domain with questions, ideally trained (`POST /v1/domains/{domain}/train`). A question that isn't trained yet is answered by your day-one backend (`source: \"fallback\"`); below 0.8 confidence it is held for a person (`route: \"review\"`), like a trained answer below the safety bar. A question the domain doesn't have is answered too, and listed in the domain's `candidate_questions`: it joins the domain (and requests without `questions`) only when you add it with PATCH. A `model` naming a domain that doesn't exist yet creates it in day-one mode, with the questions it is first asked. Names starting with `jev-` map to your `default` domain. A number that is NaN or infinity counts as missing.\n\n**After:** keep `id` and report what really happened with `POST /v1/outcomes`; answer `review` and `ask` cases with `POST /v1/domains/{domain}/answers`.\n\n**Errors:** `400` (a malformed question, a Score with fewer than 2 levels, a game domain: download it instead, or no question to ask), `402` (the free trial has ended and there's no active subscription: subscribe to keep improving your models; the models you already have are yours), `404` (unknown model version), `409` (the domain is archived), `413` (a request over 256 KB), `429` (above 50 requests per second per key: wait `Retry-After`).","operationId":"decide_v1_decide_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecideRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecideResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/systemone":{"post":{"tags":["decide"],"summary":"Ask for a decision (alias of /v1/decide)","description":"Exactly `POST /v1/decide`, at Jev's path: same body, same answer. Lets code written for Jev work after changing only the base URL and `model`.","operationId":"systemone_v1_systemone_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecideRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecideResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/models":{"get":{"tags":["decide"],"summary":"List serving models (Jev-compatible)","description":"One card per domain that has a serving version: `name` (`<domain>@<version>`), `description` and `release_date`. The same shape as Jev's model list.\n\nUse `GET /v1/domains` for everything about each decision model.","operationId":"list_models_v1_models_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ModelCard"},"type":"array","title":"Response List Models V1 Models Get"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/demo/decide":{"post":{"tags":["demo"],"summary":"Public demo decision (no key)","description":"The `bank-support` demo model on the site's front page. Same request and answer as `/v1/decide`; `model` is ignored. No key needed; 30 requests per minute per IP address.\n\n**Errors:** `429` above the demo's limit, `503` while the demo is starting.","operationId":"demo_decide_v1_demo_decide_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecideRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecideResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[]}},"/v1/demo/benchmark":{"get":{"tags":["demo"],"summary":"The head-to-head numbers shown on the site","description":"The bank-support model against hosted Jev on 3,080 real customer messages: accuracy, calibration, speed and cost. No key needed.","operationId":"demo_benchmark_v1_demo_benchmark_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Benchmark"}}}}},"security":[]}},"/v1/plans":{"get":{"tags":["account"],"summary":"Plans and prices","description":"The one plan: $20 a month per workspace, flat, with unlimited decision models, decisions and retraining, and what it includes. A 5-day free trial starts when you first use it (your first trained model or first decision), no card needed. No key needed.","operationId":"plans_v1_plans_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/Plan"},"type":"array","title":"Response Plans V1 Plans Get"}}}}},"security":[]}},"/v1/signup":{"post":{"tags":["account"],"summary":"Sign up with a password (superseded)","description":"Superseded by email sign-up (`POST /v1/signup/start`). Answers `403` unless the server allows password sign-up.\n\n**Errors:** `403` (use email sign-up, or sign-up is by invitation), `409` (the email already has an account).","operationId":"signup_v1_signup_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[]}},"/v1/signup/start":{"post":{"tags":["account"],"summary":"Sign up with your email: we send a confirmation link","description":"Sends a one-time confirmation link (valid 24 hours). Nothing is created until it's used. The answer is the same whether or not the address already has a workspace. Enabled when open sign-up is on. No key needed.\n\n**After:** the link opens the console, which calls `POST /v1/signup/verify`.\n\n**Errors:** `400` (not an email address, or the terms not accepted), `403` (sign-up is by invitation for now).","operationId":"signup_start_v1_signup_start_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupStart"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailSent"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[]}},"/v1/signup/verify":{"post":{"tags":["account"],"summary":"Confirm the email link: creates your workspace and first API key","description":"Uses the token from the confirmation link. Creates the workspace, its owner, the first API key (shown once: store it) and a 12-hour console session.\n\n**Errors:** `400` (the link expired or was already used), `409` (the email already has a workspace: sign in instead).","operationId":"signup_verify_v1_signup_verify_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupVerified"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[]}},"/v1/login/link":{"post":{"tags":["account"],"summary":"Email me a sign-in link for the console","description":"Sends a one-time sign-in link (15 minutes). The answer is the same whether or not the address has an account. No key needed. Then `POST /v1/login/verify` with the link's token.","operationId":"login_link_v1_login_link_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailSent"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[]}},"/v1/login/verify":{"post":{"tags":["account"],"summary":"Use a sign-in link: a console session","description":"Exchanges the sign-in link's token for a 12-hour console session token, used as a Bearer key.\n\n**Errors:** `400` (the link expired or was already used).","operationId":"login_verify_v1_login_verify_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[]}},"/v1/login":{"post":{"tags":["account"],"summary":"Sign in with a password","description":"Email and password to a 12-hour console session token, used as a Bearer key. For workspaces created with a password.\n\n**Errors:** `401` (wrong email or password).","operationId":"login_v1_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[]}},"/v1/account":{"get":{"tags":["account"],"summary":"Your workspace, plan and usage","description":"The workspace, the signed-in user (null for an API key), the plan, and usage: decisions this month, active decision models and the monthly price. Usage is for your dashboards; the price is flat.","operationId":"account_v1_account_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Account"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/keys":{"get":{"tags":["account"],"summary":"List API keys","description":"Every key in the workspace: id, name, prefix, when it was created and last used, and when it expires (only after a rotation with a grace period). The key itself is never shown again.","operationId":"keys_v1_keys_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyList"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["account"],"summary":"Create an API key","description":"A new key with a name. The full key is in the answer once: store it now; we keep only a hash.","operationId":"key_create_v1_keys_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreated"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/keys/{key_id}/rotate":{"post":{"tags":["account"],"summary":"Replace a key","description":"A new key with the same name, shown once. The old key stops now, or after `grace_hours` (up to 168) so you can roll it out. A replaced key gets `401` \"This key was replaced. Use the new one.\"\n\n**Errors:** `404` (no such key).","operationId":"key_rotate_v1_keys__key_id__rotate_post","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","title":"Key Id"},"description":"The key's id (`key_…`), from GET /v1/keys."}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/KeyRotate"},{"type":"null"}],"title":"Req"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreated"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/keys/{key_id}":{"delete":{"tags":["account"],"summary":"Revoke an API key","description":"The key stops working at once. **Errors:** `404` (no such key).","operationId":"key_revoke_v1_keys__key_id__delete","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","title":"Key Id"},"description":"The key's id (`key_…`), from GET /v1/keys."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Recorded"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/billing/checkout":{"post":{"tags":["account"],"summary":"Start the subscription","description":"A checkout link for the subscription: $20 a month per workspace, flat, one price. Unlimited decision models, decisions and retraining.\n\n**Errors:** `503` (billing isn't switched on yet), `409` (you already have a subscription: use `POST /v1/billing/portal`).","operationId":"billing_checkout_v1_billing_checkout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutUrl"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/billing":{"get":{"tags":["account"],"summary":"Your subscription","description":"Whether billing is on, the subscription status, the free trial (`trial`: `not_started` until your workspace trains its first model or makes its first decision, then `active` for 5 days, then `ended`), what works now (`can_train`, `can_decide`, `can_download`), the grace period after a failed payment, and the monthly price ($20, flat, however many decision models you have).\n\nAfter the trial with no active subscription, training, new options, automatic graduation and the hosted endpoint answer `402` (`message` says what to do). Everything else keeps working: the console, reports and versions, uploads, set-up, reviewing examples, billing, and downloading every version you have. The models are yours to keep.","operationId":"billing_status_v1_billing_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingStatus"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/billing/portal":{"post":{"tags":["account"],"summary":"Manage the subscription","description":"A link to the payment provider's portal: update the card, see invoices, or cancel.\n\n**Errors:** `503` (billing isn't switched on yet), `409` (no subscription yet: start one with `POST /v1/billing/checkout`).","operationId":"billing_portal_v1_billing_portal_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutUrl"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Service Unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/domains":{"get":{"tags":["domains"],"summary":"List decision models","description":"Every decision model in the workspace, each as a full `Domain`: its status, questions, actions, rules, state fields, serving version, safety bar, per-question status (trained or day-one), the review record and number of cases.","operationId":"domain_list_v1_domains_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainList"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["domains"],"summary":"Create a decision model","description":"The first step. Usually send just a `name` (lowercase letters, digits and dashes; it's what you pass as `model`) and a `description`, then set the decision up in plain words with `POST /v1/domains/{domain}/agent`. If you already know them, you can send the questions (Jev's format), the decision question, the rules and the state fields here instead.\n\n**After:** `POST /v1/domains/{domain}/agent` to describe it, or, if you sent everything, `GET /v1/domains/{domain}/examples`.\n\n**Errors:** `400` (an invalid name, question, rule or field, or `thresholds`, which isn't a setting: the safety bar sets itself), `409` (a domain with that name already exists).","operationId":"domain_create_v1_domains_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Domain"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}":{"get":{"tags":["domains"],"summary":"Get a decision model","description":"One decision model as a `Domain`. Use it to check where it stands: `status` (`draft`: nothing set up yet; `ready`: set up, not trained; `trained`: a version serves), `signoff.status`, `cases`, `serving_version` and `question_status`.\n\n**Errors:** `404` (no such domain).","operationId":"domain_get_v1_domains__domain__get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Domain"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["domains"],"summary":"Change a decision model","description":"Change any of `description`, `questions`, `decision_question`, `rules`, `state_schema` or `graduation` directly. Send only what changes. `{\"active\": false}` archives the domain (not served); `{\"active\": true}` brings it back. Most customers change the setup in plain words with `POST /v1/domains/{domain}/agent` instead.\n\n**After:** new questions or rules take effect for training from the next `POST /v1/domains/{domain}/train`; your rules apply to decisions straight away.\n\n**Errors:** `400` (invalid questions, rules or fields, or `thresholds`), `404` (no such domain).","operationId":"domain_patch_v1_domains__domain__patch","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainPatch"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Domain"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/agent":{"post":{"tags":["set-up"],"summary":"Describe your decision in plain words","description":"The set-up conversation. Tell the agent what you decide, which actions exist, which fields matter (numbers, categories, text), and which rules must never be broken. It sets up the domain's questions, actions, rules and state fields, and replies with a plain-words `summary` of the decision as it now stands, any `open_questions`, and the `next_step`.\n\nCall it again to answer open questions or refine the setup (\"card vs payment: these go to cards\"). Each message builds on the conversation so far, and a new setup gets new example cases.\n\n**Before:** `POST /v1/domains`. **After:** when `next_step` is `train`, `POST /v1/domains/{domain}/train` (past cases first, optional); while it is `describe`, answer the `open_questions`. The example cases are there to review any time (optional).\n\n**Errors:** `400` (an empty message, or a setup that isn't valid yet), `404` (no such domain).","operationId":"domain_agent_v1_domains__domain__agent_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentMessage"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentReply"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/examples":{"get":{"tags":["set-up"],"summary":"Example cases: how your model decides (optional review)","description":"About 20 example cases, each with the answer your setup gives per question and `why` (the rule or decision that applies, in plain words), plus the current review record. Reviewing them is optional and possible any time, before or after training. For a decision made on what a message says, each example shows a message and the answer it gets, covering every answer; while those messages are being prepared (about a minute after set-up), `status` is `preparing` and `examples` is empty: ask again shortly. If there are none for an answer, its examples say what kind of message it is instead (`described: true`).\n\n**Before:** `POST /v1/domains/{domain}/agent` (or `POST /v1/build`). **After (optional):** `POST /v1/domains/{domain}/signoff` to confirm or correct any of them.\n\n**Errors:** `400` (describe the decision first), `404` (no such domain).","operationId":"domain_examples_v1_domains__domain__examples_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExampleList"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/signoff":{"post":{"tags":["set-up"],"summary":"Confirm or correct example cases (optional)","description":"Optional, any time: nothing waits for it. For each example you review, `ok: true`, or `ok: false` with `correct` (the right answer per question) and an optional `note`. The review is kept as a record, and corrections are learned when your model is next retrained (for a model made with `POST /v1/build`, its instructions are made to give your answers too). `retrain: true` starts that retrain in the same call (`build_id` or `job_id` to follow).\n\n**Before:** `GET /v1/domains/{domain}/examples`. **After:** with `retrain: true`, follow the retrain; otherwise `POST /v1/domains/{domain}/train` when you like. If many corrections point at the same thing, say it once in plain words to the agent (or as a rule) instead.\n\n**Errors:** `400` (get the examples first (or they are still being prepared), an unknown example id, an unknown question, or `ok: false` without `correct`), `404` (no such domain).","operationId":"domain_signoff_v1_domains__domain__signoff_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignoffRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignoffResult"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/data":{"post":{"tags":["training"],"summary":"Upload past cases","description":"History: each past case and how it was resolved. No labelling: the outcome or category you already record is enough. The biggest lever for accuracy on decisions that read text.\n\nSend a `multipart/form-data` file (`.csv` or `.jsonl`) in a field named `file`, a `text/csv` or `application/x-ndjson` body, or JSON `{\"rows\": [...]}`. A row is `{\"state\": {...}, \"answers\": {\"<question>\": <value>}}`, or a flat row whose columns are state fields and question ids (a column named like a question holds how the case was resolved). Values: an option label (Choice), a level number (Score), true/false (Noul). Up to 250,000 cases per upload. Every row is checked: a row with a number field that isn't a number, an answer that isn't one of the options, or a question the domain doesn't have is skipped, counted in `rejected` and listed in `problems` with its row number and the reason (the first 20). NaN and infinity are kept as missing values.\n\nEvery upload is kept as one unit with an id (`upload_id`), so you can list it (`GET /v1/domains/{domain}/uploads`) and delete it later. `mode=add` (default) adds these cases to the ones already uploaded. `mode=replace` (a query parameter, or a form field next to `file`) swaps every uploaded case for these in one step, to retrain the same model on new cases: the earlier uploads are deleted permanently once the new rows are in, and `replaced` says how many. If no row is accepted, nothing is stored and nothing is removed. Corrected examples and reported outcomes stay. `file_name` (query) names a raw CSV or JSONL body in the upload list; a multipart upload uses the file's own name.\n\n**Before:** the domain's questions are set up (`POST /v1/domains/{domain}/agent`). **After:** `POST /v1/domains/{domain}/train`.\n\n**Errors:** `400` (an empty or unreadable file, wrong JSON shape, too many rows, an unknown `mode`, or no questions set up yet), `404` (no such domain), `409` (`mode=replace` while a new version of the domain is being made: wait for the job), `413` (over 50 MB: split it).","operationId":"domain_upload_v1_domains__domain__data_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."},{"name":"mode","in":"query","required":false,"schema":{"anyOf":[{"enum":["add","replace"],"type":"string"},{"type":"null"}],"title":"Mode"},"description":"`add` (default): these cases join the uploaded ones. `replace`: they take the place of every uploaded case, in one step."},{"name":"file_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Name"},"description":"The file's name, shown in the upload list (for a raw CSV or JSONL body)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadResult"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"CSV or JSONL: one past case per row."}},"required":["file"]}},"application/json":{"schema":{"$ref":"#/components/schemas/DataRows"}},"application/x-ndjson":{"schema":{"type":"string"},"example":"{\"state\": {\"message\": \"Refund my order please\", \"amount\": 40, \"tier\": \"pro\"}, \"answers\": {\"action\": \"approve\"}}\n{\"message\": \"I was charged 900 twice\", \"amount\": 900, \"tier\": \"enterprise\", \"action\": \"escalate\"}\n"},"text/csv":{"schema":{"type":"string"},"example":"message,amount,tier,fraud_flag,action\n\"Refund my order please\",40,pro,0,approve\n\"I was charged 900 twice\",900,enterprise,0,escalate\n"}},"required":true}},"get":{"tags":["training"],"summary":"How many cases the domain has","description":"Cases with a known answer: in total, per question, from uploads (`from_signoff` of them are examples you corrected) and from reported outcomes. Check it after an upload, or before training.","operationId":"domain_data_v1_domains__domain__data_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataSummary"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["training"],"summary":"Delete all uploaded cases","description":"Deletes every uploaded case of the domain permanently, all uploads at once. It can't happen by accident: send `confirm=<the domain's name>`.\n\n- By default only uploaded cases go. Examples you corrected stay, and so do reported outcomes and unsure-queue answers.\n- `signoff=true` also deletes the examples you corrected. The review record (who reviewed, when, which examples) always stays.\n- `outcomes=true` also deletes the hosted decisions the next version would learn from: those with a reported outcome or an unsure-queue answer, and those our hosted backup answered.\n- `starter=true` also deletes the starter cases (and keeps them off for this model). Otherwise they stay: they help a question that reads text until your own cases take over.\n- Versions already trained are kept: they're yours, and still download and serve.\n\nThen upload new cases and `POST /v1/domains/{domain}/train` for the next version of the same model. To swap uploads in one step instead, upload with `mode=replace`.\n\n**Errors:** `400` (`confirm` missing or not the domain's name), `404` (no such domain), `409` (a new version of the domain is being made: wait for the job, then try again).","operationId":"domain_data_clear_v1_domains__domain__data_delete","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."},{"name":"confirm","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Confirm"},"description":"The domain's name, to confirm the deletion."},{"name":"signoff","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Signoff"},"description":"true: also delete the examples you corrected (default false: they stay)."},{"name":"outcomes","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Outcomes"},"description":"true: also delete the hosted decisions the next version would learn from (reported outcomes, unsure-queue answers, backup answers). Default false: they stay."},{"name":"starter","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Starter"},"description":"true: also delete the starter cases, and keep them off for this model (default false: they stay, and step aside on their own as your cases arrive)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataRemoved"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/uploads":{"get":{"tags":["training"],"summary":"List the uploads","description":"Every upload of past cases, newest first: its id, when, the file's name, how many of its cases the domain has, and how many rows were set aside. Each review that corrected examples is listed too (`source: \"signoff\"`). Cases uploaded before uploads had ids are one group with id `earlier` (earlier corrected examples: `earlier-signoff`). `starter_cases` counts the starter cases of a question that reads text (not an upload: they help until your own cases take over).\n\n**After:** `DELETE /v1/domains/{domain}/uploads/{upload_id}` to remove one, `DELETE /v1/domains/{domain}/data?confirm=<name>` to remove them all, or `POST /v1/domains/{domain}/data?mode=replace` to swap them for a new file.\n\n**Errors:** `404` (no such domain).","operationId":"domain_uploads_v1_domains__domain__uploads_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadList"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/uploads/{upload_id}":{"delete":{"tags":["training"],"summary":"Delete one upload","description":"Deletes one upload's cases permanently (a hard delete, for good), including `earlier` or a review's corrected examples when you name them. `starter` as the id removes the starter cases (and keeps them off for this model). Nothing else changes: other uploads, reported outcomes and the review record stay, and versions already trained are kept (they're yours, and still download and serve). The next `POST /v1/domains/{domain}/train` makes the next version of the same model from the cases left; its report says how many earlier cases were removed.\n\n**Errors:** `404` (no such domain or upload), `409` (a new version of the domain is being made: wait for the job, then try again).","operationId":"domain_upload_delete_v1_domains__domain__uploads__upload_id__delete","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."},{"name":"upload_id","in":"path","required":true,"schema":{"type":"string","title":"Upload Id"},"description":"The upload's id (`upl_…`), from GET /v1/domains/{domain}/uploads, or `earlier` for cases uploaded before uploads had ids (`earlier-signoff` for earlier corrected examples), or `starter` for the starter cases (they then stay off for this model)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataRemoved"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/train":{"post":{"tags":["training"],"summary":"Train a new version","description":"Makes a new version on our servers, usually in about a minute, and returns a `Job` with the training report. The body is optional.\n\nA model made with `POST /v1/build` retrains as a targeted build: it adds situations where the current version disagrees with your instructions and rules, and more around what it confuses (and the look-alikes of what your hard rules depend on), plus your new cases and the decisions you marked wrong. The `Job` then has a `build_id` and comes back at once (it doesn't wait, whatever `wait` says): `GET /v1/build/{build_id}` shows what it added and, once checked, the before and after for those areas (`retrain`).\n\n- `wait: true` (default) waits for the new version (up to about 10 minutes); `wait: false` returns at once with `status: \"queued\"`: poll `GET /v1/jobs/{job_id}`.\n- `promote: \"auto\"` (default) puts the new version in service when the report recommends it (it is at least as accurate as the serving version on the same held-back cases); `always` or `never` override that.\n- `questions` trains only those questions.\n\nIt always learns from the cases the domain has now: after you replace or delete uploads, it makes the next version of the same model (`@2`, `@3`, ...) from the current cases only, and the report's `cases` says how many earlier cases were removed since the last version. The comparison with the serving version uses the current held-back cases with their current answers, so new cases that fix a bad habit can pass it.\n\nA question that reads text (a category only the message tells, like a ticket's topic) can start with a **starter model** when it has few of your own cases: ready to use at once, with `measured_on: \"starter_cases\"` and the report's `starter` section saying so. It learns your wording as you upload past cases or report outcomes, and real accuracy (on your own held-back cases) appears once there are enough of them. Nothing to set.\n\n**Before:** the decision is set up (`POST /v1/domains/{domain}/agent`) and, optionally, past cases are uploaded (`POST /v1/domains/{domain}/data`); reviewing the examples is optional. A question is trained once it has enough past cases with an answer (the report's `note` says how many more it needs); until then your day-one backend keeps answering it and the new version is kept but not served. **After:** read `report` (or `GET /v1/domains/{domain}/versions/{version}/report`); if it wasn't promoted automatically, `POST /v1/domains/{domain}/promote`; then `POST /v1/decide`.\n\n**Errors:** `400` (no questions set up yet, an unknown question, or a setting other than `questions`, `promote` and `wait`: the rest is chosen for you), `402` (the free trial has ended and there's no active subscription: subscribe to keep improving your models; the models you already have are yours to download), `404` (no such domain). A job that fails has `status: \"failed\"` and a `message`.","operationId":"domain_train_v1_domains__domain__train_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/TrainRequest"},{"type":"null"}],"title":"Req"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/options":{"post":{"tags":["training"],"summary":"Add an option or an action","description":"Adds an option to a Choice question (an action, when it's the decision question) and trains a new version, usually in about 30 seconds, with a before/after report. The other answers stay as they were.\n\nSay when the new option is right in plain words (`when`), and, for an action, when it must never be chosen (`never_when`, which adds a rule) and which `allow_only` rules should also allow it (`also_allowed_under`). `wait` and `promote` work as for training.\n\n**Before:** a trained domain, usually after the report suggests it (`improve` item `add_option`). **After:** read `report.before_after`; promote if it wasn't promoted automatically.\n\n**Errors:** `400` (not a Choice question, or `when` couldn't be read), `402` (the free trial has ended and there's no active subscription), `409` (it's already an option), `404` (no such domain).","operationId":"domain_option_v1_domains__domain__options_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OptionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/build":{"post":{"tags":["build"],"summary":"Build your own model from a Jev request","description":"Send exactly what you send Jev: one real example `state` (a text or the JSON object your program sends) and your `questions` (choice, noul or score, with instructions and criteria), plus optional `rules` in plain words, `name` and `description`. A pasted Jev request works as is (`model` is ignored). No past decisions or answers needed; a few examples of what you send Jev make it better: add 5-20 more real states in `examples` (states only, up to 50), and notes on what fields mean in `fields`, e.g. `{\"order.amount\": \"the refund asked for, in USD (0-5,000)\"}`. The build's `understood.field_notes` shows each note used.\n\nIt answers at once with a `Build`: what was read from your request (`understood`: the fields your model reads, the questions, the rules enforced and anything that couldn't be read as a rule) and a `build_id`. Then:\n1. `GET /v1/build/{build_id}` until `status` is `ready` (usually a few minutes). Nothing waits for you: it's prepared, trained and checked by itself.\n2. When `status` is `ready`, keep sending the same JSON to `POST /v1/decide` (or `/v1/systemone`) with `\"model\": \"<name>@latest\"`. It serves only if every question matches your instructions and rules in at least 95% of fresh situations (`quality`); otherwise `needs_attention`, with advice on what to change.\n3. Optional, any time after: review how it decides on about 20 examples (`GET /v1/domains/{domain}/examples`, also in the build's `examples`). Correct any with `POST /v1/domains/{domain}/signoff` and `\"retrain\": true`: your model is retrained to give your answers.\n\nBuilding again under the same `name` makes the next version of the same model. A build counts as training for your plan (the free trial starts with your first model).\n\n**With your history:** send your past cases in `history` (or upload them to the model and build again, or retrain). Your own cases become the main examples; rules found in them are proposed with their support and agreement (`found_rules`: optional, only confirmed ones are used; confirm or reject them with `POST /v1/build/{build_id}/found-rules`, then retrain); past cases that contradict a confirmed rule or a hard rule are flagged and not learned until you review them (`POST /v1/build/{build_id}/flagged`); and your model is also measured on held-back cases of yours (`quality.own_cases`).\n\n**Errors:** `400` (the example or the questions can't be read), `402` (subscribe to keep building), `409` (the name belongs to another model, or a build of it is still in progress), `429` (too many builds today).","operationId":"build_create_v1_build_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BuildRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Build"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/systemone/build":{"post":{"tags":["build"],"summary":"Build your own model (Jev path)","description":"The same as `POST /v1/build`, under the Jev-style path: paste your System One request body as is.","operationId":"build_alias_v1_systemone_build_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BuildRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Build"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/build/{build_id}":{"get":{"tags":["build"],"summary":"Follow a build","description":"Where a build is: `status`, each phase, what was read from your request, once checked the `quality` of your model on fresh situations (per question, with advice below the bar), the time it took and the model's size, and about 20 examples of how it decides (to review any time, optional).\n\n`ready`: your model serves as `<name>@latest`. `needs_attention`: it was built but doesn't match your instructions and rules often enough yet; follow the advice and build again. `failed`: see `errors`.","operationId":"build_get_v1_build__build_id__get","parameters":[{"name":"build_id","in":"path","required":true,"schema":{"type":"string","title":"Build Id"},"description":"The build's id (`bld_…`), from the answer to POST /v1/build."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Build"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/build":{"get":{"tags":["build"],"summary":"A model's latest build","description":"The latest build of a model made with `POST /v1/build` (its first build, a rebuild, a retrain or a rule change): the same `Build` as `GET /v1/build/{build_id}`. `404` for a model not made this way.","operationId":"build_latest_v1_domains__domain__build_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Build"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/build/{build_id}/found-rules":{"post":{"tags":["build"],"summary":"Confirm or reject rules found in your history","description":"Each rule in the build's `found_rules` comes with its support (your past cases it applies to), its agreement (how often they had its answer) and what confirming it changes. Only confirmed rules are used: your model follows them, and one marked `hard` (when `can_be_hard`) is also enforced on every decision like your own rules. Rules found in history copy past habits too, so check each one.\n\nOptional: a rule found is never used until you confirm it. Decide once the build has finished; your decisions apply from the next retrain (`POST /v1/domains/{domain}/train`).\n\n**Errors:** `400` (an unknown rule id, or `hard` on a rule that can't be hard), `409` (the build is busy).","operationId":"build_found_rules_v1_build__build_id__found_rules_post","parameters":[{"name":"build_id","in":"path","required":true,"schema":{"type":"string","title":"Build Id"},"description":"The build's id (`bld_…`), from the answer to POST /v1/build."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoundRulesRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Build"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/build/{build_id}/flagged":{"get":{"tags":["build"],"summary":"Past cases flagged against your rules","description":"Past cases that contradict a confirmed rule found in your history or one of your hard rules, with the rule, its answer, and your review so far. They're never learned silently: until you review them, they aren't learned at all. `status=pending` (default: all), `limit` (1-200) and `cursor` page through them.","operationId":"build_flagged_v1_build__build_id__flagged_get","parameters":[{"name":"build_id","in":"path","required":true,"schema":{"type":"string","title":"Build Id"},"description":"The build's id (`bld_…`), from the answer to POST /v1/build."},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"enum":["pending","reviewed"],"type":"string"},{"type":"null"}],"title":"Status"},"description":"Flagged past cases: `pending` (waiting for your review) or `reviewed`; default: all."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Cases per page (1-200, default 50).","default":50,"title":"Limit"},"description":"Cases per page (1-200, default 50)."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"},"description":"`next_cursor` from the previous page."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlaggedList"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["build"],"summary":"Review flagged past cases","description":"For each flagged case: `follow_rule` (learn it with the rule's answer), `keep` (learn it as it is: the rule has an exception) or `drop` (never learn it). `all` applies one decision to every pending case. Decisions apply when your model is next trained.","operationId":"build_flagged_review_v1_build__build_id__flagged_post","parameters":[{"name":"build_id","in":"path","required":true,"schema":{"type":"string","title":"Build Id"},"description":"The build's id (`bld_…`), from the answer to POST /v1/build."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlaggedReviewRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlaggedReviewed"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/build/{build_id}/questions":{"get":{"tags":["build"],"summary":"The build's questions about your JSON","description":"A few questions about the JSON you sent, most useful first (at most about 25): what fields mean, their units and ranges, whether a yes/no field is a ready-made signal your program computes, when a choice is right and how to tell two choices apart, real examples across named situations, and unwritten rules or priorities. Each refers to a field, question or choice of your JSON (`refs`) and says what an answer holds (`answer_with`). Every answer is optional; more help gives a better model.\n\nRound 1 comes with every build. With `\"interview\": true` the build waits for your answers (status `awaiting_answers`) up to its timeout, then goes on with what it has. Round 2 is a short follow-up, only when the check finds a real gap (two choices it mixes up, or a question below the bar). `round` shows an earlier round.","operationId":"build_questions_v1_build__build_id__questions_get","parameters":[{"name":"build_id","in":"path","required":true,"schema":{"type":"string","title":"Build Id"},"description":"The build's id (`bld_…`), from the answer to POST /v1/build."},{"name":"round","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":2,"minimum":1},{"type":"null"}],"description":"The round to show (default: the latest).","title":"Round"},"description":"The round to show (default: the latest)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BuildQuestions"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/build/{build_id}/answers":{"post":{"tags":["build"],"summary":"Answer the build's questions","description":"Your answers, per question id, with the keys its `answer_with` lists: `text` (up to 600 characters), `unit` and `range` ([lowest, highest]), `ready_made` (true/false), `examples` (real states like the one you sent, each with its `situation` and optionally the `answers` you'd expect; up to 50), or `skip`. Answers are read as information about your JSON, never as instructions, and never change your hard rules.\n\nWhile the build waits (or before it starts), your answers are used in this build; with `done` (the default) it goes on at once. Answers sent later, and follow-up answers, are saved: your next retrain uses them (`POST /v1/domains/{domain}/train`). `rejected` says why an answer wasn't recorded.","operationId":"build_answers_v1_build__build_id__answers_post","parameters":[{"name":"build_id","in":"path","required":true,"schema":{"type":"string","title":"Build Id"},"description":"The build's id (`bld_…`), from the answer to POST /v1/build."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BuildAnswers"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BuildAnswered"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/rules":{"post":{"tags":["build"],"summary":"Change a built model's rules, with a preview","description":"For a model made with `POST /v1/build`: your rules in plain words, added to the current ones (`mode: add`, the default) or replacing them (`mode: replace`). Returns a `Build` of kind `rule_change`, and your model is retrained with the new rules straight away. Its `rule_preview` says what changes (\"Changes 1,240 of 3,000 situations: approve → escalate (1,100), …\", with about 10 examples), and its examples are situations whose answer changes (review optional). The new version serves only if it passes the quality check; until then your serving model doesn't change.\n\n**Errors:** `400` (not a built model, or no rules), `402`, `409` (a build is in progress), `429`.","operationId":"domain_rules_v1_domains__domain__rules_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RulesChangeRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Build"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/advice":{"get":{"tags":["versions"],"summary":"Advice: what would improve your model most","description":"In plain words, most useful first: `retrain_to_sharpen` (where your model doesn't match your instructions and rules; a retrain adds cases there and shows before and after), `rule_may_be_wrong` (outcomes you reported, answered or marked wrong that contradict a rule), `answer_these` (the unsure cases, or least sure decisions, whose answers teach the next retrain most) and `upload_these`. Read-only: nothing is retrained for you. Also in `GET /v1/domains/{domain}/progress` as `advice`.","operationId":"domain_advice_v1_domains__domain__advice_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdviceList"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/jobs/{job_id}":{"get":{"tags":["training"],"summary":"Follow a training job","description":"A job's status (`queued`, `running`, `done`, `failed`), its place in the queue, the version it made, a message, and the report once it's done. Poll every few seconds after `wait: false`.\n\n**Errors:** `404` (no such job).","operationId":"job_get_v1_jobs__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"},"description":"The job's id (`job_…`), from the answer to train or options."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/versions":{"get":{"tags":["versions"],"summary":"Version history","description":"Every version, newest first: `serving` (what `@latest` answers with), `candidate` (made but not promoted) or `retired`, how it was made (`train`, `option`, `graduation`, `imported`, `multilingual`), accuracy per question, the recommendation and its size.\n\n**After:** `GET /v1/domains/{domain}/versions/{version}/report` for the details, `POST /v1/domains/{domain}/promote` to change what serves.","operationId":"domain_versions_v1_domains__domain__versions_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VersionList"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/progress":{"get":{"tags":["versions"],"summary":"Progress: what's waiting for the next retrain, and every version","description":"How the model is improving. `waiting`: the new cases since the latest version, by where they came from (uploaded past cases, reported outcomes, unsure cases you or our backup answered, cases synced from offline devices, examples you corrected), how many of the new outcomes differ from the answer it gave (`differed`), and one plain line (`statement`). `versions`, newest first: when each was made, how many of your cases it learned from, accuracy per question and the change against the version before (`comparison` says how: on the same held-back cases, each on its own, or not comparable because one was a starter model measured on starter example cases), and `live`: how often its answers matched the outcomes you reported, from `min_live_outcomes` (20) of them.\n\nRead-only. Nothing retrains, promotes or notifies on its own: you retrain when you choose.\n\n**After:** `POST /v1/domains/{domain}/train` to learn from the waiting cases.\n\n**Errors:** `404` (no such domain).","operationId":"domain_progress_v1_domains__domain__progress_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Progress"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/versions/{version}/report":{"get":{"tags":["versions"],"summary":"A version's training report","description":"What the version does, measured on your own held-back cases (never used for learning): accuracy per question against the previous version and your day-one backend, calibration, how many decisions each rule changed (violations are always 0), the never-worse check, a promote/keep recommendation, weak spots, the automatic safety bar, and `improve`: a ranked to-do list, each item with an estimated gain and the API call that acts on it (`fix`).\n\n**Before:** `POST /v1/domains/{domain}/train` (or read the report on its `Job`). **After:** act on `improve`, and promote with `POST /v1/domains/{domain}/promote` if you choose.\n\n**Errors:** `404` (no such version, or it has no report).","operationId":"domain_report_v1_domains__domain__versions__version__report_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."},{"name":"version","in":"path","required":true,"schema":{"type":"integer","title":"Version"},"description":"A version number (see GET /v1/domains/{domain}/versions)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/promote":{"post":{"tags":["versions"],"summary":"Choose which version serves (promote or roll back)","description":"Makes `version` the one `@latest` answers with. A roll-back is a promote of an older version. You can promote a `candidate` the never-worse check held back.\n\n**Errors:** `404` (no such version).","operationId":"domain_promote_v1_domains__domain__promote_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromoteRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromoteResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/models/{model}/download":{"get":{"tags":["versions"],"summary":"Download a finished model","description":"A zip for your own servers or offline use, named `<domain>@<version>.zip`, with three files: `model.json` (runtime settings), `heads.onnx` (the trained model, ONNX) and `rules.json` (your rules as a table of allowed and blocked actions). `model` is `<domain>@<version>` or `<domain>@latest`. Run it with `canonopy-runtime` (`pip install \"canonopy-runtime[text] @ https://canonopylabs.com/dl/canonopy_runtime-0.6.3-py3-none-any.whl\"`): same answer format, offline.\n\nAlways available, with or without a subscription: every version you have is yours to keep.\n\n**Errors:** `404` (no trained version yet, or no such version).","operationId":"model_download_v1_models__model__download_get","parameters":[{"name":"model","in":"path","required":true,"schema":{"type":"string","title":"Model"},"description":"`<domain>@<version>` or `<domain>@latest`, e.g. `refunds@latest`."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}},"application/zip":{}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/readers/{reader}/{file}":{"get":{"tags":["versions"],"summary":"The shared text reader for downloaded models","description":"A file of the shared text reader a downloaded model uses (`reader-en-1` or `reader-multi-1`, as its `model.json` names it). `canonopy-runtime` fetches it once and checks it; you only call this yourself to copy the files for fully offline use (`CANONOPY_READER_PATH`).\n\n**Errors:** `404` (unknown reader or file, or not available on this server).","operationId":"reader_file_v1_readers__reader___file__get","parameters":[{"name":"reader","in":"path","required":true,"schema":{"type":"string","title":"Reader"},"description":"The reader's id, from the downloaded model's `model.json`."},{"name":"file","in":"path","required":true,"schema":{"type":"string","title":"File"},"description":"The file's name, from the downloaded model's `model.json`."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}},"application/octet-stream":{}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/game":{"put":{"tags":["games"],"summary":"Connect your game (coming soon)","description":"Coming soon: not available in production (`503`). Your game's Python (`initial_state`, `legal_moves`, `step`), which runs on our servers in a sandbox and is never returned. Then train and download the bot.\n\n**Errors:** `400` (the code failed), `503` (not available yet).","operationId":"game_put_v1_domains__domain__game_put","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameSetup"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameInfo"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["games"],"summary":"Your connected game (coming soon)","description":"Whether a game is connected, its moves and training settings. Coming soon: not available in production.","operationId":"game_get_v1_domains__domain__game_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GameInfo"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/outcomes":{"post":{"tags":["outcomes"],"summary":"Report what really happened","description":"For a decision you asked for, report the real outcome per question (an option label, a level number or true/false), or just `action` for the decision question. It feeds the next version, and day-one questions switch to your own model once they have enough outcomes (`graduation` in the answer).\n\n**Before:** `POST /v1/decide` (keep its `id`). **After:** nothing; `POST /v1/domains/{domain}/train` when you want a new version sooner.\n\n**Errors:** `400` (an unknown question, an answer that isn't one of the options, or no answer), `404` (unknown decision id).","operationId":"outcome_v1_outcomes_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutcomeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Recorded"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/unsure":{"get":{"tags":["outcomes"],"summary":"The unsure queue","description":"Decisions held for a person and not yet answered: those whose route was `review` (below the safety bar after every check) or `ask` (your rules allow no action). Each has the case, the answers and the decision. `from_offline_device` marks cases a downloaded model decided offline and synced later. `open` is how many are waiting; `limit` (1-500, default 50) caps the list.\n\n**After:** `POST /v1/domains/{domain}/answers` for each one you resolve.","operationId":"unsure_v1_domains__domain__unsure_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"},"description":"How many held cases to return (1-500, default 50)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnsureList"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/answers":{"post":{"tags":["outcomes"],"summary":"Answer a case from the unsure queue","description":"The right answer per question for a held case. It leaves the queue, and the next version learns from it. A person, your own LLM or Jev can answer.\n\n**Before:** `GET /v1/domains/{domain}/unsure`.\n\n**Errors:** `400` (an unknown question or an invalid answer), `404` (unknown decision in this domain).","operationId":"unsure_answer_v1_domains__domain__answers_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewAnswer"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Recorded"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/offline-cases":{"post":{"tags":["outcomes"],"summary":"Sync cases a downloaded model saved offline","description":"A downloaded model that can't reach the hosted service saves the cases that needed a second look (a language it isn't strong in, or below its safety bar) in a small local file. This stores them in the domain, as your other decisions: the ones still held for a person join the unsure queue (marked `from_offline_device`), and you can report outcomes on any of them with the id the runtime gave it. Our hosted backup may answer held ones in the next seconds; what it can't answer waits for you. Answers feed the next version.\n\nYou don't usually call it yourself: `model.sync()` in the runtime, `canonopy-runtime sync` or `canonopy sync` send the file in batches and remove each case once it is accepted. Sending a case twice is harmless (`already_there`). A case that can't be stored is listed in `rejected` with the reason, and stays on the device.\n\n**Limits:** up to 100 cases and 10 MB per request, 30 requests a minute per workspace.\n\n**Before:** `GET /v1/models/{model}/download` and run it offline. **After:** `GET /v1/domains/{domain}/unsure`, `POST /v1/domains/{domain}/answers` or `POST /v1/outcomes`.\n\n**Errors:** `400` (no cases, or too many), `402` (after the free trial with no active subscription: the device keeps its cases; sync again once subscribed), `404` (unknown domain), `409` (the domain is archived), `413` (too large), `429` (too many requests).","operationId":"offline_cases_v1_domains__domain__offline_cases_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OfflineCases"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OfflineCasesResult"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Payment Required"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Request Entity Too Large"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/graduation":{"get":{"tags":["outcomes"],"summary":"Day-one questions and their progress","description":"Per question: `trained` (your own model answers) or `fallback` (your day-one backend answers), the outcomes it has, and how many more it needs before it switches to your own model (automatically when `auto` is true). `paused` says what to do when a question is ready but the free trial has ended with no active subscription.","operationId":"graduation_v1_domains__domain__graduation_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraduationStatus"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/spot-checks":{"get":{"tags":["trials"],"summary":"This week's spot-check card","description":"A few confident decisions (acted on) set aside at random for a person to check: 1% with `light` (the default), 2% with `thorough`, none with `off` (`PATCH /v1/settings`). Nothing is held up and nothing pops up: they wait on this one optional card, about 10 at a time (\"about 2 minutes\"). Answer each with `POST /v1/domains/{domain}/answers`; your answers are learned at your next retrain, and progress shows the spot-checked accuracy.","operationId":"spot_checks_card_v1_domains__domain__spot_checks_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpotCheckCard"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/shadow":{"get":{"tags":["trials"],"summary":"Shadow mode: where it stands","description":"Whether shadow mode is on, how many real requests were recorded, how often your model agreed with your current decisions, and how many disagreements wait for review.","operationId":"shadow_get_v1_domains__domain__shadow_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShadowStatus"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["trials"],"summary":"Turn shadow mode on or off","description":"Shadow mode runs your model beside Jev (or your current process) on real traffic without acting: send real requests with the decision you made (`POST /v1/domains/{domain}/shadow/cases`); your model decides each one silently, and the disagreements go to a short review list. Turning it off keeps what was recorded.","operationId":"shadow_put_v1_domains__domain__shadow_put","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShadowToggle"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShadowStatus"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/shadow/cases":{"post":{"tags":["trials"],"summary":"Send real requests with your current decision","description":"Up to 100 requests per call: each `state` as your program sends it, and `current`, the decision you made today per question (Jev's, your process's or a person's: `source`). Your model decides each one silently with its serving version and your hard rules; nothing is acted on and nothing is billed as a decision. Disagreements go to the review list.\n\n**Errors:** `409` (shadow mode is off, or the model has no trained version yet).","operationId":"shadow_cases_v1_domains__domain__shadow_cases_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShadowCasesRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShadowRecorded"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/shadow/review":{"get":{"tags":["trials"],"summary":"The shadow review list","description":"Disagreements waiting for a quick review, at most 20 at a time, your model's most confident ones first: the state, your current answer and your model's.","operationId":"shadow_review_list_v1_domains__domain__shadow_review_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"description":"How many (1-20, default 10).","default":10,"title":"Limit"},"description":"How many (1-20, default 10)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShadowReviewList"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["trials"],"summary":"Review shadow disagreements","description":"Per disagreement: `pick` (`model` or `current`: which is right), the right `answers`, or `skip`. Reviewed answers are learned at your next retrain, weighted as a person's answer: real outcomes teach most, then a person's review, then a confident Jev answer.","operationId":"shadow_review_v1_domains__domain__shadow_review_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShadowReviewRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShadowReviewed"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/play-results":{"post":{"tags":["trials"],"summary":"Send playtest results","description":"What `canonopy playtest` sends after your own program played episodes with your finished model on your machine: one object of numbers per episode, as your program printed it (score, deaths, stuck events, anything numeric). Optional `situations`: a sample of the states your game sent (`--keep-situations`); the next retrain of a model built from your JSON learns them (improve from play). The results show in the advice.","operationId":"play_results_v1_domains__domain__play_results_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlayResultsRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlayRecorded"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["trials"],"summary":"Playtest runs","description":"Your recent playtest runs, newest first, each summarised per number (mean, min, max).","operationId":"play_results_list_v1_domains__domain__play_results_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"description":"How many runs (1-50, default 10).","default":10,"title":"Limit"},"description":"How many runs (1-50, default 10)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlayRuns"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/decisions":{"get":{"tags":["decision-log"],"summary":"The decision log","description":"Every decision of a decision model, newest first: hosted decisions (`POST /v1/decide`) and cases synced from downloaded models. Each row has the time, a short summary of the case, the final answer, its confidence, `source`, `route`, the version, and whether an outcome was reported.\n\n**Filters** (all optional, combined): `since` and `until` (ISO 8601; `until` is exclusive; a date means midnight UTC), `source` (`trained`, `translated`, `fallback`, `rule`, `backup`, `local_fallback`: decisions where at least one answer came from it), `route` (`act`, `review`, `ask`), `answer` (`question:answer`, e.g. `answer=action:refund`; the final action for the decision question, a level for Score, `true` or `false` for Noul; repeat it to require several), `version`, `has_outcome` (true or false) and `q` (words to look for in the case's text, up to 100 characters, not case-sensitive; a decision id also works).\n\n**Pages:** `limit` (1-200, default 50); pass `next_cursor` as `cursor` for the next, older page.\n\nDecisions are kept for your workspace's retention (`retention_days`; 90 days unless you change it with `PATCH /v1/settings`). This works after the free trial ends too: it's your data.\n\n**After:** `GET /v1/domains/{domain}/decisions/{decision_id}` for one in full; `GET /v1/domains/{domain}/decisions/export` for a file.\n\n**Errors:** `400` (a filter that can't be read, an unknown question, a cursor from elsewhere), `404` (unknown domain).","operationId":"decisions_list_v1_domains__domain__decisions_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Since"},"description":"Only decisions from this time on (ISO 8601; a date means midnight UTC)."},{"name":"until","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Until"},"description":"Only decisions before this time (ISO 8601, exclusive; a date means midnight UTC)."},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"enum":["trained","translated","fallback","rule","backup","local_fallback"],"type":"string"},{"type":"null"}],"title":"Source"},"description":"Only decisions where at least one answer came from this source."},{"name":"route","in":"query","required":false,"schema":{"anyOf":[{"enum":["act","review","ask"],"type":"string"},{"type":"null"}],"title":"Route"},"description":"Only decisions with this route: `act`, `review` or `ask`."},{"name":"answer","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"`question:answer`, e.g. `action:refund` (repeat for several; all must hold).","title":"Answer"},"description":"`question:answer`, e.g. `action:refund` (repeat for several; all must hold)."},{"name":"version","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Only decisions made by this version.","title":"Version"},"description":"Only decisions made by this version."},{"name":"has_outcome","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Has Outcome"},"description":"true: only decisions with an outcome or an unsure-queue answer; false: only those without."},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"},"description":"Words to look for in the case's text (up to 100 characters, not case-sensitive), or a decision id."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Decisions per page (1-200, default 50).","default":50,"title":"Limit"},"description":"Decisions per page (1-200, default 50)."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"},"description":"`next_cursor` from the previous page."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecisionList"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["decision-log"],"summary":"Delete every decision before a date","description":"Deletes every decision of this decision model made before `before` (ISO 8601; a date means midnight UTC), permanently, including those with outcomes or unsure-queue answers: later versions no longer learn from them. Versions already trained are kept. Confirm with `confirm` = the decision model's name.\n\n**Errors:** `400` (no `before`, or `confirm` missing or not the name), `404` (unknown domain), `409` (a new version is being made: try again once it's done).","operationId":"decisions_delete_before_v1_domains__domain__decisions_delete","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."},{"name":"before","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Before"},"description":"Delete every decision made before this time (ISO 8601; a date means midnight UTC)."},{"name":"confirm","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Confirm"},"description":"The domain's name, to confirm the deletion."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecisionsDeleted"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/decisions/export":{"get":{"tags":["decision-log"],"summary":"Export the decision log (CSV or JSONL)","description":"The decisions that match the same filters as the list, newest first, as a file: `format=csv` (one row per decision: the final action, its confidence, each question's answer, confidence and source, the outcome, a summary and the case as JSON) or `format=jsonl` (one decision per line, in full, as `GET …/decisions/{decision_id}` returns it). Streamed; up to 100,000 decisions per export (narrow the time range for more). The response headers `X-Decisions-Exported` and `X-Decisions-Truncated` say how many and whether the cap was reached.\n\nWorks after the free trial ends too.\n\n**Errors:** `400` (an unknown format or a filter that can't be read), `404` (unknown domain).","operationId":"decisions_export_v1_domains__domain__decisions_export_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."},{"name":"format","in":"query","required":false,"schema":{"enum":["csv","jsonl"],"type":"string","default":"csv","title":"Format"},"description":"`csv` or `jsonl`."},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Since"},"description":"Only decisions from this time on (ISO 8601; a date means midnight UTC)."},{"name":"until","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Until"},"description":"Only decisions before this time (ISO 8601, exclusive; a date means midnight UTC)."},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"enum":["trained","translated","fallback","rule","backup","local_fallback"],"type":"string"},{"type":"null"}],"title":"Source"},"description":"Only decisions where at least one answer came from this source."},{"name":"route","in":"query","required":false,"schema":{"anyOf":[{"enum":["act","review","ask"],"type":"string"},{"type":"null"}],"title":"Route"},"description":"Only decisions with this route: `act`, `review` or `ask`."},{"name":"answer","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"`question:answer`, e.g. `action:refund` (repeat for several; all must hold).","title":"Answer"},"description":"`question:answer`, e.g. `action:refund` (repeat for several; all must hold)."},{"name":"version","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Only decisions made by this version.","title":"Version"},"description":"Only decisions made by this version."},{"name":"has_outcome","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Has Outcome"},"description":"true: only decisions with an outcome or an unsure-queue answer; false: only those without."},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"},"description":"Words to look for in the case's text (up to 100 characters, not case-sensitive), or a decision id."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}},"text/csv":{"schema":{"type":"string"}},"application/x-ndjson":{"schema":{"type":"string"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/decisions/{decision_id}":{"get":{"tags":["decision-log"],"summary":"One decision in full","description":"The case as it was sent, every answer with its probabilities, confidence, source and route, the final decision, your rules that blocked an option for it (`rules_applied`, with what each says), the version, the detected language, how long it took on our side (`latency_ms`), the outcome once reported, and `from_offline_device` for cases synced from a downloaded model. `decision_id` is the `id` that `POST /v1/decide` returned (for a synced case, also the id the runtime gave it).\n\n**Errors:** `404` (no such decision in this decision model: it may be past your retention, or deleted).","operationId":"decision_get_v1_domains__domain__decisions__decision_id__get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."},{"name":"decision_id","in":"path","required":true,"schema":{"type":"string","title":"Decision Id"},"description":"The decision's id (`dec_…`), as `POST /v1/decide` returned it."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecisionDetail"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["decision-log"],"summary":"Delete one decision","description":"Deletes the decision permanently: it leaves the log, the unsure queue and what the next version learns from. Versions already trained are kept.\n\n**Errors:** `404` (no such decision in this decision model), `409` (it has an outcome the next version would learn from, and a new version is being made: try again once it's done).","operationId":"decision_delete_v1_domains__domain__decisions__decision_id__delete","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."},{"name":"decision_id","in":"path","required":true,"schema":{"type":"string","title":"Decision Id"},"description":"The decision's id (`dec_…`), as `POST /v1/decide` returned it."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecisionsDeleted"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Conflict"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/decisions/{decision_id}/wrong":{"post":{"tags":["decision-log"],"summary":"Mark a decision wrong","description":"Say a decision was wrong and give the right answer (`answers`, or `action` for the decision question). It's recorded as the decision's outcome (shown as `marked_wrong` in the log) and your next retrain learns it. On a model made with `POST /v1/build`, the retrain also makes your instructions give the right answer there first, and `GET …/advice` points out a rule your corrections contradict.\n\n**Errors:** `400` (an unknown question or answer), `404`.","operationId":"decision_wrong_v1_domains__domain__decisions__decision_id__wrong_post","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."},{"name":"decision_id","in":"path","required":true,"schema":{"type":"string","title":"Decision Id"},"description":"The decision's id (`dec_…`), as `POST /v1/decide` returned it."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkWrongRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkedWrong"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/decisions/{decision_id}/wrong":{"post":{"tags":["decision-log"],"summary":"Mark a decision wrong (by its id alone)","description":"The same as `POST /v1/domains/{domain}/decisions/{decision_id}/wrong`, for when you only have the decision id `POST /v1/decide` returned.","operationId":"decision_wrong_any_v1_decisions__decision_id__wrong_post","parameters":[{"name":"decision_id","in":"path","required":true,"schema":{"type":"string","title":"Decision Id"},"description":"The decision's id (`dec_…`), as `POST /v1/decide` returned it."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkWrongRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkedWrong"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/settings":{"get":{"tags":["account"],"summary":"Workspace settings","description":"How long the decision log keeps decisions (`decision_retention`: `30_days`, `90_days`, `365_days` or `until_deleted`; 90 days unless you change it), and how many decisions are older than that now (deleted at the next daily clean-up).","operationId":"settings_get_v1_settings_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceSettings"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"tags":["account"],"summary":"Change workspace settings","description":"Set spot checks (`off`, `light` or `thorough`: how many confident decisions wait on the weekly card), or how long decisions are kept. Once a day, decisions older than that are deleted permanently in every decision model of the workspace, including those with outcomes or unsure-queue answers: later versions no longer learn from them. Versions already trained keep what they learned. `until_deleted` keeps them until you delete them (`DELETE /v1/domains/{domain}/decisions`).\n\n**Errors:** `400` (not one of the choices).","operationId":"settings_patch_v1_settings_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceSettingsPatch"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceSettings"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/domains/{domain}/fallback":{"get":{"tags":["day-one"],"summary":"The day-one backend","description":"Which backend answers questions your model hasn't learned yet: `typesafe` (Jev with your key), `openai` (any OpenAI-compatible endpoint), `local` (our built-in general model: no key, no cost) or `none`. Only the key's last 4 characters are shown.","operationId":"fallback_get_v1_domains__domain__fallback_get","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FallbackInfo"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["day-one"],"summary":"Set the day-one backend","description":"Choose the backend for questions your model hasn't learned yet, with its key (stored encrypted, used only for your day-one calls, never returned). Answers from it are marked `source: \"fallback\"`, and your rules still apply through `decision`.\n\n**Errors:** `400` (`openai` needs `base_url`; `typesafe` and `openai` need `api_key` unless one is already stored), `404` (no such domain).","operationId":"fallback_put_v1_domains__domain__fallback_put","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"},"description":"The decision model's name or id, e.g. `refunds`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FallbackConfig"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FallbackInfo"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Not Found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"Account":{"properties":{"org":{"$ref":"#/components/schemas/Org","description":"Your workspace."},"user":{"anyOf":[{"$ref":"#/components/schemas/User"},{"type":"null"}],"description":"The signed-in user (null when calling with an API key)."},"plan":{"$ref":"#/components/schemas/Plan","description":"Your plan."},"usage":{"$ref":"#/components/schemas/AccountUsage","description":"Decisions this month, active decision models and the monthly price."}},"type":"object","required":["org","plan","usage"],"title":"Account"},"AccountUsage":{"properties":{"decisions_this_month":{"type":"integer","title":"Decisions This Month","description":"Decisions asked for this calendar month (not billed)."},"active_domains":{"type":"integer","title":"Active Domains","description":"Decision models that are not archived. All of them are included in the flat price."},"monthly_price_usd":{"type":"number","title":"Monthly Price Usd","description":"Your monthly price in US dollars: $20, flat, however many decision models you have."},"builds":{"anyOf":[{"$ref":"#/components/schemas/BuildUsage"},{"type":"null"}],"description":"Builds used against your workspace's build limits."}},"type":"object","required":["decisions_this_month","active_domains","monthly_price_usd"],"title":"AccountUsage"},"Advice":{"properties":{"kind":{"type":"string","enum":["retrain_to_sharpen","rule_may_be_wrong","answer_these","upload_these","from_playtest","shadow_review","answer_questions"],"title":"Kind","description":"`retrain_to_sharpen` (your model doesn't match your rules somewhere: a retrain adds cases there), `rule_may_be_wrong` (outcomes you reported contradict a rule), `answer_these` (the cases your answers would teach it most), `upload_these` (past cases worth uploading), `from_playtest` (your last playtest), `shadow_review` (shadow-mode disagreements to review) or `answer_questions` (the build's follow-up questions)."},"title":{"type":"string","title":"Title","description":"A short heading."},"text":{"type":"string","title":"Text","description":"What we see and what to do, in plain words."},"action":{"type":"string","enum":["retrain","change_rules","answer","upload","review","none"],"title":"Action","description":"What to do: `retrain` (POST /v1/domains/{domain}/train), `change_rules` (POST /v1/domains/{domain}/rules, which previews the change), `answer` (the unsure queue, mark decisions wrong, or the build's questions), `upload`, `review` (the shadow review list) or `none` (for your information)."},"question":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Question","description":"The question it's about."},"agreement":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Agreement","description":"retrain_to_sharpen: the agreement there (0-1)."},"rule":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rule","description":"rule_may_be_wrong: the rule, in plain words."},"contradicted":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Contradicted","description":"rule_may_be_wrong: outcomes that contradict it."},"applied":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Applied","description":"rule_may_be_wrong: outcomes where it applied."},"decisions":{"items":{"$ref":"#/components/schemas/AdviceDecision"},"type":"array","title":"Decisions","description":"answer_these: the decisions to answer."}},"type":"object","required":["kind","title","text","action"],"title":"Advice","description":"One piece of advice, in plain words."},"AdviceDecision":{"properties":{"decision_id":{"type":"string","title":"Decision Id","description":"The decision (see the decision log)."},"summary":{"type":"string","title":"Summary","description":"A short line about the case.","default":""},"answer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer","description":"What your model answered."},"confidence":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Confidence","description":"How sure it was (0-1)."}},"type":"object","required":["decision_id"],"title":"AdviceDecision"},"AdviceList":{"properties":{"domain":{"type":"string","title":"Domain","description":"The model's name."},"items":{"items":{"$ref":"#/components/schemas/Advice"},"type":"array","title":"Items","description":"Advice, most useful first (empty: nothing to do right now)."},"statement":{"type":"string","title":"Statement","description":"One line, in plain words.","default":""}},"type":"object","required":["domain"],"title":"AdviceList"},"AgentMessage":{"properties":{"message":{"type":"string","maxLength":20000,"minLength":1,"title":"Message","description":"Plain words: what you decide, the actions, the fields that matter (and whether each is a number, a category or text), and the rules that must never be broken. Or an answer to the agent's open questions, or a change."}},"type":"object","required":["message"],"title":"AgentMessage","description":"A message to the set-up agent, in plain words.","examples":[{"message":"We handle refund requests. Actions: approve, escalate, decline. Fields: message (text), amount (number), tier (category: free, pro, enterprise), fraud_flag (yes/no). Never approve when amount is over 500. Always escalate when fraud_flag is true. Decline when tier is free and amount is over 100. Otherwise approve."},{"message":"Cases where the parcel never arrived and the amount is under 30 should be approved straight away."}]},"AgentReply":{"properties":{"reply":{"type":"string","title":"Reply","description":"The agent's answer, in plain words."},"build_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Build Id","description":"A model made with POST /v1/build: your message started a rule change, and your model is retrained with it. Follow GET /v1/build/{build_id}: its `rule_preview` says what your new rules change."},"summary":{"items":{"type":"string"},"type":"array","title":"Summary","description":"The decision as set up so far, in plain words."},"domain":{"$ref":"#/components/schemas/Domain","description":"The domain as it now stands."},"open_questions":{"items":{"type":"string"},"type":"array","title":"Open Questions","description":"What the agent still needs to know. Answer them in the next message."},"next_step":{"type":"string","enum":["describe","review_examples","upload_history","train","follow_build"],"title":"Next Step","description":"`describe` (answer the open questions or say more), `train` (train it now; uploading past cases first is optional, and so is reviewing the examples, any time), `follow_build` (a rule change is retraining your model: follow GET /v1/build/{build_id}), or, from older set-ups, `review_examples` or `upload_history`, both optional."}},"type":"object","required":["reply","summary","domain","next_step"],"title":"AgentReply"},"ApiKeyCreated":{"properties":{"id":{"type":"string","title":"Id","description":"Key id (`key_…`): use it to rotate or revoke the key."},"name":{"type":"string","title":"Name","description":"The key's name."},"prefix":{"type":"string","title":"Prefix","description":"The first characters of the key, to recognise it."},"created_at":{"type":"string","title":"Created At","description":"When it was created (ISO 8601)."},"last_used_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Used At","description":"When it was last used (ISO 8601), or null."},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At","description":"Set when the key was rotated with a grace period."},"key":{"type":"string","title":"Key","description":"Shown once."}},"type":"object","required":["id","name","prefix","created_at","key"],"title":"ApiKeyCreated"},"ApiKeyInfo":{"properties":{"id":{"type":"string","title":"Id","description":"Key id (`key_…`): use it to rotate or revoke the key."},"name":{"type":"string","title":"Name","description":"The key's name."},"prefix":{"type":"string","title":"Prefix","description":"The first characters of the key, to recognise it."},"created_at":{"type":"string","title":"Created At","description":"When it was created (ISO 8601)."},"last_used_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Used At","description":"When it was last used (ISO 8601), or null."},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At","description":"Set when the key was rotated with a grace period."}},"type":"object","required":["id","name","prefix","created_at"],"title":"ApiKeyInfo"},"BeforeAfter":{"properties":{"question":{"type":"string","title":"Question","description":"The question the option was added to."},"option":{"type":"string","title":"Option","description":"The new option."},"before":{"additionalProperties":true,"type":"object","title":"Before","description":"The serving version: `accuracy`, `cases`, `unchanged_cases_accuracy`."},"after":{"additionalProperties":true,"type":"object","title":"After","description":"The new version: the same, plus `option_recall` (how often it finds the new option) and `option_cases`."},"took":{"type":"string","title":"Took","description":"How long it took, roughly (\"under a minute\", \"about 2 minutes\")."}},"type":"object","required":["question","option","before","after","took"],"title":"BeforeAfter"},"Benchmark":{"properties":{"title":{"type":"string","title":"Title","description":"The comparison's title."},"dataset":{"type":"string","title":"Dataset","description":"What it was measured on."},"rows":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Rows","description":"One row per system: accuracy, calibration error, latency, cost, where it runs."},"notes":{"items":{"type":"string"},"type":"array","title":"Notes","description":"How to read it."}},"type":"object","required":["title","dataset","rows","notes"],"title":"Benchmark"},"BillingStatus":{"properties":{"enabled":{"type":"boolean","title":"Enabled","description":"false until billing is switched on (then nothing is gated)."},"status":{"type":"string","title":"Status","description":"none (no subscription yet), active, trialing, past_due, unpaid, canceled."},"can_decide":{"type":"boolean","title":"Can Decide","description":"Whether the hosted endpoint serves your decisions now."},"can_train":{"type":"boolean","title":"Can Train","description":"Whether training, new options and automatic graduation run now."},"can_download":{"type":"boolean","title":"Can Download","description":"Always true: every version you have is yours to download."},"grace_until":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Grace Until","description":"After a failed payment, everything keeps working until then."},"current_period_end":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Current Period End","description":"When the current billing period ends (ISO 8601)."},"has_subscription":{"type":"boolean","title":"Has Subscription","description":"Whether a subscription exists."},"trial":{"$ref":"#/components/schemas/TrialStatus","description":"The 5-day free trial, counted from your first trained model or first decision or first decision."},"trial_ends_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Trial Ends At","description":"When the free trial ends (ISO 8601), once started."},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message","description":"What to do, when training and the hosted endpoint are paused."},"active_domains":{"type":"integer","title":"Active Domains","description":"Decision models that are not archived. All of them are included in the flat price."},"monthly_price_usd":{"type":"number","title":"Monthly Price Usd","description":"Your monthly price in US dollars: $20, flat, however many decision models you have."}},"type":"object","required":["enabled","status","can_decide","can_train","can_download","has_subscription","trial","active_domains","monthly_price_usd"],"title":"BillingStatus"},"Build":{"properties":{"build_id":{"type":"string","title":"Build Id","description":"The build (`bld_…`): poll GET /v1/build/{build_id}."},"kind":{"type":"string","enum":["build","retrain","rule_change"],"title":"Kind","description":"`build` (POST /v1/build), `retrain` (POST /v1/domains/{domain}/train on a built model: a targeted retrain) or `rule_change` (POST /v1/domains/{domain}/rules: new rules, retrained with a preview of what they change).","default":"build"},"previous_build":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Previous Build","description":"For a retrain or a rule change: the build it starts from."},"domain":{"type":"string","title":"Domain","description":"The model's name. Paths that take `{domain}` accept it."},"model":{"type":"string","title":"Model","description":"What to pass as `model` once it's ready (`<name>@latest`)."},"status":{"type":"string","enum":["awaiting_answers","queued","building","awaiting_sign_off","training","checking","ready","needs_attention","failed"],"title":"Status","description":"`awaiting_answers` (with `interview`: a few questions wait for your answers, up to the timeout), `queued`, `building` (preparing), `training`, `checking`, `ready` (serving), `needs_attention` (built, not serving: see `quality`) or `failed` (see `errors`). Nothing waits for you to review examples (`awaiting_sign_off` only shows on builds made before that became optional; they move on by themselves)."},"phase":{"type":"string","title":"Phase","description":"The current phase (see `phases`)."},"phases":{"items":{"$ref":"#/components/schemas/BuildPhase"},"type":"array","title":"Phases","description":"Every phase and where it is."},"message":{"type":"string","title":"Message","description":"Where it is, in plain words.","default":""},"next_step":{"type":"string","title":"Next Step","description":"What to do next, in plain words.","default":""},"understood":{"$ref":"#/components/schemas/BuildUnderstood","description":"What was read from your request: the fields, the questions and the rules."},"examples":{"items":{"$ref":"#/components/schemas/Example"},"type":"array","title":"Examples","description":"Once `ready` (or `needs_attention`): about 20 examples of how your model decides, to review any time (optional; the same as GET /v1/domains/{domain}/examples)."},"quality":{"anyOf":[{"$ref":"#/components/schemas/BuildQuality"},{"type":"null"}],"description":"Once checked: how well your model matches your instructions and rules on fresh situations."},"stats":{"$ref":"#/components/schemas/BuildStats","description":"Time, sizes and counts."},"spend":{"anyOf":[{"$ref":"#/components/schemas/BuildSpend"},{"type":"null"}],"description":"What building it cost us (null when not shown)."},"errors":{"items":{"type":"string"},"type":"array","title":"Errors","description":"What went wrong and what to do, in plain words."},"version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version","description":"The version it made, once trained."},"created_at":{"type":"string","title":"Created At","description":"ISO 8601."},"updated_at":{"type":"string","title":"Updated At","description":"ISO 8601."},"finished_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Finished At","description":"ISO 8601, once ready, needing attention or failed."},"notes":{"items":{"type":"string"},"type":"array","title":"Notes","description":"Anything else worth knowing, in plain words."},"history":{"anyOf":[{"$ref":"#/components/schemas/BuildHistory"},{"type":"null"}],"description":"With your past cases: how they were used (null without history)."},"found_rules":{"items":{"$ref":"#/components/schemas/FoundRule"},"type":"array","title":"Found Rules","description":"Rules found in your history, with their support and agreement. Confirming them is optional (POST /v1/build/{build_id}/found-rules, once the build has finished); only confirmed ones are used, from your next retrain."},"flagged":{"$ref":"#/components/schemas/BuildFlagged","description":"Past cases that contradict a confirmed rule or a hard rule: not learned until you review them (POST /v1/build/{build_id}/flagged)."},"retrain":{"anyOf":[{"$ref":"#/components/schemas/BuildRetrain"},{"type":"null"}],"description":"For a retrain: what it added, and before and after."},"rule_preview":{"anyOf":[{"$ref":"#/components/schemas/RulePreview"},{"type":"null"}],"description":"For a rule change: what your new rules change (your model is retrained with them straight away)."},"questions":{"anyOf":[{"$ref":"#/components/schemas/BuildQuestionsSummary"},{"type":"null"}],"description":"The build's questions about your JSON (the latest round): see `GET /v1/build/{build_id}/questions`. Null when it has none."}},"type":"object","required":["build_id","domain","model","status","phase","created_at","updated_at"],"title":"Build","description":"A build: your own model, made from the same JSON you send Jev."},"BuildAnswer":{"properties":{"id":{"type":"string","maxLength":8,"title":"Id","description":"The question's id."},"text":{"anyOf":[{"type":"string","maxLength":600},{"type":"null"}],"title":"Text","description":"Your answer in words (up to 600 characters)."},"unit":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Unit","description":"`field_units`: the unit."},"range":{"anyOf":[{"items":{"type":"number"},"type":"array","maxItems":2,"minItems":2},{"type":"null"}],"title":"Range","description":"`field_units`: [lowest, highest] real values."},"ready_made":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Ready Made","description":"`ready_signal`: true when your program computes it."},"examples":{"anyOf":[{"items":{"$ref":"#/components/schemas/BuildExampleAnswer"},"type":"array","maxItems":50},{"type":"null"}],"title":"Examples","description":"`examples`: real states, each with its situation and optionally the answer you'd expect."},"skip":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Skip","description":"true: skip this question."}},"additionalProperties":false,"type":"object","required":["id"],"title":"BuildAnswer","description":"One answer. Only the keys its question's `answer_with` lists; everything is optional."},"BuildAnswered":{"properties":{"build_id":{"type":"string","title":"Build Id","description":"The build."},"round":{"type":"integer","title":"Round","description":"The round answered."},"accepted":{"items":{"type":"string"},"type":"array","title":"Accepted","description":"The ids recorded."},"rejected":{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array","title":"Rejected","description":"{id, why} for answers not recorded."},"used":{"type":"string","enum":["this_build","next_retrain","none"],"title":"Used","description":"`this_build` (your model is made with them), `next_retrain` (they came after the build started: your next retrain uses them) or `none`."},"status":{"type":"string","title":"Status","description":"The round's status now."},"message":{"type":"string","title":"Message","description":"What happened, in plain words.","default":""}},"type":"object","required":["build_id","round","used","status"],"title":"BuildAnswered"},"BuildAnswers":{"properties":{"answers":{"items":{"$ref":"#/components/schemas/BuildAnswer"},"type":"array","maxItems":60,"title":"Answers","description":"Your answers (any number of the questions)."},"round":{"anyOf":[{"type":"integer","maximum":2.0,"minimum":1.0},{"type":"null"}],"title":"Round","description":"The round they answer (default: the latest)."},"done":{"type":"boolean","title":"Done","description":"true (the default): that's all, the build goes on now. false: more answers follow; it waits up to its timeout.","default":true}},"additionalProperties":false,"type":"object","required":["answers"],"title":"BuildAnswers","examples":[{"answers":[{"id":"q02","text":"Escalate when the customer is upset or the amount is unusual; decline only for a clear policy reason."},{"id":"q05","range":[0,5000],"unit":"dollars"},{"id":"q07","skip":true}],"done":true}]},"BuildComparison":{"properties":{"against_version":{"type":"integer","title":"Against Version","description":"The serving version it was compared with."},"measured_on":{"type":"string","const":"your_cases","title":"Measured On","description":"Always your own held-back cases: neither version learned them.","default":"your_cases"},"cases":{"type":"integer","title":"Cases","description":"Your held-back cases compared.","default":0},"passed":{"type":"boolean","title":"Passed","description":"true: not worse on any question; false: the serving version keeps serving."},"questions":{"items":{"$ref":"#/components/schemas/BuildComparisonQuestion"},"type":"array","title":"Questions","description":"Per question."},"statement":{"type":"string","title":"Statement","description":"The same, in plain words.","default":""}},"type":"object","required":["against_version","passed"],"title":"BuildComparison"},"BuildComparisonQuestion":{"properties":{"question":{"type":"string","title":"Question","description":"The question id."},"previous":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Previous","description":"The serving version's agreement with your answers (0-1)."},"new":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"New","description":"This version's, on the same cases (0-1)."},"cases":{"type":"integer","title":"Cases","description":"Your held-back cases compared.","default":0},"ok":{"type":"boolean","title":"Ok","description":"false: this version is worse here by more than the tolerance.","default":true}},"type":"object","required":["question"],"title":"BuildComparisonQuestion"},"BuildExampleAnswer":{"properties":{"situation":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Situation","description":"The situation it shows, in a few words."},"state":{"title":"State","description":"A real state, like the one you sent (at most 20 KB)."},"answers":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Answers","description":"Optional: the answer you'd expect, per question."}},"additionalProperties":false,"type":"object","required":["state"],"title":"BuildExampleAnswer"},"BuildField":{"properties":{"name":{"type":"string","title":"Name","description":"The field's name (used in rules and in the domain's state_schema)."},"path":{"type":"string","title":"Path","description":"Where it is in `state` (`$`: the whole state is the text)."},"type":{"type":"string","enum":["number","yes/no","category","text"],"title":"Type","description":"How it's read."}},"type":"object","required":["name","path","type"],"title":"BuildField"},"BuildFieldNote":{"properties":{"path":{"type":"string","title":"Path","description":"The field's path (list positions written as [], e.g. \"items[].price\")."},"meaning":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Meaning","description":"What it means, as you wrote it."},"unit":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Unit","description":"Its unit."},"range":{"anyOf":[{"items":{"type":"number"},"type":"array"},{"type":"null"}],"title":"Range","description":"[lowest, highest], from your note."}},"type":"object","required":["path"],"title":"BuildFieldNote"},"BuildFieldNoteMissed":{"properties":{"key":{"type":"string","title":"Key","description":"The key you sent."},"why":{"type":"string","title":"Why","description":"Why it wasn't used, in plain words."}},"type":"object","required":["key","why"],"title":"BuildFieldNoteMissed"},"BuildFlagged":{"properties":{"total":{"type":"integer","title":"Total","description":"Past cases flagged.","default":0},"pending":{"type":"integer","title":"Pending","description":"Waiting for your review.","default":0},"items":{"items":{"$ref":"#/components/schemas/FlaggedRow"},"type":"array","title":"Items","description":"The first 20 (pending ones first). All of them: GET /v1/build/{build_id}/flagged."}},"type":"object","title":"BuildFlagged"},"BuildGap":{"properties":{"question":{"type":"string","title":"Question","description":"The question."},"answer":{"type":"string","title":"Answer","description":"An answer your history rarely has."},"your_cases":{"type":"integer","title":"Your Cases","description":"Your past cases with that answer.","default":0},"situations":{"type":"integer","title":"Situations","description":"Situations with that answer your model learns from.","default":0}},"type":"object","required":["question","answer"],"title":"BuildGap"},"BuildHistory":{"properties":{"cases":{"type":"integer","title":"Cases","description":"Your past cases with an answer.","default":0},"learned_from":{"type":"integer","title":"Learned From","description":"Of those, the ones your model learns from (not held back, and not flagged waiting for your review).","default":0},"held_back":{"type":"integer","title":"Held Back","description":"Held back to measure your model on your own cases (never learned from).","default":0},"variations":{"type":"integer","title":"Variations","description":"Variations of your messages (typos, slang, other wording) it also learns from.","default":0},"flagged":{"type":"integer","title":"Flagged","description":"Past cases that contradict a confirmed rule or a hard rule.","default":0},"pending":{"type":"integer","title":"Pending","description":"Of those, the ones waiting for your review (not learned until then).","default":0},"gaps":{"items":{"$ref":"#/components/schemas/BuildGap"},"type":"array","title":"Gaps","description":"Answers your history rarely has, filled with situations."},"statement":{"type":"string","title":"Statement","description":"The same, in plain words.","default":""}},"type":"object","title":"BuildHistory","description":"How your past cases were used."},"BuildHistoryAccepted":{"properties":{"accepted":{"type":"integer","title":"Accepted","description":"Past cases stored (as one upload of this model).","default":0},"rejected":{"type":"integer","title":"Rejected","description":"Past cases that couldn't be used.","default":0},"problems":{"items":{"$ref":"#/components/schemas/UploadProblem"},"type":"array","title":"Problems","description":"Why, for the first few."}},"type":"object","title":"BuildHistoryAccepted"},"BuildNotRead":{"properties":{"path":{"type":"string","title":"Path","description":"The part of the example that isn't read."},"why":{"type":"string","title":"Why","description":"Why, in plain words."}},"type":"object","required":["path","why"],"title":"BuildNotRead"},"BuildOwnCases":{"properties":{"cases":{"type":"integer","title":"Cases","description":"Your past cases held back to measure your model (never learned from).","default":0},"questions":{"items":{"$ref":"#/components/schemas/BuildOwnCasesQuestion"},"type":"array","title":"Questions","description":"Per question."},"statement":{"type":"string","title":"Statement","description":"The same, in plain words: \"Measured on your own cases: …\".","default":""}},"type":"object","title":"BuildOwnCases"},"BuildOwnCasesQuestion":{"properties":{"question":{"type":"string","title":"Question","description":"The question id."},"agreement":{"type":"number","title":"Agreement","description":"How often your model gave the answer your past case has (0-1)."},"cases":{"type":"integer","title":"Cases","description":"Held-back cases with an answer to it.","default":0}},"type":"object","required":["question","agreement"],"title":"BuildOwnCasesQuestion"},"BuildPhase":{"properties":{"phase":{"type":"string","enum":["understanding","questions","preparing","sign_off","training","checking"],"title":"Phase","description":"`understanding` (reading your example and questions), `questions` (with `interview`: waiting for your answers to a few questions), `preparing` (examples of situations for your questions), `training` (your model is being built) or `checking` (your model against your instructions and rules on fresh situations). Nothing waits for you to review examples (`sign_off` only shows on builds made before that became optional)."},"label":{"type":"string","title":"Label","description":"The same, in plain words."},"status":{"type":"string","enum":["pending","queued","running","waiting","done","attention","failed"],"title":"Status","description":"Where this phase is. `waiting`: on your answers (with `interview`, up to its timeout)."}},"type":"object","required":["phase","label","status"],"title":"BuildPhase"},"BuildQuality":{"properties":{"bar":{"type":"number","title":"Bar","description":"The agreement every question needs before your model serves (0.95)."},"passed":{"type":"boolean","title":"Passed","description":"true: every question is at or above the bar, and the model serves."},"situations":{"type":"integer","title":"Situations","description":"Fresh situations it was checked on (never used for learning).","default":0},"questions":{"items":{"$ref":"#/components/schemas/BuildQualityQuestion"},"type":"array","title":"Questions","description":"Per question."},"statement":{"type":"string","title":"Statement","description":"The same, in plain words."},"own_cases":{"anyOf":[{"$ref":"#/components/schemas/BuildOwnCases"},{"type":"null"}],"description":"With your history: your model measured on your own held-back cases (the honest real-world number). Null without enough past cases (40 or more)."},"measured_on":{"anyOf":[{"type":"string","enum":["situations","your_cases"]},{"type":"null"}],"title":"Measured On","description":"What decided whether this version serves: `situations` (the check on fresh situations alone, before you have enough answered cases of your own) or `your_cases` (also compared with the serving version on your own held-back cases, see `compared`). Added Sep 29."},"compared":{"anyOf":[{"$ref":"#/components/schemas/BuildComparison"},{"type":"null"}],"description":"With enough of your own answered cases and a version already serving: both versions on the same held-back cases of yours. A version that is worse there doesn't serve, even above the bar. Added Sep 29."}},"type":"object","required":["bar","passed","statement"],"title":"BuildQuality"},"BuildQualityQuestion":{"properties":{"question":{"type":"string","title":"Question","description":"The question id."},"agreement":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Agreement","description":"How often your model gives the answer your instructions and rules give, on fresh situations (0-1)."},"passed":{"type":"boolean","title":"Passed","description":"At or above the bar."},"cases":{"type":"integer","title":"Cases","description":"Fresh situations it was checked on.","default":0},"advice":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Advice","description":"Below the bar: where it's weakest and what to change, in plain words."},"weakest":{"items":{"$ref":"#/components/schemas/BuildWeakest"},"type":"array","title":"Weakest","description":"Where it matches least (answers or ranges of a field clearly under its overall agreement): what a retrain sharpens."}},"type":"object","required":["question","passed"],"title":"BuildQualityQuestion"},"BuildQuestion":{"properties":{"id":{"type":"string","title":"Id","description":"The question's id (`q01`…; follow-up: `f01`…)."},"kind":{"type":"string","enum":["examples","choice_boundary","priorities","choice_meaning","yes_meaning","score_ends","ready_signal","field_units","field_meaning"],"title":"Kind","description":"What it asks: `examples` (real states across named situations), `choice_boundary` (how to tell two choices apart), `priorities` (unwritten rules), `choice_meaning`, `yes_meaning`, `score_ends`, `ready_signal` (is a yes/no field computed by your program), `field_units` (unit and range) or `field_meaning`."},"text":{"type":"string","title":"Text","description":"The question, in plain words."},"priority":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Priority","description":"1 is the most useful to answer."},"refs":{"$ref":"#/components/schemas/BuildQuestionRefs","description":"What in your JSON it's about."},"answer_with":{"additionalProperties":{"type":"string"},"type":"object","title":"Answer With","description":"The answer's keys and what each holds."}},"type":"object","required":["id","kind","text","refs","answer_with"],"title":"BuildQuestion"},"BuildQuestionInfo":{"properties":{"question":{"type":"string","title":"Question","description":"The question id."},"type":{"type":"string","title":"Type","description":"`choice`, `noul` or `score`."},"options":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Options","description":"A Choice question's options."}},"type":"object","required":["question","type"],"title":"BuildQuestionInfo"},"BuildQuestionRefs":{"properties":{"question":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Question","description":"The question id in your JSON it's about."},"choices":{"items":{"type":"string"},"type":"array","title":"Choices","description":"The choices of that question it's about."},"fields":{"items":{"type":"string"},"type":"array","title":"Fields","description":"The fields of your state it's about, by path (list positions as `[]`: `world.entities[].distance`)."}},"type":"object","title":"BuildQuestionRefs"},"BuildQuestions":{"properties":{"build_id":{"type":"string","title":"Build Id","description":"The build."},"domain":{"type":"string","title":"Domain","description":"The model's name."},"round":{"type":"integer","title":"Round","description":"The round shown (0: none)."},"status":{"type":"string","enum":["open","answered","timed_out","closed","none"],"title":"Status","description":"`open` (answers welcome), `answered`, `timed_out`, `closed` or `none` (no questions)."},"questions":{"items":{"$ref":"#/components/schemas/BuildQuestion"},"type":"array","title":"Questions","description":"Most useful first."},"answered":{"items":{"type":"string"},"type":"array","title":"Answered","description":"Ids answered so far."},"rounds":{"type":"integer","title":"Rounds","description":"Rounds this build has (at most 2).","default":0},"asked_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Asked At","description":"ISO 8601."},"answer_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer By","description":"ISO 8601: when the build goes on without answers (null: it doesn't wait)."},"answered_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answered At","description":"ISO 8601."},"waited_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Waited Seconds","description":"How long the round took, once answered or timed out."},"next_step":{"type":"string","title":"Next Step","description":"What to do next, in plain words.","default":""}},"type":"object","required":["build_id","domain","round","status"],"title":"BuildQuestions"},"BuildQuestionsSummary":{"properties":{"round":{"type":"integer","title":"Round","description":"1: the questions asked before your model is made; 2: a short follow-up after the check, only when it found a gap."},"status":{"type":"string","enum":["open","answered","timed_out","closed"],"title":"Status","description":"`open` (answers welcome), `answered`, `timed_out` (the build went on without them) or `closed`."},"count":{"type":"integer","title":"Count","description":"Questions in the round."},"answered":{"type":"integer","title":"Answered","description":"Questions answered so far.","default":0},"waits":{"type":"boolean","title":"Waits","description":"true: the build waits for these answers (up to `answer_by`).","default":false},"asked_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Asked At","description":"ISO 8601."},"answer_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer By","description":"ISO 8601: when the build goes on without answers."},"answered_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answered At","description":"ISO 8601."},"waited_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Waited Seconds","description":"How long the round took, once answered or timed out."},"used":{"anyOf":[{"type":"string","enum":["this_build","next_retrain"]},{"type":"null"}],"title":"Used","description":"Where the answers go: this build, or your next retrain (answers sent after the build started)."}},"type":"object","required":["round","status","count"],"title":"BuildQuestionsSummary"},"BuildRequest":{"properties":{"state":{"title":"State","description":"One real example of the `state` your program sends: a text, or a JSON object (numbers, true/false, short codes, text, nested objects and lists)."},"questions":{"additionalProperties":{"oneOf":[{"$ref":"#/components/schemas/ChoiceQuestion"},{"$ref":"#/components/schemas/ScoreQuestion"},{"$ref":"#/components/schemas/NoulQuestion"}],"discriminator":{"propertyName":"type","mapping":{"choice":"#/components/schemas/ChoiceQuestion","noul":"#/components/schemas/NoulQuestion","score":"#/components/schemas/ScoreQuestion"}}},"type":"object","title":"Questions","description":"Your questions, exactly as you send them to Jev (choice, noul or score, with instructions and criteria)."},"examples":{"anyOf":[{"items":{},"type":"array","maxItems":50},{"type":"null"}],"title":"Examples","description":"Optional, recommended: up to 50 more real states, in the same shape as `state` (states only, no answers). No past decisions or answers needed; a few examples of what you send Jev make it better: 5 to 20 different ones (a quiet moment and a busy one, a small order and a large one). Your model's situations are made from all of them and checked against them, and the ranges and units of your fields are read from them."},"fields":{"anyOf":[{"additionalProperties":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/FieldNote"}]},"type":"object","maxProperties":300},{"type":"null"}],"title":"Fields","description":"Optional: short notes on what fields mean, keyed by the field's path in your state (as in `understood.fields`, e.g. \"player.angle\") or its name. A note is a sentence, e.g. \"turn angle in engine units (0-4,294,967,295)\", or {\"meaning\", \"unit\", \"range\": [lowest, highest]}. Your model's situations follow them."},"rules":{"anyOf":[{"type":"string","maxLength":20000},{"type":"null"}],"title":"Rules","description":"Optional: rules in plain words, e.g. \"Never approve when amount is over 500. Always escalate when fraud_flag is true.\" Rules that block answers are enforced on every decision; the build reports anything it couldn't read as such a rule (your model still follows it in its answers)."},"name":{"anyOf":[{"type":"string","pattern":"^[a-z0-9][a-z0-9\\-]{0,62}$"},{"type":"null"}],"title":"Name","description":"Optional: the model's name (what you'll pass as `model`). Default: one made from `description` or the questions. Building again under the same name makes the next version of that model."},"description":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Description","description":"Optional: what it decides, in a sentence."},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model","description":"Ignored (accepted so a pasted Jev request works as is)."},"sign_off":{"anyOf":[{"type":"string","enum":["examples","auto"]},{"type":"null"}],"title":"Sign Off","description":"Ignored (accepted so older requests work as they are). Nothing waits for you: your model is built, checked and served in minutes. About 20 examples of how it decides are there to review any time after (optional): GET /v1/domains/{domain}/examples."},"interview":{"type":"boolean","title":"Interview","description":"Optional: `true` to answer a few questions about your JSON before your model is made (what fields mean, units and ranges, where two choices meet, real examples across situations, unwritten priorities). The build waits for your answers (`GET /v1/build/{build_id}/questions`, `POST /v1/build/{build_id}/answers`) up to `answer_timeout_seconds`, then goes on with what it has. Every answer is optional. Without it, the same questions are there to answer while the build runs. The MCP connector's `build_model` asks them by default.","default":false},"answer_timeout_seconds":{"anyOf":[{"type":"integer","maximum":3600.0,"minimum":1.0},{"type":"null"}],"title":"Answer Timeout Seconds","description":"With `interview`: how long the build waits for your answers, in seconds (default 600, at most 3600). It never waits longer."},"history":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"History","description":"Optional: your past cases with their answers, up to 50,000 (more: upload them with POST /v1/domains/{domain}/data, then retrain). Each is `{\"state\": <the state as your program sends it>, \"answers\": {\"<question>\": <answer>}}` or a flat row of fields and answers, as in an upload. With them your model is built from your own cases first (see \"Make it better with your history\"): rules found in them are proposed for you to confirm, cases that contradict your rules are flagged for review, and your model is also measured on held-back cases of yours. A model built again under the same name uses the cases it already has."}},"type":"object","required":["state","questions"],"title":"BuildRequest","description":"Exactly what you send Jev (one real example `state` and your `questions`), plus optional rules in plain\nwords. A pasted Jev request works as is: `model` and anything else Jev takes are ignored.","examples":[{"description":"Refund requests","name":"refunds","questions":{"action":{"criteria":{"approve":"refund the customer","decline":"politely decline","escalate":"a person decides"},"instructions":"What should we do with this refund request?","type":"choice"},"urgent":{"instructions":"Does this need an answer within the hour?","type":"noul"}},"rules":"Never approve when amount is over 500. Always escalate when fraud_flag is true.","state":{"amount":42.5,"fraud_flag":false,"message":"I was charged twice for my order and want one of them refunded","tier":"pro"}},{"model":"jev-latest","questions":{"topic":{"criteria":{"lost_card":"a lost or stolen card","other":"anything else","refund":"a refund"},"instructions":"What is the message about?","type":"choice"}},"state":"My card was stolen yesterday, please block it"}]},"BuildRetrain":{"properties":{"since_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Since Version","description":"The version it improves on."},"added":{"$ref":"#/components/schemas/RetrainAdded","description":"What it added."},"areas":{"items":{"$ref":"#/components/schemas/RetrainArea"},"type":"array","title":"Areas","description":"Before and after, per area it worked on (filled once checked)."},"statement":{"type":"string","title":"Statement","description":"The same, in plain words.","default":""}},"type":"object","title":"BuildRetrain"},"BuildRuleNotRead":{"properties":{"sentence":{"type":"string","title":"Sentence","description":"What you wrote."},"why":{"type":"string","title":"Why","description":"Why it isn't enforced as a rule, in plain words."}},"type":"object","required":["sentence","why"],"title":"BuildRuleNotRead"},"BuildSpend":{"properties":{"usd_estimate":{"type":"number","title":"Usd Estimate","description":"What building this model cost us, estimated in USD (included in your plan; you're never charged per build).","default":0.0},"input_tokens":{"type":"integer","title":"Input Tokens","description":"Tokens read while building.","default":0},"output_tokens":{"type":"integer","title":"Output Tokens","description":"Tokens written while building.","default":0}},"type":"object","title":"BuildSpend"},"BuildStats":{"properties":{"seconds":{"type":"number","title":"Seconds","description":"Time since the build started (until it finished).","default":0.0},"situations":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Situations","description":"Examples of situations your model learned from."},"examples":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Examples","description":"Examples of how your model decides, to review any time (optional)."},"example_messages":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Example Messages","description":"For text fields: example messages of each kind of text your fields hold."},"download_bytes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Download Bytes","description":"The downloaded model's size (zip)."},"model_file_bytes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Model File Bytes","description":"The model file's size, unzipped."},"version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version","description":"The version it made."}},"type":"object","title":"BuildStats"},"BuildUnderstood":{"properties":{"state":{"type":"string","enum":["text","object"],"title":"State","description":"Your example: a text or a JSON object.","default":"object"},"fields":{"items":{"$ref":"#/components/schemas/BuildField"},"type":"array","title":"Fields","description":"The fields your model reads."},"not_read":{"items":{"$ref":"#/components/schemas/BuildNotRead"},"type":"array","title":"Not Read","description":"Parts of the example your model doesn't read (identifiers, empty values, list items past the first 8)."},"questions":{"items":{"$ref":"#/components/schemas/BuildQuestionInfo"},"type":"array","title":"Questions","description":"Your questions, as stored."},"decision_question":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Decision Question","description":"The Choice question your hard rules apply to."},"rules":{"items":{"type":"string"},"type":"array","title":"Rules","description":"The rules read and enforced, in plain words."},"rules_not_understood":{"items":{"$ref":"#/components/schemas/BuildRuleNotRead"},"type":"array","title":"Rules Not Understood","description":"What couldn't be read as a rule that blocks answers (your model still follows it in its answers)."},"rules_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rules Note","description":"How your rules apply, in plain words."},"history":{"anyOf":[{"$ref":"#/components/schemas/BuildHistoryAccepted"},{"type":"null"}],"description":"When the request had `history`: how many past cases were stored, and the problems with the rest."},"examples":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Examples","description":"Real example states received (`state` plus `examples`)."},"field_notes":{"items":{"$ref":"#/components/schemas/BuildFieldNote"},"type":"array","title":"Field Notes","description":"Your notes on fields (`fields`), as matched to the fields of your state."},"field_notes_not_matched":{"items":{"$ref":"#/components/schemas/BuildFieldNoteMissed"},"type":"array","title":"Field Notes Not Matched","description":"Notes whose key isn't a field of your example state (they weren't used)."}},"type":"object","title":"BuildUnderstood"},"BuildUsage":{"properties":{"today":{"type":"integer","title":"Today","description":"Builds started today (UTC). A build is a new model, a new version from POST /v1/build, or a rule change; retrains don't count."},"per_day":{"type":"integer","title":"Per Day","description":"The most builds a workspace can start in a UTC day."},"this_month":{"type":"integer","title":"This Month","description":"Builds started this calendar month (UTC)."},"per_month":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Per Month","description":"With a subscription: the most builds a month (null on the free trial)."},"on_trial":{"type":"boolean","title":"On Trial","description":"True until the workspace subscribes."},"used_in_trial":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Used In Trial","description":"On the free trial: builds started so far."},"trial_total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Trial Total","description":"On the free trial: the builds it includes."}},"type":"object","required":["today","per_day","this_month","on_trial"],"title":"BuildUsage"},"BuildWeakest":{"properties":{"where":{"type":"string","title":"Where","description":"Where it's weaker, in plain words (\"when the right answer is 'block'\")."},"agreement":{"type":"number","title":"Agreement","description":"Agreement there (0-1)."},"cases":{"type":"integer","title":"Cases","description":"Fresh situations of that kind it was checked on.","default":0}},"type":"object","required":["where","agreement"],"title":"BuildWeakest"},"Calibration":{"properties":{"question":{"type":"string","title":"Question","description":"The question id."},"error":{"type":"number","title":"Error","description":"Expected calibration error (0 = perfectly calibrated)."},"statement":{"type":"string","title":"Statement","description":"In plain words, e.g. \"When it says 90% sure, it's right 89% of the time.\""},"bins":{"items":{"$ref":"#/components/schemas/CalibrationBin"},"type":"array","title":"Bins","description":"Confidence given against how often it was right."}},"type":"object","required":["question","error","statement","bins"],"title":"Calibration"},"CalibrationBin":{"properties":{"said":{"type":"number","title":"Said","description":"The confidence it gave."},"right":{"type":"number","title":"Right","description":"How often it was right at that confidence."},"cases":{"type":"integer","title":"Cases","description":"Held-back cases in this bin."}},"type":"object","required":["said","right","cases"],"title":"CalibrationBin"},"CheckoutUrl":{"properties":{"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"Open this link in a browser."}},"type":"object","title":"CheckoutUrl"},"ChoiceAnswer":{"properties":{"type":{"type":"string","const":"choice","title":"Type","description":"`choice`."},"choice":{"type":"string","title":"Choice","description":"The chosen option label. For the decision question, with your rules applied."},"confidence":{"type":"number","title":"Confidence","description":"How sure the answer is, from 0 to 1, calibrated on your held-back cases."},"probabilities":{"additionalProperties":{"type":"number"},"type":"object","title":"Probabilities","description":"Probability per option (Choice) or per level (Score), summing to 1. Options your rules block are 0."},"source":{"type":"string","enum":["trained","translated","fallback","rule","backup","local_fallback"],"title":"Source","description":"How it was decided: `trained` (your model), `translated` (your model, after the message was translated to English because it was below the safety bar or in a language the model isn't strong in), `fallback` (your day-one backend), `rule` (your rules leave one option), `backup` (still below the safety bar after translation: our hosted backup answered from your allowed options, with your rules applied) or `local_fallback` (a downloaded model, offline: your own fallback function answered; only on cases synced from a device)."},"route":{"anyOf":[{"type":"string","enum":["act","review"]},{"type":"null"}],"title":"Route","description":"`act`: an automatic answer (at or above the model's safety bar). `review`: below the bar after every check; held for a person (it's in the unsure queue)."}},"type":"object","required":["type","choice","confidence","probabilities","source"],"title":"ChoiceAnswer"},"ChoiceQuestion":{"properties":{"type":{"type":"string","const":"choice","title":"Type","description":"`choice`: pick one of the options."},"instructions":{"title":"Instructions","description":"What the question asks, as you'd tell a person (text, a JSON object or array)."},"criteria":{"additionalProperties":true,"type":"object","title":"Criteria","description":"Option label -> description (text, object, array or null). 1-255 options."}},"additionalProperties":true,"type":"object","required":["type","criteria"],"title":"ChoiceQuestion","description":"Pick one option from a list (Jev's Choice)."},"Condition":{"properties":{"field":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Field","description":"The state field it reads."},"answer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer","description":"Or: another question whose answer it reads, e.g. `topic` in \"Always block-card when topic is lost_stolen\". What a message is about is never certain, so a rule on it is enforced whenever there's a real chance it applies (see `min_chance`); unsure cases go to review."},"op":{"anyOf":[{"type":"string","enum":["eq","ne","gt","gte","lt","lte","in","not_in","is_true","is_false","is_missing","contains"]},{"type":"null"}],"title":"Op","description":"eq, ne (equal, not equal), gt, gte, lt, lte (greater / less than, or equal), in, not_in (one of a list), is_true, is_false, is_missing (no value needed), contains (text or list contains the value)."},"value":{"title":"Value","description":"What the field is compared with (not needed for is_true, is_false, is_missing)."},"any":{"anyOf":[{"items":{"$ref":"#/components/schemas/Condition"},"type":"array"},{"type":"null"}],"title":"Any","description":"Holds when at least one of these holds."},"all":{"anyOf":[{"items":{"$ref":"#/components/schemas/Condition"},"type":"array"},{"type":"null"}],"title":"All","description":"Holds when every one of these holds."}},"additionalProperties":false,"type":"object","title":"Condition","description":"One condition on a state field or on another question's answer, or a group of them (`any` / `all`)."},"ConfusedPair":{"properties":{"question":{"type":"string","title":"Question","description":"The question id."},"expected":{"type":"string","title":"Expected","description":"The right option."},"chosen":{"type":"string","title":"Chosen","description":"The option chosen instead."},"cases":{"type":"integer","title":"Cases","description":"How many held-back cases."},"share":{"type":"number","title":"Share","description":"Share of all held-back cases."},"examples":{"items":{"$ref":"#/components/schemas/ExampleCase"},"type":"array","title":"Examples","description":"A few real examples."}},"type":"object","required":["question","expected","chosen","cases","share","examples"],"title":"ConfusedPair"},"DataRemoved":{"properties":{"domain":{"type":"string","title":"Domain","description":"The domain's name."},"removed":{"$ref":"#/components/schemas/RemovedCounts","description":"What was deleted, permanently."},"uploads_removed":{"items":{"type":"string"},"type":"array","title":"Uploads Removed","description":"The uploads that are gone."},"remaining":{"$ref":"#/components/schemas/Remaining","description":"What the next version would learn from."},"message":{"type":"string","title":"Message","description":"The same, in plain words."}},"type":"object","required":["domain","removed","remaining","message"],"title":"DataRemoved","description":"What a deletion removed (permanently) and what's left. Versions already trained are kept.","examples":[{"domain":"refunds","message":"Deleted permanently: 6,278 uploaded cases. Train again to make the next version from the cases left. Versions already trained are kept: they're yours, and still download and serve.","remaining":{"from_outcomes":12,"from_signoff":2,"from_uploads":6349,"total_cases":6361},"removed":{"decisions":0,"signoff_cases":0,"uploaded_cases":6278},"uploads_removed":["upl_9e8d7c6b5a4f3e2d"]}]},"DataSummary":{"properties":{"total_cases":{"type":"integer","title":"Total Cases","description":"Cases with a known answer."},"per_question":{"additionalProperties":{"type":"integer"},"type":"object","title":"Per Question","description":"Per question."},"from_uploads":{"type":"integer","title":"From Uploads","description":"From uploads (and examples you corrected)."},"from_outcomes":{"type":"integer","title":"From Outcomes","description":"From reported outcomes and unsure-queue answers."},"from_signoff":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"From Signoff","description":"Of `from_uploads`, the examples you corrected (added Sep 27)."}},"type":"object","required":["total_cases","per_question","from_uploads","from_outcomes"],"title":"DataSummary"},"DecideRequest":{"properties":{"state":{"title":"State","description":"Text, a JSON object or array: the case to decide."},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model","description":"`<domain>@<version|latest>`, e.g. `bank-support@latest`. `jev-*` names map to your `default` domain."},"questions":{"anyOf":[{"additionalProperties":{"oneOf":[{"$ref":"#/components/schemas/ChoiceQuestion"},{"$ref":"#/components/schemas/ScoreQuestion"},{"$ref":"#/components/schemas/NoulQuestion"}],"discriminator":{"propertyName":"type","mapping":{"choice":"#/components/schemas/ChoiceQuestion","noul":"#/components/schemas/NoulQuestion","score":"#/components/schemas/ScoreQuestion"}}},"type":"object"},{"type":"null"}],"title":"Questions","description":"Questions in TypeSafe's format. Omit to ask every question the domain knows."}},"additionalProperties":true,"type":"object","title":"DecideRequest","description":"A decision request in TypeSafe's System One (Jev) format.","examples":[{"model":"refunds@latest","state":{"amount":42.5,"fraud_flag":false,"message":"The parcel arrived crushed and the mug is broken","tier":"pro"}},{"model":"refunds@3","questions":{"action":{"criteria":{"approve":"refund the customer","decline":"politely decline","escalate":"a person decides"},"instructions":"What should we do with this refund request?","type":"choice"}},"state":{"amount":42.5,"fraud_flag":false,"message":"The parcel arrived crushed and the mug is broken","tier":"pro"}},{"model":"bank-support@latest","state":"I think someone has my card, there are payments I didn't make"}]},"DecideResponse":{"properties":{"id":{"type":"string","title":"Id","description":"Decision id: use it to report the outcome (`POST /v1/outcomes`)."},"model":{"type":"string","title":"Model","description":"The domain and the version that answered, e.g. `bank-support@3`."},"answers":{"additionalProperties":{"oneOf":[{"$ref":"#/components/schemas/ChoiceAnswer"},{"$ref":"#/components/schemas/ScoreAnswer"},{"$ref":"#/components/schemas/NoulAnswer"}],"discriminator":{"propertyName":"type","mapping":{"choice":"#/components/schemas/ChoiceAnswer","noul":"#/components/schemas/NoulAnswer","score":"#/components/schemas/ScoreAnswer"}}},"type":"object","title":"Answers","description":"Question id -> its answer (Choice, Score or Noul)."},"decision":{"anyOf":[{"$ref":"#/components/schemas/Decision"},{"type":"null"}],"description":"The final action with your rules applied. Present when the domain has a decision question and it was asked."},"language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Language","description":"The language the text was detected in (ISO 639-1, e.g. `es`); null when there's no text or too little to tell."},"usage":{"$ref":"#/components/schemas/Usage","description":"Counts for your dashboards. Nothing is billed per decision."}},"type":"object","required":["id","model","answers","usage"],"title":"DecideResponse","description":"Answers in Jev's format, plus `source`, `route`, the `decision` block and the detected `language`.","examples":[{"answers":{"action":{"choice":"approve","confidence":0.9705,"probabilities":{"approve":0.9705,"decline":0.0011,"escalate":0.0284},"route":"act","source":"trained","type":"choice"}},"decision":{"action":"approve","blocked_actions":[],"blocked_by_rules":[],"confidence":0.9705,"question":"action","route":"act"},"id":"dec_4f1c2a9b0e7d6a51","language":"en","model":"refunds@3","usage":{"decisions":1,"input_tokens":38,"output_tokens":0}}]},"Decision":{"properties":{"question":{"type":"string","title":"Question","description":"The question whose options are the domain's actions."},"action":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Action","description":"The final action with your rules applied (null if your rules block every action)."},"confidence":{"type":"number","title":"Confidence","description":"How sure the final action is, from 0 to 1."},"blocked_by_rules":{"items":{"type":"string"},"type":"array","title":"Blocked By Rules","description":"Ids of the rules that blocked at least one action for this case."},"blocked_actions":{"items":{"type":"string"},"type":"array","title":"Blocked Actions","description":"The actions your rules blocked for this case."},"rule_chances":{"anyOf":[{"additionalProperties":{"type":"number"},"type":"object"},{"type":"null"}],"title":"Rule Chances","description":"Only when a rule on what the message is about applied: each such rule's id and the chance it applies here (0 to 1). Those rules are enforced whenever there's a real chance they apply; when one changed the action and isn't sure to apply, the decision goes to review."},"route":{"type":"string","enum":["act","review","ask"],"title":"Route","description":"act: decided automatically, at or above the model's safety bar (set automatically after each training run: automatic answers at least 97% right). review: still below the bar after the message was double-checked; held for a person (it's in the unsure queue). ask: your rules allow no action for this case."}},"type":"object","required":["question","action","confidence","blocked_by_rules","route"],"title":"Decision","description":"The final action with your rules applied."},"DecisionDetail":{"properties":{"id":{"type":"string","title":"Id","description":"The decision id (`dec_…`, or `off_…` for a case synced from a downloaded model): the one `POST /v1/decide` returned."},"created_at":{"type":"string","title":"Created At","description":"When it was decided (ISO 8601, UTC)."},"model":{"type":"string","title":"Model","description":"The version that answered, e.g. `refunds@3` (`refunds@day-one` before the first version)."},"version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version","description":"The version number (null in day-one mode)."},"summary":{"type":"string","title":"Summary","description":"A short line about the case: its first text field (else other words in it, else a few key fields), up to 120 characters."},"question":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Question","description":"The question `answer` is for: the decision question, else the first one asked."},"answer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer","description":"The final answer as one word: the action with your rules applied (null when your rules allowed none), an option, a level (Score, rounded) or true/false (Noul)."},"confidence":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Confidence","description":"How sure the final answer was, from 0 to 1."},"route":{"anyOf":[{"type":"string","enum":["act","review","ask"]},{"type":"null"}],"title":"Route","description":"`act` (decided automatically), `review` (held for a person) or `ask` (your rules allowed no action)."},"source":{"anyOf":[{"type":"string","enum":["trained","translated","fallback","rule","backup","local_fallback"]},{"type":"null"}],"title":"Source","description":"Who answered, for the whole decision: the decision question's answer's source (else the one answer's, else the one that needed the most help). One of `trained` (your model), `translated` (your model, after the message was translated to English because it was below the safety bar or in a language the model isn't strong in), `fallback` (your day-one backend), `rule` (your rules leave one option), `backup` (still below the safety bar after translation: our hosted backup answered from your allowed options, with your rules applied) or `local_fallback` (a downloaded model, offline: your own fallback function answered; only on cases synced from a device)."},"sources":{"items":{"type":"string","enum":["trained","translated","fallback","rule","backup","local_fallback"]},"type":"array","title":"Sources","description":"Every source among its answers."},"language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Language","description":"The language the text was detected in, if any."},"has_outcome":{"type":"boolean","title":"Has Outcome","description":"true once you reported what really happened, or answered it in the unsure queue.","default":false},"from_offline_device":{"type":"boolean","title":"From Offline Device","description":"true when a downloaded model decided it while offline and it was synced later.","default":false},"marked_wrong":{"type":"boolean","title":"Marked Wrong","description":"true once you marked it wrong (POST …/decisions/{decision_id}/wrong): your next retrain learns the right answer.","default":false},"domain":{"type":"string","title":"Domain","description":"The decision model's name."},"state":{"title":"State","description":"The case, exactly as it was sent."},"questions":{"additionalProperties":{"additionalProperties":true,"type":"object"},"type":"object","title":"Questions","description":"The questions it was asked, in TypeSafe's format."},"answers":{"additionalProperties":{"oneOf":[{"$ref":"#/components/schemas/ChoiceAnswer"},{"$ref":"#/components/schemas/ScoreAnswer"},{"$ref":"#/components/schemas/NoulAnswer"}],"discriminator":{"propertyName":"type","mapping":{"choice":"#/components/schemas/ChoiceAnswer","noul":"#/components/schemas/NoulAnswer","score":"#/components/schemas/ScoreAnswer"}}},"type":"object","title":"Answers","description":"Every answer, with its probabilities, confidence, source and route."},"decision":{"anyOf":[{"$ref":"#/components/schemas/Decision"},{"type":"null"}],"description":"The final action with your rules applied."},"rules_applied":{"items":{"$ref":"#/components/schemas/RuleApplied"},"type":"array","title":"Rules Applied","description":"Your rules that blocked an option for this case, with what they say."},"latency_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Latency Ms","description":"How long it took to decide on our side, in milliseconds (null for synced cases and older decisions)."},"outcome":{"anyOf":[{"$ref":"#/components/schemas/DecisionOutcome"},{"type":"null"}],"description":"What really happened, once reported."}},"type":"object","required":["id","created_at","model","summary","domain","answers"],"title":"DecisionDetail","description":"One decision in full.","examples":[{"answer":"escalate","answers":{"action":{"choice":"escalate","confidence":0.93,"probabilities":{"approve":0.0,"decline":0.07,"escalate":0.93},"route":"act","source":"trained","type":"choice"}},"confidence":0.93,"created_at":"2026-09-27T10:15:00Z","decision":{"action":"escalate","blocked_actions":["approve"],"blocked_by_rules":["never-approve-over-500"],"confidence":0.93,"question":"action","route":"act"},"domain":"refunds","from_offline_device":false,"has_outcome":true,"id":"dec_4f1c2a9b0e7d6a51","language":"en","latency_ms":21.4,"model":"refunds@3","outcome":{"answers":{"action":"escalate"},"reported_at":"2026-09-27T11:02:00Z","via":"outcome"},"question":"action","questions":{"action":{"criteria":{"approve":"refund the customer","decline":"politely decline","escalate":"a person decides"},"instructions":"What should we do with this refund request?","type":"choice"}},"route":"act","rules_applied":[{"description":"Never approve when amount is over 500","id":"never-approve-over-500","still_in_place":true}],"source":"trained","sources":["trained"],"state":{"amount":900,"fraud_flag":false,"message":"I was charged 900 twice","tier":"enterprise"},"summary":"I was charged 900 twice","version":3}]},"DecisionItem":{"properties":{"id":{"type":"string","title":"Id","description":"The decision id (`dec_…`, or `off_…` for a case synced from a downloaded model): the one `POST /v1/decide` returned."},"created_at":{"type":"string","title":"Created At","description":"When it was decided (ISO 8601, UTC)."},"model":{"type":"string","title":"Model","description":"The version that answered, e.g. `refunds@3` (`refunds@day-one` before the first version)."},"version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version","description":"The version number (null in day-one mode)."},"summary":{"type":"string","title":"Summary","description":"A short line about the case: its first text field (else other words in it, else a few key fields), up to 120 characters."},"question":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Question","description":"The question `answer` is for: the decision question, else the first one asked."},"answer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer","description":"The final answer as one word: the action with your rules applied (null when your rules allowed none), an option, a level (Score, rounded) or true/false (Noul)."},"confidence":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Confidence","description":"How sure the final answer was, from 0 to 1."},"route":{"anyOf":[{"type":"string","enum":["act","review","ask"]},{"type":"null"}],"title":"Route","description":"`act` (decided automatically), `review` (held for a person) or `ask` (your rules allowed no action)."},"source":{"anyOf":[{"type":"string","enum":["trained","translated","fallback","rule","backup","local_fallback"]},{"type":"null"}],"title":"Source","description":"Who answered, for the whole decision: the decision question's answer's source (else the one answer's, else the one that needed the most help). One of `trained` (your model), `translated` (your model, after the message was translated to English because it was below the safety bar or in a language the model isn't strong in), `fallback` (your day-one backend), `rule` (your rules leave one option), `backup` (still below the safety bar after translation: our hosted backup answered from your allowed options, with your rules applied) or `local_fallback` (a downloaded model, offline: your own fallback function answered; only on cases synced from a device)."},"sources":{"items":{"type":"string","enum":["trained","translated","fallback","rule","backup","local_fallback"]},"type":"array","title":"Sources","description":"Every source among its answers."},"language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Language","description":"The language the text was detected in, if any."},"has_outcome":{"type":"boolean","title":"Has Outcome","description":"true once you reported what really happened, or answered it in the unsure queue.","default":false},"from_offline_device":{"type":"boolean","title":"From Offline Device","description":"true when a downloaded model decided it while offline and it was synced later.","default":false},"marked_wrong":{"type":"boolean","title":"Marked Wrong","description":"true once you marked it wrong (POST …/decisions/{decision_id}/wrong): your next retrain learns the right answer.","default":false}},"type":"object","required":["id","created_at","model","summary"],"title":"DecisionItem","description":"One decision in the log (a row of the table)."},"DecisionList":{"properties":{"domain":{"type":"string","title":"Domain","description":"The decision model's name."},"items":{"items":{"$ref":"#/components/schemas/DecisionItem"},"type":"array","title":"Items","description":"Decisions, newest first, up to `limit`."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Pass it as `cursor` for the next (older) page; null on the last page."},"filters":{"additionalProperties":true,"type":"object","title":"Filters","description":"The filters applied, as read."},"retention_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Retention Days","description":"How many days your workspace keeps decisions (null: until you delete them). See GET /v1/settings."}},"type":"object","required":["domain","items"],"title":"DecisionList","description":"A page of the decision log, newest first.","examples":[{"domain":"refunds","filters":{"route":"review"},"items":[{"answer":"approve","confidence":0.62,"created_at":"2026-09-27T10:15:00Z","from_offline_device":false,"has_outcome":false,"id":"dec_4f1c2a9b0e7d6a51","language":"en","model":"refunds@3","question":"action","route":"review","source":"trained","sources":["trained"],"summary":"The parcel arrived crushed and the mug is broken","version":3}],"next_cursor":"WyIyMDI2LTA5LTI3VDEwOjE1OjAwKzAwOjAwIiwiZGVjXzRmMWMyYTliMGU3ZDZhNTEiXQ","retention_days":90}]},"DecisionOutcome":{"properties":{"answers":{"additionalProperties":true,"type":"object","title":"Answers","description":"What really happened, per question."},"reported_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reported At","description":"When it was reported (ISO 8601)."},"via":{"type":"string","enum":["outcome","unsure_queue","marked_wrong"],"title":"Via","description":"`outcome` (POST /v1/outcomes), `unsure_queue` (answered in the unsure queue) or `marked_wrong` (you marked the decision wrong and gave the right answer)."}},"type":"object","required":["answers","via"],"title":"DecisionOutcome"},"DecisionsDeleted":{"properties":{"domain":{"type":"string","title":"Domain","description":"The decision model's name."},"deleted":{"type":"integer","title":"Deleted","description":"Decisions deleted."},"learning_cases_deleted":{"type":"integer","title":"Learning Cases Deleted","description":"Of those, how many the next version would have learned from (with an outcome, an unsure-queue answer or a backup answer)."},"message":{"type":"string","title":"Message","description":"The same, in plain words."}},"type":"object","required":["domain","deleted","learning_cases_deleted","message"],"title":"DecisionsDeleted","description":"What was deleted, permanently."},"DependencyStatus":{"properties":{"status":{"type":"string","enum":["ok","degraded","down"],"title":"Status","description":"`ok`, `degraded` (works partly) or `down`."}},"type":"object","required":["status"],"title":"DependencyStatus"},"Domain":{"properties":{"id":{"type":"string","title":"Id","description":"Domain id (`dom_…`). Paths accept this or the name."},"name":{"type":"string","title":"Name","description":"The name you pass as `model` (`<name>@latest`)."},"description":{"type":"string","title":"Description","description":"What it decides."},"kind":{"type":"string","title":"Kind","description":"`decision` (or `game`, coming soon)."},"status":{"type":"string","enum":["draft","ready","trained"],"title":"Status","description":"`draft` (no questions set up yet), `ready` (set up, not trained yet) or `trained` (a version serves)."},"questions":{"additionalProperties":{"oneOf":[{"$ref":"#/components/schemas/ChoiceQuestion"},{"$ref":"#/components/schemas/ScoreQuestion"},{"$ref":"#/components/schemas/NoulQuestion"}],"discriminator":{"propertyName":"type","mapping":{"choice":"#/components/schemas/ChoiceQuestion","noul":"#/components/schemas/NoulQuestion","score":"#/components/schemas/ScoreQuestion"}}},"type":"object","title":"Questions","description":"Question id -> question, in Jev's format."},"decision_question":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Decision Question","description":"The Choice question whose options are the actions."},"actions":{"items":{"type":"string"},"type":"array","title":"Actions","description":"The decision question's options."},"rules":{"items":{"$ref":"#/components/schemas/RuleOut"},"type":"array","title":"Rules","description":"Rules that can't be broken, enforced on every decision."},"state_schema":{"$ref":"#/components/schemas/StateSchema","description":"The fields of `state` the decision reads."},"safety_bar":{"$ref":"#/components/schemas/SafetyInfo","description":"The automatic safety bar of the serving version (read-only)."},"graduation":{"$ref":"#/components/schemas/Graduation","description":"When day-one questions switch to your own model."},"serving_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Serving Version","description":"The version `@latest` answers with (null before the first training run)."},"active":{"type":"boolean","title":"Active","description":"false: archived (not served).","default":true},"latest_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Latest Version","description":"The newest version, serving or not."},"question_status":{"additionalProperties":{"$ref":"#/components/schemas/QuestionStatus"},"type":"object","title":"Question Status","description":"Per question: trained or day-one, and its progress."},"candidate_questions":{"additionalProperties":{"oneOf":[{"$ref":"#/components/schemas/ChoiceQuestion"},{"$ref":"#/components/schemas/ScoreQuestion"},{"$ref":"#/components/schemas/NoulQuestion"}],"discriminator":{"propertyName":"type","mapping":{"choice":"#/components/schemas/ChoiceQuestion","noul":"#/components/schemas/NoulQuestion","score":"#/components/schemas/ScoreQuestion"}}},"type":"object","title":"Candidate Questions","description":"Questions asked in a decide request that this domain doesn't have. They were answered, but they don't join the domain (or requests that omit `questions`) until you add them with PATCH `questions`."},"fallback":{"$ref":"#/components/schemas/FallbackInfo","description":"The day-one backend."},"signoff":{"$ref":"#/components/schemas/SignoffInfo","description":"The record of your review of the examples (optional)."},"cases":{"type":"integer","title":"Cases","description":"Past cases uploaded plus decisions with a known outcome.","default":0},"created_at":{"type":"string","title":"Created At","description":"ISO 8601."},"updated_at":{"type":"string","title":"Updated At","description":"ISO 8601."}},"type":"object","required":["id","name","description","kind","status","questions","actions","rules","state_schema","safety_bar","graduation","question_status","fallback","signoff","created_at","updated_at"],"title":"Domain","description":"A decision model."},"DomainCreate":{"properties":{"name":{"type":"string","pattern":"^[a-z0-9][a-z0-9\\-]{0,62}$","title":"Name","description":"Lowercase letters, digits and dashes. It's what you pass as `model`."},"description":{"type":"string","title":"Description","description":"What it decides, in a sentence.","default":""},"kind":{"type":"string","enum":["decision","game"],"title":"Kind","description":"`decision` (default). `game` is coming soon.","default":"decision"},"questions":{"additionalProperties":{"oneOf":[{"$ref":"#/components/schemas/ChoiceQuestion"},{"$ref":"#/components/schemas/ScoreQuestion"},{"$ref":"#/components/schemas/NoulQuestion"}],"discriminator":{"propertyName":"type","mapping":{"choice":"#/components/schemas/ChoiceQuestion","noul":"#/components/schemas/NoulQuestion","score":"#/components/schemas/ScoreQuestion"}}},"type":"object","title":"Questions","description":"Question id -> question, in Jev's format. Usually left to the set-up agent."},"decision_question":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Decision Question","description":"The Choice question whose options are the actions."},"rules":{"items":{"$ref":"#/components/schemas/Rule"},"type":"array","title":"Rules","description":"Rules that can't be broken."},"state_schema":{"$ref":"#/components/schemas/StateSchema","description":"The fields of `state` the decision reads."},"graduation":{"$ref":"#/components/schemas/Graduation","description":"When day-one questions switch to your own model."}},"type":"object","required":["name"],"title":"DomainCreate","description":"A new decision model. Usually just `name` and `description`: then describe it with the set-up agent.","examples":[{"description":"Approve, escalate or decline refund requests","name":"refunds"},{"decision_question":"action","description":"Approve, escalate or decline refund requests","graduation":{"auto":true,"min_outcomes":1000},"name":"refunds","questions":{"action":{"criteria":{"approve":"refund the customer","decline":"politely decline","escalate":"a person decides"},"instructions":"What should we do with this refund request?","type":"choice"}},"rules":[{"block":["approve"],"description":"Never approve more than $500 without a person","id":"over-500-needs-a-person","when":[{"field":"amount","op":"gt","value":500}]},{"allow_only":["escalate"],"description":"Fraud-flagged accounts always go to a person","id":"fraud-goes-to-a-person","when":[{"field":"fraud_flag","op":"is_true"}]}],"state_schema":{"fields":[{"name":"message","type":"text"},{"name":"amount","path":"order.amount","type":"number"},{"name":"tier","type":"category","values":["free","pro","enterprise"]},{"description":"yes/no","name":"fraud_flag","type":"number"}]}}]},"DomainList":{"properties":{"domains":{"items":{"$ref":"#/components/schemas/Domain"},"type":"array","title":"Domains","description":"Every decision model in the workspace."}},"type":"object","required":["domains"],"title":"DomainList"},"DomainPatch":{"properties":{"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"What it decides."},"questions":{"anyOf":[{"additionalProperties":{"oneOf":[{"$ref":"#/components/schemas/ChoiceQuestion"},{"$ref":"#/components/schemas/ScoreQuestion"},{"$ref":"#/components/schemas/NoulQuestion"}],"discriminator":{"propertyName":"type","mapping":{"choice":"#/components/schemas/ChoiceQuestion","noul":"#/components/schemas/NoulQuestion","score":"#/components/schemas/ScoreQuestion"}}},"type":"object"},{"type":"null"}],"title":"Questions","description":"Replaces all questions."},"decision_question":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Decision Question","description":"The Choice question whose options are the actions."},"rules":{"anyOf":[{"items":{"$ref":"#/components/schemas/Rule"},"type":"array"},{"type":"null"}],"title":"Rules","description":"Replaces all rules."},"state_schema":{"anyOf":[{"$ref":"#/components/schemas/StateSchema"},{"type":"null"}],"description":"Replaces the state fields."},"graduation":{"anyOf":[{"$ref":"#/components/schemas/Graduation"},{"type":"null"}],"description":"When day-one questions switch to your own model."},"active":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Active","description":"false archives the domain: the hosted endpoint stops serving it (added Sep 25). true brings it back. The price is the same either way."}},"type":"object","title":"DomainPatch","description":"Change any part of the setup. Send only what changes."},"EmailSent":{"properties":{"status":{"type":"string","const":"sent","title":"Status","description":"Always `sent` (the same answer whether or not the address has an account).","default":"sent"},"email":{"type":"string","title":"Email","description":"The address the link was sent to."},"message":{"type":"string","title":"Message","description":"What to do next, in words."}},"type":"object","required":["email","message"],"title":"EmailSent"},"ErrorBody":{"properties":{"type":{"type":"string","title":"Type","description":"invalid_request, authentication_error, payment_required, permission_denied, not_found, conflict, too_large, rate_limited, server_error or unavailable."},"message":{"type":"string","title":"Message","description":"What went wrong and, where it helps, what to do next."}},"type":"object","required":["type","message"],"title":"ErrorBody"},"ErrorResponse":{"properties":{"error":{"$ref":"#/components/schemas/ErrorBody","description":"Every error has this shape."}},"type":"object","required":["error"],"title":"ErrorResponse"},"Example":{"properties":{"id":{"type":"string","title":"Id","description":"Example id, used to confirm or correct it."},"state":{"title":"State","description":"The case."},"answers":{"additionalProperties":true,"type":"object","title":"Answers","description":"The answer your setup gives for this case, per question."},"why":{"type":"string","title":"Why","description":"Which of your rules or decisions applies, in plain words.","default":""},"described":{"type":"boolean","title":"Described","description":"true: there's no example message for this answer, so the message field says what kind of message it is (\"A message about payments, charges or invoices\") instead of quoting one. Confirm the answer for that kind of message.","default":false}},"type":"object","required":["id","state","answers"],"title":"Example"},"ExampleCase":{"properties":{"state":{"title":"State","description":"The case."},"expected":{"title":"Expected","description":"The right answer."},"chosen":{"title":"Chosen","description":"What the model chose."},"confidence":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Confidence","description":"How sure it was."}},"type":"object","required":["state"],"title":"ExampleCase"},"ExampleList":{"properties":{"examples":{"items":{"$ref":"#/components/schemas/Example"},"type":"array","title":"Examples","description":"About 20 example cases: how your model decides. Reviewing them is optional; confirm or correct any, any time (none while `status` is `preparing`)."},"status":{"type":"string","enum":["ready","preparing"],"title":"Status","description":"`ready`, or `preparing`: a decision made on what a message says shows an example message for each answer, and they are still being prepared. Ask again in a minute.","default":"ready"},"note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Note","description":"Anything to know about these examples, in plain words."},"signoff":{"$ref":"#/components/schemas/SignoffInfo","description":"The current review record (reviewing is optional)."}},"type":"object","required":["examples","signoff"],"title":"ExampleList"},"FallbackConfig":{"properties":{"provider":{"type":"string","enum":["typesafe","openai","local","none"],"title":"Provider","description":"`typesafe` (Jev with your key), `openai` (any OpenAI-compatible endpoint), `local` (our built-in general model: no key, no cost) or `none`."},"api_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key","description":"Your key for that backend. Stored encrypted; never returned."},"base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base Url","description":"For `openai`: an OpenAI-compatible base URL. It must be a public https address; private and internal addresses are refused."},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model","description":"Backend model name, e.g. `jev-latest` or `gpt-4o-mini`."}},"type":"object","required":["provider"],"title":"FallbackConfig","description":"The backend for questions your model hasn't learned yet.","examples":[{"provider":"local"},{"api_key":"<your TypeSafe key>","model":"jev-latest","provider":"typesafe"},{"api_key":"<your key>","base_url":"https://api.openai.com/v1","model":"gpt-4o-mini","provider":"openai"}]},"FallbackInfo":{"properties":{"provider":{"type":"string","enum":["typesafe","openai","local","none"],"title":"Provider","description":"`typesafe` (Jev with your key), `openai` (any OpenAI-compatible endpoint), `local` (our built-in general model: no key, no cost) or `none`."},"base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base Url","description":"For `openai`: the endpoint's base URL."},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model","description":"The backend's model name."},"has_key":{"type":"boolean","title":"Has Key","description":"Whether a key is stored (it is never returned).","default":false},"key_last4":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Key Last4","description":"The stored key's last 4 characters."}},"type":"object","required":["provider"],"title":"FallbackInfo"},"FieldNote":{"properties":{"meaning":{"anyOf":[{"type":"string","maxLength":300},{"type":"null"}],"title":"Meaning","description":"What the field is, in a few words."},"unit":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}],"title":"Unit","description":"Its unit, e.g. \"seconds\", \"USD\", \"map units\"."},"range":{"anyOf":[{"items":{"type":"number"},"type":"array","maxItems":2,"minItems":2},{"type":"null"}],"title":"Range","description":"[lowest, highest] value it takes in your program."}},"type":"object","title":"FieldNote","description":"What a field of your state means (all parts optional)."},"Fix":{"properties":{"method":{"type":"string","title":"Method","description":"HTTP method of the call that acts on the item."},"path":{"type":"string","title":"Path","description":"Its path."},"body":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Body","description":"A starting body for it, when there is one."}},"type":"object","required":["method","path"],"title":"Fix"},"FlaggedDecision":{"properties":{"id":{"type":"string","title":"Id","description":"The flagged case's id."},"decision":{"type":"string","enum":["follow_rule","keep","drop"],"title":"Decision","description":"`follow_rule` (learn it with the rule's answer), `keep` (learn it as it is: the rule has an exception) or `drop` (never learn it)."}},"type":"object","required":["id","decision"],"title":"FlaggedDecision"},"FlaggedList":{"properties":{"build_id":{"type":"string","title":"Build Id","description":"The build."},"domain":{"type":"string","title":"Domain","description":"The model's name."},"total":{"type":"integer","title":"Total","description":"Past cases flagged.","default":0},"pending":{"type":"integer","title":"Pending","description":"Waiting for your review.","default":0},"items":{"items":{"$ref":"#/components/schemas/FlaggedRow"},"type":"array","title":"Items","description":"This page."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Pass it as `cursor` for the next page; null on the last."}},"type":"object","required":["build_id","domain"],"title":"FlaggedList"},"FlaggedReviewRequest":{"properties":{"rows":{"items":{"$ref":"#/components/schemas/FlaggedDecision"},"type":"array","title":"Rows","description":"Decisions on some flagged cases."},"all":{"anyOf":[{"type":"string","enum":["follow_rule","keep","drop"]},{"type":"null"}],"title":"All","description":"One decision for every case still pending (with `follow_rule`, cases whose rule only blocks answers stay pending)."}},"type":"object","title":"FlaggedReviewRequest","examples":[{"rows":[{"decision":"follow_rule","id":"h1042"},{"decision":"drop","id":"h2210"}]},{"all":"follow_rule"}]},"FlaggedReviewed":{"properties":{"build_id":{"type":"string","title":"Build Id","description":"The build."},"domain":{"type":"string","title":"Domain","description":"The model's name."},"reviewed":{"type":"integer","title":"Reviewed","description":"Decisions recorded by this call.","default":0},"total":{"type":"integer","title":"Total","description":"Past cases flagged.","default":0},"pending":{"type":"integer","title":"Pending","description":"Still waiting for your review.","default":0},"message":{"type":"string","title":"Message","description":"The same, in plain words.","default":""}},"type":"object","required":["build_id","domain"],"title":"FlaggedReviewed"},"FlaggedRow":{"properties":{"id":{"type":"string","title":"Id","description":"The case's id, used to review it."},"state":{"title":"State","description":"The case, as uploaded."},"answers":{"additionalProperties":true,"type":"object","title":"Answers","description":"Its answers, as uploaded."},"rule":{"type":"string","title":"Rule","description":"The rule it contradicts, in plain words."},"question":{"type":"string","title":"Question","description":"The question they disagree on."},"rule_answer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rule Answer","description":"The rule's answer (null for a rule that only blocks answers)."},"kind":{"type":"string","enum":["found","hard"],"title":"Kind","description":"`found` (a confirmed rule found in your history) or `hard` (one of your hard rules).","default":"found"},"status":{"type":"string","enum":["pending","follow_rule","keep","drop"],"title":"Status","description":"`pending` (not learned), `follow_rule` (learned with the rule's answer), `keep` (learned as it is) or `drop` (never learned).","default":"pending"},"why":{"type":"string","title":"Why","description":"The disagreement, in plain words.","default":""}},"type":"object","required":["id","rule","question"],"title":"FlaggedRow","description":"A past case that contradicts a rule. Not learned until you review it."},"FoundRule":{"properties":{"id":{"type":"string","title":"Id","description":"Its id (`fr_1`…), used to confirm or reject it."},"sentence":{"type":"string","title":"Sentence","description":"The rule in plain words."},"question":{"type":"string","title":"Question","description":"The question it answers."},"answer":{"type":"string","title":"Answer","description":"The answer it gives where it applies."},"support":{"type":"integer","title":"Support","description":"Your past cases it applies to.","default":0},"agreement":{"type":"number","title":"Agreement","description":"How often those cases had its answer (0-1).","default":0.0},"statement":{"type":"string","title":"Statement","description":"\"Escalate refunds over 500: true in 97% of the 4,000 past cases it applies to.\"","default":""},"status":{"type":"string","enum":["proposed","confirmed","rejected"],"title":"Status","description":"`proposed` (not used unless you confirm it), `confirmed` (your model follows it) or `rejected`.","default":"proposed"},"hard":{"type":"boolean","title":"Hard","description":"Confirmed as a hard rule: enforced on every decision, like your rules.","default":false},"can_be_hard":{"type":"boolean","title":"Can Be Hard","description":"Whether it can be a hard rule (it answers the Choice question your hard rules apply to).","default":false},"changes":{"$ref":"#/components/schemas/FoundRuleChanges","description":"What confirming it changes in the situations your model learns from."}},"type":"object","required":["id","sentence","question","answer"],"title":"FoundRule","description":"A rule found in your history, for you to confirm or reject."},"FoundRuleChanges":{"properties":{"situations":{"type":"integer","title":"Situations","description":"Situations whose answer confirming it changes.","default":0},"of":{"type":"integer","title":"Of","description":"Situations looked at.","default":0},"statement":{"type":"string","title":"Statement","description":"\"Changes 120 of 30,000 situations: approve → escalate.\"","default":""}},"type":"object","title":"FoundRuleChanges"},"FoundRuleDecision":{"properties":{"id":{"type":"string","title":"Id","description":"The rule's id (`fr_1`…)."},"decision":{"type":"string","enum":["confirm","reject"],"title":"Decision","description":"`confirm` (your model follows it) or `reject`."},"hard":{"type":"boolean","title":"Hard","description":"With confirm: also enforce it on every decision, like your rules (only when `can_be_hard`).","default":false}},"type":"object","required":["id","decision"],"title":"FoundRuleDecision"},"FoundRulesRequest":{"properties":{"rules":{"items":{"$ref":"#/components/schemas/FoundRuleDecision"},"type":"array","minItems":1,"title":"Rules","description":"Your decision on each rule."}},"type":"object","required":["rules"],"title":"FoundRulesRequest","examples":[{"rules":[{"decision":"confirm","hard":true,"id":"fr_1"},{"decision":"reject","id":"fr_2"}]}]},"GameInfo":{"properties":{"connected":{"type":"boolean","title":"Connected","description":"Whether a game is connected."},"moves":{"items":{"type":"string"},"type":"array","title":"Moves","description":"The moves your game allows."},"episodes":{"type":"integer","title":"Episodes","description":"Games per training run.","default":30},"max_steps":{"type":"integer","title":"Max Steps","description":"Step limit per game.","default":300},"effort":{"type":"string","enum":["fast","balanced","thorough"],"title":"Effort","description":"Training effort.","default":"balanced"},"checked_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Checked At","description":"When the code was last checked (ISO 8601)."}},"type":"object","required":["connected"],"title":"GameInfo"},"GameSetup":{"properties":{"code":{"type":"string","maxLength":200000,"minLength":10,"title":"Code","description":"Python defining initial_state(seed), legal_moves(state), step(state, move) -> (next_state, reward, done); optional features(state, move) -> {name: number} (facts your game already computes about a move) and score(state) -> number (your game's own score)."},"episodes":{"type":"integer","maximum":200.0,"minimum":5.0,"title":"Episodes","description":"Games per training run.","default":30},"max_steps":{"type":"integer","maximum":5000.0,"minimum":10.0,"title":"Max Steps","description":"Step limit per game.","default":300},"effort":{"type":"string","enum":["fast","balanced","thorough"],"title":"Effort","description":"Training effort: thorough takes longer and usually plays better.","default":"balanced"}},"type":"object","required":["code"],"title":"GameSetup"},"GameSummary":{"properties":{"games":{"type":"integer","title":"Games","description":"Test games played."},"avg_score":{"type":"number","title":"Avg Score","description":"Average score of the new bot."},"avg_steps":{"type":"number","title":"Avg Steps","description":"Average game length."},"random_avg_score":{"type":"number","title":"Random Avg Score","description":"Average score of random moves, for comparison."},"previous_avg_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Previous Avg Score","description":"The previous version's average score."},"max_steps":{"type":"integer","title":"Max Steps","description":"The step limit per game."}},"type":"object","required":["games","avg_score","avg_steps","random_avg_score","max_steps"],"title":"GameSummary"},"Gate":{"properties":{"against_version":{"type":"integer","title":"Against Version","description":"The serving version it was compared with."},"tolerance":{"type":"number","title":"Tolerance","description":"How much less accurate (0.005 = half a point, or one case's worth on small sets) a new version may be on unchanged cases."},"passed":{"type":"boolean","title":"Passed","description":"true: never worse on any check. false: kept as a candidate, not promoted."},"measured_on":{"anyOf":[{"type":"string","enum":["your_cases","starter_cases","situations"]},{"type":"null"}],"title":"Measured On","description":"What the comparison was measured on: `your_cases` once every question has enough of your own held-back cases (then only those, never examples we made), else `situations` or `starter_cases`. Added Sep 29."},"checks":{"items":{"$ref":"#/components/schemas/GateCheck"},"type":"array","title":"Checks","description":"Each comparison."}},"type":"object","required":["against_version","tolerance","passed"],"title":"Gate"},"GateCheck":{"properties":{"question":{"type":"string","title":"Question","description":"The question id."},"language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Language","description":"null: all held-back cases; else one strong language."},"cases":{"type":"integer","title":"Cases","description":"Held-back cases compared."},"previous":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Previous","description":"The serving version's accuracy on them."},"new":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"New","description":"The new version's accuracy on them."},"ok":{"type":"boolean","title":"Ok","description":"false: the new version is worse here by more than the tolerance."},"measured_on":{"anyOf":[{"type":"string","enum":["your_cases","starter_cases","situations"]},{"type":"null"}],"title":"Measured On","description":"What the two versions were compared on: `your_cases` (your own held-back cases, never learned by either), or, before there are enough of those, `situations` (held-back examples of situations) or `starter_cases`. Added Sep 29."}},"type":"object","required":["question","cases","ok"],"title":"GateCheck"},"Graduation":{"properties":{"min_outcomes":{"type":"integer","minimum":1.0,"title":"Min Outcomes","description":"Outcomes a day-one question needs before it switches to your own model.","default":1000},"auto":{"type":"boolean","title":"Auto","description":"Switch automatically once a question has `min_outcomes` (false: you decide when to train).","default":true}},"type":"object","title":"Graduation"},"GraduationRow":{"properties":{"question":{"type":"string","title":"Question","description":"The question id."},"status":{"type":"string","enum":["trained","fallback"],"title":"Status","description":"`trained` or `fallback` (day-one)."},"outcomes":{"type":"integer","title":"Outcomes","description":"Outcomes it has."},"needed":{"type":"integer","title":"Needed","description":"More needed before it switches to your own model."}},"type":"object","required":["question","status","outcomes","needed"],"title":"GraduationRow"},"GraduationStatus":{"properties":{"questions":{"additionalProperties":{"$ref":"#/components/schemas/QuestionStatus"},"type":"object","title":"Questions","description":"Per question: trained or day-one, and progress."},"min_outcomes":{"type":"integer","title":"Min Outcomes","description":"Outcomes a day-one question needs."},"auto":{"type":"boolean","title":"Auto","description":"Whether questions switch automatically."},"paused":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Paused","description":"Set when a question was ready to switch but training is paused (no active subscription): what to do."}},"type":"object","required":["questions","min_outcomes","auto"],"title":"GraduationStatus"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"Health":{"properties":{"ok":{"type":"boolean","title":"Ok","description":"true when the service is up."},"version":{"type":"string","title":"Version","description":"The API version."}},"type":"object","required":["ok","version"],"title":"Health"},"HealthDetail":{"properties":{"ok":{"type":"boolean","title":"Ok","description":"false only when the service can't work (its database is down)."},"status":{"type":"string","enum":["ok","degraded","down"],"title":"Status","description":"The worst of the checks that matter."},"version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Version","description":"The API version (with the operators' admin key only)."},"checks":{"anyOf":[{"additionalProperties":{"$ref":"#/components/schemas/DependencyStatus"},"type":"object"},{"type":"null"}],"title":"Checks","description":"database, queue, reader, translator, backup, email (with the operators' admin key only)."}},"type":"object","required":["ok","status"],"title":"HealthDetail"},"HistoryLanguage":{"properties":{"language":{"type":"string","title":"Language","description":"ISO 639-1 code."},"name":{"type":"string","title":"Name","description":"The language's name."},"cases":{"type":"integer","title":"Cases","description":"Past cases in it."},"share":{"type":"number","title":"Share","description":"Share of the past cases whose language could be told."}},"type":"object","required":["language","name","cases","share"],"title":"HistoryLanguage"},"Improvement":{"properties":{"rank":{"type":"integer","title":"Rank","description":"1 = the biggest estimated gain."},"kind":{"type":"string","enum":["more_cases","clarify_rule","add_option","more_language_cases","fix_history"],"title":"Kind","description":"`more_cases` (accuracy is still climbing with more cases: upload more), `clarify_rule` (cases on a boundary: say once which way they go), `add_option` (cases fit no option), `more_language_cases` (a language below the bar: upload cases written in it) or `fix_history` (the same situation was resolved differently: confirm the right answer)."},"question":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Question","description":"The question it's about, if one."},"title":{"type":"string","title":"Title","description":"The item in a line."},"detail":{"type":"string","title":"Detail","description":"What to do and why."},"estimated_gain_points":{"type":"number","title":"Estimated Gain Points","description":"Estimated accuracy gain, in points, on your held-back cases."},"examples":{"items":{"$ref":"#/components/schemas/ExampleCase"},"type":"array","title":"Examples","description":"Real cases it's about."},"fix":{"anyOf":[{"$ref":"#/components/schemas/Fix"},{"type":"null"}],"description":"The API call that acts on it."}},"type":"object","required":["rank","kind","title","detail","estimated_gain_points"],"title":"Improvement"},"Job":{"properties":{"id":{"type":"string","title":"Id","description":"Job id (`job_…`): poll GET /v1/jobs/{job_id}."},"build_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Build Id","description":"A model made with POST /v1/build retrains as a build: follow GET /v1/build/{build_id} (the before and after for the areas it worked on are in its `retrain`)."},"domain":{"type":"string","title":"Domain","description":"The domain's name."},"kind":{"type":"string","enum":["train","option","graduation","multilingual","starter","build"],"title":"Kind","description":"`train` (POST …/train), `option` (POST …/options), `graduation` (a day-one question switching to your own model), `multilingual` (the version that reads about 100 languages, built in the background when your past cases call for one) or `starter` (getting a question that reads text ready for its starter model, so the first training run is quick; it makes no version) or `build` (POST /v1/build: preparing a model from your example; it makes no version itself: follow GET /v1/build/{build_id})."},"status":{"type":"string","enum":["queued","running","done","failed"],"title":"Status","description":"Where it is. `done` has a `version` and a `report`."},"created_at":{"type":"string","title":"Created At","description":"ISO 8601."},"finished_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Finished At","description":"ISO 8601, once done or failed."},"version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version","description":"The version it made."},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message","description":"What happened, in plain words (e.g. \"Version 3 is serving.\")."},"report":{"anyOf":[{"$ref":"#/components/schemas/Report"},{"type":"null"}],"description":"The training report."},"attempts":{"type":"integer","title":"Attempts","description":"How many times a worker has started it (a job is retried after a problem on our side).","default":0},"queue_position":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Queue Position","description":"While queued: 1 = next."}},"type":"object","required":["id","domain","kind","status","created_at"],"title":"Job","description":"A training job: a new version, a new option, a day-one question switching to your own model, or the version\nthat reads about 100 languages."},"KeyCreate":{"properties":{"name":{"type":"string","maxLength":80,"title":"Name","description":"A name to recognise the key by, e.g. `production`.","default":"default"}},"type":"object","title":"KeyCreate"},"KeyList":{"properties":{"keys":{"items":{"$ref":"#/components/schemas/ApiKeyInfo"},"type":"array","title":"Keys","description":"Every key in the workspace (never the key itself)."}},"type":"object","required":["keys"],"title":"KeyList"},"KeyRotate":{"properties":{"grace_hours":{"type":"number","maximum":168.0,"minimum":0.0,"title":"Grace Hours","description":"Keep the old key working this long (0: revoke it now).","default":0}},"type":"object","title":"KeyRotate"},"LanguageAccuracy":{"properties":{"language":{"type":"string","title":"Language","description":"ISO 639-1 code."},"name":{"type":"string","title":"Name","description":"The language's name."},"cases":{"type":"integer","title":"Cases","description":"Held-back cases in it."},"english_reader":{"type":"number","title":"English Reader","description":"Accuracy of the version that reads English."},"multilingual_reader":{"type":"number","title":"Multilingual Reader","description":"Accuracy of the version that reads about 100 languages."}},"type":"object","required":["language","name","cases","english_reader","multilingual_reader"],"title":"LanguageAccuracy"},"LanguageName":{"properties":{"language":{"type":"string","title":"Language","description":"ISO 639-1 code."},"name":{"type":"string","title":"Name","description":"The language's name."}},"type":"object","required":["language","name"],"title":"LanguageName"},"LinkRequest":{"properties":{"email":{"type":"string","maxLength":254,"minLength":3,"title":"Email","description":"Your account's email address."}},"type":"object","required":["email"],"title":"LinkRequest"},"LoginRequest":{"properties":{"email":{"type":"string","title":"Email","description":"Your account's email address."},"password":{"type":"string","title":"Password","description":"Your password."}},"type":"object","required":["email","password"],"title":"LoginRequest"},"LoginResponse":{"properties":{"token":{"type":"string","title":"Token","description":"A console session token, used as a Bearer key."},"expires_at":{"type":"string","title":"Expires At","description":"When the session ends (ISO 8601)."}},"type":"object","required":["token","expires_at"],"title":"LoginResponse"},"MarkWrongRequest":{"properties":{"answers":{"additionalProperties":true,"type":"object","title":"Answers","description":"The right answer, per question."},"action":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Action","description":"Shortcut: the right answer to the decision question."},"note":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Note","description":"Optional: why, for your own records."}},"type":"object","title":"MarkWrongRequest","examples":[{"answers":{"action":"escalate"}},{"action":"escalate","note":"over the limit"}]},"MarkedWrong":{"properties":{"recorded":{"type":"boolean","title":"Recorded","description":"true.","default":true},"decision_id":{"type":"string","title":"Decision Id","description":"The decision."},"domain":{"type":"string","title":"Domain","description":"The model's name."},"answers":{"additionalProperties":true,"type":"object","title":"Answers","description":"The right answers, as recorded."},"message":{"type":"string","title":"Message","description":"What happens next, in plain words.","default":""}},"type":"object","required":["decision_id","domain"],"title":"MarkedWrong"},"ModelCard":{"properties":{"name":{"type":"string","title":"Name","description":"`<domain>@<version>` of the serving version."},"description":{"type":"string","title":"Description","description":"The domain's description and how many questions are trained."},"release_date":{"type":"string","title":"Release Date","description":"When that version was made (YYYY-MM-DD)."}},"type":"object","required":["name","description","release_date"],"title":"ModelCard"},"NoulAnswer":{"properties":{"type":{"type":"string","const":"noul","title":"Type","description":"`noul`."},"noul":{"type":"number","title":"Noul","description":"The probability, from 0 to 1, that the statement is true."},"source":{"type":"string","enum":["trained","translated","fallback","rule","backup","local_fallback"],"title":"Source","description":"How it was decided: `trained` (your model), `translated` (your model, after the message was translated to English because it was below the safety bar or in a language the model isn't strong in), `fallback` (your day-one backend), `rule` (your rules leave one option), `backup` (still below the safety bar after translation: our hosted backup answered from your allowed options, with your rules applied) or `local_fallback` (a downloaded model, offline: your own fallback function answered; only on cases synced from a device)."},"route":{"anyOf":[{"type":"string","enum":["act","review"]},{"type":"null"}],"title":"Route","description":"`act`: an automatic answer (at or above the model's safety bar). `review`: below the bar after every check; held for a person (it's in the unsure queue)."}},"type":"object","required":["type","noul","source"],"title":"NoulAnswer"},"NoulCriteria":{"properties":{"true":{"title":"True","description":"What `true` means."},"false":{"title":"False","description":"What `false` means."}},"additionalProperties":true,"type":"object","title":"NoulCriteria"},"NoulQuestion":{"properties":{"type":{"type":"string","const":"noul","title":"Type","description":"`noul`: the probability that a statement is true."},"instructions":{"title":"Instructions","description":"What the question asks, as you'd tell a person (text, a JSON object or array)."},"criteria":{"anyOf":[{"$ref":"#/components/schemas/NoulCriteria"},{"type":"null"}],"description":"What true and false mean (optional)."}},"additionalProperties":true,"type":"object","required":["type"],"title":"NoulQuestion","description":"How likely a yes-or-no statement is true (Jev's Noul)."},"OfflineCase":{"properties":{"id":{"type":"string","title":"Id","description":"The id the runtime gave the case (e.g. `loc_3f9a…`; 8-64 letters, digits, `_` or `-`). Sending the same id again changes nothing. Report its outcome with this id, or with its `decision_ids` entry."},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At","description":"When the device decided it (ISO 8601). Default: now."},"model":{"type":"string","title":"Model","description":"The downloaded version that decided it, e.g. `bank-support@3`. Its name must be this domain's."},"state":{"title":"State","description":"The case, as it was decided."},"questions":{"anyOf":[{"additionalProperties":{"additionalProperties":true,"type":"object"},"type":"object"},{"type":"null"}],"title":"Questions","description":"The questions it was asked, in TypeSafe's format (question id -> definition). Omitted: the domain's."},"answers":{"additionalProperties":{"additionalProperties":true,"type":"object"},"type":"object","title":"Answers","description":"The answers the device gave (Choice / Score / Noul, with `source` `trained`, `rule` or `local_fallback`, and `route`)."},"decision":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Decision","description":"The decision block the device gave, if any."},"language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Language","description":"The language the device detected, if any."},"routed":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Routed","description":"The questions that needed a second look (a language the model isn't strong in, or below its safety bar)."},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source","description":"`local_fallback` when your own fallback answered the routed questions, else `review` (held for a person)."}},"type":"object","required":["id","model","answers"],"title":"OfflineCase","description":"One case a downloaded model saved while it couldn't reach the hosted service, as the runtime wrote it."},"OfflineCaseRejected":{"properties":{"id":{"type":"string","title":"Id","description":"The case's id."},"reason":{"type":"string","title":"Reason","description":"Why it wasn't stored, in plain words. It stays on the device."}},"type":"object","required":["id","reason"],"title":"OfflineCaseRejected"},"OfflineCases":{"properties":{"cases":{"items":{"$ref":"#/components/schemas/OfflineCase"},"type":"array","minItems":1,"title":"Cases","description":"Up to 100 cases per request (the runtime sends batches)."}},"type":"object","required":["cases"],"title":"OfflineCases","description":"Cases saved while offline. The runtime sends them for you (`model.sync()`, `canonopy-runtime sync`).","examples":[{"cases":[{"answers":{"action":{"choice":"card-delivery","confidence":0.62,"probabilities":{"card-delivery":0.62,"lost-card":0.38},"route":"review","source":"trained","type":"choice"}},"created_at":"2026-09-27T10:15:00Z","id":"loc_3f9a1c2b7d8e4f5a6b7c8d9e","model":"bank-support@3","routed":["action"],"source":"review","state":{"amount":0,"message":"Mi tarjeta no llega"}}]}]},"OfflineCasesResult":{"properties":{"accepted":{"items":{"type":"string"},"type":"array","title":"Accepted","description":"Ids stored now. The runtime removes them from the device."},"already_there":{"items":{"type":"string"},"type":"array","title":"Already There","description":"Ids stored by an earlier sync: nothing changed. The runtime removes them from the device too."},"rejected":{"items":{"$ref":"#/components/schemas/OfflineCaseRejected"},"type":"array","title":"Rejected","description":"Cases not stored, and why. They stay on the device."},"decision_ids":{"additionalProperties":{"type":"string"},"type":"object","title":"Decision Ids","description":"Case id -> its decision id here. Outcomes can use either."},"held":{"type":"integer","title":"Held","description":"Of the accepted cases, how many are held for a person (the unsure queue). Our hosted backup may answer some of them in the next seconds; the rest wait for you."}},"type":"object","required":["accepted","already_there","rejected","decision_ids","held"],"title":"OfflineCasesResult"},"OptionRequest":{"properties":{"question":{"type":"string","title":"Question","description":"The Choice question to add it to."},"option":{"type":"string","pattern":"^[A-Za-z0-9_\\-. ]{1,80}$","title":"Option","description":"The new option's label."},"description":{"title":"Description","description":"What the option means, as you'd write a Choice criterion."},"when":{"anyOf":[{"type":"string","maxLength":4000},{"type":"null"}],"title":"When","description":"When this option is the right one, in plain words."},"never_when":{"anyOf":[{"items":{"$ref":"#/components/schemas/Condition"},"type":"array"},{"type":"null"}],"title":"Never When","description":"Conditions under which the option must never be chosen (adds a rule)."},"also_allowed_under":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Also Allowed Under","description":"Ids of `allow_only` rules that should also allow the new action."},"promote":{"type":"string","enum":["auto","always","never"],"title":"Promote","description":"`auto` (default): put the new version in service when the report recommends it. `always`: put it in service anyway. `never`: keep it as a candidate; promote it yourself with POST …/promote.","default":"auto"},"wait":{"type":"boolean","title":"Wait","description":"Wait for the new version instead of returning a job to poll.","default":true}},"type":"object","required":["question","option","description"],"title":"OptionRequest","description":"A new option for a Choice question (a new action, when it's the decision question).","examples":[{"description":"offer store credit instead of a refund","option":"store-credit","question":"action","when":"reason is changed_mind and tier is pro"},{"also_allowed_under":["fraud-goes-to-the-fraud-team"],"description":"freeze the whole account, including the app and all cards","never_when":[{"field":"new_device_login_24h","op":"is_false"}],"option":"freeze-account","promote":"auto","question":"action","wait":true,"when":"topic is lost_stolen or unrecognised and new_device_login_24h is true"}]},"Org":{"properties":{"id":{"type":"string","title":"Id","description":"Workspace id (`org_…`)."},"name":{"type":"string","title":"Name","description":"Workspace name."},"plan":{"type":"string","title":"Plan","description":"The plan id."}},"type":"object","required":["id","name","plan"],"title":"Org"},"OutcomeRequest":{"properties":{"decision_id":{"type":"string","title":"Decision Id","description":"The `id` from the decision's answer."},"answers":{"additionalProperties":true,"type":"object","title":"Answers","description":"What really happened, per question: an option label, a level number, or true/false."},"action":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Action","description":"Shorthand for the decision question's answer."}},"type":"object","required":["decision_id"],"title":"OutcomeRequest","description":"What really happened on a decision.","examples":[{"action":"escalate","decision_id":"dec_4f1c2a9b0e7d6a51"},{"action":"block-card","answers":{"needs_human":false,"urgency":2},"decision_id":"dec_4f1c2a9b0e7d6a51"}]},"Plan":{"properties":{"name":{"type":"string","title":"Name","description":"The plan's name."},"price_usd_per_month":{"type":"number","title":"Price Usd Per Month","description":"The price per workspace per month, in US dollars: flat, however many decision models you have."},"price_usd_per_domain_month":{"type":"number","title":"Price Usd Per Domain Month","description":"Deprecated: the same flat monthly price as `price_usd_per_month`, kept for older clients. The price doesn't count decision models."},"billing":{"type":"string","title":"Billing","description":"How it's billed, in words."},"included":{"items":{"type":"string"},"type":"array","title":"Included","description":"What the price includes."},"rate_limit_per_second":{"type":"integer","title":"Rate Limit Per Second","description":"Fair-use limit on the hosted endpoint, per key."}},"type":"object","required":["name","price_usd_per_month","price_usd_per_domain_month","billing","included","rate_limit_per_second"],"title":"Plan"},"PlayRecorded":{"properties":{"id":{"type":"string","title":"Id","description":"The run (`ply_…`)."},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At","description":"ISO 8601."},"model":{"type":"string","title":"Model","description":"The version played.","default":""},"version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version","description":"Its number."},"episodes":{"type":"integer","title":"Episodes","description":"Episodes in the run."},"summary":{"additionalProperties":{"additionalProperties":{"type":"number"},"type":"object"},"type":"object","title":"Summary","description":"Per number your program printed: mean, min, max and how many episodes had it."},"situations_saved":{"type":"integer","title":"Situations Saved","description":"Situations sent with it.","default":0},"learned":{"type":"boolean","title":"Learned","description":"Its situations were learned in a retrain.","default":false},"statement":{"type":"string","title":"Statement","description":"The run in plain words.","default":""},"domain":{"type":"string","title":"Domain","description":"The model's name."},"next_step":{"type":"string","title":"Next Step","description":"What to do next, in plain words.","default":""}},"type":"object","required":["id","episodes","domain"],"title":"PlayRecorded"},"PlayResultsRequest":{"properties":{"model":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Model","description":"The version played, e.g. `doom-bot@3`."},"episodes":{"items":{"additionalProperties":true,"type":"object"},"type":"array","maxItems":1000,"minItems":1,"title":"Episodes","description":"One object per episode, as your program printed it: numbers (or true/false) only, e.g. {\"score\": 1240, \"deaths\": 1, \"stuck\": 0}. Other values are ignored."},"situations":{"anyOf":[{"items":{},"type":"array","maxItems":300},{"type":"null"}],"title":"Situations","description":"Optional: a sample of the states your game sent while it played (`canonopy playtest --keep-situations`). The next retrain of a model built from your JSON learns them."}},"type":"object","required":["episodes"],"title":"PlayResultsRequest","examples":[{"episodes":[{"deaths":1,"score":1240,"stuck":0},{"deaths":2,"score":980,"stuck":1}],"model":"doom-bot@3"}]},"PlayRun":{"properties":{"id":{"type":"string","title":"Id","description":"The run (`ply_…`)."},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At","description":"ISO 8601."},"model":{"type":"string","title":"Model","description":"The version played.","default":""},"version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version","description":"Its number."},"episodes":{"type":"integer","title":"Episodes","description":"Episodes in the run."},"summary":{"additionalProperties":{"additionalProperties":{"type":"number"},"type":"object"},"type":"object","title":"Summary","description":"Per number your program printed: mean, min, max and how many episodes had it."},"situations_saved":{"type":"integer","title":"Situations Saved","description":"Situations sent with it.","default":0},"learned":{"type":"boolean","title":"Learned","description":"Its situations were learned in a retrain.","default":false},"statement":{"type":"string","title":"Statement","description":"The run in plain words.","default":""}},"type":"object","required":["id","episodes"],"title":"PlayRun"},"PlayRuns":{"properties":{"domain":{"type":"string","title":"Domain","description":"The model's name."},"runs":{"items":{"$ref":"#/components/schemas/PlayRun"},"type":"array","title":"Runs","description":"Newest first."}},"type":"object","required":["domain"],"title":"PlayRuns"},"Progress":{"properties":{"domain":{"type":"string","title":"Domain","description":"The domain's name."},"serving_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Serving Version","description":"The version `@latest` answers with."},"latest_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Latest Version","description":"The newest version (serving or not)."},"waiting":{"$ref":"#/components/schemas/ProgressWaiting","description":"New cases since the latest version, by source."},"versions":{"items":{"$ref":"#/components/schemas/ProgressVersion"},"type":"array","title":"Versions","description":"Every version, newest first."},"min_live_outcomes":{"type":"integer","title":"Min Live Outcomes","description":"Reported outcomes a version needs before its agreement is shown."},"advice":{"items":{"$ref":"#/components/schemas/Advice"},"type":"array","title":"Advice","description":"What would improve your model most, in plain words (the same as GET /v1/domains/{domain}/advice)."},"spot_checked":{"anyOf":[{"$ref":"#/components/schemas/SpotChecked"},{"type":"null"}],"description":"Spot checks: how often your model was right on the confident decisions people checked (null until some are answered)."}},"type":"object","required":["domain","waiting","versions","min_live_outcomes"],"title":"Progress","description":"How a decision model is improving, and what's waiting for its next retrain. Read-only: retraining is always\nyour call (POST /v1/domains/{domain}/train)."},"ProgressLive":{"properties":{"outcomes":{"type":"integer","title":"Outcomes","description":"Reported outcomes on decisions this version made (answered by the model itself)."},"agreement":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Agreement","description":"Share of those answers that matched (null below `min_live_outcomes`)."},"questions":{"items":{"$ref":"#/components/schemas/ProgressLiveQuestion"},"type":"array","title":"Questions","description":"The same, per question."},"statement":{"type":"string","title":"Statement","description":"In plain words."}},"type":"object","required":["outcomes","statement"],"title":"ProgressLive","description":"How a version's own answers compared with the outcomes you reported for its decisions."},"ProgressLiveQuestion":{"properties":{"question":{"type":"string","title":"Question","description":"The question id."},"outcomes":{"type":"integer","title":"Outcomes","description":"Reported outcomes for this question on decisions this version made."},"agreement":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Agreement","description":"How often its answer matched them (null below `min_live_outcomes`)."}},"type":"object","required":["question","outcomes"],"title":"ProgressLiveQuestion"},"ProgressQuestion":{"properties":{"question":{"type":"string","title":"Question","description":"The question id."},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"`trained` or `fallback` (day-one mode) in this version."},"accuracy":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Accuracy","description":"Measured accuracy on held-back cases (see `measured_on`)."},"held_back_cases":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Held Back Cases","description":"How many held-back cases it was measured on."},"measured_on":{"anyOf":[{"type":"string","enum":["your_cases","starter_cases","situations"]},{"type":"null"}],"title":"Measured On","description":"`your_cases` (your own held-back cases), `starter_cases` (a starter model: measured on starter example cases, not your own) or `situations` (a model made with POST /v1/build: held-back examples of situations for your questions)."},"change_points":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Change Points","description":"Change in accuracy against `compared_with`, in points."},"compared_with":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Compared With","description":"The version the change is against."},"comparison":{"anyOf":[{"type":"string","enum":["same_cases","own_held_back","not_comparable"]},{"type":"null"}],"title":"Comparison","description":"How the change was measured: `same_cases` (both versions on this version's held-back cases: the headline number), `own_held_back` (each version on its own held-back cases), `not_comparable` (one of them was measured on starter example cases: no change shown). Null for a question's first version."}},"type":"object","required":["question"],"title":"ProgressQuestion"},"ProgressSource":{"properties":{"source":{"type":"string","enum":["uploads","outcomes","unsure_answers","backup_answers","offline","signoff","marked_wrong"],"title":"Source","description":"Where the cases came from: `uploads` (uploaded past cases), `outcomes` (reported outcomes), `unsure_answers` (unsure cases you answered), `backup_answers` (unsure cases our backup answered), `offline` (cases a downloaded model saved while offline, synced later and answered), `signoff` (examples you corrected) or `marked_wrong` (decisions you marked wrong, with the right answer)."},"label":{"type":"string","title":"Label","description":"The same, in plain words."},"cases":{"type":"integer","title":"Cases","description":"How many new cases from this source the next retrain learns from."}},"type":"object","required":["source","label","cases"],"title":"ProgressSource"},"ProgressTraining":{"properties":{"job_id":{"type":"string","title":"Job Id","description":"The job (`job_…`): poll GET /v1/jobs/{job_id}."},"status":{"type":"string","enum":["queued","running"],"title":"Status","description":"Where it is."},"kind":{"type":"string","title":"Kind","description":"The job's kind (`train`, `option`, `graduation` or `multilingual`)."}},"type":"object","required":["job_id","status","kind"],"title":"ProgressTraining"},"ProgressVersion":{"properties":{"version":{"type":"integer","title":"Version","description":"The version number."},"created_at":{"type":"string","title":"Created At","description":"ISO 8601."},"status":{"type":"string","enum":["serving","candidate","retired"],"title":"Status","description":"`serving`, `candidate` or `retired`."},"kind":{"type":"string","title":"Kind","description":"How it was made: `train`, `option`, `graduation`, `imported` or `multilingual`."},"cases":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Cases","description":"Your own cases it learned from (null when unknown)."},"starter_cases":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Starter Cases","description":"Starter cases it also learned from (null when unknown)."},"starter":{"type":"boolean","title":"Starter","description":"True for a starter model: its accuracy is on starter example cases, not your own.","default":false},"questions":{"items":{"$ref":"#/components/schemas/ProgressQuestion"},"type":"array","title":"Questions","description":"Measured accuracy per question, and the change against the version before."},"live":{"anyOf":[{"$ref":"#/components/schemas/ProgressLive"},{"type":"null"}],"description":"Agreement with your reported outcomes (null: none yet)."},"notes":{"items":{"type":"string"},"type":"array","title":"Notes","description":"How to read its numbers, in plain words."}},"type":"object","required":["version","created_at","status","kind","questions"],"title":"ProgressVersion"},"ProgressWaiting":{"properties":{"since_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Since Version","description":"The latest version (null: no version yet, so every case counts)."},"since":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Since","description":"ISO 8601: when that version gathered its cases."},"total":{"type":"integer","title":"Total","description":"New cases since then, all sources together."},"sources":{"items":{"$ref":"#/components/schemas/ProgressSource"},"type":"array","title":"Sources","description":"The same, by where they came from (every source, zeros included)."},"differed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Differed","description":"Of the new outcomes and answered unsure cases, how many differ from the answer the model gave (the most useful cases to learn from). Null when none could be compared (e.g. only uploads, which it never answered)."},"compared":{"type":"integer","title":"Compared","description":"How many new cases `differed` was counted over: those with an answer given by the model and a real outcome for the same question.","default":0},"removed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Removed","description":"Cases deleted since that version (null when unknown)."},"statement":{"type":"string","title":"Statement","description":"In plain words, e.g. \"48 new cases since version 4, 12 where the real outcome differed from its answer. Retrain to learn from them.\""},"training":{"anyOf":[{"$ref":"#/components/schemas/ProgressTraining"},{"type":"null"}],"description":"A training job already queued or running for this model (it learns from these cases)."}},"type":"object","required":["total","sources","statement"],"title":"ProgressWaiting","description":"The cases the next retrain learns from that the latest version hasn't seen yet."},"PromoteRequest":{"properties":{"version":{"type":"integer","title":"Version","description":"The version to serve (an older one to roll back)."}},"type":"object","required":["version"],"title":"PromoteRequest","examples":[{"version":3}]},"PromoteResponse":{"properties":{"serving_version":{"type":"integer","title":"Serving Version","description":"The version `@latest` now answers with."}},"type":"object","required":["serving_version"],"title":"PromoteResponse"},"QuestionStatus":{"properties":{"status":{"type":"string","enum":["trained","fallback"],"title":"Status","description":"`trained`: your own model answers. `fallback`: your day-one backend answers until it graduates."},"version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version","description":"The version that answers it, when trained."},"outcomes":{"type":"integer","title":"Outcomes","description":"Cases with a known answer for this question.","default":0},"needed":{"type":"integer","title":"Needed","description":"More outcomes needed before it switches to your own model (0 when trained).","default":0}},"type":"object","required":["status"],"title":"QuestionStatus"},"RareSituations":{"properties":{"accuracy":{"type":"number","title":"Accuracy","description":"Accuracy on the rare situations it was tested on."}},"type":"object","required":["accuracy"],"title":"RareSituations"},"ReaderAccuracy":{"properties":{"cases":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Cases","description":"Held-back cases compared."},"english_reader":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"English Reader","description":"Accuracy of the version that reads English."},"multilingual_reader":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Multilingual Reader","description":"Accuracy of the version that reads about 100 languages."}},"type":"object","title":"ReaderAccuracy"},"ReaderBackground":{"properties":{"status":{"type":"string","enum":["queued","not_needed","promoted","kept_english"],"title":"Status","description":"The version that reads about 100 languages: queued (being built), not_needed (your cases are in English), promoted (better on your held-back cases; it serves) or kept_english (not better; the English reader keeps serving)."},"version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version","description":"That version's number, when promoted."},"statement":{"type":"string","title":"Statement","description":"In plain words."},"comparison":{"anyOf":[{"$ref":"#/components/schemas/ReaderComparison"},{"type":"null"}],"description":"The comparison, once it's done."}},"type":"object","required":["status","statement"],"title":"ReaderBackground"},"ReaderComparison":{"properties":{"cases":{"type":"integer","title":"Cases","description":"Held-back cases compared."},"overall":{"$ref":"#/components/schemas/ReaderAccuracy","description":"On all of them."},"english":{"$ref":"#/components/schemas/ReaderAccuracy","description":"On the English ones."},"other_languages":{"$ref":"#/components/schemas/ReaderAccuracy","description":"On the rest."},"languages":{"items":{"$ref":"#/components/schemas/LanguageAccuracy"},"type":"array","title":"Languages","description":"Per language."}},"type":"object","required":["cases","overall","english","other_languages"],"title":"ReaderComparison"},"ReaderInfo":{"properties":{"serving":{"type":"string","enum":["english","multilingual"],"title":"Serving","description":"english: reads English; other languages are translated to English before it decides. multilingual: reads about 100 languages."},"statement":{"type":"string","title":"Statement","description":"In plain words."},"history_languages":{"items":{"$ref":"#/components/schemas/HistoryLanguage"},"type":"array","title":"History Languages","description":"The languages in your past cases."},"background":{"anyOf":[{"$ref":"#/components/schemas/ReaderBackground"},{"type":"null"}],"description":"The version that reads about 100 languages, when your cases call for one."}},"type":"object","required":["serving","statement"],"title":"ReaderInfo"},"Recommendation":{"properties":{"action":{"type":"string","enum":["promote","keep"],"title":"Action","description":"`promote` (put this version in service) or `keep` (keep the serving one)."},"reason":{"type":"string","title":"Reason","description":"Why, in plain words."}},"type":"object","required":["action","reason"],"title":"Recommendation"},"Recorded":{"properties":{"recorded":{"type":"boolean","title":"Recorded","description":"true when it was recorded."},"decision_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Decision Id","description":"The decision it was about."},"graduation":{"anyOf":[{"additionalProperties":{"$ref":"#/components/schemas/QuestionStatus"},"type":"object"},{"type":"null"}],"title":"Graduation","description":"Day-one progress of the questions this outcome counted for."}},"type":"object","required":["recorded"],"title":"Recorded"},"Remaining":{"properties":{"total_cases":{"type":"integer","title":"Total Cases","description":"Cases the next version would learn from."},"from_uploads":{"type":"integer","title":"From Uploads","description":"Uploaded cases."},"from_signoff":{"type":"integer","title":"From Signoff","description":"Examples you corrected."},"from_outcomes":{"type":"integer","title":"From Outcomes","description":"Hosted decisions with a reported outcome or an unsure-queue answer."}},"type":"object","required":["total_cases","from_uploads","from_signoff","from_outcomes"],"title":"Remaining"},"RemovedCounts":{"properties":{"uploaded_cases":{"type":"integer","title":"Uploaded Cases","description":"Uploaded cases deleted."},"signoff_cases":{"type":"integer","title":"Signoff Cases","description":"Examples you corrected, deleted."},"decisions":{"type":"integer","title":"Decisions","description":"Hosted decisions deleted (with `outcomes=true`)."},"starter_cases":{"type":"integer","title":"Starter Cases","description":"Starter cases deleted (DELETE …/uploads/starter, or `starter=true`); they then stay off for this model.","default":0}},"type":"object","required":["uploaded_cases","signoff_cases","decisions"],"title":"RemovedCounts"},"Replaced":{"properties":{"cases":{"type":"integer","title":"Cases","description":"Earlier uploaded cases deleted."},"uploads":{"items":{"type":"string"},"type":"array","title":"Uploads","description":"The uploads they came from (`earlier`: cases uploaded before uploads had ids)."}},"type":"object","required":["cases"],"title":"Replaced"},"Report":{"properties":{"domain":{"type":"string","title":"Domain","description":"The domain's name."},"version":{"type":"integer","title":"Version","description":"The version it describes."},"kind":{"type":"string","title":"Kind","description":"How the version was made: `train`, `option`, `graduation`, `imported` or `multilingual`."},"created_at":{"type":"string","title":"Created At","description":"ISO 8601."},"summary":{"$ref":"#/components/schemas/ReportSummary","description":"Accuracy, calibration, rules, the never-worse check and the recommendation."},"weak_spots":{"$ref":"#/components/schemas/WeakSpots","description":"The weakest options, the most-confused pairs and day-one progress."},"improve":{"items":{"$ref":"#/components/schemas/Improvement"},"type":"array","title":"Improve","description":"What would make it better: a ranked to-do list, each with an estimated gain and the call that acts on it."},"safety_bar":{"anyOf":[{"$ref":"#/components/schemas/SafetyBar"},{"type":"null"}],"description":"The automatic safety bar this version set for itself."},"before_after":{"anyOf":[{"$ref":"#/components/schemas/BeforeAfter"},{"type":"null"}],"description":"For a new option: the serving version against the new one."},"game":{"anyOf":[{"$ref":"#/components/schemas/GameSummary"},{"type":"null"}],"description":"Game domains: how the new bot plays on test games."},"reader":{"anyOf":[{"$ref":"#/components/schemas/ReaderInfo"},{"type":"null"}],"description":"Which text reader this version uses, and why (added Sep 25)."},"cases":{"anyOf":[{"$ref":"#/components/schemas/ReportCases"},{"type":"null"}],"description":"How many cases it learned from, and what changed since the last version (added Sep 27)."},"starter":{"anyOf":[{"$ref":"#/components/schemas/ReportStarter"},{"type":"null"}],"description":"The starter model, for questions that read text and have few of your own cases yet (added Sep 27)."},"build":{"anyOf":[{"$ref":"#/components/schemas/ReportBuild"},{"type":"null"}],"description":"For a model made with POST /v1/build: how well it matches your instructions and rules on fresh situations, its size, and how long it took (added Sep 29)."},"notes":{"items":{"type":"string"},"type":"array","title":"Notes","description":"Anything else worth knowing, in plain words."}},"type":"object","required":["domain","version","kind","created_at","summary","weak_spots","improve"],"title":"Report","description":"A version's training report. Every number comes from your own held-back cases."},"ReportBuild":{"properties":{"build_id":{"type":"string","title":"Build Id","description":"The build that made this version."},"quality":{"$ref":"#/components/schemas/BuildQuality","description":"Its check on fresh situations."},"seconds":{"type":"number","title":"Seconds","description":"How long the build took, from the request to this check.","default":0.0},"situations":{"type":"integer","title":"Situations","description":"Examples of situations it learned from.","default":0},"download_bytes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Download Bytes","description":"The downloaded model's size (zip)."},"model_file_bytes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Model File Bytes","description":"The model file's size, unzipped."},"spend":{"anyOf":[{"$ref":"#/components/schemas/BuildSpend"},{"type":"null"}],"description":"What building it cost us (null when not shown)."},"retrain":{"anyOf":[{"$ref":"#/components/schemas/BuildRetrain"},{"type":"null"}],"description":"A retrain's before and after, per area it worked on."}},"type":"object","required":["build_id","quality"],"title":"ReportBuild"},"ReportCases":{"properties":{"total":{"type":"integer","title":"Total","description":"Your own cases it learned from (including its held-back cases; starter cases not included)."},"previous_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Previous Version","description":"The last version before it."},"removed_since_previous":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Removed Since Previous","description":"Earlier cases deleted since that version (null when unknown)."},"statement":{"type":"string","title":"Statement","description":"The same, in plain words."}},"type":"object","required":["total","statement"],"title":"ReportCases","description":"The cases a version learned from, and what changed since the last version."},"ReportQuestion":{"properties":{"question":{"type":"string","title":"Question","description":"The question id."},"type":{"type":"string","title":"Type","description":"`choice`, `score` or `noul`."},"status":{"type":"string","enum":["trained","fallback"],"title":"Status","description":"`trained` (your model answers it) or `fallback` (your day-one backend does, for now)."},"accuracy":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Accuracy","description":"On your held-back cases (never used for learning)."},"held_back_cases":{"type":"integer","title":"Held Back Cases","description":"How many held-back cases it was measured on.","default":0},"previous":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Previous","description":"The previous version, same held-back cases."},"day_one":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Day One","description":"Your day-one backend on the same real cases, when known."},"change_points":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Change Points","description":"Change against the previous version, in points."},"rare_situations":{"anyOf":[{"$ref":"#/components/schemas/RareSituations"},{"type":"null"}],"description":"Accuracy on rare situations it was tested on."},"note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Note","description":"Anything worth knowing, in plain words."},"measured_on":{"anyOf":[{"type":"string","enum":["your_cases","starter_cases","situations"]},{"type":"null"}],"title":"Measured On","description":"What `accuracy` was measured on: `your_cases` (your own held-back cases), `starter_cases` (a starter model with too few of your cases yet: measured on starter example cases; real accuracy appears once there are enough of yours) or `situations` (a model made with POST /v1/build, before it has enough of your own answered cases: held-back examples of situations for your questions; see the report's `build` for the check on fresh situations). Once a question has enough of your own held-back cases (about 200 answered cases), it is `your_cases`: measured on those only. Added Sep 27."}},"type":"object","required":["question","type","status"],"title":"ReportQuestion"},"ReportStarter":{"properties":{"status":{"type":"string","enum":["ready","stepping_aside","retired","off","unavailable"],"title":"Status","description":"`ready` (a starter model answers, measured on starter example cases), `stepping_aside` (measured on your own cases; starter cases still help options with few of yours), `retired` (your cases have taken over), `off` (you removed them) or `unavailable` (none this time: day-one mode until your cases arrive)."},"statement":{"type":"string","title":"Statement","description":"In plain words."},"questions":{"items":{"$ref":"#/components/schemas/ReportStarterQuestion"},"type":"array","title":"Questions","description":"Per question that reads text."}},"type":"object","required":["status","statement"],"title":"ReportStarter","description":"Questions that read text can start with a starter model on day one; it learns your wording as your own\ncases arrive, and steps aside option by option."},"ReportStarterQuestion":{"properties":{"question":{"type":"string","title":"Question","description":"A question that reads text."},"options_with_starter_cases":{"type":"integer","title":"Options With Starter Cases","description":"Options still helped by starter cases."},"options_with_your_cases":{"type":"integer","title":"Options With Your Cases","description":"Options with enough of your own cases: starter cases no longer used for them."},"your_cases_per_option":{"type":"integer","title":"Your Cases Per Option","description":"Your own cases an option needs before its starter cases step aside."}},"type":"object","required":["question","options_with_starter_cases","options_with_your_cases","your_cases_per_option"],"title":"ReportStarterQuestion"},"ReportSummary":{"properties":{"questions":{"items":{"$ref":"#/components/schemas/ReportQuestion"},"type":"array","title":"Questions","description":"Accuracy per question."},"calibration":{"items":{"$ref":"#/components/schemas/Calibration"},"type":"array","title":"Calibration","description":"Calibration per question."},"rules":{"$ref":"#/components/schemas/RulesSummary","description":"What your rules did."},"recommendation":{"$ref":"#/components/schemas/Recommendation","description":"Promote or keep, and why."},"gate":{"anyOf":[{"$ref":"#/components/schemas/Gate"},{"type":"null"}],"description":"Never worse (added Sep 25): the new version against the serving one on the same held-back cases, overall and in each strong language. A version that fails is kept, not promoted."}},"type":"object","required":["questions","calibration","rules","recommendation"],"title":"ReportSummary"},"RetrainAdded":{"properties":{"disagreements":{"type":"integer","title":"Disagreements","description":"Situations where the previous version disagreed with your instructions and rules.","default":0},"around_confusions":{"type":"integer","title":"Around Confusions","description":"More situations around the answers it confused.","default":0},"look_alikes":{"type":"integer","title":"Look Alikes","description":"More situations around the answers your hard rules depend on and their look-alikes.","default":0},"example_messages":{"type":"integer","title":"Example Messages","description":"New example messages for those kinds of text.","default":0},"hard_examples":{"type":"integer","title":"Hard Examples","description":"Hard-to-tell situations around the answers your hard rules depend on and their look-alikes, which your model learns with more weight. Added Sep 29.","default":0},"corrections":{"type":"integer","title":"Corrections","description":"Decisions you marked wrong that your instructions now follow.","default":0},"from_play":{"type":"integer","title":"From Play","description":"Situations your game hit in your playtests (sent with `canonopy playtest --keep-situations`). Added Sep 30.","default":0}},"type":"object","title":"RetrainAdded"},"RetrainArea":{"properties":{"question":{"type":"string","title":"Question","description":"The question."},"answer":{"type":"string","title":"Answer","description":"The answer the area is about."},"area":{"type":"string","title":"Area","description":"The same, in plain words."},"before":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Before","description":"The previous version's agreement there (0-1), on the same fresh situations."},"after":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"After","description":"The new version's agreement there (0-1)."},"cases":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Cases","description":"Fresh situations in the area."}},"type":"object","required":["question","answer","area"],"title":"RetrainArea"},"ReviewAnswer":{"properties":{"decision_id":{"type":"string","title":"Decision Id","description":"From the unsure queue."},"answers":{"additionalProperties":true,"type":"object","title":"Answers","description":"The right answer per question: an option label, a level number, or true/false."}},"type":"object","required":["decision_id","answers"],"title":"ReviewAnswer","description":"The right answer for a held case.","examples":[{"answers":{"action":"escalate"},"decision_id":"dec_4f1c2a9b0e7d6a51"}]},"Rule":{"properties":{"id":{"type":"string","pattern":"^[A-Za-z0-9_\\-]{1,80}$","title":"Id","description":"A short id, reported in `decision.blocked_by_rules`."},"description":{"type":"string","title":"Description","description":"The rule in plain words.","default":""},"when":{"items":{"$ref":"#/components/schemas/Condition"},"type":"array","title":"When","description":"All must hold. Conditions read state fields, or another question's answer (`answer`)."},"block":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Block","description":"Actions this rule never allows when it applies."},"allow_only":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Allow Only","description":"When it applies, only these actions are allowed."},"min_chance":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Min Chance","description":"Only for a rule on another question's answer: the chance at which it applies (default 0.15). It applies whenever the chance its conditions hold is at least this; below 0.5, a decision it changed goes to review."}},"type":"object","required":["id"],"title":"Rule","description":"A rule that can't be broken: enforced on every decision."},"RuleApplied":{"properties":{"id":{"type":"string","title":"Id","description":"Your rule's id, as in `decision.blocked_by_rules`."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Your rule in plain words, as it reads now."},"still_in_place":{"type":"boolean","title":"Still In Place","description":"false when the rule has since been removed from the decision model.","default":true},"chance":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Chance","description":"For a rule on what the message is about: the chance it applied to this case (0 to 1). Null for rules on your fields."}},"type":"object","required":["id"],"title":"RuleApplied"},"RuleCount":{"properties":{"rule":{"type":"string","title":"Rule","description":"The rule id."},"description":{"type":"string","title":"Description","description":"The rule in plain words.","default":""},"cases_matched":{"type":"integer","title":"Cases Matched","description":"Held-back cases the rule applied to."},"decisions_changed":{"type":"integer","title":"Decisions Changed","description":"Held-back cases where the rule blocked what would otherwise have been chosen."}},"type":"object","required":["rule","cases_matched","decisions_changed"],"title":"RuleCount"},"RuleOut":{"properties":{"id":{"type":"string","title":"Id","description":"The rule's id."},"description":{"type":"string","title":"Description","description":"The rule in plain words.","default":""},"when":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"When","description":"Its conditions (all must hold)."},"block":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Block","description":"Actions it never allows when it applies."},"allow_only":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Allow Only","description":"When it applies, only these actions are allowed."},"min_chance":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Chance","description":"For a rule on another question's answer: the chance at which it applies (default 0.15)."}},"type":"object","required":["id"],"title":"RuleOut"},"RulePreview":{"properties":{"rules":{"type":"string","title":"Rules","description":"Your rules as they'll be, in your words.","default":""},"previous_rules":{"type":"string","title":"Previous Rules","description":"Your rules before.","default":""},"situations":{"type":"integer","title":"Situations","description":"Situations whose answer changes.","default":0},"of":{"type":"integer","title":"Of","description":"Situations looked at.","default":0},"changes":{"items":{"$ref":"#/components/schemas/RulePreviewChange"},"type":"array","title":"Changes","description":"The changes, most common first."},"examples":{"items":{"$ref":"#/components/schemas/RulePreviewExample"},"type":"array","title":"Examples","description":"About 10 changed situations."},"statement":{"type":"string","title":"Statement","description":"\"Changes 1,240 of 30,000 situations: approve → escalate (1,100), …\"","default":""}},"type":"object","title":"RulePreview","description":"What new rules change."},"RulePreviewChange":{"properties":{"question":{"type":"string","title":"Question","description":"The question."},"from":{"type":"string","title":"From","description":"The answer before."},"to":{"type":"string","title":"To","description":"The answer with your new rules."},"situations":{"type":"integer","title":"Situations","description":"Situations that change this way.","default":0}},"type":"object","required":["question","from","to"],"title":"RulePreviewChange"},"RulePreviewExample":{"properties":{"state":{"title":"State","description":"The situation."},"before":{"additionalProperties":true,"type":"object","title":"Before","description":"The answers that change, before."},"after":{"additionalProperties":true,"type":"object","title":"After","description":"The same answers with your new rules."}},"type":"object","title":"RulePreviewExample"},"RulesChangeRequest":{"properties":{"rules":{"type":"string","maxLength":20000,"minLength":1,"title":"Rules","description":"Your rules in plain words."},"mode":{"type":"string","enum":["add","replace"],"title":"Mode","description":"`add` (to your current rules, the default) or `replace` (these are all your rules now).","default":"add"},"sign_off":{"anyOf":[{"type":"string","enum":["examples","auto"]},{"type":"null"}],"title":"Sign Off","description":"Ignored (accepted so older requests work as they are). Your model is retrained with the new rules straight away; the build's `rule_preview` and examples show what changes (review optional)."}},"type":"object","required":["rules"],"title":"RulesChangeRequest","examples":[{"rules":"Always escalate when amount is over 300."},{"mode":"replace","rules":"Never approve when amount is over 400. Always escalate when fraud_flag is true."}]},"RulesSummary":{"properties":{"violations":{"type":"integer","title":"Violations","description":"Decisions that broke a rule. Always 0: rules are enforced on every decision.","default":0},"blocked":{"items":{"$ref":"#/components/schemas/RuleCount"},"type":"array","title":"Blocked","description":"Per rule: how often it applied and changed the decision."}},"type":"object","required":["blocked"],"title":"RulesSummary"},"SafetyBar":{"properties":{"target":{"type":"number","title":"Target","description":"Automatic answers are at least this accurate (fixed: 0.97)."},"statement":{"type":"string","title":"Statement","description":"In plain words, e.g. \"Automatic answers 97%+ accurate; 78% handled automatically; the rest double-checked.\""},"questions":{"items":{"$ref":"#/components/schemas/SafetyBarQuestion"},"type":"array","title":"Questions","description":"Per question."},"languages":{"items":{"$ref":"#/components/schemas/SafetyBarLanguage"},"type":"array","title":"Languages","description":"Per language measured."},"strong_languages":{"items":{"$ref":"#/components/schemas/LanguageName"},"type":"array","title":"Strong Languages","description":"Languages answered automatically."}},"type":"object","required":["target","statement"],"title":"SafetyBar"},"SafetyBarLanguage":{"properties":{"language":{"type":"string","title":"Language","description":"ISO 639-1 code."},"name":{"type":"string","title":"Name","description":"The language's name."},"strong":{"type":"boolean","title":"Strong","description":"Answered automatically (at the bar). Other languages are always double-checked."},"automatic_share":{"type":"number","title":"Automatic Share","description":"Share of its held-back cases handled automatically."},"automatic_accuracy":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Automatic Accuracy","description":"Accuracy of those automatic answers."},"statement":{"type":"string","title":"Statement","description":"In plain words."}},"type":"object","required":["language","name","strong","automatic_share","statement"],"title":"SafetyBarLanguage"},"SafetyBarQuestion":{"properties":{"question":{"type":"string","title":"Question","description":"The question id."},"threshold":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Threshold","description":"The confidence an answer needs to be automatic."},"automatic_share":{"type":"number","title":"Automatic Share","description":"Share of your held-back cases handled automatically."},"automatic_accuracy":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Automatic Accuracy","description":"Accuracy of those automatic answers."},"statement":{"type":"string","title":"Statement","description":"In plain words."},"curve":{"items":{"$ref":"#/components/schemas/ThresholdPoint"},"type":"array","title":"Curve","description":"Confidence vs share handled and accuracy."}},"type":"object","required":["question","automatic_share","statement"],"title":"SafetyBarQuestion"},"SafetyInfo":{"properties":{"target":{"type":"number","title":"Target","description":"Automatic answers are at least this accurate. Fixed.","default":0.97},"statement":{"type":"string","title":"Statement","description":"The safety bar in plain words."},"strong_languages":{"items":{"type":"string"},"type":"array","title":"Strong Languages","description":"Languages answered automatically (ISO 639-1). Others are always double-checked."},"questions":{"additionalProperties":{"$ref":"#/components/schemas/SafetyQuestion"},"type":"object","title":"Questions","description":"Per question: its threshold and the share handled automatically."}},"type":"object","required":["statement"],"title":"SafetyInfo"},"SafetyQuestion":{"properties":{"threshold":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Threshold","description":"The confidence an answer needs to be automatic (null: none is automatic yet)."},"automatic_share":{"type":"number","title":"Automatic Share","description":"Share of your held-back cases handled automatically.","default":0.0}},"type":"object","title":"SafetyQuestion"},"SchemaField":{"properties":{"name":{"type":"string","pattern":"^[A-Za-z_][A-Za-z0-9_\\-]{0,63}$","title":"Name","description":"The field's name, used in rules and uploads."},"type":{"type":"string","enum":["number","category","text"],"title":"Type","description":"`number` (amounts, counts, days, and yes/no flags as true/false or 1/0), `category` (one of a known set of values) or `text` (free text, like a customer's message)."},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path","description":"Where the field lives in `state` (e.g. `account.amount`). Defaults to the name."},"values":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Values","description":"Known values of a category field."},"min":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min","description":"A number field's usual lowest value (optional)."},"max":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max","description":"A number field's usual highest value (optional)."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"What the field means, in plain words."}},"type":"object","required":["name","type"],"title":"SchemaField"},"ScoreAnswer":{"properties":{"type":{"type":"string","const":"score","title":"Type","description":"`score`."},"score":{"type":"number","title":"Score","description":"The expected level (0 = the first level), a number between the lowest and highest level."},"confidence":{"type":"number","title":"Confidence","description":"How sure the answer is, from 0 to 1, calibrated on your held-back cases."},"legend":{"additionalProperties":true,"type":"object","title":"Legend","description":"Level number -> your description of it."},"probabilities":{"additionalProperties":{"type":"number"},"type":"object","title":"Probabilities","description":"Probability per option (Choice) or per level (Score), summing to 1."},"source":{"type":"string","enum":["trained","translated","fallback","rule","backup","local_fallback"],"title":"Source","description":"How it was decided: `trained` (your model), `translated` (your model, after the message was translated to English because it was below the safety bar or in a language the model isn't strong in), `fallback` (your day-one backend), `rule` (your rules leave one option), `backup` (still below the safety bar after translation: our hosted backup answered from your allowed options, with your rules applied) or `local_fallback` (a downloaded model, offline: your own fallback function answered; only on cases synced from a device)."},"route":{"anyOf":[{"type":"string","enum":["act","review"]},{"type":"null"}],"title":"Route","description":"`act`: an automatic answer (at or above the model's safety bar). `review`: below the bar after every check; held for a person (it's in the unsure queue)."}},"type":"object","required":["type","score","confidence","legend","probabilities","source"],"title":"ScoreAnswer"},"ScoreQuestion":{"properties":{"type":{"type":"string","const":"score","title":"Type","description":"`score`: a level on a scale."},"instructions":{"title":"Instructions","description":"What the question asks, as you'd tell a person (text, a JSON object or array)."},"criteria":{"items":{},"type":"array","maxItems":10,"minItems":2,"title":"Criteria","description":"Level descriptions indexed from 0."}},"additionalProperties":true,"type":"object","required":["type","criteria"],"title":"ScoreQuestion","description":"Rate on a scale of 2-10 levels (Jev's Score)."},"ShadowCaseIn":{"properties":{"state":{"title":"State","description":"The real state, as your program sends it."},"current":{"additionalProperties":true,"type":"object","title":"Current","description":"The decision you made today, per question, e.g. {\"action\": \"refund\"} (Jev's answer, your process's, or a person's)."},"source":{"type":"string","enum":["jev","process","person"],"title":"Source","description":"Who made the current decision: `jev` (the default), `process` (your own code or process) or `person`.","default":"jev"},"confident":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Confident","description":"Optional: true when the current decision was confident (e.g. Jev's confidence was high). Agreements on confident decisions are learned at a lower weight; a person's are learned like a review."}},"type":"object","required":["state","current"],"title":"ShadowCaseIn"},"ShadowCasesRequest":{"properties":{"cases":{"items":{"$ref":"#/components/schemas/ShadowCaseIn"},"type":"array","maxItems":100,"minItems":1,"title":"Cases","description":"Up to 100 real requests."}},"type":"object","required":["cases"],"title":"ShadowCasesRequest","examples":[{"cases":[{"confident":true,"current":{"action":"approve"},"source":"jev","state":{"amount":42.5,"message":"Parcel arrived crushed","tier":"pro"}}]}]},"ShadowRecorded":{"properties":{"recorded":{"type":"integer","title":"Recorded","description":"Requests recorded."},"agreed":{"type":"integer","title":"Agreed","description":"Of those, where your model agreed.","default":0},"disagreed":{"type":"integer","title":"Disagreed","description":"Where it didn't: added to the review list.","default":0},"items":{"items":{"$ref":"#/components/schemas/ShadowRecordedItem"},"type":"array","title":"Items","description":"Per request."},"message":{"type":"string","title":"Message","description":"What happened, in plain words.","default":""}},"type":"object","required":["recorded"],"title":"ShadowRecorded"},"ShadowRecordedItem":{"properties":{"index":{"type":"integer","title":"Index","description":"Its position in `cases` (from 1)."},"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id","description":"Its id (`shd_…`), when recorded."},"agrees":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Agrees","description":"Whether your model decided as you did."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Why it wasn't recorded."}},"type":"object","required":["index"],"title":"ShadowRecordedItem"},"ShadowReviewIn":{"properties":{"id":{"type":"string","title":"Id","description":"The request (`shd_…`)."},"pick":{"anyOf":[{"type":"string","enum":["model","current"]},{"type":"null"}],"title":"Pick","description":"Which answer is right."},"answers":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Answers","description":"Or the right answers, per question."},"skip":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Skip","description":"true: not sure; leave it out."}},"type":"object","required":["id"],"title":"ShadowReviewIn"},"ShadowReviewItem":{"properties":{"id":{"type":"string","title":"Id","description":"The request (`shd_…`)."},"created_at":{"type":"string","title":"Created At","description":"ISO 8601."},"state":{"title":"State","description":"The state."},"question":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Question","description":"The question they disagree on."},"current":{"title":"Current","description":"Your current answer to it."},"current_source":{"type":"string","title":"Current Source","description":"Who made it: jev, process or person.","default":"jev"},"model":{"title":"Model","description":"Your model's answer to it."},"model_confidence":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Model Confidence","description":"Your model's confidence in its answer (0-1)."},"all_current":{"additionalProperties":true,"type":"object","title":"All Current","description":"Every current answer sent."},"all_model":{"additionalProperties":true,"type":"object","title":"All Model","description":"Your model's answer to each."}},"type":"object","required":["id","created_at"],"title":"ShadowReviewItem"},"ShadowReviewList":{"properties":{"domain":{"type":"string","title":"Domain","description":"The model's name."},"open":{"type":"integer","title":"Open","description":"Disagreements waiting in all.","default":0},"items":{"items":{"$ref":"#/components/schemas/ShadowReviewItem"},"type":"array","title":"Items","description":"A short list (at most 20), your model's most confident disagreements first."},"minutes":{"type":"integer","title":"Minutes","description":"About how long they take.","default":0},"next_step":{"type":"string","title":"Next Step","description":"What to do next, in plain words.","default":""}},"type":"object","required":["domain"],"title":"ShadowReviewList"},"ShadowReviewRequest":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ShadowReviewIn"},"type":"array","maxItems":200,"minItems":1,"title":"Items","description":"Your reviews."}},"type":"object","required":["items"],"title":"ShadowReviewRequest","examples":[{"items":[{"id":"shd_4f1c2a9b0e7d6a51","pick":"model"},{"answers":{"action":"escalate"},"id":"shd_9a0e7d6a514f1c2b"}]}]},"ShadowReviewed":{"properties":{"reviewed":{"type":"integer","title":"Reviewed","description":"Reviews recorded."},"problems":{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array","title":"Problems","description":"{id, why} for reviews not recorded."},"open":{"type":"integer","title":"Open","description":"Disagreements still waiting.","default":0},"message":{"type":"string","title":"Message","description":"What happened, in plain words.","default":""}},"type":"object","required":["reviewed"],"title":"ShadowReviewed"},"ShadowStatus":{"properties":{"domain":{"type":"string","title":"Domain","description":"The model's name."},"on":{"type":"boolean","title":"On","description":"Shadow mode is on."},"since":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Since","description":"ISO 8601: when it was turned on."},"version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version","description":"The version deciding silently (the serving one)."},"cases":{"type":"integer","title":"Cases","description":"Requests recorded.","default":0},"agreed":{"type":"integer","title":"Agreed","description":"Where your model decided as you did.","default":0},"disagreed":{"type":"integer","title":"Disagreed","description":"Where it didn't.","default":0},"to_review":{"type":"integer","title":"To Review","description":"Disagreements waiting for a quick review.","default":0},"reviewed":{"type":"integer","title":"Reviewed","description":"Disagreements reviewed (learned at your next retrain).","default":0},"agreement":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Agreement","description":"agreed / cases (0-1)."},"statement":{"type":"string","title":"Statement","description":"Where it stands, in plain words.","default":""},"next_step":{"type":"string","title":"Next Step","description":"What to do next, in plain words.","default":""}},"type":"object","required":["domain","on"],"title":"ShadowStatus"},"ShadowToggle":{"properties":{"on":{"type":"boolean","title":"On","description":"true: turn shadow mode on; false: off (what was recorded stays)."}},"type":"object","required":["on"],"title":"ShadowToggle","examples":[{"on":true}]},"SignoffInfo":{"properties":{"status":{"type":"string","enum":["none","signed_off","corrections_recorded"],"title":"Status","description":"`none` (not reviewed: optional), `signed_off` (every example confirmed) or `corrections_recorded` (reviewed with corrections; they apply when your model is next retrained)."},"at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"At","description":"When (ISO 8601)."},"by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"By","description":"Who: a user or key id."},"examples":{"type":"integer","title":"Examples","description":"Examples reviewed.","default":0},"corrections":{"type":"integer","title":"Corrections","description":"How many were corrected.","default":0}},"type":"object","required":["status"],"title":"SignoffInfo","description":"The record of your review of the examples. Reviewing is optional: nothing waits for it."},"SignoffItem":{"properties":{"id":{"type":"string","title":"Id","description":"The example's id."},"ok":{"type":"boolean","title":"Ok","description":"true: the answer is right. false: send `correct`."},"correct":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Correct","description":"If not ok: the right answer, per question."},"note":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Note","description":"Why, in plain words (optional)."}},"type":"object","required":["id","ok"],"title":"SignoffItem"},"SignoffRequest":{"properties":{"examples":{"items":{"$ref":"#/components/schemas/SignoffItem"},"type":"array","title":"Examples","description":"The examples you confirm or correct (from GET …/examples). Any of them: the ones you leave out stay unreviewed."},"retrain":{"type":"boolean","title":"Retrain","description":"true: with corrections, retrain now so your model gives the corrected answers (one call: record and retrain). false: they apply at your next retrain.","default":false}},"type":"object","required":["examples"],"title":"SignoffRequest","description":"Confirm or correct example cases (optional, any time). Corrections are learned when your model is next\nretrained; `retrain: true` starts that retrain now.","examples":[{"examples":[{"id":"ex_01","ok":true},{"id":"ex_02","ok":true}]},{"examples":[{"correct":{"action":"escalate"},"id":"ex_02","note":"pro accounts under 30 days go to a person","ok":false}],"retrain":true}]},"SignoffResult":{"properties":{"status":{"type":"string","enum":["none","signed_off","corrections_recorded"],"title":"Status","description":"`none` (not reviewed: optional), `signed_off` (every example confirmed) or `corrections_recorded` (reviewed with corrections; they apply when your model is next retrained)."},"at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"At","description":"When (ISO 8601)."},"by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"By","description":"Who: a user or key id."},"examples":{"type":"integer","title":"Examples","description":"Examples reviewed.","default":0},"corrections":{"type":"integer","title":"Corrections","description":"How many were corrected.","default":0},"message":{"type":"string","title":"Message","description":"What happens next, in plain words.","default":""},"build_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Build Id","description":"A model made with POST /v1/build: the retrain that applies your corrections (follow GET /v1/build/{build_id}), or the build your review moved on."},"job_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Job Id","description":"Another model: the training job that learns your corrections (follow GET /v1/jobs/{job_id})."}},"type":"object","required":["status"],"title":"SignoffResult","description":"The review is recorded. With `retrain: true` and corrections, the retrain that applies them has started."},"SignupRequest":{"properties":{"org_name":{"type":"string","maxLength":120,"minLength":1,"title":"Org Name","description":"Your company or team."},"email":{"type":"string","maxLength":254,"minLength":3,"title":"Email","description":"The owner's email address."},"password":{"type":"string","maxLength":200,"minLength":10,"title":"Password","description":"At least 10 characters."}},"type":"object","required":["org_name","email","password"],"title":"SignupRequest"},"SignupResponse":{"properties":{"org":{"$ref":"#/components/schemas/Org","description":"The new workspace."},"user":{"$ref":"#/components/schemas/User","description":"Its owner."},"api_key":{"type":"string","title":"Api Key","description":"Shown once. Store it; we keep only a hash."}},"type":"object","required":["org","user","api_key"],"title":"SignupResponse"},"SignupStart":{"properties":{"org_name":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Org Name","description":"Optional: your company or team. Without it, the workspace is named after your email; rename it any time in Settings."},"email":{"type":"string","maxLength":254,"minLength":3,"title":"Email","description":"Where the confirmation link goes."},"accept_terms":{"type":"boolean","title":"Accept Terms","description":"The Terms of Service, the Acceptable Use Policy and the Privacy Policy (canonopylabs.com/legal) must be accepted."}},"type":"object","required":["email","accept_terms"],"title":"SignupStart"},"SignupVerified":{"properties":{"org":{"$ref":"#/components/schemas/Org","description":"The new workspace."},"user":{"$ref":"#/components/schemas/User","description":"Its owner."},"api_key":{"type":"string","title":"Api Key","description":"Your first API key. Shown once; we keep only a hash."},"session":{"$ref":"#/components/schemas/LoginResponse","description":"A console session (12 hours)."}},"type":"object","required":["org","user","api_key","session"],"title":"SignupVerified"},"SpotCheckCard":{"properties":{"domain":{"type":"string","title":"Domain","description":"The model's name."},"setting":{"type":"string","enum":["off","light","thorough"],"title":"Setting","description":"The workspace's spot-check setting."},"rate":{"type":"number","title":"Rate","description":"The share of confident decisions set aside (0.01 is 1%)."},"title":{"type":"string","title":"Title","description":"The card's title, e.g. \"Check these 10 decisions (about 2 minutes)\"."},"open":{"type":"integer","title":"Open","description":"Set-aside decisions from the last 7 days still unanswered.","default":0},"minutes":{"type":"integer","title":"Minutes","description":"About how long the card takes.","default":0},"items":{"items":{"$ref":"#/components/schemas/SpotCheckItem"},"type":"array","title":"Items","description":"The decisions on the card."},"spot_checked":{"anyOf":[{"$ref":"#/components/schemas/SpotChecked"},{"type":"null"}],"description":"How often your model was right on the ones checked so far."},"next_step":{"type":"string","title":"Next Step","description":"What to do next, in plain words.","default":""}},"type":"object","required":["domain","setting","rate","title"],"title":"SpotCheckCard","description":"This week's optional spot-check card: a few confident decisions set aside for a person to check."},"SpotCheckItem":{"properties":{"decision_id":{"type":"string","title":"Decision Id","description":"The decision (answer it with POST /v1/domains/{domain}/answers)."},"created_at":{"type":"string","title":"Created At","description":"ISO 8601."},"model":{"type":"string","title":"Model","description":"The version that decided it."},"state":{"title":"State","description":"The state it decided on."},"answers":{"additionalProperties":true,"type":"object","title":"Answers","description":"The answers it gave."},"decision":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Decision","description":"The decision block, if any."}},"type":"object","required":["decision_id","created_at","model"],"title":"SpotCheckItem"},"SpotChecked":{"properties":{"checked":{"type":"integer","title":"Checked","description":"Answers checked by a person."},"agreed":{"type":"integer","title":"Agreed","description":"Of those, where your model was right."},"accuracy":{"type":"number","title":"Accuracy","description":"agreed / checked (0-1)."},"statement":{"type":"string","title":"Statement","description":"One line, e.g. \"spot-checked accuracy: 94% (50 answers checked)\"."}},"type":"object","required":["checked","agreed","accuracy","statement"],"title":"SpotChecked"},"StateSchema":{"properties":{"fields":{"items":{"$ref":"#/components/schemas/SchemaField"},"type":"array","title":"Fields","description":"The fields of `state` the decision reads."}},"type":"object","title":"StateSchema"},"ThresholdPoint":{"properties":{"threshold":{"type":"number","title":"Threshold","description":"A confidence threshold."},"automated":{"type":"number","title":"Automated","description":"Share of held-back cases at or above it."},"accuracy":{"type":"number","title":"Accuracy","description":"Accuracy of those cases."}},"type":"object","required":["threshold","automated","accuracy"],"title":"ThresholdPoint"},"TokenRequest":{"properties":{"token":{"type":"string","maxLength":200,"minLength":10,"title":"Token","description":"The token from the emailed link."}},"type":"object","required":["token"],"title":"TokenRequest"},"TrainRequest":{"properties":{"questions":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Questions","description":"Only these questions (default: every question with enough cases)."},"promote":{"type":"string","enum":["auto","always","never"],"title":"Promote","description":"`auto` (default): put the new version in service when the report recommends it. `always`: put it in service anyway. `never`: keep it as a candidate; promote it yourself with POST …/promote.","default":"auto"},"wait":{"type":"boolean","title":"Wait","description":"Wait for the new version (up to ~10 minutes) instead of returning a job to poll.","default":true}},"type":"object","title":"TrainRequest","description":"Optional: train only some questions, choose whether to promote, and whether to wait.","examples":[{},{"wait":false},{"promote":"never","questions":["action"],"wait":true}]},"TrialStatus":{"properties":{"state":{"type":"string","enum":["not_started","active","ended"],"title":"State","description":"not_started: the trial starts when your workspace trains its first model or makes its first decision. active: running until `ends_at`. ended: subscribe to keep improving your models; the ones you have are yours."},"days":{"type":"number","title":"Days","description":"How long the free trial lasts, in days (5)."},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started At","description":"When it started: your first trained model or first decision, whichever came first (ISO 8601)."},"ends_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ends At","description":"When it ends (ISO 8601), once started."},"days_left":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Days Left","description":"Whole days left while it runs (rounded up)."}},"type":"object","required":["state","days"],"title":"TrialStatus"},"UnsureItem":{"properties":{"decision_id":{"type":"string","title":"Decision Id","description":"Use it to answer the case."},"created_at":{"type":"string","title":"Created At","description":"When it was decided (ISO 8601)."},"model":{"type":"string","title":"Model","description":"The version that answered."},"state":{"title":"State","description":"The case."},"answers":{"additionalProperties":{"oneOf":[{"$ref":"#/components/schemas/ChoiceAnswer"},{"$ref":"#/components/schemas/ScoreAnswer"},{"$ref":"#/components/schemas/NoulAnswer"}],"discriminator":{"propertyName":"type","mapping":{"choice":"#/components/schemas/ChoiceAnswer","noul":"#/components/schemas/NoulAnswer","score":"#/components/schemas/ScoreAnswer"}}},"type":"object","title":"Answers","description":"The answers it gave."},"decision":{"anyOf":[{"$ref":"#/components/schemas/Decision"},{"type":"null"}],"description":"The decision block, with its route (`review` or `ask`)."},"from_offline_device":{"type":"boolean","title":"From Offline Device","description":"true when a downloaded model decided it while offline and it was synced later.","default":false}},"type":"object","required":["decision_id","created_at","model","state","answers"],"title":"UnsureItem"},"UnsureList":{"properties":{"items":{"items":{"$ref":"#/components/schemas/UnsureItem"},"type":"array","title":"Items","description":"Held cases, oldest first, up to `limit`."},"open":{"type":"integer","title":"Open","description":"How many are waiting in total."}},"type":"object","required":["items","open"],"title":"UnsureList"},"UploadInfo":{"properties":{"id":{"type":"string","title":"Id","description":"`upl_…`; `earlier` for cases uploaded before uploads had ids, `earlier-signoff` for earlier corrected examples."},"source":{"type":"string","title":"Source","description":"`upload` (past cases you uploaded) or `signoff` (examples you corrected)."},"mode":{"type":"string","title":"Mode","description":"`add` or `replace` (it replaced every earlier uploaded case)."},"file_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Name","description":"The file's name, when there was one."},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At","description":"When it was uploaded (ISO 8601; for `earlier`, the first of those cases)."},"cases":{"type":"integer","title":"Cases","description":"Its cases the domain has now."},"rejected":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rejected","description":"Rows set aside when it was uploaded (unknown for `earlier`)."}},"type":"object","required":["id","source","mode","cases"],"title":"UploadInfo","description":"One upload of past cases (or one review's corrected examples)."},"UploadList":{"properties":{"domain":{"type":"string","title":"Domain","description":"The domain's name."},"uploads":{"items":{"$ref":"#/components/schemas/UploadInfo"},"type":"array","title":"Uploads","description":"Newest first; the `earlier` groups last."},"total_cases":{"type":"integer","title":"Total Cases","description":"Cases the next version would learn from."},"from_uploads":{"type":"integer","title":"From Uploads","description":"Uploaded cases (examples you corrected not included)."},"from_signoff":{"type":"integer","title":"From Signoff","description":"Examples you corrected."},"from_outcomes":{"type":"integer","title":"From Outcomes","description":"Hosted decisions with a reported outcome or an unsure-queue answer."},"starter_cases":{"type":"integer","title":"Starter Cases","description":"Starter cases: for a question that reads text, what its starter model learns from until your own cases take over (not an upload, not counted above). Remove them with DELETE …/uploads/starter (added Sep 27).","default":0}},"type":"object","required":["domain","uploads","total_cases","from_uploads","from_signoff","from_outcomes"],"title":"UploadList","examples":[{"domain":"refunds","from_outcomes":12,"from_signoff":2,"from_uploads":6349,"total_cases":6361,"uploads":[{"cases":6347,"created_at":"2026-09-27T09:12:00Z","file_name":"cases-sep.csv","id":"upl_4f1c2a9b0d3e5f67","mode":"replace","rejected":3,"source":"upload"},{"cases":2,"created_at":"2026-09-20T15:02:00Z","id":"upl_0a1b2c3d4e5f6a7b","mode":"add","rejected":0,"source":"signoff"}]}]},"UploadProblem":{"properties":{"row":{"type":"integer","title":"Row","description":"The row number in your upload."},"problem":{"type":"string","title":"Problem","description":"What's wrong with it."}},"type":"object","required":["row","problem"],"title":"UploadProblem"},"UploadResult":{"properties":{"accepted":{"type":"integer","title":"Accepted","description":"Cases added."},"rejected":{"type":"integer","title":"Rejected","description":"Rows skipped (see `problems`)."},"total_cases":{"type":"integer","title":"Total Cases","description":"Cases the domain has now."},"per_question":{"additionalProperties":{"type":"integer"},"type":"object","title":"Per Question","description":"Cases with a known answer, per question."},"problems":{"items":{"$ref":"#/components/schemas/UploadProblem"},"type":"array","title":"Problems","description":"The first 20 problems."},"upload_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Upload Id","description":"This upload's id (`upl_…`), to find it in GET /v1/domains/{domain}/uploads or delete it later. null when no row was accepted (nothing was stored)."},"mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mode","description":"`add` or `replace`."},"replaced":{"anyOf":[{"$ref":"#/components/schemas/Replaced"},{"type":"null"}],"description":"With `mode=replace`: the earlier uploaded cases this upload deleted (nothing when no row was accepted)."}},"type":"object","required":["accepted","rejected","total_cases","per_question"],"title":"UploadResult"},"Usage":{"properties":{"input_tokens":{"type":"integer","title":"Input Tokens","description":"Counted for compatibility with TypeSafe clients. Not billed."},"output_tokens":{"type":"integer","title":"Output Tokens","description":"Always 0. Kept for compatibility with TypeSafe clients. Not billed."},"decisions":{"type":"integer","title":"Decisions","description":"Decisions in this request (for your dashboards; pricing is flat)."}},"type":"object","required":["input_tokens","output_tokens","decisions"],"title":"Usage"},"User":{"properties":{"id":{"type":"string","title":"Id","description":"User id (`usr_…`)."},"email":{"type":"string","title":"Email","description":"The user's email address."},"role":{"type":"string","title":"Role","description":"`owner` or `member`."}},"type":"object","required":["id","email","role"],"title":"User"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VersionInfo":{"properties":{"version":{"type":"integer","title":"Version","description":"The version number."},"status":{"type":"string","enum":["serving","candidate","retired"],"title":"Status","description":"`serving` (what `@latest` answers with), `candidate` (made, not promoted) or `retired` (served before)."},"kind":{"type":"string","enum":["train","option","graduation","imported","multilingual"],"title":"Kind","description":"How it was made: `train`, `option` (a new option), `graduation` (a day-one question switched to your own model), `imported` (installed from a finished model) or `multilingual` (reads about 100 languages)."},"created_at":{"type":"string","title":"Created At","description":"ISO 8601."},"questions":{"additionalProperties":{"additionalProperties":true,"type":"object"},"type":"object","title":"Questions","description":"Per question: `status` and `accuracy`."},"recommendation":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Recommendation","description":"The report's recommendation: `action` and `reason`."},"size_bytes":{"type":"integer","title":"Size Bytes","description":"Size of the model files.","default":0}},"type":"object","required":["version","status","kind","created_at","questions"],"title":"VersionInfo"},"VersionList":{"properties":{"serving_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Serving Version","description":"The version `@latest` answers with."},"versions":{"items":{"$ref":"#/components/schemas/VersionInfo"},"type":"array","title":"Versions","description":"Every version, newest first."}},"type":"object","required":["versions"],"title":"VersionList"},"WeakOption":{"properties":{"question":{"type":"string","title":"Question","description":"The question id."},"option":{"type":"string","title":"Option","description":"The option."},"accuracy":{"type":"number","title":"Accuracy","description":"Accuracy on held-back cases whose right answer is this option."},"cases":{"type":"integer","title":"Cases","description":"How many such cases."}},"type":"object","required":["question","option","accuracy","cases"],"title":"WeakOption"},"WeakSpots":{"properties":{"weakest":{"items":{"$ref":"#/components/schemas/WeakOption"},"type":"array","title":"Weakest","description":"The least accurate options."},"confused_pairs":{"items":{"$ref":"#/components/schemas/ConfusedPair"},"type":"array","title":"Confused Pairs","description":"Options most often mistaken for each other."},"graduation":{"items":{"$ref":"#/components/schemas/GraduationRow"},"type":"array","title":"Graduation","description":"Day-one questions and how far they are from switching to your own model."}},"type":"object","required":["weakest","confused_pairs","graduation"],"title":"WeakSpots"},"WorkspaceSettings":{"properties":{"workspace_name":{"type":"string","title":"Workspace Name","description":"The workspace's name, shown in the console.","default":""},"decision_retention":{"type":"string","title":"Decision Retention","description":"How long the decision log keeps decisions: `30_days`, `90_days` (the default), `365_days` or `until_deleted`."},"decision_retention_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Decision Retention Days","description":"The same in days (null: until you delete them)."},"decision_retention_default":{"type":"string","title":"Decision Retention Default","description":"The default for new workspaces."},"choices":{"items":{"type":"string"},"type":"array","title":"Choices","description":"The values `decision_retention` accepts."},"older_than_retention":{"type":"integer","title":"Older Than Retention","description":"Decisions older than the retention now: deleted at the next daily clean-up (within a day).","default":0},"spot_checks":{"type":"string","enum":["off","light","thorough"],"title":"Spot Checks","description":"Spot checks: how many confident decisions are set aside for an optional weekly check (`off`, `light`: 1% (the default), `thorough`: 2%). Nothing is held up; they wait on one card: GET /v1/domains/{domain}/spot-checks.","default":"light"},"spot_check_choices":{"items":{"type":"string"},"type":"array","title":"Spot Check Choices","description":"The values `spot_checks` accepts."}},"type":"object","required":["decision_retention","decision_retention_default","choices"],"title":"WorkspaceSettings","description":"Workspace settings: its name, and how long decisions are kept."},"WorkspaceSettingsPatch":{"properties":{"workspace_name":{"anyOf":[{"type":"string","maxLength":120,"minLength":1},{"type":"null"}],"title":"Workspace Name","description":"Rename the workspace."},"spot_checks":{"anyOf":[{"type":"string","enum":["off","light","thorough"]},{"type":"null"}],"title":"Spot Checks","description":"Spot checks of confident decisions: `off`, `light` (1%, the default) or `thorough` (2%). Everything else works the same when they're off."},"decision_retention":{"anyOf":[{"type":"string","enum":["30_days","90_days","365_days","until_deleted"]},{"type":"null"}],"title":"Decision Retention","description":"How long decisions are kept: `30_days`, `90_days`, `365_days` or `until_deleted`. Once a day, decisions older than this are deleted permanently, including those with outcomes or unsure-queue answers: later versions no longer learn from them. Versions already trained keep what they learned."}},"type":"object","title":"WorkspaceSettingsPatch","examples":[{"decision_retention":"365_days"},{"workspace_name":"Acme support"}]},"DataRows":{"description":"Past cases as JSON: each case and how it was resolved.","examples":[{"rows":[{"answers":{"action":"approve"},"state":{"amount":40,"fraud_flag":false,"message":"Refund my order please","tier":"pro"}},{"action":"escalate","amount":900,"fraud_flag":false,"message":"I was charged 900 twice","tier":"enterprise"}]}],"properties":{"rows":{"description":"Each row: {\"state\": {...}, \"answers\": {question: value}} or a flat row whose columns are state fields and question ids.","items":{"additionalProperties":true,"type":"object"},"title":"Rows","type":"array"}},"required":["rows"],"title":"DataRows","type":"object"}},"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"Your API key: `Authorization: Bearer <key>`. `X-API-Key: <key>` also works."}}},"tags":[{"name":"build","description":"Send the same JSON you send Jev (one example state and your questions); get your own model back in minutes. No past decisions or answers needed; a few examples of what you send Jev make it better."},{"name":"domains","description":"Decision models (called domains in the API): create, list, read, change and archive them. Start here."},{"name":"set-up","description":"Describe the decision in plain words, then confirm about 20 example cases. Comes after creating the domain and before training."},{"name":"training","description":"Upload, list, replace or delete past cases, train a new version, add options, and follow jobs."},{"name":"versions","description":"Version history, training reports, promote or roll back, and download a finished model to run yourself."},{"name":"decide","description":"Ask for decisions in Jev's System One format. What your application calls in production."},{"name":"outcomes","description":"Report what really happened, work through the unsure queue, and follow day-one questions as they switch to your own model."},{"name":"trials","description":"Try your model on real work before it acts: playtest results from your own game, shadow mode beside your current decisions, and the weekly spot checks."},{"name":"decision-log","description":"Every decision, to browse, search, export and delete: for debugging an integration and for your own records. Readable after the free trial too."},{"name":"day-one","description":"The backend that answers questions your model hasn't learned yet: your Jev key, an OpenAI-compatible model, or our built-in general model."},{"name":"account","description":"Your workspace, API keys, usage and subscription. Sign-up and sign-in."},{"name":"demo","description":"The public demo on the site: no key needed."},{"name":"games","description":"Game bots. Coming soon: not available in production yet."},{"name":"meta","description":"Service health."}],"servers":[{"url":"https://api.canonopylabs.com","description":"production (planned)"},{"url":"http://localhost:8810","description":"local development"}],"security":[{"bearer":[]}]}