Decisions
Decision models and the two decision endpoints are in public preview. Availability, and any change to the request or response shapes before general availability, will be announced in the release notes.
Decision models answer typed questions about an input with calibrated probabilities instead of generated text. You send a ticket, a message or a document together with questions such as "is this a refund request?", "which team should handle it?" or "how urgent is it, from low to high?", and you get back a probability, a choice or a score for each one, ready to drive your code.
| Endpoints | POST /v1/decisions (the format of OpenAI's Decisions API), POST /v1/systemone (Jev's format) |
| Models | orion-compass, orion-compass-flash, d3 (see Models) |
| Question types | predicate (yes or no), choice (one of several options), score (a level on an ordered scale) |
| Input | Text; also images on orion-compass-flash and d3 (see Images) |
| Billing | Input tokens only, images included; output is not billed |
| Access | Serenity Edge API keys (see Access) |
When to use decision models
Use a decision model when the result of a model call is a decision your code acts on, not text a person reads:
- Routing: pick the team, queue or model that should handle a request (
choice). - Classification: label content with one of a fixed set of categories (
choice), or with several yes or no tags at once (predicate). - Gating: let an action go ahead (publish a comment, send an email, call a tool) only when a
predicateprobability clears a threshold. - Triage: place a ticket or an alert on an urgency or severity scale (
score). - Scoring: grade an answer or a document against a rubric (
score), for example to evaluate the output of another model.
| Decision models | Chat completions | |
|---|---|---|
| Result | Typed answers: a probability, a choice or a score per question | Generated text, or JSON with structured outputs |
| Probabilities | For every option or level | Not returned |
| Invalid labels | Impossible: the answer is always one of your options | Possible; validate the output |
| Billing | Input tokens only | Input and output tokens |
| Streaming | No | Yes |
Use chat completions when you need text: answers, summaries, explanations, free-form extraction, conversation or tool calling.
The probabilities are calibrated: across many answers, an answer given with probability 0.8 should be right about 80% of the time, which is what makes a threshold meaningful. Calibration is tuned on general data, so check it on a sample of your own data before you rely on a threshold.
Models
Three decision models are in preview, two in the Orion line and one open-weight:
orion-compasswhen the question needs more depth: nuanced inputs, fine-grained options or detailed rubrics.orion-compass-flashfor the lowest latency and price at volume: high-volume routing, filtering and triage. It also reads images (see Images).d3(aliasvllm-sr/d3), the open-weight 27B decision model of vLLM Semantic Router under the Apache-2.0 licence, first on the text board of the Jev Decision Index. It also reads images (see Images). Its context is shorter: 24,576 tokens.
The Orion ids are aliases that follow the current version of the model; the versioned id each points to (such as orion-compass-26.1) pins one version. d3 is served from its published weights. The model field of every reply is the versioned id that answered. Decision models are served only on the decision endpoints, and chat models cannot be used on them.
The table is read from GET /v1/models?format=openai when this page is published and again when you open it. That list marks each decision model with an endpoints array and what it reads (input_modalities); the default catalogue of GET /v1/models lists chat models only.
| Model id | Context | Reads | Input | Output | Endpoints |
|---|---|---|---|---|---|
d3also vllm-sr/d3 | 24,576 | textimage | $0.042 | Free | /v1/decisions/v1/systemone |
orion-compassalias of orion-compass-26.1 | 32,000 | text | $0.034 | Free | /v1/decisions/v1/systemone |
orion-compass-flashalias of orion-compass-flash-26.1 | 32,000 | textimage | $0.017 | Free | /v1/decisions/v1/systemone |
Read from the API (GET /v1/models?format=openai) when this page was published, on 6 November 2026, 19:49 UTC.
Quick start
All examples send the same ticket and the same three questions. Replace $SERENITY_EDGE_API_KEY with a Serenity Edge API key.
curl
curl https://api.serenityedge.ai/v1/decisions \
-H "Authorization: Bearer $SERENITY_EDGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "orion-compass",
"input": "Ticket #4821. Customer: You charged my card twice for the same order last week. Refund the duplicate payment today or I will dispute it with my bank.",
"questions": [
{"type": "predicate", "name": "refund", "instructions": "Is the customer asking for a refund?"},
{
"type": "choice",
"name": "team",
"instructions": "Which team should handle this ticket?",
"choices": [
{"value": "billing", "description": "Payments, charges and refunds"},
{"value": "shipping", "description": "Delivery and tracking"},
{"value": "technical", "description": "Bugs and sign-in problems"}
]
},
{
"type": "score",
"name": "urgency",
"instructions": "How urgent is this ticket?",
"levels": [
{"label": "low", "description": "Can wait a week"},
{"label": "medium", "description": "Within two days"},
{"label": "high", "description": "Today, or the customer escalates"}
]
}
]
}'
Python
OpenAI's Python library has a decisions resource (client.decisions.create). It is not yet in every released version: upgrade with pip install --upgrade openai and, if your version still has no client.decisions, use the library's generic client.post shown below, which works with any recent release.
from openai import OpenAI
client = OpenAI(
base_url="https://api.serenityedge.ai/v1",
api_key="YOUR_SERENITY_EDGE_API_KEY",
)
decision = client.decisions.create(
model="orion-compass",
input=(
"Ticket #4821. Customer: You charged my card twice for the same order last week. "
"Refund the duplicate payment today or I will dispute it with my bank."
),
questions=[
{"type": "predicate", "name": "refund", "instructions": "Is the customer asking for a refund?"},
{
"type": "choice",
"name": "team",
"instructions": "Which team should handle this ticket?",
"choices": [
{"value": "billing", "description": "Payments, charges and refunds"},
{"value": "shipping", "description": "Delivery and tracking"},
{"value": "technical", "description": "Bugs and sign-in problems"},
],
},
{
"type": "score",
"name": "urgency",
"instructions": "How urgent is this ticket?",
"levels": [
{"label": "low", "description": "Can wait a week"},
{"label": "medium", "description": "Within two days"},
{"label": "high", "description": "Today, or the customer escalates"},
],
},
],
)
answers = {answer.name: answer for answer in decision.answers}
print(answers["refund"].probability) # 0.97
print(answers["team"].choice, answers["team"].confidence) # billing 0.91
print(answers["urgency"].score) # 1.72
print(decision.usage.input_tokens)
With a released version that has no decisions resource yet, send the same body with the library's generic post method and read the JSON yourself:
import httpx
response = client.post("/decisions", cast_to=httpx.Response, body={"model": "orion-compass", "input": "...", "questions": [...]})
decision = response.json()
Node.js
The request is plain JSON over HTTPS, so fetch (Node.js 18 or later) is enough:
const response = await fetch("https://api.serenityedge.ai/v1/decisions", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SERENITY_EDGE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "orion-compass",
input:
"Ticket #4821. Customer: You charged my card twice for the same order last week. " +
"Refund the duplicate payment today or I will dispute it with my bank.",
questions: [
{ type: "predicate", name: "refund", instructions: "Is the customer asking for a refund?" },
{
type: "choice",
name: "team",
instructions: "Which team should handle this ticket?",
choices: [
{ value: "billing", description: "Payments, charges and refunds" },
{ value: "shipping", description: "Delivery and tracking" },
{ value: "technical", description: "Bugs and sign-in problems" },
],
},
{
type: "score",
name: "urgency",
instructions: "How urgent is this ticket?",
levels: [
{ label: "low", description: "Can wait a week" },
{ label: "medium", description: "Within two days" },
{ label: "high", description: "Today, or the customer escalates" },
],
},
],
}),
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`HTTP ${response.status} ${error.code}: ${error.message}`);
}
const decision = await response.json();
const answers = Object.fromEntries(decision.answers.map((answer) => [answer.name, answer]));
console.log(answers.refund.probability, answers.team.choice, answers.urgency.score);
The reply
{
"answers": [
{ "type": "predicate", "name": "refund", "probability": 0.97 },
{
"type": "choice",
"name": "team",
"choice": "billing",
"confidence": 0.91,
"probabilities": [
{ "value": "billing", "probability": 0.94 },
{ "value": "shipping", "probability": 0.02 },
{ "value": "technical", "probability": 0.04 }
]
},
{
"type": "score",
"name": "urgency",
"score": 1.72,
"confidence": 0.625,
"probabilities": [
{ "value": 0, "label": "low", "probability": 0.03 },
{ "value": 1, "label": "medium", "probability": 0.22 },
{ "value": 2, "label": "high", "probability": 0.75 }
]
}
],
"model": "orion-compass-26.1",
"usage": {
"input_tokens": 412,
"input_tokens_details": { "cached_tokens": 0, "cache_write_tokens": 0 },
"output_tokens": 0,
"output_tokens_details": { "reasoning_tokens": 0 },
"total_tokens": 412
}
}
The probabilities in these examples are rounded for readability; the API returns them unrounded.
Request
| Field | Required | Description |
|---|---|---|
model | Yes | A decision model id, such as orion-compass, orion-compass-flash or d3. |
input | Yes | What the questions are about: a string, an array of user messages, or a whole conversation (see below). |
questions | Yes | One to 256 questions. The answers come back in the same order. |
safety_identifier | No | A stable identifier of your end user, as in OpenAI's API. Accepted for compatibility; like the rest of the body, it is never logged. |
input can also be an array of user messages, each with a string or an array of input_text parts. Their text is read in order, separated by a blank line:
"input": [
{
"role": "user",
"content": [
{ "type": "input_text", "text": "Order 1182, delivered on 2 October." },
{ "type": "input_text", "text": "Customer: The box arrived crushed and the lamp inside is broken." }
]
}
]
orion-compass-flash and d3 also read images, as input_image parts: see Images. orion-compass reads text only and refuses an input_image part with HTTP 400.
Every question has a type, instructions (the question in natural language) and an optional name. Names must be unique within a request; each answer repeats the name of its question, and has none when the question had none. Write the instructions as you would ask a careful colleague, and describe each option or level when its meaning is not obvious from its value: the model reads the descriptions.
Conversations
input can also hold a whole conversation, in the format of OpenAI's Decisions API, so you can ask questions about it: whether an agent followed its instructions, used its tools well or solved the user's problem. Besides user messages, it takes:
systemanddevelopermessages, with a string orinput_textparts;assistantmessages, with a string oroutput_textandrefusalparts, and an optionalphase(commentaryorfinal_answer);function_callitems (name,call_id,arguments) andfunction_call_outputitems (call_id,output: a string orinput_textparts);custom_tool_callitems (name,call_id,input) andcustom_tool_call_outputitems (call_id,output);input_jsonparts in user messages, whosedatais an object or an array of objects.
The whole conversation is evidence: the model reads it as the input your questions are about. System and developer messages do not change how the model answers, since the questions' instructions do that, so you can ask whether an agent followed its own system prompt. Tool calls and their outputs are read too. Every item counts as input tokens.
{
"model": "orion-compass",
"input": [
{ "role": "system", "content": "You are a support agent. Never promise a refund before checking the order." },
{ "role": "user", "content": "You charged me twice for order 4821." },
{ "type": "function_call", "call_id": "call_1", "name": "get_order", "arguments": "{\"id\":\"4821\"}" },
{ "type": "function_call_output", "call_id": "call_1", "output": "{\"status\":\"paid twice\"}" },
{ "role": "assistant", "content": "I see the duplicate payment. I have refunded it." }
],
"questions": [
{ "type": "predicate", "name": "checked_first", "instructions": "Did the agent check the order before promising a refund?" }
]
}
The model reads the conversation as a transcript: one block per item, in order, separated by a blank line, each under a label. The request above reads:
[system]
You are a support agent. Never promise a refund before checking the order.
[user]
You charged me twice for order 4821.
[function_call get_order call_1]
{"id":"4821"}
[function_call_output call_1]
{"status":"paid twice"}
[assistant]
I see the duplicate payment. I have refunded it.
An assistant phase is part of its label ([assistant final_answer]), a namespace prefixes a tool's name (billing.refund), input_json is read as compact JSON, and a refusal part reads Refusal: followed by its text. An assistant message without text, one that only called tools, has no block. An input of user messages only has no labels: it is read as described above.
These are refused with HTTP 400 and the item at fault in param:
- a tool output whose
call_iddoes not match an earlier call of the same kind; - images anywhere but in user messages, or on a model that reads text only;
- other item types, such as
reasoning, and parts a role does not take, such as aninput_imagein a system message.
Question types
Predicate
A yes or no question. The answer is the probability that the answer is yes.
{ "type": "predicate", "name": "refund", "instructions": "Is the customer asking for a refund?" }
{ "type": "predicate", "name": "refund", "probability": 0.97 }
Compare probability with a threshold that matches the cost of a mistake: a high one before an irreversible action, a lower one to flag content for review. Several predicates in one request are independent, so they work as multi-label tags.
Choice
Pick one of several options. Each option has a value, a string or a boolean that is returned as is, and an optional description.
{
"type": "choice",
"name": "team",
"instructions": "Which team should handle this ticket?",
"choices": [
{ "value": "billing", "description": "Payments, charges and refunds" },
{ "value": "shipping", "description": "Delivery and tracking" },
{ "value": "technical", "description": "Bugs and sign-in problems" }
]
}
{
"type": "choice",
"name": "team",
"choice": "billing",
"confidence": 0.91,
"probabilities": [
{ "value": "billing", "probability": 0.94 },
{ "value": "shipping", "probability": 0.02 },
{ "value": "technical", "probability": 0.04 }
]
}
choiceis the value of the most likely option, typed as in the request; on a tie, the option listed first.probabilitieslists every option in the order ofchoices, and they add up to 1.confidencesays how far the most likely option stands above chance:(p_max - 1/n) / (1 - 1/n)fornoptions, 0 when all options are equally likely and 1 when one takes all the probability.- A question takes at most 255 options. Values must be distinct, also as text: a string and a boolean that read the same (
"true"andtrue) cannot both be offered.
Add an option such as "other" or "none" when the input may fit none of the real ones; otherwise the model has to pick the closest.
Score
Place the input on an ordered scale of 2 to 10 levels, from the first to the last. Each level has a distinct label and an optional description.
{
"type": "score",
"name": "urgency",
"instructions": "How urgent is this ticket?",
"levels": [
{ "label": "low", "description": "Can wait a week" },
{ "label": "medium", "description": "Within two days" },
{ "label": "high", "description": "Today, or the customer escalates" }
]
}
{
"type": "score",
"name": "urgency",
"score": 1.72,
"confidence": 0.625,
"probabilities": [
{ "value": 0, "label": "low", "probability": 0.03 },
{ "value": 1, "label": "medium", "probability": 0.22 },
{ "value": 2, "label": "high", "probability": 0.75 }
]
}
scoreis the expected position on the scale: the probability-weighted mean of the positions, where the first level is 0. Here0 × 0.03 + 1 × 0.22 + 2 × 0.75 = 1.72, between "medium" and "high" and closer to "high".probabilitieslists every level with its position (value) andlabel, in the order oflevels.confidenceis computed as for a choice, over the levels.
Use score when the order matters (sorting a queue, a threshold such as "1.5 or more goes to the on-call team"), and the most likely level in probabilities when you need one label.
Images
orion-compass-flash and d3 read images together with the text: a scanned invoice, a screenshot, a photo of a damaged parcel. Send each image as an input_image part holding a base64 data URL:
"input": [
{
"role": "user",
"content": [
{ "type": "input_text", "text": "Customer photo of the delivered parcel, order 1182." },
{ "type": "input_image", "image_url": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ..." }
]
}
]
To build the data URL from a file in Python:
import base64
with open("parcel.jpg", "rb") as f:
image_url = "data:image/jpeg;base64," + base64.b64encode(f.read()).decode()
- Formats. PNG, JPEG or WebP, as base64 data URLs (
data:image/png;base64,...). File ids and web URLs are refused: the API fetches nothing. - Limits. At most 4 images per request, 8 MiB in total once decoded, and 16 megapixels per image. The request body may be up to 12 MiB on these two models.
- Order. The model sees the images at the start of the message, before its text, whatever the order of the parts.
- Billing. The tokens the images expand to are input tokens:
usage.input_tokenscounts them, andusage.input_tokens_detailssplits it intotext_tokensandimage_tokens. Like the text, the images are read with each question: a request with one image and ten questions bills that image's tokens ten times. - Not supported. Videos (
input_videoparts, orvideosonPOST /v1/systemone) are refused. So is text that holds the model's own image tokens, in the input, the instructions or the options. - Other models.
orion-compassreads text only, and refuses an image with HTTP 400 (422 onPOST /v1/systemone).
On the Jev-compatible route, send the same data URLs as images, a list beside state; usage.input_tokens counts the images, and usage.text_tokens and usage.image_tokens split it:
{
"model": "orion-compass-flash",
"state": { "order": 1182, "note": "Customer photo of the delivered parcel." },
"images": ["data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ..."],
"questions": {
"damaged": { "type": "noul", "instructions": "Does the parcel look damaged?" }
}
}
Response
| Field | Description |
|---|---|
answers | One answer per question, in question order, with the question's type and name. |
model | The versioned id of the model that answered, such as orion-compass-26.1. |
usage.input_tokens | Tokens the model read to answer, images included. This is what you are billed for. |
usage.output_tokens | Always 0: the answer is read from the model's probabilities and no text is generated. |
usage.input_tokens_details | cached_tokens and cache_write_tokens, both reported as 0. With images, text_tokens and image_tokens, which add up to input_tokens. |
usage.output_tokens_details | reasoning_tokens, always 0. |
usage.total_tokens | Equal to input_tokens. |
The model reads the input together with each question, so usage.input_tokens grows with both the length of the input and the number of questions. Asking several questions in one request saves round trips, not tokens.
Jev-compatible route
POST /v1/systemone serves the same models in the format of Jev's POST /v1/systemone (TypeSafe), for callers and tools migrating from Jev. Point your client at https://api.serenityedge.ai/v1/systemone with a Serenity Edge API key and a decision model id. For new integrations, prefer POST /v1/decisions.
POST /v1/decisions | POST /v1/systemone | |
|---|---|---|
| Input | input: a string, user messages or a conversation | state: any JSON value |
| Questions | An array; optional name | An object keyed by ids of your choice |
| Yes or no | predicate | noul |
| One of several | choice with choices: [{value, description}] | choice with criteria: {name: description} or [names] |
| Ordered scale | score with levels: [{label, description}] | score with criteria: the levels in order |
| Images | input_image parts in input | images: a list of data URLs |
| Answers | An array in question order | An object keyed by question id |
| Calibration | Always calibrated | Calibrated; "calibration": "raw" for uncalibrated probabilities |
| Refused question | HTTP 400 | HTTP 422, as Jev |
curl https://api.serenityedge.ai/v1/systemone \
-H "Authorization: Bearer $SERENITY_EDGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "orion-compass",
"state": {
"ticket_id": 4821,
"channel": "email",
"message": "You charged my card twice for the same order last week. Refund the duplicate payment today or I will dispute it with my bank."
},
"questions": {
"refund": {"type": "noul", "instructions": "Is the customer asking for a refund?"},
"team": {
"type": "choice",
"instructions": "Which team should handle this ticket?",
"criteria": {
"billing": "Payments, charges and refunds",
"shipping": "Delivery and tracking",
"technical": "Bugs and sign-in problems"
}
},
"urgency": {"type": "score", "instructions": "How urgent is this ticket?", "criteria": ["low", "medium", "high"]}
}
}'
{
"model": "orion-compass-26.1",
"answers": {
"refund": { "type": "noul", "noul": 0.97 },
"team": {
"type": "choice",
"choice": "billing",
"confidence": 0.91,
"probabilities": { "billing": 0.94, "shipping": 0.02, "technical": 0.04 }
},
"urgency": {
"type": "score",
"score": 1.72,
"confidence": 0.625,
"legend": { "0": "low", "1": "medium", "2": "high" },
"probabilities": { "0": 0.03, "1": 0.22, "2": 0.75 }
}
},
"usage": { "input_tokens": 398, "output_tokens": 3 },
"latency_ms": 84.6,
"calibration": { "applied": true, "temperatures": { "noul": 1.21, "choice": 1.08, "score": 1.14 } }
}
- A
scoreanswer lists its levels by position:legendmaps each position to its level andprobabilitiesgives the probability of each position. usage.output_tokensfollows Jev's format (one per answer) and is not billed; as on/v1/decisions, onlyusage.input_tokensis, images included (usage.text_tokensandusage.image_tokenssplit it for a request with images).calibration.appliedisfalsewhen the request asked for"calibration": "raw".- Errors use the same error object as every other route (see Errors); a question the model cannot read is refused with HTTP 422 instead of 400.
See Create decision (Jev format) for every field.
Access
Decision models can be used only with Serenity Edge API keys, the keys Substrate AI issues directly to customers and partner platforms. Today they are issued on request: see Enterprise or write to [email protected].
- Keys from a Serenity Star account get HTTP 403 with
code: "permission_denied"on the decision endpoints for now. Support for them is coming and will be announced in the release notes. - Decision models are not part of the OpenRouter onboarding, which covers the chat models only.
Errors
Errors use the same error object as chat completions, on both endpoints.
| Status | code | When | What to do |
|---|---|---|---|
| 400 | invalid_request_error | Malformed body, missing model, an unknown question type, an invalid option or level, a conversation item that is not accepted (see Conversations), or an image the model cannot read (a model that reads text only, more than 4 images, more than 8 MiB once decoded, more than 16 megapixels, a format other than PNG, JPEG or WebP, a broken file). On /v1/systemone, only a body that is not a JSON object or has no model. message says what to fix and param points at the parameter, such as questions[1].choices[2].value. | Fix the request. Do not retry as is. |
| 400 | context_length_exceeded | The input and a question do not fit the model's context. Nothing is truncated. | Shorten the input. |
| 422 | invalid_request_error or context_length_exceeded | /v1/systemone only: the model refused a question or the state, for the reasons above. | Fix the request. Do not retry as is. |
| 401 | invalid_api_key | Missing, malformed or revoked API key. | Check the Authorization header and the key. |
| 403 | permission_denied | The key cannot use the decision endpoints, such as a key from a Serenity Star account (see Access). | Use a Serenity Edge API key. |
| 404 | model_not_found | The model is not a decision model, for example a chat model id. | Check GET /v1/models?format=openai. |
| 404 | not_found | The endpoint is not enabled yet (see the preview note at the top). | Watch the release notes. |
| 413 | request_too_large | Request body larger than 4 MB, or 12 MiB on orion-compass-flash and d3. | Reduce the input, or send smaller images. |
| 429 | rate_limit_exceeded | Your rate limit is exceeded, or the model is temporarily at capacity. The Retry-After header says how many seconds to wait. | Wait for Retry-After, then retry with backoff. |
| 500, 503 | upstream_error, timeout (500), upstream_unavailable (503) | As for chat completions. | Retry with backoff; check the status page if it persists. |
Decisions are idempotent: retrying a request that failed with 429 or a 5xx is safe.
Pricing and limits
- Input tokens only. You are billed on
usage.input_tokens, images included, at the model's input price; output is not billed. Prices are in US dollars per million input tokens, shown live in the table above and returned byGET /v1/models?format=openai(pricing.input;pricing.outputis 0). See also Pricing and limits. - Context. The input and each question must fit the model's context length, shown in the same table. A longer request is refused (HTTP 400, or 422 on
/v1/systemone) withcode: "context_length_exceeded"; nothing is truncated. - Rate limits and capacity. Requests are admitted per model as on chat completions. Over your limit or when the model is at capacity, the API answers HTTP 429 with
Retry-After; handle it as described in Errors and rate limits. - Request size. At most 4 MB per request body, or 12 MiB on
orion-compass-flashandd3, for images. - Data. The same data policy as chat completions applies (see Data residency): request and response bodies are never written to disk or logs and never used for training.
Current limitations
- Images on
orion-compass-flashandd3only.orion-compassreads text only. Images must be base64 data URLs, and videos are not supported. - No streaming. The reply is a single JSON object.
- Token reporting.
output_tokensis always 0 and cached tokens are reported as 0, so there is no cached-input discount on decisions. - Questions, options and levels. At most 256 questions per request, on both endpoints; at most 255 options per
choicequestion; 2 to 10 levels perscorequestion. A request over a limit is refused with HTTP 400 (422 onPOST /v1/systemone) and the parameter at fault inparam. - No per-question refusal. A request the model cannot answer is refused as a whole with an error; there is no
refusalanswer for a single question. - Access routes. Serenity Edge API keys only: not yet with keys from a Serenity Star account, and not part of the OpenRouter onboarding.
Next steps
- Create decision and Create decision (Jev format) in the API reference.
- Models and Pricing and limits for the chat models.
- Errors and rate limits for retries and backoff.