POST /v1/systemone
Evaluate a state against typed questions and get one answer per question. This is the Jev-compatible endpoint: the same request and answers as TypeSafe's System One API.
POSThttps://api.sonoeai.com/v1/systemone
POST /v1/systemone HTTP/1.1
Host: api.sonoeai.com
Authorization: Bearer sk_sonoe_...
Content-Type: application/jsonRequest body
statestring | object | arrayrequiredWhat to decide about. See State.
modelstringrequiredsonoe-latest,sonoe-previeworsonoe-1.1.0. Jev's names (jev-latest,jev-preview,jev-1.x.y) are accepted as aliases. See GET /v1/models.questionsmap<string, Question>requiredUp to 64 questions. You choose each key; answers come back under the same keys. Each question is a Noul, a Choice or a Score:
type"noul" | "choice" | "score"requiredinstructionsstring | object | arrayoptional- The question. Objects and arrays are read as text, like the state.
criteriaobject | map | arrayoptional- Noul:
true/falsedescriptions. Choice: option → description ornull(2–255). Score: ordered levels (2–10).
Unknown top-level fields are ignored.
Example
{
"model": "sonoe-latest",
"state": "My card was charged twice for order 4417 and I need the money back today.",
"questions": {
"wants_refund": { "type": "noul", "instructions": "Does the customer want their money back?" },
"team": {
"type": "choice",
"instructions": "Which team should handle this?",
"criteria": {
"billing": "Payments, charges, refunds",
"shipping": "Deliveries and tracking",
"technical": "Bugs, the app or the website"
}
},
"urgency": {
"type": "score",
"instructions": "How urgent is this?",
"criteria": ["Can wait", "Soon", "Today"]
}
}
}Response
modelstringrequired- The versioned model that answered, e.g.
sonoe-1.1.0. answersmap<string, Answer>requiredOne answer per question, under the same keys. Every answer has a
type:noulobjectoptional{ type, noul }choiceobjectoptional{ type, choice, probabilities, confidence }scoreobjectoptional{ type, score, legend, probabilities, confidence }
usageobjectrequiredinput_tokensintegerrequired- Tokens Sonoe read for this request. This is what's charged.
output_tokensintegerrequired- Always
0: Sonoe doesn't generate text.
{
"model": "sonoe-1.1.0",
"answers": {
"wants_refund": { "type": "noul", "noul": 0.8695 },
"team": {
"type": "choice",
"choice": "billing",
"probabilities": { "billing": 0.9913, "shipping": 0.0031, "technical": 0.0056 },
"confidence": 0.9493
},
"urgency": {
"type": "score",
"score": 1.15,
"legend": { "0": "Can wait", "1": "Soon", "2": "Today" },
"probabilities": { "0": 0.2452, "1": 0.3596, "2": 0.3952 },
"confidence": 0.0175
}
},
"usage": { "input_tokens": 372, "output_tokens": 0 }
}Response headers
| Header | |
|---|---|
x-typesafe-request-id | A unique id for the request, such as req_7bd253c46fc2c54145dbe9e9. The TypeSafe SDKs expose it as request_id / requestId. |
x-request-id | The same id. |
Retry-After | On 429: seconds to wait before retrying. |
Compression
Bodies can be compressed with Content-Encoding: zstd, gzip or x-gzip. The TypeSafe SDKs compress with zstd from 1 KiB on. The size limit (64 KiB) applies after decompression. Any other encoding returns 415; a body that doesn't decompress returns 400.
Limits
| Body | 64 KiB, after decompression |
| Questions per request | 64 |
| Choice options | 2 to 255 |
| Score levels | 2 to 10 |
| Instructions | 8,000 characters (Sonoe reads at most 256 tokens per option) |
Images, assets, Box questions, multipart bodies | Not supported (422) |
Errors
Errors are JSON with both error and detail, so any client finds a message:
{
"detail": [
{ "loc": ["body", "questions", "tone", "criteria"], "msg": "A Choice needs between 2 and 255 options.", "type": "value_error" }
],
"error": { "type": "invalid_request_error", "message": "questions.tone.criteria: A Choice needs between 2 and 255 options." }
}| Status | When |
|---|---|
400 | The body isn't valid UTF-8 JSON, or a compressed body doesn't decompress. |
401 | Missing, invalid or revoked key. |
404 | Unknown model. |
413 | The body is over 64 KiB. |
415 | Unsupported Content-Encoding. |
422 | A missing or invalid field (detail[].loc says which), or images / Box. |
429 | Over a limit: per minute, per day, monthly quota or the key's limit. See Errors and limits. |
503 | The model isn't available on the server right now. Retry in a few seconds. |
Examples
curl https://api.sonoeai.com/v1/systemone \
-H "Authorization: Bearer $SONOE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"sonoe-latest","state":"Help! My payouts have been failing for 3 days.","questions":{"urgent":{"type":"noul","instructions":"Is this urgent?"}}}'from typesafe_sdk import Noul, TypeSafeClient
# TYPESAFE_BASE_URL=https://api.sonoeai.com and TYPESAFE_API_KEY=sk_sonoe_… in the environment
client = TypeSafeClient()
result = client.system_one(
"Help! My payouts have been failing for 3 days.",
{"urgent": Noul(instructions="Is this urgent?")},
)
print(result.nouls["urgent"].noul, result.request_id)import { noul, TypeSafeClient } from "@typesafe-ai/sdk";
// TYPESAFE_BASE_URL=https://api.sonoeai.com and TYPESAFE_API_KEY=sk_sonoe_… in the environment
const client = new TypeSafeClient();
const { data, requestId } = await client
.systemOne({
state: "Help! My payouts have been failing for 3 days.",
questions: { urgent: noul("Is this urgent?") },
})
.withResponse();
console.log(data.answers.urgent.noul, requestId);