{"openapi":"3.1.0","info":{"title":"NormaHub public API","version":"2026-09-30","description":"Safe public contract for model discovery, status and documented gateway routes. Authentication uses a NormaHub API key."},"servers":[{"url":"https://api.normahub.cc","description":"API host. OpenAI-compatible routes live under /v1 (SDK baseURL https://api.normahub.cc/v1); Anthropic SDK uses the host root (baseURL https://api.normahub.cc, no /v1 suffix)."}],"paths":{"/api/v1/public/models":{"get":{"summary":"List public models","operationId":"listPublicModels","responses":{"200":{"description":"Current public model catalog","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicModelsResponse"}}}}}}},"/api/v1/public/status":{"get":{"summary":"Get public service status","operationId":"getPublicStatus","responses":{"200":{"description":"Aggregated, anonymized status snapshot","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/v1/models":{"get":{"summary":"List models allowed for the API key","operationId":"listModels","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Models allowed for this key","headers":{"X-Request-Id":{"description":"Связывает запрос с записью в журнале личного кабинета. Сохраняйте значение для обращений в поддержку.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicModelsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/responses":{"post":{"summary":"Create a response (единственный маршрут с полноценным streaming)","operationId":"createResponse","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerationRequest"}}}},"responses":{"200":{"description":"Response object","headers":{"X-Request-Id":{"description":"Связывает запрос с записью в журнале личного кабинета. Сохраняйте значение для обращений в поддержку.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/InsufficientBalance"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/ProviderUnavailable"}}}},"/v1/chat/completions":{"post":{"summary":"Create a chat completion (streaming выключен: отправляйте stream:false либо используйте /v1/responses)","operationId":"createChatCompletion","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionRequest"}}}},"responses":{"200":{"description":"Chat completion object","headers":{"X-Request-Id":{"description":"Связывает запрос с записью в журнале личного кабинета. Сохраняйте значение для обращений в поддержку.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/InsufficientBalance"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/ProviderUnavailable"}}}},"/v1/messages":{"post":{"summary":"Create an Anthropic-compatible message (streaming выключен: отправляйте stream:false либо используйте /v1/responses)","operationId":"createMessage","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerationRequest"}}}},"responses":{"200":{"description":"Message object","headers":{"X-Request-Id":{"description":"Связывает запрос с записью в журнале личного кабинета. Сохраняйте значение для обращений в поддержку.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/InsufficientBalance"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/ProviderUnavailable"}}}},"/v1/completions":{"post":{"summary":"Legacy Completions (streaming не поддерживается: stream:true вернёт 503 streaming_not_enabled)","operationId":"createLegacyCompletion","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerationRequest"}}}},"responses":{"200":{"description":"Completion object","headers":{"X-Request-Id":{"description":"Связывает запрос с записью в журнале личного кабинета. Сохраняйте значение для обращений в поддержку.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/InsufficientBalance"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/ProviderUnavailable"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API key"}},"schemas":{"GenerationRequest":{"type":"object","required":["model"],"properties":{"model":{"type":"string","description":"Model ID from /v1/models"},"input":{},"messages":{"type":"array","items":{"type":"object","additionalProperties":true}},"max_output_tokens":{"type":"integer","minimum":1},"stream":{"type":"boolean"}},"additionalProperties":true},"ChatCompletionRequest":{"type":"object","required":["model","messages"],"properties":{"model":{"type":"string","description":"Model ID from /v1/models"},"messages":{"type":"array","minItems":1,"items":{"type":"object","required":["role","content"],"properties":{"role":{"type":"string"},"content":{}},"additionalProperties":true}},"max_tokens":{"type":"integer","minimum":1},"max_completion_tokens":{"type":"integer","minimum":1},"response_format":{"oneOf":[{"type":"object","required":["type"],"properties":{"type":{"const":"text"}},"additionalProperties":false},{"type":"object","required":["type"],"properties":{"type":{"const":"json_object"}},"additionalProperties":false},{"type":"object","required":["type","json_schema"],"properties":{"type":{"const":"json_schema"},"json_schema":{"type":"object"}},"additionalProperties":false}],"description":"Requested output format; availability depends on the selected model."},"stream":{"type":"boolean","default":false}},"additionalProperties":true},"PublicModelsResponse":{"type":"object","properties":{"models":{"type":"array","items":{"$ref":"#/components/schemas/PublicModel"}},"updated_at":{"type":"string","format":"date-time"}},"additionalProperties":false},"PublicModel":{"type":"object","required":["id","pricing"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"endpoints":{"type":"array","items":{"type":"string"}},"context_window":{"type":["integer","null"]},"max_output_tokens":{"type":["integer","null"]},"capabilities":{"type":"object","additionalProperties":{"type":"boolean"}},"pricing":{"type":"object","required":["currency","input_price_per_million","output_price_per_million","image_price"],"properties":{"currency":{"type":"string"},"input_price_per_million":{"type":"string"},"output_price_per_million":{"type":"string"},"input_price_per_million_cached":{"type":"string"},"output_price_per_million_cached":{"type":"string"},"cache_percent":{"type":"string"},"image_price":{"type":"string"}},"additionalProperties":false}},"additionalProperties":true}},"responses":{"Unauthorized":{"description":"Invalid or missing API key","headers":{"X-Request-Id":{"description":"Связывает запрос с записью в журнале личного кабинета. Сохраняйте значение для обращений в поддержку.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["message","code"],"properties":{"message":{"type":"string"},"type":{"type":"string"},"code":{"type":"string"}},"additionalProperties":true}},"additionalProperties":true},"example":{"error":{"message":"Missing bearer API key","type":"authentication_error","code":"invalid_api_key"}}}}},"BadRequest":{"description":"Invalid request","headers":{"X-Request-Id":{"description":"Связывает запрос с записью в журнале личного кабинета. Сохраняйте значение для обращений в поддержку.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["message","code"],"properties":{"message":{"type":"string"},"type":{"type":"string"},"code":{"type":"string"}},"additionalProperties":true}},"additionalProperties":true},"example":{"error":{"message":"Invalid request","type":"invalid_request_error","code":"invalid_request"}}}}},"InsufficientBalance":{"description":"Insufficient balance or key spend limit reached (402 — пополните баланс или поднимите spend limit, повтор с тем же ключом не поможет)","headers":{"X-Request-Id":{"description":"Связывает запрос с записью в журнале личного кабинета. Сохраняйте значение для обращений в поддержку.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["message","code"],"properties":{"message":{"type":"string"},"type":{"type":"string"},"code":{"type":"string"}},"additionalProperties":true}},"additionalProperties":true},"example":{"error":{"message":"Insufficient balance","type":"invalid_request_error","code":"insufficient_balance"}}}}},"Forbidden":{"description":"Model or scope not allowed for this key (ключ жив, модель закрыта — проверьте каталог)","headers":{"X-Request-Id":{"description":"Связывает запрос с записью в журнале личного кабинета. Сохраняйте значение для обращений в поддержку.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["message","code"],"properties":{"message":{"type":"string"},"type":{"type":"string"},"code":{"type":"string"}},"additionalProperties":true}},"additionalProperties":true},"example":{"error":{"message":"Model not allowed for this API key","type":"invalid_request_error","code":"model_not_allowed"}}}}},"TooLarge":{"description":"Request body exceeds 2 MB (уменьшите тело запроса, повтор не поможет)","headers":{"X-Request-Id":{"description":"Связывает запрос с записью в журнале личного кабинета. Сохраняйте значение для обращений в поддержку.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["message","code"],"properties":{"message":{"type":"string"},"type":{"type":"string"},"code":{"type":"string"}},"additionalProperties":true}},"additionalProperties":true},"example":{"error":{"message":"Request body is too large","type":"invalid_request_error","code":"request_too_large"}}}}},"RateLimited":{"description":"Rate or budget limit (429). Заголовок Retry-After не гарантируется — повторяйте с экспоненциальной задержкой и общим deadline.","headers":{"X-Request-Id":{"description":"Связывает запрос с записью в журнале личного кабинета. Сохраняйте значение для обращений в поддержку.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["message","code"],"properties":{"message":{"type":"string"},"type":{"type":"string"},"code":{"type":"string"}},"additionalProperties":true}},"additionalProperties":true},"example":{"error":{"message":"Too many requests","type":"rate_limit_error","code":"rate_limit_exceeded"}}}}},"ProviderUnavailable":{"description":"Provider unavailable (503: provider_unavailable, provider_not_configured, streaming_not_enabled)","headers":{"X-Request-Id":{"description":"Связывает запрос с записью в журнале личного кабинета. Сохраняйте значение для обращений в поддержку.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["message","code"],"properties":{"message":{"type":"string"},"type":{"type":"string"},"code":{"type":"string"}},"additionalProperties":true}},"additionalProperties":true},"example":{"error":{"message":"Provider unavailable","type":"server_error","code":"provider_unavailable"}}}}}}}}