{"openapi":"3.1.0","info":{"title":"SeaCat API","description":"Ask typed questions about a text or JSON `state` and get each answer's probabilities from one\nforward pass of the model.\n\nSend your API key as `Authorization: Bearer <key>`. Create keys on the [dashboard](/dashboard).\nThe [guide](/docs) covers question design, limits, pricing, errors and queued requests.","version":"0.1.0"},"paths":{"/v1/decide":{"post":{"tags":["Decisions"],"summary":"Answer questions about a state","description":"Answer every question about `state`, each evaluated independently and in parallel.\n\nEach answer is read from the model's next-token probabilities over the option labels (`A` to `Z`, or `Yes` and\n`No`). Nothing is generated, so every answer is one of your options. Only successful requests are billed, per\ninput token; see `usage`.\n\nA request can be queued while GPU capacity comes online, which can take a minute or two. A request not finished\nwithin about a minute gets a `303` to a URL that returns its result: follow redirects, keeping the\n`Authorization` header, with a client timeout of at least 180 seconds. See the [guide](/docs).","operationId":"decide","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecideRequest"},"examples":{"lead":{"summary":"Qualify a sales lead (text state)","value":{"state":"Hi, I run operations at a 40-person logistics company. We are moving dispatch off spreadsheets and need something live before our peak season in November. Budget is approved for this quarter. Could someone walk me through pricing for 25 seats?","questions":{"stage":{"type":"category","text":"How far along is this lead in buying?","options":{"researching":"Early research, no timeline or budget yet","evaluating":"Comparing options, with a rough timeline","ready":"Budget approved and a firm deadline"}},"fit":{"type":"scale","text":"How well does the company in this message match our target customer: logistics or retail companies with 20 to 500 employees?","options":["Poor match","Partial match","Strong match"]},"wants_pricing":{"type":"yes_no","text":"Does the message ask about prices or plans?"}}}},"expense":{"summary":"Review expenses (JSON state)","value":{"state":{"trip":{"purpose":"Customer workshop in Chicago","nights":3},"policy":{"hotel_cap_per_night_usd":250,"receipt_required_over_usd":25},"totals":{"hotel_per_night_usd":304,"meals_usd":186,"items_over_25_usd_without_receipt":1},"employee_note":"The conference hotel was sold out, so I booked the closest one."},"questions":{"justified":{"type":"yes_no","text":"Does the employee note give a sound business reason for going over the hotel cap?"},"decision":{"type":"category","text":"What should the reviewer do with this expense report?","options":{"approve":"Approve as submitted","approve_with_reminder":"Approve, and remind the employee of the policy","return":"Send it back to the employee to fix","escalate":"Escalate to finance"}},"audit_risk":{"type":"scale","text":"How likely is this report to need a finance audit?","options":["Low","Medium","High"]}}}},"spam":{"summary":"One yes/no question","value":{"state":"Buy 10,000 followers for $5!!! Link in my profile.","questions":{"is_spam":{"type":"yes_no","text":"Is this comment spam?"}}}}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecideResponse"},"example":{"model":"seacat-1","answers":{"stage":{"type":"category","answer":"ready","probabilities":{"researching":0.0063,"evaluating":0.1102,"ready":0.8835},"certainty":0.6501},"fit":{"type":"scale","answer":"Strong match","probabilities":{"Poor match":0.0041,"Partial match":0.0514,"Strong match":0.9445},"certainty":0.7915,"mean":1.9404},"wants_pricing":{"type":"yes_no","answer":"yes","probabilities":{"yes":0.9981,"no":0.0019},"certainty":0.9801}},"usage":{"input_tokens":251,"cost_usd":5.1e-05}}}}},"303":{"description":"Queued: not finished after about 55 seconds. `GET` the `Location`, `/v1/decide/result/{call_id}`, with the same `Authorization` header. Clients that follow redirects do this for you.","headers":{"Location":{"description":"The result URL, relative to this host.","schema":{"type":"string"}}},"content":{"application/json":{"example":{"status":"queued","result_url":"/v1/decide/result/fc-01K5EXAMPLE","detail":"Your request is queued. GET result_url with the same API key to collect the answer."}}}},"400":{"description":"The state plus the longest question is over the model's input limit (nothing is truncated), or `model` isn't the model this server runs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"State plus question is 40213 tokens; the limit is 32768."}}}},"401":{"description":"The API key is missing, invalid or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid or missing API key."}}}},"402":{"description":"The account is out of credits.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Out of credits. Add more at https://seacat.dev/dashboard"}}}},"403":{"description":"The account is on the waitlist and hasn't been invited yet (servers with ACCESS_QUEUE on).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"This account is on the waitlist. We'll email you when it has access."}}}},"429":{"description":"Over one of this key's rate limits: requests per minute, or requests in progress at once. Wait `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Too many requests: each API key can make 600 requests per minute."}}}},"500":{"description":"An unexpected error. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Internal server error. Retry with backoff, and contact us if it keeps happening."}}}},"503":{"description":"The model is unavailable: it couldn't be reached, timed out or crashed. Wait `Retry-After` seconds and retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"The model is unavailable right now. Retry in a minute."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"BearerAuth":[]}]}},"/v1/decide/result/{call_id}":{"get":{"tags":["Decisions"],"summary":"Collect a delayed answer","description":"The answer to a `POST /v1/decide` that redirected here because it took longer than about a minute.\n\nWaits up to about a minute for it. If it's still not ready, redirects to this same URL again. Only the API key that\nmade the request can collect it, for up to an hour. The request is charged once, when it finishes, however many\ntimes its result is fetched, or if it's never fetched.","operationId":"decide_result","security":[{"BearerAuth":[]}],"parameters":[{"name":"call_id","in":"path","required":true,"schema":{"type":"string","title":"Call Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecideResponse"}}}},"303":{"description":"Still not finished: `GET` the same URL again.","headers":{"Location":{"description":"The result URL, relative to this host.","schema":{"type":"string"}}},"content":{"application/json":{"example":{"status":"queued","result_url":"/v1/decide/result/fc-01K5EXAMPLE","detail":"Your request is queued. GET result_url with the same API key to collect the answer."}}}},"400":{"description":"The request turned out to be over the model's input limit.","content":{"application/json":{"example":{"detail":"State plus question is 40213 tokens; the limit is 32768."},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing, invalid or revoked.","content":{"application/json":{"example":{"detail":"Invalid or missing API key."},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"No such result for this key: the ID is wrong, it's over an hour old, or another key made the request.","content":{"application/json":{"example":{"detail":"No result with this ID for this API key. A result can be collected for 1 hour, with the key that made the request."},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Over one of this key's rate limits: requests per minute, or requests in progress at once. Wait `Retry-After` seconds.","content":{"application/json":{"example":{"detail":"Too many requests: each API key can make 600 requests per minute."},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"An unexpected error. Retry with backoff.","content":{"application/json":{"example":{"detail":"Internal server error. Retry with backoff, and contact us if it keeps happening."},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"The model is unavailable: it couldn't be reached, timed out or crashed. Wait `Retry-After` seconds and retry.","content":{"application/json":{"example":{"detail":"The model is unavailable right now. Retry in a minute."},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/models":{"get":{"tags":["Models"],"summary":"List models","description":"The model this server runs and its price. No API key needed.","operationId":"models","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelsResponse"}}}}}}}},"components":{"schemas":{"CategoryAnswer":{"properties":{"type":{"type":"string","const":"category","title":"Type"},"answer":{"type":"string","title":"Answer","description":"The most likely option."},"probabilities":{"additionalProperties":{"type":"number"},"type":"object","title":"Probabilities","description":"Each option's probability, keyed by option, in request order. They sum to 1 before rounding to 4 decimal places."},"certainty":{"type":"number","title":"Certainty","description":"`1 - entropy / ln(n)` over the n probabilities: 1 when one option has all of it, 0 when it's split evenly."}},"type":"object","required":["type","answer","probabilities","certainty"],"title":"CategoryAnswer"},"DecideRequest":{"properties":{"state":{"anyOf":[{"type":"string"},{"additionalProperties":true,"type":"object"},{"items":{},"type":"array"}],"title":"State","description":"The text or JSON the questions are about. A string is used as is; an object or array is serialized as JSON with 2-space indentation. It is sent once and shared by every question."},"questions":{"additionalProperties":{"$ref":"#/components/schemas/Question"},"type":"object","maxProperties":64,"minProperties":1,"title":"Questions","description":"1 to 64 questions, keyed by names you choose. Answers come back under the same names. No question sees another question or its answer."},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model","description":"Optional. Omit it, or pass `latest` or the name from `GET /v1/models`. Any other value is a 400.","examples":["latest"]}},"additionalProperties":false,"type":"object","required":["state","questions"],"title":"DecideRequest"},"DecideResponse":{"properties":{"model":{"type":"string","title":"Model","description":"The model that answered."},"answers":{"additionalProperties":{"oneOf":[{"$ref":"#/components/schemas/CategoryAnswer"},{"$ref":"#/components/schemas/ScaleAnswer"},{"$ref":"#/components/schemas/YesNoAnswer"}],"discriminator":{"propertyName":"type","mapping":{"category":"#/components/schemas/CategoryAnswer","scale":"#/components/schemas/ScaleAnswer","yes_no":"#/components/schemas/YesNoAnswer"}}},"type":"object","title":"Answers","description":"One answer per question, under the question's name, in request order. Every type has `answer`, `probabilities` and `certainty`; a scale also has `mean`."},"usage":{"$ref":"#/components/schemas/Usage"}},"type":"object","required":["model","answers","usage"],"title":"DecideResponse"},"ErrorResponse":{"properties":{"detail":{"type":"string","title":"Detail","description":"What went wrong."}},"type":"object","required":["detail"],"title":"ErrorResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ModelInfo":{"properties":{"name":{"type":"string","title":"Name","description":"The model's name. Pass it as `model` to pin it, or omit `model`."},"price_per_mtok_usd":{"type":"number","title":"Price Per Mtok Usd","description":"Price per million input tokens, in US dollars."}},"type":"object","required":["name","price_per_mtok_usd"],"title":"ModelInfo"},"ModelsResponse":{"properties":{"models":{"items":{"$ref":"#/components/schemas/ModelInfo"},"type":"array","title":"Models"}},"type":"object","required":["models"],"title":"ModelsResponse"},"Question":{"properties":{"type":{"type":"string","enum":["category","scale","yes_no"],"title":"Type","description":"`category`: pick one of 2 to 26 options. `scale`: rate on 2 to 26 ordered levels. `yes_no`: yes or no."},"text":{"type":"string","maxLength":4000,"minLength":1,"title":"Text","description":"The question. The model sees it as `Question: <text>`, after the state.","examples":["How far along is this lead in buying?"]},"options":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Options","description":"category: `{option: description}` or `[option, ...]`, 2 to 26 unique options. scale: `[level, ...]`, 2 to 26 unique levels, lowest first. yes_no: omit. The model sees them as lettered lines (`A. option: description`), and answers are keyed by option.","examples":[{"evaluating":"Comparing options, with a rough timeline","ready":"Budget approved and a firm deadline","researching":"Early research, no timeline or budget yet"},["Poor match","Partial match","Strong match"]]}},"additionalProperties":false,"type":"object","required":["type","text"],"title":"Question","description":"A typed question about the state. Each question is answered on its own, from the state and its own text."},"ScaleAnswer":{"properties":{"type":{"type":"string","const":"scale","title":"Type"},"answer":{"type":"string","title":"Answer","description":"The most likely option."},"probabilities":{"additionalProperties":{"type":"number"},"type":"object","title":"Probabilities","description":"Each option's probability, keyed by option, in request order. They sum to 1 before rounding to 4 decimal places."},"certainty":{"type":"number","title":"Certainty","description":"`1 - entropy / ln(n)` over the n probabilities: 1 when one option has all of it, 0 when it's split evenly."},"mean":{"type":"number","title":"Mean","description":"The expected level: the sum of each level's position (0 for the lowest) times its probability."}},"type":"object","required":["type","answer","probabilities","certainty","mean"],"title":"ScaleAnswer"},"Usage":{"properties":{"input_tokens":{"type":"integer","title":"Input Tokens","description":"Billed input tokens: the system prompt and state once, plus each question's own tokens."},"cost_usd":{"type":"number","title":"Cost Usd","description":"This request's cost: input_tokens times the price per million, rounded up to a millionth of a dollar. 0 on a server without billing."}},"type":"object","required":["input_tokens","cost_usd"],"title":"Usage"},"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"},"YesNoAnswer":{"properties":{"type":{"type":"string","const":"yes_no","title":"Type"},"answer":{"type":"string","enum":["yes","no"],"title":"Answer","description":"The more likely answer."},"probabilities":{"additionalProperties":{"type":"number"},"type":"object","title":"Probabilities","description":"Each option's probability, keyed by option, in request order. They sum to 1 before rounding to 4 decimal places."},"certainty":{"type":"number","title":"Certainty","description":"`1 - entropy / ln(n)` over the n probabilities: 1 when one option has all of it, 0 when it's split evenly."}},"type":"object","required":["type","answer","probabilities","certainty"],"title":"YesNoAnswer"}},"securitySchemes":{"BearerAuth":{"type":"http","description":"An API key from the dashboard.","scheme":"bearer"}}}}