{
  "openapi": "3.1.0",
  "info": {
    "title": "OmniRouter Client API",
    "version": "1.0.0",
    "summary": "OpenAI-compatible and Anthropic-compatible AI API",
    "description": "The public OmniRouter contract for model discovery and inference. Use a model ID returned by GET /v1/models. An omni_* token grants access only to these model-routing operations; it does not grant dashboard, account-management, filesystem, terminal, repository, or coding-agent session access.",
    "license": {
      "name": "MIT",
      "identifier": "MIT"
    },
    "contact": {
      "name": "OmniRouter support",
      "url": "https://omnirouter.ru/contact/",
      "email": "support@omnirouter.ru"
    }
  },
  "externalDocs": {
    "description": "Human-readable API reference",
    "url": "https://omnirouter.ru/docs/api-reference/"
  },
  "servers": [
    {
      "url": "https://api.omnirouter.ru",
      "description": "Public API"
    }
  ],
  "tags": [
    { "name": "Models", "description": "Discover models available to the current token." },
    { "name": "Messages", "description": "Anthropic-compatible message generation." },
    { "name": "Responses", "description": "OpenAI-compatible response generation." },
    { "name": "Chat", "description": "OpenAI-compatible chat completions." },
    { "name": "Media", "description": "Image generation and audio transcription." },
    { "name": "Search", "description": "Credits-backed web search." },
    { "name": "MCP", "description": "JSON-RPC MCP endpoint." }
  ],
  "paths": {
    "/v1/models": {
      "get": {
        "operationId": "listModels",
        "summary": "List available models",
        "description": "Returns the exact model IDs available to the authenticated OmniRouter token. Clients should call this operation instead of guessing or hard-coding an ID.",
        "tags": ["Models"],
        "security": [{ "OmniRouterApiKey": [] }, { "OmniRouterBearer": [] }],
        "x-omnirouter-permission": "model:read",
        "responses": {
          "200": {
            "description": "Available models",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ModelList" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/messages": {
      "post": {
        "operationId": "createMessage",
        "summary": "Create an Anthropic-compatible message",
        "description": "Generates a message in the Anthropic Messages format. Text, image input, function tools, tool results, and streaming are supported when the selected model and connected account support them. Unrepresentable cross-surface behavior is rejected with HTTP 400.",
        "tags": ["Messages"],
        "security": [{ "OmniRouterApiKey": [] }],
        "x-omnirouter-permission": "inference:create",
        "parameters": [
          {
            "name": "anthropic-version",
            "in": "header",
            "required": false,
            "description": "Anthropic protocol version requested by compatible clients.",
            "schema": { "type": "string", "example": "2023-06-01" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/MessagesRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Completed JSON message or an SSE stream when stream=true.",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/MessageResponse" } },
              "text/event-stream": { "schema": { "type": "string" } }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/messages/count_tokens": {
      "post": {
        "operationId": "countMessageTokens",
        "summary": "Count input tokens",
        "description": "Counts input tokens for an Anthropic-compatible message request when supported by the selected connected account.",
        "tags": ["Messages"],
        "security": [{ "OmniRouterApiKey": [] }],
        "x-omnirouter-permission": "inference:inspect",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/CountTokensRequest" } }
          }
        },
        "responses": {
          "200": {
            "description": "Token count",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["input_tokens"],
                  "properties": { "input_tokens": { "type": "integer", "minimum": 0 } }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/responses": {
      "post": {
        "operationId": "createResponse",
        "summary": "Create an OpenAI-compatible response",
        "description": "Generates a response using text or structured input. Function and custom tools are accepted when supported by the selected route. Unsupported compaction or cross-surface fields fail closed with HTTP 400.",
        "tags": ["Responses"],
        "security": [{ "OmniRouterBearer": [] }],
        "x-omnirouter-permission": "inference:create",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/ResponsesRequest" } }
          }
        },
        "responses": {
          "200": {
            "description": "Completed JSON response or an SSE stream when stream=true.",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ResponseObject" } },
              "text/event-stream": { "schema": { "type": "string" } }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/chat/completions": {
      "post": {
        "operationId": "createChatCompletion",
        "summary": "Create an OpenAI-compatible chat completion",
        "description": "Generates an OpenAI-compatible chat completion for a token whose connected account supports this surface.",
        "tags": ["Chat"],
        "security": [{ "OmniRouterBearer": [] }],
        "x-omnirouter-permission": "inference:create",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/ChatRequest" } }
          }
        },
        "responses": {
          "200": {
            "description": "Completed JSON chat completion or an SSE stream when stream=true.",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ChatResponse" } },
              "text/event-stream": { "schema": { "type": "string" } }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/search": {
      "post": {
        "operationId": "searchWeb",
        "summary": "Search the web",
        "description": "Runs the public Credits-backed search product and returns a structured result.",
        "tags": ["Search"],
        "security": [{ "OmniRouterBearer": [] }],
        "x-omnirouter-permission": "search:create",
        "parameters": [
          {
            "name": "x-request-id",
            "in": "header",
            "required": false,
            "description": "Stable non-secret idempotency identifier, at most 80 characters. Reuse only for identical parameters.",
            "schema": { "type": "string", "minLength": 1, "maxLength": 80 }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/SearchRequest" } }
          }
        },
        "responses": {
          "200": {
            "description": "Search result",
            "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/images/generations": {
      "post": {
        "operationId": "createImageGeneration",
        "summary": "Create an image generation",
        "description": "Starts a Credits-backed image generation using an exact model ID from the catalog.",
        "tags": ["Media"],
        "security": [{ "OmniRouterBearer": [] }],
        "x-omnirouter-permission": "image:create",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Stable non-secret idempotency key. Reuse only for an identical generation request.",
            "schema": { "type": "string", "minLength": 1 }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/ImageRequest" } }
          }
        },
        "responses": {
          "200": {
            "description": "Image generation result or accepted job",
            "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/audio/transcriptions": {
      "post": {
        "operationId": "createAudioTranscription",
        "summary": "Transcribe audio",
        "description": "Transcribes an uploaded audio file using the Credits-backed transcription product.",
        "tags": ["Media"],
        "security": [{ "OmniRouterBearer": [] }],
        "x-omnirouter-permission": "audio:create",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Stable non-secret idempotency key. Reuse only for an identical transcription request.",
            "schema": { "type": "string", "minLength": 1 }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["file", "model"],
                "properties": {
                  "file": { "type": "string", "format": "binary" },
                  "model": { "type": "string", "minLength": 1 },
                  "language": { "type": "string", "description": "Optional language hint." },
                  "prompt": { "type": "string", "description": "Optional transcription context." }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transcription",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["text"],
                  "properties": { "text": { "type": "string" } }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "413": { "$ref": "#/components/responses/BadRequest" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/mcp": {
      "post": {
        "operationId": "callMcp",
        "summary": "Call the OmniRouter MCP server",
        "description": "Sends a JSON-RPC 2.0 MCP request. Supported protocol versions and tools are returned by the MCP initialize and tools/list methods.",
        "tags": ["MCP"],
        "security": [{ "OmniRouterBearer": [] }],
        "x-omnirouter-permission": "mcp:call",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/JsonRpcRequest" } }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC result",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/JsonRpcResponse" } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "415": { "$ref": "#/components/responses/BadRequest" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "OmniRouterApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "An omni_* client token. Its permission boundary is model discovery and inference only; it cannot access dashboard or account-management APIs.",
        "x-permissions": ["model:read", "inference:inspect", "inference:create", "search:create", "image:create", "audio:create", "mcp:call"]
      },
      "OmniRouterBearer": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "omni_*",
        "description": "The same restricted OmniRouter client token passed as a Bearer credential. Never put it in a URL, request body, log, or browser-side code.",
        "x-permissions": ["model:read", "inference:inspect", "inference:create", "search:create", "image:create", "audio:create", "mcp:call"]
      }
    },
    "responses": {
      "BadRequest": {
        "description": "The request is malformed or uses behavior that the selected client surface cannot represent.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "Unauthorized": {
        "description": "The token is missing, invalid, disabled, or cannot use this client surface.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "RateLimited": {
        "description": "A request or usage limit was reached.",
        "headers": {
          "retry-after": { "description": "Seconds to wait before retrying when known.", "schema": { "type": "integer", "minimum": 1 } }
        },
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "ServerError": {
        "description": "A temporary internal or upstream failure occurred.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      }
    },
    "schemas": {
      "ErrorResponse": {
        "anyOf": [
          {
            "type": "object",
            "required": ["error"],
            "properties": {
              "type": false,
              "error": {
                "type": "object",
                "required": ["type", "message"],
                "properties": {
                  "type": { "type": "string" },
                  "message": { "type": "string" },
                  "code": { "type": ["string", "null"] }
                },
                "additionalProperties": true
              }
            }
          },
          {
            "type": "object",
            "required": ["type", "error"],
            "properties": {
              "type": { "const": "error" },
              "error": {
                "type": "object",
                "required": ["type", "message"],
                "properties": {
                  "type": { "type": "string" },
                  "message": { "type": "string" }
                },
                "additionalProperties": true
              }
            }
          }
        ]
      },
      "Model": {
        "type": "object",
        "required": ["id"],
        "properties": {
          "id": { "type": "string", "minLength": 1 },
          "object": { "type": "string" },
          "type": { "type": "string" },
          "display_name": { "type": "string" },
          "created": { "type": "integer" },
          "created_at": { "type": "string" }
        },
        "additionalProperties": true
      },
      "ModelList": {
        "type": "object",
        "required": ["data"],
        "properties": {
          "object": { "type": "string", "default": "list" },
          "data": { "type": "array", "items": { "$ref": "#/components/schemas/Model" } },
          "has_more": { "type": "boolean" }
        },
        "additionalProperties": true
      },
      "ContentBlock": {
        "oneOf": [
          {
            "type": "object",
            "required": ["type", "text"],
            "properties": { "type": { "const": "text" }, "text": { "type": "string" } }
          },
          {
            "type": "object",
            "required": ["type", "source"],
            "properties": {
              "type": { "const": "image" },
              "source": { "type": "object", "additionalProperties": true }
            }
          },
          {
            "type": "object",
            "required": ["type", "id", "name", "input"],
            "properties": {
              "type": { "const": "tool_use" },
              "id": { "type": "string" },
              "name": { "type": "string" },
              "input": { "type": "object", "additionalProperties": true }
            }
          },
          {
            "type": "object",
            "required": ["type", "tool_use_id", "content"],
            "properties": {
              "type": { "const": "tool_result" },
              "tool_use_id": { "type": "string" },
              "content": { "oneOf": [{ "type": "string" }, { "type": "array", "items": { "type": "object" } }] }
            }
          }
        ]
      },
      "InputMessage": {
        "type": "object",
        "required": ["role", "content"],
        "properties": {
          "role": { "type": "string", "enum": ["user", "assistant"] },
          "content": { "oneOf": [{ "type": "string" }, { "type": "array", "items": { "$ref": "#/components/schemas/ContentBlock" } }] }
        }
      },
      "FunctionTool": {
        "type": "object",
        "required": ["name", "input_schema"],
        "properties": {
          "name": { "type": "string", "minLength": 1 },
          "description": { "type": "string" },
          "input_schema": { "type": "object", "description": "JSON Schema for the tool arguments." }
        }
      },
      "MessagesRequest": {
        "type": "object",
        "required": ["model", "max_tokens", "messages"],
        "properties": {
          "model": { "type": "string", "minLength": 1, "description": "Exact ID returned by GET /v1/models." },
          "max_tokens": { "type": "integer", "minimum": 1 },
          "messages": { "type": "array", "minItems": 1, "items": { "$ref": "#/components/schemas/InputMessage" } },
          "system": { "oneOf": [{ "type": "string" }, { "type": "array", "items": { "type": "object" } }] },
          "stream": { "type": "boolean", "default": false },
          "temperature": { "type": "number" },
          "tools": { "type": "array", "items": { "$ref": "#/components/schemas/FunctionTool" } },
          "tool_choice": { "oneOf": [{ "type": "string" }, { "type": "object", "additionalProperties": true }] }
        },
        "additionalProperties": true
      },
      "CountTokensRequest": {
        "type": "object",
        "required": ["model", "messages"],
        "properties": {
          "model": { "type": "string", "minLength": 1 },
          "messages": { "type": "array", "minItems": 1, "items": { "$ref": "#/components/schemas/InputMessage" } },
          "system": { "oneOf": [{ "type": "string" }, { "type": "array", "items": { "type": "object" } }] },
          "tools": { "type": "array", "items": { "$ref": "#/components/schemas/FunctionTool" } }
        },
        "additionalProperties": true
      },
      "Usage": {
        "type": "object",
        "properties": {
          "input_tokens": { "type": "integer", "minimum": 0 },
          "output_tokens": { "type": "integer", "minimum": 0 },
          "cache_read_input_tokens": { "type": "integer", "minimum": 0, "description": "Informational subset of input_tokens." }
        },
        "additionalProperties": true
      },
      "MessageResponse": {
        "type": "object",
        "required": ["id", "type", "role", "content", "model"],
        "properties": {
          "id": { "type": "string" },
          "type": { "const": "message" },
          "role": { "const": "assistant" },
          "content": { "type": "array", "items": { "$ref": "#/components/schemas/ContentBlock" } },
          "model": { "type": "string" },
          "stop_reason": { "type": ["string", "null"] },
          "usage": { "$ref": "#/components/schemas/Usage" }
        },
        "additionalProperties": true
      },
      "ResponsesFunctionTool": {
        "type": "object",
        "required": ["type", "name", "parameters"],
        "properties": {
          "type": { "const": "function" },
          "name": { "type": "string", "minLength": 1 },
          "description": { "type": "string" },
          "parameters": { "type": "object", "description": "JSON Schema for function arguments." },
          "strict": { "type": "boolean" }
        }
      },
      "ResponsesRequest": {
        "type": "object",
        "required": ["model", "input"],
        "properties": {
          "model": { "type": "string", "minLength": 1, "description": "Exact ID returned by GET /v1/models." },
          "input": { "oneOf": [{ "type": "string" }, { "type": "array", "items": { "type": "object", "additionalProperties": true } }] },
          "instructions": { "type": "string" },
          "stream": { "type": "boolean", "default": false },
          "store": { "type": "boolean" },
          "previous_response_id": { "type": "string" },
          "tools": { "type": "array", "items": { "oneOf": [{ "$ref": "#/components/schemas/ResponsesFunctionTool" }, { "type": "object", "additionalProperties": true }] } },
          "tool_choice": { "oneOf": [{ "type": "string" }, { "type": "object", "additionalProperties": true }] },
          "temperature": { "type": "number" },
          "max_output_tokens": { "type": "integer", "minimum": 1 }
        },
        "additionalProperties": true
      },
      "ResponseObject": {
        "type": "object",
        "required": ["id", "status", "output"],
        "properties": {
          "id": { "type": "string" },
          "object": { "type": "string" },
          "status": { "type": "string" },
          "model": { "type": "string" },
          "output": { "type": "array", "items": { "type": "object", "additionalProperties": true } },
          "usage": { "$ref": "#/components/schemas/Usage" },
          "error": { "oneOf": [{ "type": "null" }, { "type": "object", "additionalProperties": true }] }
        },
        "additionalProperties": true
      },
      "ChatMessage": {
        "type": "object",
        "required": ["role", "content"],
        "properties": {
          "role": { "type": "string", "enum": ["system", "developer", "user", "assistant", "tool"] },
          "content": { "oneOf": [{ "type": "string" }, { "type": "array", "items": { "type": "object", "additionalProperties": true } }] },
          "tool_call_id": { "type": "string" }
        },
        "additionalProperties": true
      },
      "ChatRequest": {
        "type": "object",
        "required": ["model", "messages"],
        "properties": {
          "model": { "type": "string", "minLength": 1 },
          "messages": { "type": "array", "minItems": 1, "items": { "$ref": "#/components/schemas/ChatMessage" } },
          "stream": { "type": "boolean", "default": false },
          "temperature": { "type": "number" },
          "tools": { "type": "array", "items": { "type": "object", "additionalProperties": true } },
          "tool_choice": { "oneOf": [{ "type": "string" }, { "type": "object", "additionalProperties": true }] }
        },
        "additionalProperties": true
      },
      "ChatResponse": {
        "type": "object",
        "required": ["id", "choices"],
        "properties": {
          "id": { "type": "string" },
          "object": { "type": "string" },
          "model": { "type": "string" },
          "choices": { "type": "array", "items": { "type": "object", "additionalProperties": true } },
          "usage": { "$ref": "#/components/schemas/Usage" }
        },
        "additionalProperties": true
      },
      "SearchRequest": {
        "type": "object",
        "required": ["query"],
        "properties": {
          "query": { "type": "string", "minLength": 1, "maxLength": 2000 },
          "effort": { "type": "string", "enum": ["basic"], "default": "basic" },
          "max_results": { "type": "integer", "minimum": 1, "maximum": 10, "default": 8 }
        },
        "additionalProperties": false
      },
      "ImageRequest": {
        "type": "object",
        "required": ["model", "prompt"],
        "properties": {
          "model": { "type": "string", "minLength": 1 },
          "prompt": { "type": "string", "minLength": 1 },
          "aspect_ratio": { "type": "string", "default": "auto" },
          "resolution": { "type": "string", "enum": ["1K", "2K", "4K"], "default": "1K" },
          "output_format": { "type": "string", "enum": ["png", "jpg"], "default": "png" },
          "input_images": {
            "type": "array",
            "maxItems": 8,
            "items": {
              "type": "object",
              "required": ["name", "media_type", "data"],
              "properties": {
                "name": { "type": "string", "minLength": 1 },
                "media_type": { "type": "string" },
                "data": { "type": "string", "contentEncoding": "base64" }
              }
            }
          }
        },
        "additionalProperties": true
      },
      "JsonRpcRequest": {
        "type": "object",
        "required": ["jsonrpc", "method"],
        "properties": {
          "jsonrpc": { "const": "2.0" },
          "id": { "oneOf": [{ "type": "string" }, { "type": "integer" }, { "type": "null" }] },
          "method": { "type": "string", "minLength": 1 },
          "params": { "type": "object", "additionalProperties": true }
        }
      },
      "JsonRpcResponse": {
        "type": "object",
        "required": ["jsonrpc"],
        "properties": {
          "jsonrpc": { "const": "2.0" },
          "id": { "oneOf": [{ "type": "string" }, { "type": "integer" }, { "type": "null" }] },
          "result": {},
          "error": {
            "type": "object",
            "required": ["code", "message"],
            "properties": { "code": { "type": "integer" }, "message": { "type": "string" }, "data": {} }
          }
        }
      }
    }
  }
}
