{
  "openapi": "3.1.0",
  "info": {
    "title": "Serenity Edge API",
    "version": "1.0.0",
    "summary": "OpenAI-compatible inference API running on Substrate AI's own GPU infrastructure in Spain.",
    "description": "Serenity Edge exposes an OpenAI-compatible API for chat completions, embeddings and model discovery, a rerank API, a redaction API for personal data and, in preview, decisions: typed, calibrated answers to typed questions. Requests are authenticated with a bearer API key and served from GPUs in Valencia, Spain. Prompts and completions are never written to disk or logs; prompt prefixes may stay in a volatile memory cache for at most 24 hours.\n\nIf you already use the OpenAI SDK, point `base_url` to `https://api.serenityedge.ai/v1` and keep the rest of your code.",
    "contact": {
      "name": "Serenity Edge",
      "url": "https://docs.serenityedge.ai"
    },
    "termsOfService": "https://docs.serenityedge.ai/terms/terms-of-service"
  },
  "servers": [
    {
      "url": "https://api.serenityedge.ai/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "BearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Chat",
      "description": "Generate a model response for a conversation. Supports streaming, tool calling, structured outputs and reasoning."
    },
    {
      "name": "Responses",
      "description": "OpenAI's Responses API over the chat models, stateless: send the whole conversation in `input` on every request. See the [Responses API guide](/docs/responses-api)."
    },
    {
      "name": "Decisions",
      "description": "Preview. Typed, calibrated answers (probabilities) to typed questions from the Orion Compass decision models, in the format of OpenAI's Decisions API or in the System One format of TypeSafe Jev. See the [Decisions guide](/docs/decisions)."
    },
    {
      "name": "Embeddings, rerank and redaction",
      "description": "Vector embeddings in OpenAI's format, reranking in the format of Cohere and Jina, and redaction of personal data in the privacy filter's own format, each with its own model and billed on input tokens only. See the [Embeddings, rerank and redaction guide](/docs/embeddings-rerank-and-redaction)."
    },
    {
      "name": "Models",
      "description": "List the models available to your API key."
    }
  ],
  "paths": {
    "/chat/completions": {
      "post": {
        "tags": ["Chat"],
        "operationId": "createChatCompletion",
        "summary": "Create chat completion",
        "description": "Creates a model response for the given conversation. Set `stream: true` to receive the response as a stream of server-sent events; the final chunk carries the `usage` object when `stream_options.include_usage` is `true`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatCompletionRequest"
              },
              "examples": {
                "simple": {
                  "summary": "Simple request",
                  "value": {
                    "model": "orion-pro",
                    "messages": [
                      { "role": "system", "content": "You are a helpful assistant." },
                      { "role": "user", "content": "Summarise the benefits of EU data residency in two sentences." }
                    ]
                  }
                },
                "streaming": {
                  "summary": "Streaming with usage in the final chunk",
                  "value": {
                    "model": "orion-plus",
                    "stream": true,
                    "stream_options": { "include_usage": true },
                    "messages": [
                      { "role": "user", "content": "Write a haiku about the Mediterranean." }
                    ]
                  }
                },
                "tools": {
                  "summary": "Tool calling",
                  "value": {
                    "model": "orion-pro",
                    "messages": [
                      { "role": "user", "content": "What is the weather in Valencia today?" }
                    ],
                    "tools": [
                      {
                        "type": "function",
                        "function": {
                          "name": "get_weather",
                          "description": "Get the current weather for a city.",
                          "parameters": {
                            "type": "object",
                            "properties": {
                              "city": { "type": "string", "description": "City name" }
                            },
                            "required": ["city"]
                          }
                        }
                      }
                    ],
                    "tool_choice": "auto"
                  }
                },
                "json_schema": {
                  "summary": "Structured output with a JSON schema",
                  "value": {
                    "model": "orion-pro",
                    "messages": [
                      { "role": "user", "content": "Extract the invoice number and total from: Invoice INV-2041, total 1,250.00 EUR." }
                    ],
                    "response_format": {
                      "type": "json_schema",
                      "json_schema": {
                        "name": "invoice",
                        "strict": true,
                        "schema": {
                          "type": "object",
                          "properties": {
                            "invoice_number": { "type": "string" },
                            "total": { "type": "number" },
                            "currency": { "type": "string" }
                          },
                          "required": ["invoice_number", "total", "currency"],
                          "additionalProperties": false
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A chat completion. When `stream` is `true` the body is a `text/event-stream` of `ChatCompletionChunk` objects terminated by `data: [DONE]`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatCompletion"
                },
                "example": {
                  "id": "chatcmpl-8f0f1e2a",
                  "object": "chat.completion",
                  "created": 1758542400,
                  "model": "orion-pro",
                  "choices": [
                    {
                      "index": 0,
                      "message": {
                        "role": "assistant",
                        "content": "Keeping data within the EU simplifies GDPR compliance and removes the need for international transfer safeguards. It also gives customers a single, predictable legal framework for audits and contracts."
                      },
                      "finish_reason": "stop"
                    }
                  ],
                  "usage": {
                    "prompt_tokens": 31,
                    "completion_tokens": 42,
                    "total_tokens": 73,
                    "prompt_tokens_details": { "cached_tokens": 0 }
                  }
                }
              },
              "text/event-stream": {
                "schema": {
                  "$ref": "#/components/schemas/ChatCompletionChunk"
                },
                "example": "data: {\"id\":\"chatcmpl-8f0f1e2a\",\"object\":\"chat.completion.chunk\",\"created\":1758542400,\"model\":\"orion-plus\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"Blue\"},\"finish_reason\":null}]}\n\ndata: {\"id\":\"chatcmpl-8f0f1e2a\",\"object\":\"chat.completion.chunk\",\"created\":1758542400,\"model\":\"orion-plus\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" waves\"},\"finish_reason\":null}]}\n\ndata: {\"id\":\"chatcmpl-8f0f1e2a\",\"object\":\"chat.completion.chunk\",\"created\":1758542400,\"model\":\"orion-plus\",\"choices\":[{\"index\":0,\"delta\":{},\"finish_reason\":\"stop\"}]}\n\ndata: {\"id\":\"chatcmpl-8f0f1e2a\",\"object\":\"chat.completion.chunk\",\"created\":1758542400,\"model\":\"orion-plus\",\"choices\":[],\"usage\":{\"prompt_tokens\":14,\"completion_tokens\":17,\"total_tokens\":31}}\n\ndata: [DONE]\n\n"
              }
            }
          },
          "400": {
            "description": "The request is malformed or a parameter is invalid. More images than the model reads, counted over the whole conversation (from 1 to 8 depending on the model: `references.max` in `GET /v1/models`), are refused with `code: too_many_images` and `param: messages`.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "Invalid value for 'max_tokens': must be a positive integer.",
                    "type": "invalid_request_error",
                    "param": "max_tokens",
                    "code": "invalid_value"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "Incorrect API key provided.",
                    "type": "authentication_error",
                    "param": null,
                    "code": "invalid_api_key"
                  }
                }
              }
            }
          },
          "404": {
            "description": "The requested model does not exist or is not available to this key.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "The model 'orion-max' does not exist.",
                    "type": "invalid_request_error",
                    "param": "model",
                    "code": "model_not_found"
                  }
                }
              }
            }
          },
          "413": {
            "description": "The request body is larger than the gateway accepts (4 MB).",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "The request body is too large. The limit is 4 MB.",
                    "type": "invalid_request_error",
                    "param": null,
                    "code": "request_too_large"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded, or the service is temporarily at capacity for this model. Wait for the number of seconds in the `Retry-After` header before retrying.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": { "type": "integer", "minimum": 0 }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "Rate limit reached. Please retry after 12 seconds.",
                    "type": "rate_limit_error",
                    "param": null,
                    "code": "rate_limit_exceeded"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error: the model service returned an unexpected response (`upstream_error`), the request got no answer within 600 seconds (`timeout`), or an error in the gateway. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "The server had an error while processing your request.",
                    "type": "server_error",
                    "param": null,
                    "code": null
                  }
                }
              }
            }
          },
          "503": {
            "description": "The model service is temporarily unavailable. Retry later and check the status page at https://status.serenityedge.ai.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "The model service is temporarily unavailable. Please retry later.",
                    "type": "server_error",
                    "param": null,
                    "code": "upstream_unavailable"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/responses": {
      "post": {
        "tags": ["Responses"],
        "operationId": "createResponse",
        "summary": "Create a model response",
        "description": "OpenAI's Responses API (`client.responses.create` in the OpenAI SDKs) over the same chat models as `POST /v1/chat/completions`, with the same keys, prices and limits.\n\n**Stateless.** Nothing is stored, so the whole conversation goes in `input` on every request. `store: true`, `previous_response_id`, `conversation`, `background: true` and stored `prompt` templates are refused with 400, every response says `\"store\": false`, and the routes under `/v1/responses/` (retrieve, delete, cancel, input items, compact, input tokens) answer 404.\n\n**Served:**\n\n- text and inline images, `instructions`, and the items of earlier turns;\n- function tools (`tools`, `tool_choice`, `parallel_tool_calls`);\n- `text.format` (`text`, `json_object`, `json_schema`);\n- `reasoning.effort`, with the reasoning returned in plain text in a `reasoning` item;\n- `max_output_tokens`, `temperature`, `top_p`.\n\n**Streaming.** With `stream: true` the body is a `text/event-stream` of Responses events (`event:` line plus JSON with `type` and `sequence_number`), in this order:\n\n1. `response.created`, then `response.in_progress`;\n2. each output item: `response.output_item.added`, its content part, the deltas (`response.output_text.delta`, `response.reasoning_text.delta`, `response.function_call_arguments.delta`) and the matching `done` events;\n3. exactly one of `response.completed`, `response.incomplete` or `response.failed`, carrying the full response.\n\nNo `[DONE]` follows. See the [Responses API guide](/docs/responses-api).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResponseRequest"
              },
              "example": {
                "model": "orion-plus",
                "instructions": "Answer in one sentence.",
                "input": "Why does EU data residency matter for a SaaS company?"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The response. With `stream: true`, a `text/event-stream` of `ResponseStreamEvent` objects instead, ending with `response.completed`, `response.incomplete` or `response.failed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                },
                "example": {
                  "id": "resp_6a1f0c9e2b7d4f8a9c3e5b1d7f2a4c6e",
                  "object": "response",
                  "created_at": 1793131557,
                  "status": "completed",
                  "background": false,
                  "error": null,
                  "incomplete_details": null,
                  "instructions": "Answer in one sentence.",
                  "max_output_tokens": null,
                  "max_tool_calls": null,
                  "model": "orion-plus",
                  "output": [
                    {
                      "id": "msg_3c8e1a5f7b9d2e4a6c0f8b1d3e5a7c9f",
                      "type": "message",
                      "status": "completed",
                      "role": "assistant",
                      "content": [
                        {
                          "type": "output_text",
                          "text": "Keeping data in the EU simplifies GDPR compliance and removes the need for international transfer safeguards.",
                          "annotations": [],
                          "logprobs": []
                        }
                      ]
                    }
                  ],
                  "parallel_tool_calls": true,
                  "previous_response_id": null,
                  "prompt_cache_key": null,
                  "reasoning": {
                    "effort": null,
                    "summary": null
                  },
                  "safety_identifier": null,
                  "service_tier": "default",
                  "store": false,
                  "temperature": null,
                  "text": {
                    "format": {
                      "type": "text"
                    }
                  },
                  "tool_choice": "auto",
                  "tools": [],
                  "top_logprobs": 0,
                  "top_p": null,
                  "truncation": "disabled",
                  "usage": {
                    "input_tokens": 31,
                    "input_tokens_details": {
                      "cached_tokens": 0
                    },
                    "output_tokens": 24,
                    "output_tokens_details": {
                      "reasoning_tokens": 0
                    },
                    "total_tokens": 55
                  },
                  "user": null,
                  "metadata": {}
                }
              },
              "text/event-stream": {
                "schema": {
                  "$ref": "#/components/schemas/ResponseStreamEvent"
                }
              }
            }
          },
          "400": {
            "description": "The request was refused before reaching the model. Causes:\n\n- a stateful parameter: `store: true`, `previous_response_id`, `conversation`, `background: true`, `prompt` or an `item_reference` item. The API is stateless;\n- a hosted tool (`web_search`, `file_search`, `code_interpreter`, `computer_use`, `image_generation`, `mcp`, custom tools) or its items in `input`. In Codex, turn web search off with `web_search = \"disabled\"` in `config.toml`;\n- a file input, or an image by URL or file id: images must be inline base64 data URLs;\n- logprobs, `truncation: \"auto\"`, `context_management` (compaction) or an unknown parameter (such as chat's `messages`);\n- more images than the model reads, counted over the whole `input`: from 1 to 8 depending on the model (`code: too_many_images`, `param: input`);\n- any invalid value, or input longer than the context window (`context_length_exceeded`).\n\n`param` names the field at fault in the Responses API's terms (`input`, `max_output_tokens`, `tools[0].type`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "message": "This API is stateless (zero data retention): responses are never stored, so 'previous_response_id' is not supported. Send the whole conversation history in 'input' on every request.",
                    "type": "invalid_request_error",
                    "param": "previous_response_id",
                    "code": "invalid_request_error"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "message": "Incorrect API key provided.",
                    "type": "authentication_error",
                    "param": null,
                    "code": "invalid_api_key"
                  }
                }
              }
            }
          },
          "404": {
            "description": "The requested model does not exist or is not available to this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "message": "The model 'orion-max' does not exist.",
                    "type": "invalid_request_error",
                    "param": "model",
                    "code": "model_not_found"
                  }
                }
              }
            }
          },
          "413": {
            "description": "The request body is larger than the gateway accepts (4 MB).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "message": "The request body is too large. The limit is 4 MB.",
                    "type": "invalid_request_error",
                    "param": null,
                    "code": "request_too_large"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded, or the service is temporarily at capacity for this model. Wait for the number of seconds in the `Retry-After` header before retrying.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "message": "Rate limit reached. Please retry after 12 seconds.",
                    "type": "rate_limit_error",
                    "param": null,
                    "code": "rate_limit_exceeded"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error: the model service returned an unexpected response (`upstream_error`), the request got no answer within 600 seconds (`timeout`), or an error in the gateway. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "message": "The server had an error while processing your request.",
                    "type": "server_error",
                    "param": null,
                    "code": null
                  }
                }
              }
            }
          },
          "503": {
            "description": "The model service is temporarily unavailable. Retry later and check the status page at https://status.serenityedge.ai.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": {
                    "message": "The model service is temporarily unavailable. Please retry later.",
                    "type": "server_error",
                    "param": null,
                    "code": "upstream_unavailable"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/decisions": {
      "post": {
        "tags": ["Decisions"],
        "operationId": "createDecision",
        "summary": "Create decision",
        "description": "**Preview.** Answers typed questions about an input with calibrated probabilities instead of generated text, in the format of OpenAI's Decisions API (`client.decisions.create` in OpenAI's Python SDK). Each question is a `predicate` (yes or no), a `choice` (one of several typed values) or a `score` (one of 2 to 10 ordered levels); the answers come back in question order.\n\nOnly decision models can be used: `GET /v1/models?format=openai` lists them, each with `endpoints`. Only input tokens are billed. There is no streaming. Only Serenity Edge API keys can use this route; a key from a Serenity Star account gets 403 `permission_denied` for now. Until the service is enabled, the route answers 404 like an unknown path. See the [Decisions guide](/docs/decisions).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DecisionRequest"
              },
              "examples": {
                "triage": {
                  "summary": "Ticket triage with the three question types",
                  "value": {
                    "model": "orion-compass",
                    "input": [
                      {
                        "role": "user",
                        "content": [
                          { "type": "input_text", "text": "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" }
                        ]
                      }
                    ]
                  }
                },
                "gate": {
                  "summary": "Text input with a predicate and a boolean choice",
                  "value": {
                    "model": "orion-compass-flash",
                    "input": "Hi, this is Laura from Acme. Please call me back on +34 600 000 000 about the invoice.",
                    "questions": [
                      { "type": "predicate", "instructions": "Does the message contain personal data such as a name, an email address or a phone number?" },
                      {
                        "type": "choice",
                        "name": "needs_human",
                        "instructions": "Does the message need an answer from a person?",
                        "choices": [
                          { "value": true, "description": "A person must call or write back" },
                          { "value": false, "description": "An automatic acknowledgement is enough" }
                        ]
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answers, one per question in question order, with the versioned id of the model that answered and the token usage.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Decision"
                },
                "example": {
                  "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
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request was refused: malformed body, missing `model`, an unknown question type, an invalid option or level, an image the model cannot read, or an input longer than the model's context (`code: context_length_exceeded`). The message says what to fix and `param` points at the parameter when it is known.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "this model reads text only; input_image parts are not supported",
                    "type": "invalid_request_error",
                    "param": "input[0].content[1]",
                    "code": "invalid_request_error"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "Missing or invalid API key. Send it as 'Authorization: Bearer <key>'.",
                    "type": "authentication_error",
                    "param": null,
                    "code": "invalid_api_key"
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but cannot use the decision API. For now only Serenity Edge API keys can; keys from a Serenity Star account cannot yet.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "This API key cannot use the decision API. Use a Serenity Edge API key.",
                    "type": "permission_error",
                    "param": null,
                    "code": "permission_denied"
                  }
                }
              }
            }
          },
          "404": {
            "description": "The model is not a decision model (chat models cannot be used here), or the route is not enabled yet and answers like an unknown path.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "The model 'orion-pro' does not exist or you do not have access to it.",
                    "type": "not_found_error",
                    "param": "model",
                    "code": "model_not_found"
                  }
                }
              }
            }
          },
          "413": {
            "description": "The request body is larger than the gateway accepts (4 MB, or 12 MiB on `orion-compass-flash` and `d3`).",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "The request body exceeds the maximum size of 4194304 bytes.",
                    "type": "invalid_request_error",
                    "param": null,
                    "code": "request_too_large"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded, or the service is temporarily at capacity for this model. Wait for the number of seconds in the `Retry-After` header before retrying.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": { "type": "integer", "minimum": 0 }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "The service is at capacity for this model. Retry after the number of seconds in the Retry-After header.",
                    "type": "rate_limit_error",
                    "param": null,
                    "code": "rate_limit_exceeded"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error: the model service returned an unexpected response (`upstream_error`), the request got no answer within 600 seconds (`timeout`), or an error in the gateway. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "503": {
            "description": "The model service is temporarily unavailable (`upstream_unavailable`). Retry later and check the status page at https://status.serenityedge.ai.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    },
    "/systemone": {
      "post": {
        "tags": ["Decisions"],
        "operationId": "createSystemOneDecision",
        "summary": "Create decision (Jev format)",
        "description": "**Preview.** The same decision models in the System One format of TypeSafe Jev (`POST /v1/systemone`), for callers and tools migrating from Jev: `state` is any JSON value, `questions` is an object keyed by your own ids, and the question types are `noul` (yes or no), `choice` and `score`, with the options or levels in `criteria`. The answers come back under the same ids. Add `\"calibration\": \"raw\"` to get uncalibrated probabilities.\n\nA question the model service cannot read is refused with HTTP 422, as Jev does; the error body is the same error object as on every other route. Access, billing (input tokens only), limits and the other errors are the same as on [Create decision](/docs/api/edge/create-decision). See the [Decisions guide](/docs/decisions#jev-compatible-route).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SystemOneRequest"
              },
              "example": {
                "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"] }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "One answer per question, under the question's id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SystemOneResponse"
                },
                "example": {
                  "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 } }
                }
              }
            }
          },
          "400": {
            "description": "The body is not a JSON object, or `model` is missing.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "'model' is required.",
                    "type": "invalid_request_error",
                    "param": "model",
                    "code": "invalid_request_error"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "403": {
            "description": "The key is valid but cannot use the decision API (`permission_denied`). For now only Serenity Edge API keys can; keys from a Serenity Star account cannot yet.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "404": {
            "description": "The model is not a decision model (`model_not_found`), or the route is not enabled yet and answers like an unknown path.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "413": {
            "description": "The request body is larger than the gateway accepts (4 MB, or 12 MiB on `orion-compass-flash` and `d3`; `request_too_large`).",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "422": {
            "description": "The model service refused the questions or the state: an unknown question type, invalid `criteria`, too many options, images the model cannot read, or a state longer than the model's context (`code: context_length_exceeded`). The message says what to fix.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "'questions' must be a non-empty object of {id: question}",
                    "type": "invalid_request_error",
                    "param": null,
                    "code": "invalid_request_error"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded, or the service is temporarily at capacity for this model. Wait for the number of seconds in the `Retry-After` header before retrying.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": { "type": "integer", "minimum": 0 }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "500": {
            "description": "Unexpected server error: the model service returned an unexpected response (`upstream_error`), the request got no answer within 600 seconds (`timeout`), or an error in the gateway. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "503": {
            "description": "The model service is temporarily unavailable (`upstream_unavailable`). Retry later and check the status page at https://status.serenityedge.ai.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    },
    "/embeddings": {
      "post": {
        "tags": ["Embeddings, rerank and redaction"],
        "operationId": "createEmbedding",
        "summary": "Create embeddings",
        "description": "Turns text into vectors, in the format of OpenAI's embeddings API (`client.embeddings.create` in the OpenAI SDKs). `qwen3-embedding-0.6b` (alias `qwen/qwen3-embedding-0.6b`) returns one vector of 1024 numbers per input, for at most 512 inputs per request.\n\nBilled on `usage.prompt_tokens`, the input tokens the model read, at the model's input price; output is not billed. `GET /v1/models?format=openai` lists the model with `endpoints: [\"/v1/embeddings\"]` and its price per million tokens. Only Serenity Edge API keys can use this route. See the [Embeddings, rerank and redaction guide](/docs/embeddings-rerank-and-redaction#embeddings).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmbeddingRequest"
              },
              "example": {
                "model": "qwen3-embedding-0.6b",
                "input": ["Refunds are issued within 5 working days.", "Orders ship from Valencia within 48 hours."],
                "encoding_format": "float"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "One embedding per input, in input order, with the model id and the tokens the model read. The vectors of the example are shortened to four numbers; each has 1024.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmbeddingList"
                },
                "example": {
                  "object": "list",
                  "data": [
                    { "object": "embedding", "index": 0, "embedding": [0.0213, -0.0472, 0.0091, 0.0368] },
                    { "object": "embedding", "index": 1, "embedding": [-0.0154, 0.0327, 0.0619, -0.0083] }
                  ],
                  "model": "qwen3-embedding-0.6b",
                  "usage": { "prompt_tokens": 19, "total_tokens": 19 }
                }
              }
            }
          },
          "400": {
            "description": "The request was refused: a body that is not a JSON object, a missing or invalid `model`, `input` or `encoding_format`, more than 512 inputs, more than about 300,000 tokens (a quarter of the characters), a model served on another route (`The model 'qwen3-reranker-0.6b' is not served on /v1/embeddings.`), or a request the model server could not process (`The model server rejected the request. Check the input sizes and parameters.`). `param` names the field at fault when there is one.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "'input' takes at most 512 inputs per request.",
                    "type": "invalid_request_error",
                    "param": "input",
                    "code": "invalid_request_error"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "Missing or invalid API key. Send it as 'Authorization: Bearer <key>'.",
                    "type": "authentication_error",
                    "param": null,
                    "code": "invalid_api_key"
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but cannot use this route: only Serenity Edge API keys can. Any other key, such as a key from a Serenity Star account, gets `permission_denied` with a message that names the route's API (`embeddings`, `rerank` or `redact`).",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "This API key cannot use the embeddings API. Use a Serenity Edge API key.",
                    "type": "permission_error",
                    "param": null,
                    "code": "permission_denied"
                  }
                }
              }
            }
          },
          "404": {
            "description": "The model id is unknown, or it is a chat or decision model, which cannot be used on this route (`model_not_found`).",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "The model 'orion-pro' does not exist or you do not have access to it.",
                    "type": "not_found_error",
                    "param": "model",
                    "code": "model_not_found"
                  }
                }
              }
            }
          },
          "413": {
            "description": "The request body is larger than this route accepts (4 MB, `request_too_large`).",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "The request body exceeds the maximum size of 4194304 bytes.",
                    "type": "invalid_request_error",
                    "param": null,
                    "code": "request_too_large"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded, or the service is temporarily at capacity for this model. Wait for the number of seconds in the `Retry-After` header before retrying.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": { "type": "integer", "minimum": 0 }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "500": {
            "description": "Unexpected server error: the model service returned an unexpected response (`upstream_error`), the request got no answer within 600 seconds (`timeout`), or an error in the gateway. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "503": {
            "description": "The model service is temporarily unavailable (`upstream_unavailable`). Retry later and check the status page at https://status.serenityedge.ai.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    },
    "/rerank": {
      "post": {
        "tags": ["Embeddings, rerank and redaction"],
        "operationId": "rerankDocuments",
        "summary": "Rerank documents",
        "description": "Scores how relevant each document is to a query, in the format of the rerank APIs of Cohere and Jina, with `qwen3-reranker-0.6b` (alias `qwen/qwen3-reranker-0.6b`). At most 1000 documents per request, a query of at most 4096 characters and about 300,000 tokens (the estimate below); the model reads each document with the query up to 8,192 tokens.\n\nThe model reports no usage, so the request is billed on an estimate that the API writes into `usage`: for each document, `ceil((characters(query) + characters(document)) / 4)` tokens, added up, with characters counted as Unicode code points. Every document is scored and billed, also when `top_n` returns fewer. Output is not billed. Only Serenity Edge API keys can use this route. See the [Embeddings, rerank and redaction guide](/docs/embeddings-rerank-and-redaction#rerank).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RerankRequest"
              },
              "example": {
                "model": "qwen3-reranker-0.6b",
                "query": "Which city is the capital of Spain?",
                "documents": [
                  "Madrid is the capital and largest city of Spain.",
                  "Valencia is known for paella and the City of Arts and Sciences.",
                  "Málaga lies on the Costa del Sol, in Andalucía."
                ],
                "top_n": 2
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The most relevant documents with their scores, the model id and the estimated tokens the request is billed on. The scores of the example are illustrative; its usage is the estimate for the example request (21 + 25 + 21 tokens).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RerankResponse"
                },
                "example": {
                  "results": [
                    { "index": 0, "relevance_score": 0.982, "document": { "text": "Madrid is the capital and largest city of Spain." } },
                    { "index": 2, "relevance_score": 0.031, "document": { "text": "Málaga lies on the Costa del Sol, in Andalucía." } }
                  ],
                  "model": "qwen3-reranker-0.6b",
                  "usage": { "prompt_tokens": 67, "total_tokens": 67 }
                }
              }
            }
          },
          "400": {
            "description": "The request was refused: a body that is not a JSON object, a missing or invalid `model`, `query`, `documents`, `top_n` or `return_documents`, more than 1000 documents, a query over 4096 characters, more than about 300,000 tokens, a model served on another route, or a request the model server could not process (`The model server rejected the request. Check the input sizes and parameters.`). `param` names the field at fault when there is one.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "'documents' must be a non-empty array of strings or of objects with a string 'text'.",
                    "type": "invalid_request_error",
                    "param": "documents",
                    "code": "invalid_request_error"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "Missing or invalid API key. Send it as 'Authorization: Bearer <key>'.",
                    "type": "authentication_error",
                    "param": null,
                    "code": "invalid_api_key"
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but cannot use this route: only Serenity Edge API keys can. Any other key, such as a key from a Serenity Star account, gets `permission_denied` with a message that names the route's API (`embeddings`, `rerank` or `redact`).",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "This API key cannot use the rerank API. Use a Serenity Edge API key.",
                    "type": "permission_error",
                    "param": null,
                    "code": "permission_denied"
                  }
                }
              }
            }
          },
          "404": {
            "description": "The model id is unknown, or it is a chat or decision model, which cannot be used on this route (`model_not_found`).",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "The model 'orion-pro' does not exist or you do not have access to it.",
                    "type": "not_found_error",
                    "param": "model",
                    "code": "model_not_found"
                  }
                }
              }
            }
          },
          "413": {
            "description": "The request body is larger than this route accepts (4 MB, `request_too_large`).",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "The request body exceeds the maximum size of 4194304 bytes.",
                    "type": "invalid_request_error",
                    "param": null,
                    "code": "request_too_large"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded, or the service is temporarily at capacity for this model. Wait for the number of seconds in the `Retry-After` header before retrying.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": { "type": "integer", "minimum": 0 }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "500": {
            "description": "Unexpected server error: the model service returned an unexpected response (`upstream_error`), the request got no answer within 600 seconds (`timeout`), or an error in the gateway. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "503": {
            "description": "The model service is temporarily unavailable (`upstream_unavailable`). Retry later and check the status page at https://status.serenityedge.ai.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    },
    "/redact": {
      "post": {
        "tags": ["Embeddings, rerank and redaction"],
        "operationId": "redactText",
        "summary": "Redact personal data",
        "description": "Finds personal data in text (names, email addresses, phone numbers, postal addresses, account numbers and more) and masks it, in the privacy filter's own format, with `privacy-filter` (alias `openai/privacy-filter`). `model` is optional. At most 256 inputs and a body of 192 KiB (196,608 bytes) per request. The text sent is processed in memory only: it is never written to disk or logs and never used for training.\n\nThe request is billed on an estimate: `ceil(characters of all inputs / 4)` tokens, with characters counted as Unicode code points. The answer carries no `usage`. Only Serenity Edge API keys can use this route. See the [Embeddings, rerank and redaction guide](/docs/embeddings-rerank-and-redaction#redaction).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RedactRequest"
              },
              "examples": {
                "text": {
                  "summary": "One text",
                  "value": {
                    "inputs": "Hi, I am Ana García. Write to ana.garcia@example.com or call +34 600 000 000.",
                    "placeholders": true
                  }
                },
                "texts": {
                  "summary": "Several texts, phone numbers only",
                  "value": {
                    "model": "privacy-filter",
                    "inputs": ["My name is Ana García.", "Call +34 600 000 000"],
                    "placeholders": true,
                    "categories": ["private_phone"]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "For a string in `inputs`, one result: the text with each item found masked, and the items found. For an array, an array of results in input order.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RedactResponse"
                },
                "example": {
                  "text": "Hi, I am [PERSON]. Write to [EMAIL] or call [PHONE].",
                  "spans": [
                    { "entity_group": "private_person", "score": 1.0, "word": "Ana García", "start": 9, "end": 19, "placeholder": "<PRIVATE_PERSON>" },
                    { "entity_group": "private_email", "score": 1.0, "word": "ana.garcia@example.com", "start": 30, "end": 52, "placeholder": "<PRIVATE_EMAIL>" },
                    { "entity_group": "private_phone", "score": 1.0, "word": "+34 600 000 000", "start": 61, "end": 76, "placeholder": "<PRIVATE_PHONE>" }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request was refused: a body that is not a JSON object, a missing or invalid `inputs`, `placeholders`, `categories` or `model`, more than 256 inputs, a model served on another route, or a request the model server could not process (`The model server rejected the request. Check the input sizes and parameters.`). `param` names the field at fault when there is one.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "'inputs' takes at most 256 inputs per request.",
                    "type": "invalid_request_error",
                    "param": "inputs",
                    "code": "invalid_request_error"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "Missing or invalid API key. Send it as 'Authorization: Bearer <key>'.",
                    "type": "authentication_error",
                    "param": null,
                    "code": "invalid_api_key"
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but cannot use this route: only Serenity Edge API keys can. Any other key, such as a key from a Serenity Star account, gets `permission_denied` with a message that names the route's API (`embeddings`, `rerank` or `redact`).",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "This API key cannot use the redact API. Use a Serenity Edge API key.",
                    "type": "permission_error",
                    "param": null,
                    "code": "permission_denied"
                  }
                }
              }
            }
          },
          "404": {
            "description": "The model id is unknown, or it is a chat or decision model, which cannot be used on this route (`model_not_found`).",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "The model 'orion-pro' does not exist or you do not have access to it.",
                    "type": "not_found_error",
                    "param": "model",
                    "code": "model_not_found"
                  }
                }
              }
            }
          },
          "413": {
            "description": "The request body is larger than this route accepts (192 KiB, 196,608 bytes, `request_too_large`).",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": {
                  "error": {
                    "message": "The request body exceeds the maximum size of 196608 bytes.",
                    "type": "invalid_request_error",
                    "param": null,
                    "code": "request_too_large"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded, or the service is temporarily at capacity for this model. Wait for the number of seconds in the `Retry-After` header before retrying.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": { "type": "integer", "minimum": 0 }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "500": {
            "description": "Unexpected server error: the model service returned an unexpected response (`upstream_error`), the request got no answer within 600 seconds (`timeout`), or an error in the gateway. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "503": {
            "description": "The model service is temporarily unavailable (`upstream_unavailable`). Retry later and check the status page at https://status.serenityedge.ai.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    },
    "/models": {
      "get": {
        "tags": ["Models"],
        "operationId": "listModels",
        "summary": "List models",
        "description": "Lists the models the API serves, as a catalogue document in the OpenRouter provider schema 2.4: one entry per model id with its name, context length, maximum output, prices per token (decimal strings in US dollars), streaming support and supported parameters. The `id` of each entry is the value to send as `model` in a chat completion. No API key is needed, and the endpoint answers cross-origin requests from browsers, which is how the tables on [Models](/docs/models) and [Pricing and limits](/docs/pricing-and-limits) are filled.\n\nAdd `?format=openai` to get the OpenAI-style list instead: `{\"object\": \"list\", \"data\": [{\"id\", \"object\", \"created\", \"owned_by\", \"pricing\", \"context_length\"}]}`, with every id and alias and its prices in US dollars per million tokens. Only this list includes the [decision models](/docs/decisions) (preview) and the [embeddings, rerank and redaction](/docs/embeddings-rerank-and-redaction) models, each with an `endpoints` array naming the routes it is served on (`/v1/decisions` and `/v1/systemone`; `/v1/embeddings`, `/v1/rerank` or `/v1/redact`) and an output price of 0; chat models have no `endpoints`. The tables of these models on [Decisions](/docs/decisions#models) and [Embeddings, rerank and redaction](/docs/embeddings-rerank-and-redaction#models) are filled from it.",
        "responses": {
          "200": {
            "description": "The catalogue, in the OpenRouter provider schema 2.4; with `format=openai`, the OpenAI-style list.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    { "$ref": "#/components/schemas/ModelList" },
                    { "$ref": "#/components/schemas/OpenAIModelList" }
                  ]
                },
                "example": {
                  "data": [
                    {
                      "schema_version": "2.4",
                      "id": "orion-pro",
                      "name": "Serenity: Orion Pro",
                      "created": 1790035200,
                      "description": "Orion Pro, Serenity's own model for quality-sensitive work: long documents, complex instructions and multi-step tool calling. Served from Serenity Edge's own infrastructure in Spain (EU). Zero data retention: prompts and completions are never stored or logged.",
                      "input_modalities": [
                        {
                          "type": "text",
                          "supported_inputs": {
                            "max_context_length": { "value": 262144, "unit": "token" }
                          },
                          "pricing": [
                            { "type": "prompt", "unit": "token", "cost_usd": "0.000000144" },
                            { "type": "cached_prompt", "unit": "token", "cost_usd": "0.000000036", "implicit": true }
                          ]
                        }
                      ],
                      "output_modalities": [
                        {
                          "type": "text",
                          "max_length": { "value": 32768, "unit": "token" },
                          "streaming": true,
                          "supported_parameters": {
                            "temperature": { "type": "range", "min": 0, "max": 2, "default": 0.7 },
                            "top_p": { "type": "range", "min": 0, "max": 1, "default": 0.8 },
                            "top_k": { "type": "integer", "min": 1, "max": 200, "default": 20 },
                            "max_tokens": { "type": "integer", "min": 1, "max": 32768 },
                            "stop": {
                              "type": "array",
                              "items": { "type": "unknown" },
                              "max_items": 4
                            },
                            "seed": { "type": "integer", "min": 0, "max": 9007199254740991 },
                            "tools": { "type": "boolean" },
                            "structured_outputs": { "type": "boolean" },
                            "reasoning": {
                              "type": "object",
                              "properties": {
                                "effort": {
                                  "type": "enum",
                                  "values": ["none", "minimal", "low", "medium", "high", "xhigh"],
                                  "default": "none"
                                }
                              }
                            }
                          },
                          "pricing": [
                            { "type": "completion", "unit": "token", "cost_usd": "0.0000015" }
                          ]
                        }
                      ],
                      "is_free": false,
                      "discount_to_user": 0,
                      "datacenters": [
                        { "country_code": "ES", "region": "valencia" }
                      ],
                      "deployment_region": "EU",
                      "compliance": { "zdr": true, "hipaa": false }
                    },
                    {
                      "schema_version": "2.4",
                      "id": "qwen3.8-27b",
                      "name": "Qwen: Qwen3.8 27B",
                      "created": 1790035200,
                      "quantization": "nvfp4",
                      "description": "Qwen3.8 27B dense model, served with its published weights from Serenity Edge's own infrastructure in Spain (EU). Zero data retention: prompts and completions are never stored or logged.",
                      "input_modalities": [
                        {
                          "type": "text",
                          "supported_inputs": {
                            "max_context_length": { "value": 262144, "unit": "token" }
                          },
                          "pricing": [
                            { "type": "prompt", "unit": "token", "cost_usd": "0.000000144" },
                            { "type": "cached_prompt", "unit": "token", "cost_usd": "0.000000036", "implicit": true }
                          ]
                        }
                      ],
                      "output_modalities": [
                        {
                          "type": "text",
                          "max_length": { "value": 32768, "unit": "token" },
                          "streaming": true,
                          "supported_parameters": {
                            "temperature": { "type": "range", "min": 0, "max": 2, "default": 0.7 },
                            "top_p": { "type": "range", "min": 0, "max": 1, "default": 0.8 },
                            "top_k": { "type": "integer", "min": 1, "max": 200, "default": 20 },
                            "max_tokens": { "type": "integer", "min": 1, "max": 32768 },
                            "stop": {
                              "type": "array",
                              "items": { "type": "unknown" },
                              "max_items": 4
                            },
                            "seed": { "type": "integer", "min": 0, "max": 9007199254740991 },
                            "tools": { "type": "boolean" },
                            "structured_outputs": { "type": "boolean" },
                            "reasoning": {
                              "type": "object",
                              "properties": {
                                "effort": {
                                  "type": "enum",
                                  "values": ["none", "minimal", "low", "medium", "high", "xhigh"],
                                  "default": "none"
                                }
                              }
                            }
                          },
                          "pricing": [
                            { "type": "completion", "unit": "token", "cost_usd": "0.0000015" }
                          ]
                        }
                      ],
                      "is_free": false,
                      "discount_to_user": 0,
                      "openrouter": { "slug": "qwen/qwen3.8-27b" },
                      "datacenters": [
                        { "country_code": "ES", "region": "valencia" }
                      ],
                      "deployment_region": "EU",
                      "compliance": { "zdr": true, "hipaa": false }
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded, or the service is temporarily at capacity for this model. Wait for the number of seconds in the `Retry-After` header before retrying.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": { "type": "integer", "minimum": 0 }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        },
        "security": [],
        "parameters": [
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "`openai` returns the OpenAI-style list (`object`, `data[]` with `id`, `object`, `created` and `owned_by`, plus `pricing` and `context_length`) that the OpenAI SDKs expect from `models.list()`. It is the only list that includes the decision, embeddings, rerank and redaction models, marked with `endpoints`. Omit it for the provider catalogue.",
            "schema": {
              "type": "string",
              "enum": ["openai"]
            }
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Send your API key in the `Authorization` header: `Authorization: Bearer <key>`."
      }
    },
    "schemas": {
      "ChatCompletionRequest": {
        "type": "object",
        "required": ["model", "messages"],
        "properties": {
          "model": {
            "type": "string",
            "description": "Id of the model to use. See the list of models for the available ids.",
            "examples": ["orion-pro", "orion-plus", "qwen3.8-27b", "qwen3.6-35b-a3b"]
          },
          "messages": {
            "type": "array",
            "description": "The conversation so far, oldest first.",
            "minItems": 1,
            "items": { "$ref": "#/components/schemas/ChatCompletionMessage" }
          },
          "stream": {
            "type": "boolean",
            "default": false,
            "description": "If `true`, partial deltas are sent as server-sent events. The stream ends with `data: [DONE]`."
          },
          "stream_options": {
            "$ref": "#/components/schemas/StreamOptions"
          },
          "max_tokens": {
            "type": "integer",
            "minimum": 1,
            "maximum": 32768,
            "description": "Upper bound on the number of tokens to generate. The maximum output for every model is 32,768 tokens."
          },
          "temperature": {
            "type": "number",
            "minimum": 0,
            "maximum": 2,
            "default": 1,
            "description": "Sampling temperature. Lower values make the output more deterministic."
          },
          "top_p": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "default": 1,
            "description": "Nucleus sampling: only tokens within the top `top_p` probability mass are considered."
          },
          "n": {
            "type": "integer",
            "minimum": 1,
            "default": 1,
            "description": "Number of completions to generate for each request."
          },
          "stop": {
            "description": "Up to four sequences at which generation stops.",
            "oneOf": [
              { "type": "string" },
              { "type": "array", "items": { "type": "string" }, "maxItems": 4 }
            ]
          },
          "presence_penalty": {
            "type": "number",
            "minimum": -2,
            "maximum": 2,
            "default": 0,
            "description": "Penalises tokens that already appear in the text so far."
          },
          "frequency_penalty": {
            "type": "number",
            "minimum": -2,
            "maximum": 2,
            "default": 0,
            "description": "Penalises tokens in proportion to how often they already appear."
          },
          "seed": {
            "type": "integer",
            "description": "Best-effort deterministic sampling. Repeated requests with the same seed and parameters aim to return the same result."
          },
          "tools": {
            "type": "array",
            "description": "Functions the model may call. See the tool calling guide.",
            "items": { "$ref": "#/components/schemas/Tool" }
          },
          "tool_choice": {
            "$ref": "#/components/schemas/ToolChoice"
          },
          "parallel_tool_calls": {
            "type": "boolean",
            "default": true,
            "description": "Whether the model may return several tool calls in one response."
          },
          "response_format": {
            "$ref": "#/components/schemas/ResponseFormat"
          },
          "reasoning": {
            "$ref": "#/components/schemas/ReasoningOptions"
          },
          "user": {
            "type": "string",
            "description": "An opaque identifier for your end user, useful for abuse detection on your side. Not stored beyond the request metadata retention period."
          }
        }
      },
      "ChatCompletionMessage": {
        "description": "A message in the conversation. The shape depends on `role`.",
        "oneOf": [
          { "$ref": "#/components/schemas/SystemMessage" },
          { "$ref": "#/components/schemas/UserMessage" },
          { "$ref": "#/components/schemas/AssistantMessage" },
          { "$ref": "#/components/schemas/ToolMessage" }
        ],
        "discriminator": {
          "propertyName": "role",
          "mapping": {
            "system": "#/components/schemas/SystemMessage",
            "user": "#/components/schemas/UserMessage",
            "assistant": "#/components/schemas/AssistantMessage",
            "tool": "#/components/schemas/ToolMessage"
          }
        }
      },
      "SystemMessage": {
        "type": "object",
        "required": ["role", "content"],
        "properties": {
          "role": { "type": "string", "enum": ["system"] },
          "content": { "type": "string", "description": "Instructions that steer the behaviour of the model." },
          "name": { "type": "string", "description": "Optional name of the participant." }
        }
      },
      "UserMessage": {
        "type": "object",
        "required": ["role", "content"],
        "properties": {
          "role": { "type": "string", "enum": ["user"] },
          "content": {
            "description": "The message, as a plain string or as an array of text and image parts (up to the model's limit of 1 to 8 images per request, `references.max` in `GET /v1/models`; base64 data URLs only; image URLs are refused with 400).",
            "oneOf": [
              { "type": "string" },
              {
                "type": "array",
                "items": { "oneOf": [{ "$ref": "#/components/schemas/TextContentPart" }, { "$ref": "#/components/schemas/ImageContentPart" }] }
              }
            ]
          },
          "name": { "type": "string", "description": "Optional name of the participant." }
        }
      },
      "ImageContentPart": {
        "type": "object",
        "description": "An image inline as a base64 data URL. Up to the model's limit of 1 to 8 images per request (`references.max` in `GET /v1/models`); image URLs are not fetched (400).",
        "required": ["type", "image_url"],
        "properties": {
          "type": { "type": "string", "enum": ["image_url"] },
          "image_url": {
            "type": "object",
            "required": ["url"],
            "properties": {
              "url": { "type": "string", "description": "A data URL: data:image/png;base64,... (PNG, JPEG, WebP or GIF)." },
              "detail": { "type": "string", "enum": ["auto", "low", "high"] }
            }
          }
        }
      },
      "TextContentPart": {
        "type": "object",
        "required": ["type", "text"],
        "properties": {
          "type": { "type": "string", "enum": ["text"] },
          "text": { "type": "string" }
        }
      },
      "AssistantMessage": {
        "type": "object",
        "required": ["role"],
        "properties": {
          "role": { "type": "string", "enum": ["assistant"] },
          "content": {
            "type": ["string", "null"],
            "description": "The text of the message. `null` when the message only carries tool calls."
          },
          "tool_calls": {
            "type": "array",
            "description": "Tool calls the model made in a previous turn.",
            "items": { "$ref": "#/components/schemas/ToolCall" }
          },
          "name": { "type": "string", "description": "Optional name of the participant." }
        }
      },
      "ToolMessage": {
        "type": "object",
        "required": ["role", "content", "tool_call_id"],
        "properties": {
          "role": { "type": "string", "enum": ["tool"] },
          "content": { "type": "string", "description": "The result returned by your function, as a string (usually JSON)." },
          "tool_call_id": { "type": "string", "description": "The `id` of the tool call this message answers." }
        }
      },
      "Tool": {
        "type": "object",
        "required": ["type", "function"],
        "properties": {
          "type": { "type": "string", "enum": ["function"] },
          "function": { "$ref": "#/components/schemas/FunctionDefinition" }
        }
      },
      "FunctionDefinition": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "name": {
            "type": "string",
            "description": "Function name. Letters, digits, underscores and dashes; at most 64 characters.",
            "pattern": "^[a-zA-Z0-9_-]{1,64}$"
          },
          "description": { "type": "string", "description": "What the function does. The model uses it to decide when to call the function." },
          "parameters": {
            "type": "object",
            "description": "JSON Schema object describing the arguments.",
            "additionalProperties": true
          },
          "strict": {
            "type": "boolean",
            "default": false,
            "description": "When `true`, the arguments are guaranteed to match `parameters` exactly."
          }
        }
      },
      "ToolChoice": {
        "description": "Controls whether and which tool the model calls. `none` disables tools, `auto` lets the model decide, `required` forces at least one call, and an object forces a specific function.",
        "oneOf": [
          { "type": "string", "enum": ["none", "auto", "required"] },
          {
            "type": "object",
            "required": ["type", "function"],
            "properties": {
              "type": { "type": "string", "enum": ["function"] },
              "function": {
                "type": "object",
                "required": ["name"],
                "properties": { "name": { "type": "string" } }
              }
            }
          }
        ]
      },
      "ToolCall": {
        "type": "object",
        "required": ["id", "type", "function"],
        "properties": {
          "id": { "type": "string", "description": "Identifier to echo back in the `tool_call_id` of the tool message." },
          "type": { "type": "string", "enum": ["function"] },
          "function": {
            "type": "object",
            "required": ["name", "arguments"],
            "properties": {
              "name": { "type": "string" },
              "arguments": { "type": "string", "description": "JSON-encoded arguments. Always validate before use." }
            }
          }
        }
      },
      "ResponseFormat": {
        "description": "Format of the output. `text` (default), `json_object` for any valid JSON, or `json_schema` to constrain the output to a schema.",
        "oneOf": [
          {
            "type": "object",
            "title": "Text",
            "required": ["type"],
            "properties": { "type": { "type": "string", "enum": ["text"] } }
          },
          {
            "type": "object",
            "title": "JSON object",
            "required": ["type"],
            "properties": { "type": { "type": "string", "enum": ["json_object"] } }
          },
          {
            "type": "object",
            "title": "JSON schema",
            "required": ["type", "json_schema"],
            "properties": {
              "type": { "type": "string", "enum": ["json_schema"] },
              "json_schema": { "$ref": "#/components/schemas/JsonSchemaFormat" }
            }
          }
        ]
      },
      "JsonSchemaFormat": {
        "type": "object",
        "required": ["name", "schema"],
        "properties": {
          "name": { "type": "string", "description": "Name of the schema.", "pattern": "^[a-zA-Z0-9_-]{1,64}$" },
          "description": { "type": "string" },
          "schema": {
            "type": "object",
            "description": "A JSON Schema object the output must satisfy.",
            "additionalProperties": true
          },
          "strict": {
            "type": "boolean",
            "default": false,
            "description": "When `true`, the output is guaranteed to match the schema exactly."
          }
        }
      },
      "ReasoningOptions": {
        "type": "object",
        "description": "Reasoning settings for models that support it. Reasoning tokens are billed as output tokens.",
        "properties": {
          "effort": {
            "type": "string",
            "enum": ["low", "medium", "high"],
            "description": "How much reasoning the model should do before answering."
          },
          "exclude": {
            "type": "boolean",
            "default": false,
            "description": "When `true`, the model reasons but the reasoning text is not returned."
          }
        }
      },
      "StreamOptions": {
        "type": "object",
        "description": "Options that only apply when `stream` is `true`.",
        "properties": {
          "include_usage": {
            "type": "boolean",
            "default": false,
            "description": "When `true`, one extra chunk with an empty `choices` array and the `usage` object is sent before `data: [DONE]`."
          }
        }
      },
      "ChatCompletion": {
        "type": "object",
        "required": ["id", "object", "created", "model", "choices"],
        "properties": {
          "id": { "type": "string", "description": "Unique identifier of the completion." },
          "object": { "type": "string", "enum": ["chat.completion"] },
          "created": { "type": "integer", "description": "Unix timestamp (seconds) of creation." },
          "model": { "type": "string", "description": "The model that generated the response." },
          "choices": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ChatCompletionChoice" }
          },
          "usage": { "$ref": "#/components/schemas/Usage" },
          "system_fingerprint": { "type": "string", "description": "Identifier of the backend configuration that served the request." }
        }
      },
      "ChatCompletionChoice": {
        "type": "object",
        "required": ["index", "message", "finish_reason"],
        "properties": {
          "index": { "type": "integer" },
          "message": { "$ref": "#/components/schemas/AssistantResponseMessage" },
          "finish_reason": { "$ref": "#/components/schemas/FinishReason" }
        }
      },
      "AssistantResponseMessage": {
        "type": "object",
        "required": ["role"],
        "properties": {
          "role": { "type": "string", "enum": ["assistant"] },
          "content": { "type": ["string", "null"], "description": "The generated text, or `null` when the response only carries tool calls." },
          "tool_calls": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ToolCall" }
          },
          "reasoning": {
            "type": ["string", "null"],
            "description": "Reasoning text, when the request enabled reasoning and did not exclude it."
          }
        }
      },
      "FinishReason": {
        "type": ["string", "null"],
        "enum": ["stop", "length", "tool_calls", "content_filter", null],
        "description": "`stop`: natural end or stop sequence. `length`: `max_tokens` or the context window was reached. `tool_calls`: the model wants to call a tool. `content_filter`: output was withheld. `null` in streaming chunks that are not the last one."
      },
      "Usage": {
        "type": "object",
        "required": ["prompt_tokens", "completion_tokens", "total_tokens"],
        "properties": {
          "prompt_tokens": { "type": "integer", "description": "Tokens in the prompt, including cached tokens." },
          "completion_tokens": { "type": "integer", "description": "Tokens generated, including reasoning tokens." },
          "total_tokens": { "type": "integer" },
          "prompt_tokens_details": {
            "type": "object",
            "properties": {
              "cached_tokens": { "type": "integer", "description": "Prompt tokens served from the prompt cache, billed at the cached input price." }
            }
          },
          "completion_tokens_details": {
            "type": "object",
            "properties": {
              "reasoning_tokens": { "type": "integer", "description": "Tokens spent on reasoning." }
            }
          }
        }
      },
      "ChatCompletionChunk": {
        "type": "object",
        "description": "One server-sent event of a streamed completion. Sent as `data: <json>` lines separated by blank lines; the stream ends with `data: [DONE]`.",
        "required": ["id", "object", "created", "model", "choices"],
        "properties": {
          "id": { "type": "string", "description": "Same for every chunk of one completion." },
          "object": { "type": "string", "enum": ["chat.completion.chunk"] },
          "created": { "type": "integer" },
          "model": { "type": "string" },
          "choices": {
            "type": "array",
            "description": "Empty in the final usage chunk when `stream_options.include_usage` is `true`.",
            "items": { "$ref": "#/components/schemas/ChatCompletionChunkChoice" }
          },
          "usage": {
            "description": "Present only in the final chunk when `stream_options.include_usage` is `true`; `null` or absent otherwise.",
            "oneOf": [
              { "$ref": "#/components/schemas/Usage" },
              { "type": "null" }
            ]
          }
        }
      },
      "ChatCompletionChunkChoice": {
        "type": "object",
        "required": ["index", "delta"],
        "properties": {
          "index": { "type": "integer" },
          "delta": { "$ref": "#/components/schemas/ChatCompletionDelta" },
          "finish_reason": { "$ref": "#/components/schemas/FinishReason" }
        }
      },
      "ChatCompletionDelta": {
        "type": "object",
        "description": "The incremental change carried by this chunk. Concatenate `content` across chunks to rebuild the message.",
        "properties": {
          "role": { "type": "string", "enum": ["assistant"], "description": "Present in the first chunk only." },
          "content": { "type": ["string", "null"] },
          "reasoning": { "type": ["string", "null"] },
          "tool_calls": {
            "type": "array",
            "description": "Tool call fragments. Match fragments by `index` and concatenate `function.arguments`.",
            "items": { "$ref": "#/components/schemas/ToolCallDelta" }
          }
        }
      },
      "ToolCallDelta": {
        "type": "object",
        "required": ["index"],
        "properties": {
          "index": { "type": "integer" },
          "id": { "type": "string", "description": "Present in the first fragment of each tool call." },
          "type": { "type": "string", "enum": ["function"] },
          "function": {
            "type": "object",
            "properties": {
              "name": { "type": "string", "description": "Present in the first fragment of each tool call." },
              "arguments": { "type": "string", "description": "A fragment of the JSON-encoded arguments." }
            }
          }
        }
      },
      "ResponseRequest": {
      "type": "object",
      "required": ["model", "input"],
      "properties": {
        "model": {
          "type": "string",
          "description": "Id or alias of a chat model, as on `POST /v1/chat/completions`.",
          "examples": ["orion-plus"]
        },
        "input": {
          "description": "The conversation: a string (one user message) or an array of input items. Send every earlier turn: nothing is stored between requests.",
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "array",
              "minItems": 1,
              "items": {
                "$ref": "#/components/schemas/ResponseInputItem"
              }
            }
          ]
        },
        "instructions": {
          "type": "string",
          "description": "System message for this request. Every `system` and `developer` message of `input` is added to it, in order."
        },
        "tools": {
          "type": "array",
          "items": {
            "oneOf": [
              { "$ref": "#/components/schemas/ResponseFunctionTool" },
              { "$ref": "#/components/schemas/ResponseNamespaceTool" }
            ]
          },
          "description": "Function tools, alone or grouped in `namespace` tools (as Codex groups the tools of its plugins and MCP servers). Hosted tools are refused."
        },
        "tool_choice": {
          "description": "`auto` (default), `none`, `required`, or `{\"type\": \"function\", \"name\": \"...\"}`.",
          "oneOf": [
            {
              "type": "string",
              "enum": ["auto", "none", "required"]
            },
            {
              "type": "object",
              "required": ["type", "name"],
              "properties": {
                "type": {
                  "type": "string",
                  "enum": ["function"]
                },
                "name": {
                  "type": "string"
                }
              }
            }
          ]
        },
        "parallel_tool_calls": {
          "type": "boolean",
          "description": "Whether the model may call several functions at once. Default `true`."
        },
        "text": {
          "$ref": "#/components/schemas/ResponseTextConfig"
        },
        "reasoning": {
          "type": "object",
          "properties": {
            "effort": {
              "type": "string",
              "enum": ["none", "minimal", "low", "medium", "high", "xhigh"],
              "description": "`none` (default) turns reasoning off; any other value turns it on."
            },
            "summary": {
              "type": "string",
              "description": "Accepted; no summary is produced. The reasoning comes back in plain text."
            }
          }
        },
        "max_output_tokens": {
          "type": "integer",
          "minimum": 1,
          "description": "Cap on generated tokens, reasoning included. Capped at the model's output limit. A response cut by it has `status: \"incomplete\"`."
        },
        "temperature": {
          "type": "number",
          "minimum": 0,
          "maximum": 2
        },
        "top_p": {
          "type": "number",
          "minimum": 0,
          "maximum": 1
        },
        "stream": {
          "type": "boolean",
          "description": "Stream Responses events. Default `false`."
        },
        "store": {
          "type": "boolean",
          "enum": [false],
          "description": "Only `false` (or omitted): responses are never stored."
        },
        "include": {
          "type": "array",
          "items": {
            "type": "string",
            "enum": ["reasoning.encrypted_content", "message.input_image.image_url"]
          },
          "description": "Accepted values; neither changes the answer. `message.output_text.logprobs` is refused."
        },
        "truncation": {
          "type": "string",
          "enum": ["disabled"],
          "description": "Input longer than the context window is refused, never cut."
        },
        "metadata": {
          "type": "object",
          "additionalProperties": {
            "type": "string"
          },
          "description": "Repeated in the response; not stored."
        },
        "user": {
          "type": "string",
          "description": "Repeated in the response; not stored."
        },
        "client_metadata": {
          "type": "object",
          "description": "Client identifiers, as Codex sends them. Accepted and dropped: they reach neither the model nor the response."
        }
      }
    },
    "ResponseInputItem": {
      "description": "An input item: a message, or an item of an earlier turn (`function_call`, `function_call_output`, `reasoning`). Output items of a response can be sent back as they are.",
      "oneOf": [
        {
          "$ref": "#/components/schemas/ResponseInputMessage"
        },
        {
          "$ref": "#/components/schemas/ResponseFunctionCall"
        },
        {
          "$ref": "#/components/schemas/ResponseFunctionCallOutput"
        },
        {
          "$ref": "#/components/schemas/ResponseReasoningItem"
        }
      ]
    },
    "ResponseInputMessage": {
      "type": "object",
      "required": ["role", "content"],
      "properties": {
        "type": {
          "type": "string",
          "enum": ["message"],
          "description": "Optional for messages."
        },
        "role": {
          "type": "string",
          "enum": ["user", "assistant", "system", "developer"],
          "description": "`developer` is treated as `system`."
        },
        "content": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "array",
              "items": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/ResponseInputText"
                  },
                  {
                    "$ref": "#/components/schemas/ResponseInputImage"
                  },
                  {
                    "$ref": "#/components/schemas/ResponseOutputText"
                  }
                ]
              }
            }
          ]
        }
      }
    },
    "ResponseInputText": {
      "type": "object",
      "required": ["type", "text"],
      "properties": {
        "type": {
          "type": "string",
          "enum": ["input_text"]
        },
        "text": {
          "type": "string"
        }
      }
    },
    "ResponseInputImage": {
      "type": "object",
      "required": ["type", "image_url"],
      "properties": {
        "type": {
          "type": "string",
          "enum": ["input_image"]
        },
        "image_url": {
          "type": "string",
          "description": "A base64 data URL (`data:image/png;base64,...`). Image URLs and file ids are refused.",
          "examples": ["data:image/png;base64,iVBORw0KGgo..."]
        },
        "detail": {
          "type": "string",
          "enum": ["low", "high", "auto"]
        }
      }
    },
    "ResponseFunctionCallOutput": {
      "type": "object",
      "required": ["type", "call_id", "output"],
      "properties": {
        "type": {
          "type": "string",
          "enum": ["function_call_output"]
        },
        "call_id": {
          "type": "string",
          "description": "The `call_id` of the `function_call` this answers."
        },
        "output": {
          "description": "The function's result: a string or an array of `input_text` parts.",
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/ResponseInputText"
              }
            }
          ]
        }
      }
    },
    "ResponseFunctionTool": {
      "type": "object",
      "required": ["type", "name"],
      "properties": {
        "type": {
          "type": "string",
          "enum": ["function"]
        },
        "name": {
          "type": "string"
        },
        "description": {
          "type": "string"
        },
        "parameters": {
          "type": "object",
          "description": "JSON schema of the arguments."
        },
        "strict": {
          "type": "boolean"
        }
      }
    },
    "ResponseNamespaceTool": {
      "type": "object",
      "description": "Function tools grouped under a namespace. The model sees each one as a function named after its namespace and name, and a call to it comes back as a `function_call` with its `name` and `namespace`.",
      "required": ["type", "name", "tools"],
      "properties": {
        "type": {
          "type": "string",
          "enum": ["namespace"]
        },
        "name": {
          "type": "string",
          "examples": ["mcp__node_repl"]
        },
        "description": {
          "type": "string"
        },
        "tools": {
          "type": "array",
          "description": "Function tools only.",
          "items": {
            "$ref": "#/components/schemas/ResponseFunctionTool"
          }
        }
      }
    },
    "ResponseTextConfig": {
      "type": "object",
      "properties": {
        "format": {
          "description": "`text` (default), `json_object`, or `json_schema` with `name` and `schema`, as `response_format` on chat.",
          "oneOf": [
            {
              "type": "object",
              "required": ["type"],
              "properties": {
                "type": {
                  "type": "string",
                  "enum": ["text", "json_object"]
                }
              }
            },
            {
              "type": "object",
              "required": ["type", "name", "schema"],
              "properties": {
                "type": {
                  "type": "string",
                  "enum": ["json_schema"]
                },
                "name": {
                  "type": "string"
                },
                "schema": {
                  "type": "object"
                },
                "description": {
                  "type": "string"
                },
                "strict": {
                  "type": "boolean"
                }
              }
            }
          ]
        },
        "verbosity": {
          "type": "string",
          "enum": ["low", "medium", "high"],
          "description": "Accepted; no effect."
        }
      }
    },
    "Response": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "description": "`resp_` and 32 hex digits. Never stored: it cannot be retrieved."
        },
        "object": {
          "type": "string",
          "enum": ["response"]
        },
        "created_at": {
          "type": "integer"
        },
        "status": {
          "type": "string",
          "enum": ["completed", "incomplete", "failed", "in_progress"]
        },
        "error": {
          "description": "Set when `status` is `failed` (only in a stream's `response.failed`).",
          "oneOf": [
            {
              "type": "null"
            },
            {
              "type": "object",
              "properties": {
                "code": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          ]
        },
        "incomplete_details": {
          "description": "`{\"reason\": \"max_output_tokens\"}` when the answer was cut.",
          "oneOf": [
            {
              "type": "null"
            },
            {
              "type": "object",
              "properties": {
                "reason": {
                  "type": "string",
                  "enum": ["max_output_tokens", "content_filter"]
                }
              }
            }
          ]
        },
        "model": {
          "type": "string"
        },
        "output": {
          "type": "array",
          "items": {
            "$ref": "#/components/schemas/ResponseOutputItem"
          }
        },
        "store": {
          "type": "boolean",
          "enum": [false]
        },
        "usage": {
          "$ref": "#/components/schemas/ResponseUsage"
        }
      },
      "description": "A response. The request's parameters (`instructions`, `tools`, `tool_choice`, `text`, `reasoning`, `temperature`, `top_p`, `max_output_tokens`, `metadata`, `user`) are repeated as sent, or with OpenAI's defaults."
    },
    "ResponseOutputItem": {
      "description": "An output item, in this order: `reasoning` (when the model reasoned), `message`, `function_call` (one per call).",
      "oneOf": [
        {
          "$ref": "#/components/schemas/ResponseReasoningItem"
        },
        {
          "$ref": "#/components/schemas/ResponseOutputMessage"
        },
        {
          "$ref": "#/components/schemas/ResponseFunctionCall"
        }
      ]
    },
    "ResponseReasoningItem": {
      "type": "object",
      "required": ["type"],
      "properties": {
        "id": {
          "type": "string"
        },
        "type": {
          "type": "string",
          "enum": ["reasoning"]
        },
        "status": {
          "type": "string"
        },
        "summary": {
          "type": "array",
          "items": {
            "type": "object"
          },
          "description": "Always empty in output."
        },
        "content": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": ["reasoning_text"]
              },
              "text": {
                "type": "string"
              }
            }
          },
          "description": "The reasoning, in plain text."
        },
        "encrypted_content": {
          "type": "null",
          "description": "Always `null`: the reasoning is returned in plain text."
        }
      }
    },
    "ResponseOutputMessage": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string"
        },
        "type": {
          "type": "string",
          "enum": ["message"]
        },
        "status": {
          "type": "string",
          "enum": ["completed", "incomplete", "in_progress"]
        },
        "role": {
          "type": "string",
          "enum": ["assistant"]
        },
        "content": {
          "type": "array",
          "items": {
            "$ref": "#/components/schemas/ResponseOutputText"
          }
        }
      }
    },
    "ResponseOutputText": {
      "type": "object",
      "required": ["type", "text"],
      "properties": {
        "type": {
          "type": "string",
          "enum": ["output_text"]
        },
        "text": {
          "type": "string"
        },
        "annotations": {
          "type": "array",
          "items": {
            "type": "object"
          }
        },
        "logprobs": {
          "type": "array",
          "items": {
            "type": "object"
          }
        }
      }
    },
    "ResponseFunctionCall": {
      "type": "object",
      "required": ["type", "call_id", "name", "arguments"],
      "properties": {
        "id": {
          "type": "string"
        },
        "type": {
          "type": "string",
          "enum": ["function_call"]
        },
        "status": {
          "type": "string"
        },
        "call_id": {
          "type": "string",
          "description": "Answer it with a `function_call_output` with the same `call_id`."
        },
        "name": {
          "type": "string"
        },
        "namespace": {
          "type": "string",
          "description": "Set on a call to a function of a `namespace` tool: the namespace's name. Send it back as it came."
        },
        "arguments": {
          "type": "string",
          "description": "The arguments as a JSON string."
        }
      }
    },
    "ResponseUsage": {
      "type": "object",
      "properties": {
        "input_tokens": {
          "type": "integer"
        },
        "input_tokens_details": {
          "type": "object",
          "properties": {
            "cached_tokens": {
              "type": "integer"
            }
          }
        },
        "output_tokens": {
          "type": "integer",
          "description": "Generated tokens, reasoning included."
        },
        "output_tokens_details": {
          "type": "object",
          "properties": {
            "reasoning_tokens": {
              "type": "integer",
              "description": "0 when the model does not report it."
            }
          }
        },
        "total_tokens": {
          "type": "integer"
        }
      }
    },
    "ResponseStreamEvent": {
      "type": "object",
      "required": ["type", "sequence_number"],
      "description": "One streamed event; the `event:` line repeats `type`. Item events carry `output_index` and `item_id`, part events `content_index`, deltas `delta`, done events the full `text`, `arguments` or `item`, and the first two and the last carry the whole `response`.",
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "response.created",
            "response.in_progress",
            "response.output_item.added",
            "response.content_part.added",
            "response.output_text.delta",
            "response.output_text.done",
            "response.reasoning_text.delta",
            "response.reasoning_text.done",
            "response.function_call_arguments.delta",
            "response.function_call_arguments.done",
            "response.content_part.done",
            "response.output_item.done",
            "response.completed",
            "response.incomplete",
            "response.failed"
          ]
        },
        "sequence_number": {
          "type": "integer",
          "description": "Counts from 0 within a stream."
        },
        "response": {
          "$ref": "#/components/schemas/Response"
        }
      }
    },
    "DecisionRequest": {
        "type": "object",
        "required": ["model", "input", "questions"],
        "properties": {
          "model": {
            "type": "string",
            "description": "Id of the decision model: an alias such as `orion-compass`, which follows the current version, or a versioned id such as `orion-compass-26.1`. `GET /v1/models?format=openai` lists the decision models, each with `endpoints`.",
            "examples": ["orion-compass", "orion-compass-flash"]
          },
          "input": { "$ref": "#/components/schemas/DecisionInput" },
          "questions": {
            "type": "array",
            "description": "The questions to answer about the input, 1 to 256. The answers come back in the same order.",
            "minItems": 1,
            "maxItems": 256,
            "items": { "$ref": "#/components/schemas/DecisionQuestion" }
          },
          "safety_identifier": {
            "type": "string",
            "description": "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."
          }
        }
      },
      "DecisionInput": {
        "description": "What the questions are about: a string, an array of user messages whose text parts are read in order, separated by a blank line, or a whole conversation (system, developer and assistant messages, tool calls and their outputs), read as a labelled transcript: see [Conversations](/docs/decisions#conversations). `orion-compass-flash` and `d3` also read images in user messages: `input_image` parts with base64 data URLs, at most 4 images, 8 MiB in total once decoded and 16 megapixels each. `orion-compass` refuses them with HTTP 400.",
        "oneOf": [
          { "type": "string", "title": "Text" },
          {
            "type": "array",
            "title": "Messages and tool calls",
            "minItems": 1,
            "items": {
              "oneOf": [
                { "$ref": "#/components/schemas/DecisionInputMessage" },
                { "$ref": "#/components/schemas/DecisionFunctionCall" },
                { "$ref": "#/components/schemas/DecisionFunctionCallOutput" },
                { "$ref": "#/components/schemas/DecisionCustomToolCall" },
                { "$ref": "#/components/schemas/DecisionCustomToolCallOutput" }
              ]
            }
          }
        ]
      },
      "DecisionInputMessage": {
        "type": "object",
        "required": ["role", "content"],
        "properties": {
          "type": { "type": "string", "enum": ["message"], "description": "Optional." },
          "role": {
            "type": "string",
            "enum": ["user", "system", "developer", "assistant"],
            "description": "A conversation may mix roles. An input of user messages only is read without labels."
          },
          "content": {
            "description": "The message, as a string or as an array of parts. User messages take `input_text`, `input_json` and, on `orion-compass-flash` and `d3`, `input_image`; system and developer messages take `input_text`; assistant messages take `output_text` and `refusal`.",
            "oneOf": [
              { "type": "string" },
              {
                "type": "array",
                "items": {
                  "oneOf": [
                    { "$ref": "#/components/schemas/DecisionInputTextPart" },
                    { "$ref": "#/components/schemas/DecisionInputImagePart" },
                    { "$ref": "#/components/schemas/DecisionInputJSONPart" },
                    { "$ref": "#/components/schemas/DecisionOutputTextPart" },
                    { "$ref": "#/components/schemas/DecisionRefusalPart" }
                  ]
                }
              }
            ]
          },
          "phase": {
            "type": "string",
            "enum": ["commentary", "final_answer"],
            "description": "Assistant messages only; optional. Read as part of the label."
          }
        }
      },
      "DecisionInputTextPart": {
        "type": "object",
        "required": ["type", "text"],
        "properties": {
          "type": { "type": "string", "enum": ["input_text"] },
          "text": { "type": "string" }
        }
      },
      "DecisionInputImagePart": {
        "type": "object",
        "description": "An image, read by `orion-compass-flash` and `d3` (at most 4 images, 8 MiB in total once decoded and 16 megapixels each). `orion-compass` refuses it with HTTP 400.",
        "required": ["type", "image_url"],
        "properties": {
          "type": { "type": "string", "enum": ["input_image"] },
          "image_url": {
            "type": "string",
            "description": "A base64 data URL of a PNG, JPEG or WebP image (`data:image/png;base64,...`). File ids and web URLs are refused: the API fetches nothing."
          }
        }
      },
      "DecisionInputJSONPart": {
        "type": "object",
        "description": "Structured data in a user message, read as compact JSON.",
        "required": ["type", "data"],
        "properties": {
          "type": { "type": "string", "enum": ["input_json"] },
          "data": {
            "description": "An object, or an array of objects.",
            "oneOf": [
              { "type": "object" },
              {
                "type": "array",
                "items": { "type": "object" }
              }
            ]
          }
        }
      },
      "DecisionOutputTextPart": {
        "type": "object",
        "required": ["type", "text"],
        "properties": {
          "type": { "type": "string", "enum": ["output_text"] },
          "text": { "type": "string" }
        }
      },
      "DecisionRefusalPart": {
        "type": "object",
        "description": "Read as `Refusal: ` followed by its text.",
        "required": ["type", "refusal"],
        "properties": {
          "type": { "type": "string", "enum": ["refusal"] },
          "refusal": { "type": "string" }
        }
      },
      "DecisionFunctionCall": {
        "type": "object",
        "description": "A function call made in the conversation, read as `[function_call <name> <call_id>]` followed by the arguments.",
        "required": ["type", "name", "call_id", "arguments"],
        "properties": {
          "type": { "type": "string", "enum": ["function_call"] },
          "name": { "type": "string" },
          "namespace": { "type": "string", "description": "Optional. Prefixes the name, as in `billing.refund`." },
          "call_id": { "type": "string" },
          "arguments": { "type": "string" }
        }
      },
      "DecisionFunctionCallOutput": {
        "type": "object",
        "description": "The output of a function call, read as `[function_call_output <call_id>]` followed by the output.",
        "required": ["type", "call_id", "output"],
        "properties": {
          "type": { "type": "string", "enum": ["function_call_output"] },
          "call_id": {
            "type": "string",
            "description": "The `call_id` of an earlier call of the same kind in `input`, else HTTP 400."
          },
          "output": {
            "description": "A string, or an array of `input_text` parts. Images in tool outputs are refused with HTTP 400.",
            "oneOf": [
              { "type": "string" },
              {
                "type": "array",
                "items": { "$ref": "#/components/schemas/DecisionInputTextPart" }
              }
            ]
          }
        }
      },
      "DecisionCustomToolCall": {
        "type": "object",
        "description": "A custom tool call made in the conversation, read as `[custom_tool_call <name> <call_id>]` followed by its input.",
        "required": ["type", "name", "call_id", "input"],
        "properties": {
          "type": { "type": "string", "enum": ["custom_tool_call"] },
          "name": { "type": "string" },
          "namespace": { "type": "string", "description": "Optional. Prefixes the name." },
          "call_id": { "type": "string" },
          "input": { "type": "string" }
        }
      },
      "DecisionCustomToolCallOutput": {
        "type": "object",
        "description": "The output of a custom tool call, read as `[custom_tool_call_output <call_id>]` followed by the output.",
        "required": ["type", "call_id", "output"],
        "properties": {
          "type": { "type": "string", "enum": ["custom_tool_call_output"] },
          "call_id": {
            "type": "string",
            "description": "The `call_id` of an earlier call of the same kind in `input`, else HTTP 400."
          },
          "output": {
            "description": "A string, or an array of `input_text` parts. Images in tool outputs are refused with HTTP 400.",
            "oneOf": [
              { "type": "string" },
              {
                "type": "array",
                "items": { "$ref": "#/components/schemas/DecisionInputTextPart" }
              }
            ]
          }
        }
      },
      "DecisionQuestion": {
        "description": "A question about the input. The shape depends on `type`.",
        "oneOf": [
          { "$ref": "#/components/schemas/PredicateQuestion" },
          { "$ref": "#/components/schemas/ChoiceQuestion" },
          { "$ref": "#/components/schemas/ScoreQuestion" }
        ],
        "discriminator": {
          "propertyName": "type",
          "mapping": {
            "predicate": "#/components/schemas/PredicateQuestion",
            "choice": "#/components/schemas/ChoiceQuestion",
            "score": "#/components/schemas/ScoreQuestion"
          }
        }
      },
      "PredicateQuestion": {
        "type": "object",
        "title": "Predicate",
        "description": "A yes or no question. The answer is the probability of yes.",
        "required": ["type", "instructions"],
        "properties": {
          "type": { "type": "string", "enum": ["predicate"] },
          "name": { "type": "string", "minLength": 1, "description": "Optional name, unique in the request, repeated in the answer." },
          "instructions": { "type": "string", "description": "The question, in natural language." }
        }
      },
      "ChoiceQuestion": {
        "type": "object",
        "title": "Choice",
        "description": "Pick one of several options. The answer is the most likely option, its confidence and the probability of every option.",
        "required": ["type", "instructions", "choices"],
        "properties": {
          "type": { "type": "string", "enum": ["choice"] },
          "name": { "type": "string", "minLength": 1, "description": "Optional name, unique in the request, repeated in the answer." },
          "instructions": { "type": "string", "description": "The question, in natural language." },
          "choices": {
            "type": "array",
            "description": "The options, at most 255. Values must be distinct, also as text: a string and a boolean that read the same (`\"true\"` and `true`) cannot both be offered.",
            "maxItems": 255,
            "items": { "$ref": "#/components/schemas/DecisionChoiceOption" }
          }
        }
      },
      "DecisionChoiceOption": {
        "type": "object",
        "required": ["value"],
        "properties": {
          "value": { "type": ["string", "boolean"], "description": "The value returned in `choice` when this option is picked." },
          "description": { "type": "string", "description": "What the option means. The model reads it." }
        }
      },
      "ScoreQuestion": {
        "type": "object",
        "title": "Score",
        "description": "Rate the input on an ordered scale. The answer is the expected position on the scale, its confidence and the probability of every level.",
        "required": ["type", "instructions", "levels"],
        "properties": {
          "type": { "type": "string", "enum": ["score"] },
          "name": { "type": "string", "minLength": 1, "description": "Optional name, unique in the request, repeated in the answer." },
          "instructions": { "type": "string", "description": "The question, in natural language." },
          "levels": {
            "type": "array",
            "description": "The levels in order, from 2 to 10, with distinct labels. The first level is position 0.",
            "minItems": 2,
            "maxItems": 10,
            "items": { "$ref": "#/components/schemas/DecisionScoreLevel" }
          }
        }
      },
      "DecisionScoreLevel": {
        "type": "object",
        "required": ["label"],
        "properties": {
          "label": { "type": "string", "description": "Name of the level." },
          "description": { "type": "string", "description": "What the level means. The model reads it." }
        }
      },
      "Decision": {
        "type": "object",
        "required": ["answers", "model", "usage"],
        "properties": {
          "answers": {
            "type": "array",
            "description": "One answer per question, in question order.",
            "items": { "$ref": "#/components/schemas/DecisionAnswer" }
          },
          "model": { "type": "string", "description": "The versioned id of the model that answered (`orion-compass-26.1` when the request named `orion-compass`)." },
          "usage": { "$ref": "#/components/schemas/DecisionUsage" }
        }
      },
      "DecisionAnswer": {
        "description": "The answer to one question. The shape depends on `type`, the type of the question.",
        "oneOf": [
          { "$ref": "#/components/schemas/PredicateAnswer" },
          { "$ref": "#/components/schemas/ChoiceAnswer" },
          { "$ref": "#/components/schemas/ScoreAnswer" }
        ],
        "discriminator": {
          "propertyName": "type",
          "mapping": {
            "predicate": "#/components/schemas/PredicateAnswer",
            "choice": "#/components/schemas/ChoiceAnswer",
            "score": "#/components/schemas/ScoreAnswer"
          }
        }
      },
      "PredicateAnswer": {
        "type": "object",
        "title": "Predicate",
        "required": ["type", "probability"],
        "properties": {
          "type": { "type": "string", "enum": ["predicate"] },
          "name": { "type": "string", "description": "The question's name, present when the question had one." },
          "probability": { "type": "number", "minimum": 0, "maximum": 1, "description": "Probability that the answer is yes." }
        }
      },
      "ChoiceAnswer": {
        "type": "object",
        "title": "Choice",
        "required": ["type", "choice", "confidence", "probabilities"],
        "properties": {
          "type": { "type": "string", "enum": ["choice"] },
          "name": { "type": "string", "description": "The question's name, present when the question had one." },
          "choice": { "type": ["string", "boolean"], "description": "The value of the most likely option, typed as in the request. On a tie, the option listed first." },
          "confidence": { "$ref": "#/components/schemas/DecisionConfidence" },
          "probabilities": {
            "type": "array",
            "description": "The probability of every option, in the order of `choices`. They add up to 1.",
            "items": { "$ref": "#/components/schemas/ChoiceProbability" }
          }
        }
      },
      "ChoiceProbability": {
        "type": "object",
        "required": ["value", "probability"],
        "properties": {
          "value": { "type": ["string", "boolean"] },
          "probability": { "type": "number", "minimum": 0, "maximum": 1 }
        }
      },
      "ScoreAnswer": {
        "type": "object",
        "title": "Score",
        "required": ["type", "score", "confidence", "probabilities"],
        "properties": {
          "type": { "type": "string", "enum": ["score"] },
          "name": { "type": "string", "description": "The question's name, present when the question had one." },
          "score": { "type": "number", "minimum": 0, "description": "The expected position on the scale: the probability-weighted mean of the level positions, from 0 (first level) to the number of levels minus one." },
          "confidence": { "$ref": "#/components/schemas/DecisionConfidence" },
          "probabilities": {
            "type": "array",
            "description": "The probability of every level, in the order of `levels`. They add up to 1.",
            "items": { "$ref": "#/components/schemas/ScoreProbability" }
          }
        }
      },
      "ScoreProbability": {
        "type": "object",
        "required": ["value", "label", "probability"],
        "properties": {
          "value": { "type": "integer", "minimum": 0, "description": "Position of the level, 0 for the first." },
          "label": { "type": "string" },
          "probability": { "type": "number", "minimum": 0, "maximum": 1 }
        }
      },
      "DecisionConfidence": {
        "type": "number",
        "minimum": 0,
        "maximum": 1,
        "description": "How far the most likely option stands above chance: `(p_max - 1/n) / (1 - 1/n)` for `n` options or levels, 0 when they are all equally likely and 1 when one takes all the probability."
      },
      "DecisionUsage": {
        "type": "object",
        "required": ["input_tokens", "output_tokens", "total_tokens"],
        "properties": {
          "input_tokens": { "type": "integer", "description": "Tokens the model read to answer, images included, billed at the input price. The input is read with each question, so the count grows with the number of questions." },
          "input_tokens_details": {
            "type": "object",
            "properties": {
              "cached_tokens": { "type": "integer", "description": "Always 0: cached input is not reported on decisions." },
              "cache_write_tokens": { "type": "integer", "description": "Always 0." },
              "text_tokens": { "type": "integer", "description": "Present only for a request with images: the text part of `input_tokens`, each image counted as its placeholder." },
              "image_tokens": { "type": "integer", "description": "Present only for a request with images: the tokens the images expand to, over every question's read. Part of `input_tokens`: `text_tokens + image_tokens = input_tokens`." }
            }
          },
          "output_tokens": { "type": "integer", "description": "Always 0: the answer is read from the model's probabilities, no text is generated." },
          "output_tokens_details": {
            "type": "object",
            "properties": {
              "reasoning_tokens": { "type": "integer", "description": "Always 0." }
            }
          },
          "total_tokens": { "type": "integer", "description": "Equal to `input_tokens`." }
        }
      },
      "SystemOneRequest": {
        "type": "object",
        "required": ["model", "state", "questions"],
        "properties": {
          "model": {
            "type": "string",
            "description": "Id of the decision model, as on `POST /v1/decisions`.",
            "examples": ["orion-compass", "orion-compass-flash"]
          },
          "state": {
            "description": "What the questions are about: any JSON value (a string, an object, an array)."
          },
          "questions": {
            "type": "object",
            "description": "The questions, keyed by ids of your choice, 1 to 256. The answers come back under the same ids.",
            "minProperties": 1,
            "maxProperties": 256,
            "additionalProperties": { "$ref": "#/components/schemas/SystemOneQuestion" }
          },
          "calibration": {
            "type": "string",
            "enum": ["raw"],
            "description": "`raw` returns the probabilities without calibration. Omit it for calibrated probabilities."
          },
          "images": {
            "type": "array",
            "description": "Images the questions are about, read by `orion-compass-flash` and `d3` (at most 4 images, 8 MiB in total once decoded and 16 megapixels each). `orion-compass` refuses them with HTTP 422.",
            "maxItems": 4,
            "items": { "type": "string", "description": "A base64 data URL of a PNG, JPEG or WebP image." }
          }
        }
      },
      "SystemOneQuestion": {
        "type": "object",
        "required": ["type", "instructions"],
        "properties": {
          "type": {
            "type": "string",
            "enum": ["noul", "choice", "score"],
            "description": "`noul` (yes or no), `choice` (one of the options in `criteria`) or `score` (one of the ordered levels in `criteria`)."
          },
          "instructions": {
            "type": ["string", "object"],
            "description": "The question. A JSON object is also accepted and read as text."
          },
          "criteria": {
            "description": "For `choice`, the options (at most 255); for `score`, the levels in order (2 to 10). Either an object that maps each name to its description (or `null`), or an array of names. Not used by `noul`.",
            "oneOf": [
              {
                "type": "object",
                "title": "Names with descriptions",
                "additionalProperties": { "type": ["string", "null"] }
              },
              {
                "type": "array",
                "title": "Names",
                "items": { "type": "string" }
              }
            ]
          }
        }
      },
      "SystemOneResponse": {
        "type": "object",
        "required": ["model", "answers", "usage"],
        "properties": {
          "model": { "type": "string", "description": "The versioned id of the model that answered." },
          "answers": {
            "type": "object",
            "description": "One answer per question, under the question's id.",
            "additionalProperties": { "$ref": "#/components/schemas/SystemOneAnswer" }
          },
          "usage": {
            "type": "object",
            "required": ["input_tokens", "output_tokens"],
            "properties": {
              "input_tokens": { "type": "integer", "description": "Tokens the model read to answer, images included, billed at the input price. The state is read with each question, so the count grows with the number of questions." },
              "output_tokens": { "type": "integer", "description": "One per answer, as in Jev's format. Not billed." },
              "text_tokens": { "type": "integer", "description": "Present only for a request with images: the text part of `input_tokens`, each image counted as its placeholder." },
              "image_tokens": { "type": "integer", "description": "Present only for a request with images: the tokens the images expand to, over every question's read. Part of `input_tokens`: `text_tokens + image_tokens = input_tokens`." }
            }
          },
          "latency_ms": { "type": "number", "description": "Time the model service took to answer, in milliseconds." },
          "calibration": { "$ref": "#/components/schemas/SystemOneCalibration" }
        }
      },
      "SystemOneCalibration": {
        "type": "object",
        "properties": {
          "applied": { "type": "boolean", "description": "`true` when the probabilities are calibrated; `false` when the request asked for `raw`." },
          "temperatures": {
            "type": "object",
            "description": "The temperature applied to each question type.",
            "additionalProperties": { "type": "number" }
          }
        }
      },
      "SystemOneAnswer": {
        "description": "The answer to one question. The shape depends on `type`, the type of the question.",
        "oneOf": [
          { "$ref": "#/components/schemas/NoulAnswer" },
          { "$ref": "#/components/schemas/SystemOneChoiceAnswer" },
          { "$ref": "#/components/schemas/SystemOneScoreAnswer" }
        ],
        "discriminator": {
          "propertyName": "type",
          "mapping": {
            "noul": "#/components/schemas/NoulAnswer",
            "choice": "#/components/schemas/SystemOneChoiceAnswer",
            "score": "#/components/schemas/SystemOneScoreAnswer"
          }
        }
      },
      "NoulAnswer": {
        "type": "object",
        "title": "Noul",
        "required": ["type", "noul"],
        "properties": {
          "type": { "type": "string", "enum": ["noul"] },
          "noul": { "type": "number", "minimum": 0, "maximum": 1, "description": "Probability that the answer is yes." }
        }
      },
      "SystemOneChoiceAnswer": {
        "type": "object",
        "title": "Choice",
        "required": ["type", "choice", "confidence", "probabilities"],
        "properties": {
          "type": { "type": "string", "enum": ["choice"] },
          "choice": { "type": "string", "description": "The name of the most likely option. On a tie, the option listed first." },
          "confidence": { "$ref": "#/components/schemas/DecisionConfidence" },
          "probabilities": {
            "type": "object",
            "description": "The probability of every option, by name. They add up to 1.",
            "additionalProperties": { "type": "number" }
          }
        }
      },
      "SystemOneScoreAnswer": {
        "type": "object",
        "title": "Score",
        "required": ["type", "score", "confidence", "probabilities"],
        "properties": {
          "type": { "type": "string", "enum": ["score"] },
          "score": { "type": "number", "minimum": 0, "description": "The expected position on the scale, from 0 (first level) to the number of levels minus one." },
          "confidence": { "$ref": "#/components/schemas/DecisionConfidence" },
          "legend": {
            "type": "object",
            "description": "The level at each position: `\"0\"` for the first level.",
            "additionalProperties": { "type": "string" }
          },
          "probabilities": {
            "type": "object",
            "description": "The probability of every level, by position (`\"0\"`, `\"1\"`...). They add up to 1.",
            "additionalProperties": { "type": "number" }
          }
        }
      },
      "EmbeddingRequest": {
        "type": "object",
        "required": ["model", "input"],
        "properties": {
          "model": {
            "type": "string",
            "description": "Id of the embeddings model: `qwen3-embedding-0.6b`, or its alias `qwen/qwen3-embedding-0.6b`. `GET /v1/models?format=openai` lists it with `endpoints: [\"/v1/embeddings\"]`.",
            "examples": ["qwen3-embedding-0.6b"]
          },
          "input": { "$ref": "#/components/schemas/EmbeddingInput" },
          "encoding_format": {
            "type": "string",
            "enum": ["float", "base64"],
            "description": "Accepted as in OpenAI's API, but vectors always come back as arrays of numbers, also for `base64`; the official OpenAI SDKs accept either form. `dimensions` is not supported: every vector has 1024 numbers."
          }
        }
      },
      "EmbeddingInput": {
        "description": "The text to embed: a non-empty string, or an array of at most 512 non-empty strings. Each input is read up to its first 8,192 tokens; the rest is ignored and not billed. At most about 300,000 tokens per request (a quarter of the characters). Token ids are refused with a 400: the model reads text through its own tokenizer, so send the strings themselves.",
        "oneOf": [
          { "type": "string", "title": "Text", "minLength": 1 },
          {
            "type": "array",
            "title": "Texts",
            "minItems": 1,
            "maxItems": 512,
            "items": { "type": "string", "minLength": 1 }
          }
        ]
      },
      "EmbeddingList": {
        "type": "object",
        "required": ["object", "data", "model"],
        "properties": {
          "object": { "type": "string", "enum": ["list"] },
          "data": {
            "type": "array",
            "description": "One embedding per input, in input order.",
            "items": { "$ref": "#/components/schemas/Embedding" }
          },
          "model": { "type": "string", "description": "`qwen3-embedding-0.6b`, also when the request named the alias." },
          "usage": { "$ref": "#/components/schemas/EmbeddingUsage" }
        }
      },
      "Embedding": {
        "type": "object",
        "required": ["object", "index", "embedding"],
        "properties": {
          "object": { "type": "string", "enum": ["embedding"] },
          "index": { "type": "integer", "description": "Position of the input in `input`." },
          "embedding": {
            "description": "The vector: 1024 numbers, or a base64 string with `encoding_format: base64`.",
            "oneOf": [
              { "type": "array", "title": "Float", "items": { "type": "number" } },
              { "type": "string", "title": "Base64" }
            ]
          }
        }
      },
      "EmbeddingUsage": {
        "type": "object",
        "required": ["prompt_tokens", "total_tokens"],
        "properties": {
          "prompt_tokens": { "type": "integer", "description": "Input tokens the model read, billed at the model's input price: each input's own tokens, up to 8,192 per input, so a batch costs the same as its inputs sent one by one. If an answer ever comes without `usage`, the request is billed on an estimate instead: a quarter of the characters of each string, rounded up." },
          "total_tokens": { "type": "integer", "description": "Equal to `prompt_tokens`: output is not billed." }
        }
      },
      "RerankRequest": {
        "type": "object",
        "required": ["model", "query", "documents"],
        "properties": {
          "model": {
            "type": "string",
            "description": "Id of the rerank model: `qwen3-reranker-0.6b`, or its alias `qwen/qwen3-reranker-0.6b`. `GET /v1/models?format=openai` lists it with `endpoints: [\"/v1/rerank\"]`.",
            "examples": ["qwen3-reranker-0.6b"]
          },
          "query": { "type": "string", "minLength": 1, "maxLength": 4096, "description": "The query the documents are scored against, at most 4096 characters. It is counted once per document in the token estimate." },
          "documents": {
            "type": "array",
            "description": "The documents to score, 1 to 1000.",
            "minItems": 1,
            "maxItems": 1000,
            "items": { "$ref": "#/components/schemas/RerankDocument" }
          },
          "top_n": { "type": "integer", "minimum": 1, "description": "Return only the `top_n` most relevant documents. Every document is still scored and billed." },
          "return_documents": { "type": "boolean", "description": "Accepted for compatibility with Cohere and Jina clients; results never repeat the documents. Use `index`." }
        }
      },
      "RerankDocument": {
        "description": "A document: a string, or an object with a string `text`. Other members of the object are accepted.",
        "oneOf": [
          { "type": "string", "title": "Text" },
          {
            "type": "object",
            "title": "Object",
            "required": ["text"],
            "properties": {
              "text": { "type": "string" }
            },
            "additionalProperties": true
          }
        ]
      },
      "RerankResponse": {
        "type": "object",
        "description": "The answer in the format of Cohere and Jina. Other members of that format, such as `id` or `meta`, may be present.",
        "required": ["results", "model", "usage"],
        "properties": {
          "results": {
            "type": "array",
            "description": "The `top_n` most relevant documents, or every document when `top_n` is not set.",
            "items": { "$ref": "#/components/schemas/RerankResult" }
          },
          "model": { "type": "string", "description": "`qwen3-reranker-0.6b`, also when the request named the alias." },
          "usage": { "$ref": "#/components/schemas/RerankUsage" }
        },
        "additionalProperties": true
      },
      "RerankResult": {
        "type": "object",
        "required": ["index", "relevance_score"],
        "properties": {
          "index": { "type": "integer", "description": "Position of the document in `documents`." },
          "relevance_score": { "type": "number", "description": "How relevant the document is to the query, between 0 and 1: the higher, the more relevant. Results are sorted from the most to the least relevant." }
        }
      },
      "RerankUsage": {
        "type": "object",
        "description": "The token estimate the request is billed on, written by the API into every answer: for each document, `ceil((characters(query) + characters(document)) / 4)`, added up, with characters counted as Unicode code points.",
        "required": ["prompt_tokens", "total_tokens"],
        "properties": {
          "prompt_tokens": { "type": "integer", "description": "Estimated input tokens, billed at the model's input price." },
          "total_tokens": { "type": "integer", "description": "Equal to `prompt_tokens`." }
        }
      },
      "RedactRequest": {
        "type": "object",
        "required": ["inputs"],
        "properties": {
          "model": {
            "type": "string",
            "description": "Optional. `privacy-filter`, or its alias `openai/privacy-filter`. When it is left out, `privacy-filter` answers.",
            "examples": ["privacy-filter"]
          },
          "inputs": {
            "description": "The text to redact: a string, or an array of 1 to 256 strings. The answer has the same shape: one result for a string, an array of results in input order for an array.",
            "oneOf": [
              { "type": "string", "title": "Text" },
              {
                "type": "array",
                "title": "Texts",
                "minItems": 1,
                "maxItems": 256,
                "items": { "type": "string" }
              }
            ]
          },
          "placeholders": { "type": "boolean", "default": true, "description": "`true` (the default) replaces each item found with a placeholder that names its category, such as `[PERSON]`, `[EMAIL]` or `[PHONE]`; `false` removes the item from the text." },
          "categories": {
            "type": "array",
            "description": "Look only for these categories, named as in `entity_group`: `private_person`, `private_address`, `private_email`, `private_phone`, `private_date`, `account_number`, `private_url` and `secret`. Omit it, or send an empty array, to look for every category. Write the names in lower case: a name the filter does not know (`PRIVATE_PERSON` in capitals included) is ignored without an error, so a request with only unknown names answers 200 with no spans.",
            "items": { "type": "string" }
          }
        }
      },
      "RedactResponse": {
        "description": "One result for a string in `inputs`; an array of results, in input order, for an array.",
        "oneOf": [
          { "$ref": "#/components/schemas/RedactResult" },
          {
            "type": "array",
            "title": "Results",
            "items": { "$ref": "#/components/schemas/RedactResult" }
          }
        ]
      },
      "RedactResult": {
        "type": "object",
        "title": "Result",
        "required": ["text", "spans"],
        "properties": {
          "text": { "type": "string", "description": "The input with each item found masked: replaced with its placeholder, or removed when `placeholders` is `false`." },
          "spans": {
            "type": "array",
            "description": "One entry per item of personal data found.",
            "items": { "$ref": "#/components/schemas/RedactSpan" }
          }
        }
      },
      "RedactSpan": {
        "type": "object",
        "description": "An item of personal data found in the input.",
        "properties": {
          "entity_group": { "type": "string", "description": "The category of the item: `private_person`, `private_address`, `private_email`, `private_phone`, `private_date`, `account_number`, `private_url` or `secret`." },
          "score": { "type": "number", "description": "The model's confidence, from 0 to 1." },
          "word": { "type": "string", "description": "The text found." },
          "start": { "type": "integer", "description": "Position of the item's first character in the input, counted in characters." },
          "end": { "type": "integer", "description": "Position just after the item's last character in the input." },
          "placeholder": { "type": "string", "description": "The category's tag, such as `<PRIVATE_PERSON>`." }
        },
        "additionalProperties": true
      },
      "ModelList": {
        "type": "object",
        "title": "Provider catalogue",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ProviderModel" }
          }
        }
      },
      "OpenAIModelList": {
        "type": "object",
        "title": "OpenAI-style list",
        "description": "The list returned with `format=openai`: every model id and alias, sorted by id. It is the only list that includes the decision, embeddings, rerank and redaction models.",
        "required": ["object", "data"],
        "properties": {
          "object": { "type": "string", "enum": ["list"] },
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/OpenAIModel" }
          }
        }
      },
      "OpenAIModel": {
        "type": "object",
        "description": "One model id or alias of the OpenAI-style list.",
        "required": ["id", "object", "created", "owned_by"],
        "properties": {
          "id": { "type": "string", "description": "Model id or alias, used as the `model` parameter." },
          "object": { "type": "string", "enum": ["model"] },
          "created": { "type": "integer", "description": "Unix timestamp (seconds) of the listing." },
          "owned_by": { "type": "string", "description": "`serenity`." },
          "pricing": {
            "type": "object",
            "description": "Prices in US dollars per million tokens. Absent when not known.",
            "required": ["input", "output"],
            "properties": {
              "input": { "type": "number", "description": "Price per million input tokens." },
              "output": { "type": "number", "description": "Price per million output tokens. `0` for decision, embeddings, rerank and redaction models, whose output is not billed." }
            }
          },
          "context_length": { "type": "integer", "description": "Context window in tokens. Absent when not known." },
          "endpoints": {
            "type": "array",
            "items": { "type": "string" },
            "description": "Present only on the models that are not chat models: the routes the model is served on, `/v1/decisions` and `/v1/systemone` for a decision model, or one of `/v1/embeddings`, `/v1/rerank` and `/v1/redact`. Chat models, served on `/v1/chat/completions`, have no `endpoints`.",
            "examples": [["/v1/decisions", "/v1/systemone"], ["/v1/embeddings"]]
          }
        }
      },
      "ProviderModel": {
        "type": "object",
        "description": "One model in the OpenRouter provider schema 2.4. Other fields of that schema may be present.",
        "required": ["schema_version", "id", "name", "created", "input_modalities", "output_modalities"],
        "properties": {
          "schema_version": { "type": "string", "description": "Version of the provider schema (`2.4`)." },
          "id": { "type": "string", "description": "Model id, used as the `model` parameter." },
          "name": { "type": "string", "description": "Display name, prefixed with the vendor and a colon (`Serenity: Orion Pro`, `Qwen: Qwen3.8 27B`)." },
          "created": { "type": "integer", "description": "Unix timestamp (seconds) of the listing." },
          "quantization": { "type": "string", "description": "Serving precision of the open models: `nvfp4`, or `bf16` for `paddleocr-vl-1.6`. The Orion ids do not publish it." },
          "description": { "type": "string", "description": "Free-text description of the model and of where it is served." },
          "input_modalities": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/InputModality" }
          },
          "output_modalities": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/OutputModality" }
          },
          "is_ready": { "type": "boolean", "description": "Whether the provider declares the model ready for production traffic." },
          "is_free": { "type": "boolean" },
          "discount_to_user": { "type": "number", "description": "Discount applied to the listed prices, 0 when none." },
          "openrouter": {
            "type": "object",
            "description": "Present when the model is listed on OpenRouter.",
            "properties": {
              "slug": { "type": "string", "description": "The model id on OpenRouter (`qwen/qwen3.8-27b`)." }
            }
          },
          "datacenters": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "country_code": { "type": "string" },
                "region": { "type": "string" }
              }
            },
            "description": "Where inference runs."
          },
          "deployment_region": { "type": "string", "description": "`EU`." },
          "compliance": {
            "type": "object",
            "properties": {
              "zdr": { "type": "boolean", "description": "Zero data retention: prompts and completions are never written to disk or logs." },
              "hipaa": { "type": "boolean" }
            }
          }
        },
        "additionalProperties": true
      },
      "InputModality": {
        "type": "object",
        "required": ["type", "supported_inputs", "pricing"],
        "properties": {
          "type": {
            "type": "string",
            "enum": ["text", "image"]
          },
          "supported_inputs": {
            "type": "object",
            "description": "For `text`, the context window. For `image`, the accepted `sources` (`base64`), `formats` and `references`, whose `max` is the most images per request on that model (from 1 to 8).",
            "properties": {
              "max_context_length": {
                "allOf": [
                  { "$ref": "#/components/schemas/TokenQuantity" }
                ],
                "description": "Context window (input plus output)."
              }
            }
          },
          "pricing": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/TokenPrice" },
            "description": "Input prices: one `prompt` entry and, when the prompt cache applies, one `cached_prompt` entry."
          },
          "capacity": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/TokenCapacity" }
          }
        }
      },
      "OutputModality": {
        "type": "object",
        "required": ["type", "max_length", "streaming", "supported_parameters", "pricing"],
        "properties": {
          "type": {
            "type": "string",
            "enum": ["text"]
          },
          "max_length": {
            "allOf": [
              { "$ref": "#/components/schemas/TokenQuantity" }
            ],
            "description": "Maximum output (`max_tokens`)."
          },
          "streaming": { "type": "boolean", "description": "Whether `stream: true` is supported." },
          "supported_parameters": {
            "type": "object",
            "description": "Map from request parameter (`temperature`, `top_p`, `top_k`, `max_tokens`, `stop`, `seed`, `tools`, `structured_outputs`, `reasoning`) to its constraints. A parameter present in the map is supported.",
            "additionalProperties": { "type": "object", "description": "Constraints of the parameter: `type`, and depending on it `min`, `max`, `default`, `values` or `properties`." }
          },
          "pricing": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/TokenPrice" },
            "description": "Output price: one `completion` entry."
          },
          "capacity": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/TokenCapacity" }
          }
        }
      },
      "TokenQuantity": {
        "type": "object",
        "required": ["value", "unit"],
        "properties": {
          "value": { "type": "integer", "description": "Number of tokens." },
          "unit": {
            "type": "string",
            "enum": ["token"]
          }
        }
      },
      "TokenPrice": {
        "type": "object",
        "required": ["type", "unit", "cost_usd"],
        "properties": {
          "type": {
            "type": "string",
            "enum": ["prompt", "cached_prompt", "completion"],
            "description": "`prompt` is input, `cached_prompt` is input served from the prompt cache, `completion` is output."
          },
          "unit": {
            "type": "string",
            "enum": ["token"]
          },
          "cost_usd": { "type": "string", "description": "Price per token in US dollars, as a decimal string so that no rounding takes place. Multiply by 1,000,000 for the price per million tokens shown on Pricing and limits." },
          "implicit": { "type": "boolean", "description": "For `cached_prompt`: the cache applies automatically, without a request parameter." }
        }
      },
      "TokenCapacity": {
        "type": "object",
        "required": ["type", "unit", "per", "value"],
        "properties": {
          "type": {
            "type": "string",
            "enum": ["prompt", "completion"]
          },
          "unit": {
            "type": "string",
            "enum": ["token"]
          },
          "per": {
            "type": "string",
            "enum": ["minute"]
          },
          "value": { "type": "integer", "description": "Tokens per minute the provider can serve for this model." }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": { "$ref": "#/components/schemas/Error" }
        }
      },
      "Error": {
        "type": "object",
        "description": "OpenAI-style error object.",
        "required": ["message", "type"],
        "properties": {
          "message": { "type": "string", "description": "Human-readable description of the problem." },
          "type": {
            "type": "string",
            "description": "Error category.",
            "enum": ["invalid_request_error", "authentication_error", "permission_error", "not_found_error", "rate_limit_error", "server_error"]
          },
          "code": { "type": ["string", "null"], "description": "Machine-readable error code, when available." },
          "param": { "type": ["string", "null"], "description": "The request parameter the error refers to, when applicable." }
        }
      }
    }
  }
}
