{
  "components": {
    "headers": {
      "JobId": {
        "description": "Id задачи, когда тело ответа — не JSON.",
        "schema": {
          "type": "string"
        }
      },
      "Location": {
        "description": "Адрес задачи, `/v1/jobs/{id}`.",
        "schema": {
          "type": "string"
        }
      },
      "RetryAfter": {
        "description": "Через сколько секунд имеет смысл спросить снова.",
        "schema": {
          "minimum": 0,
          "type": "integer"
        }
      }
    },
    "parameters": {
      "After": {
        "description": "Id последнего элемента предыдущей страницы.",
        "in": "query",
        "name": "after",
        "required": false,
        "schema": {
          "type": "string"
        }
      },
      "FileId": {
        "description": "Id файла.",
        "example": "file_9f8e7d6c5b4a",
        "in": "path",
        "name": "id",
        "required": true,
        "schema": {
          "pattern": "^file_",
          "type": "string"
        }
      },
      "IdempotencyKey": {
        "description": "Строка до 255 символов, уникальная для аккаунта. Повтор с тем же ключом и параметрами\nвозвращает ту же задачу с текущим статусом без новой задачи и повторного списания,\nв том числе при одновременных запросах, даже если настройки аккаунта за это время\nизменились: сравниваются только поля запроса. Другие параметры — `409 idempotency_key_conflict`;\nstore и callback_url в сравнение не входят. У изображений, видео и музыки\nтакже не сравнивается response_format; у синтеза речи формат звука сравнивается.\nКлюч хранится вместе с задачей, сейчас без ограничения срока.\nПовтор задачи со статусом failed не запускает её заново: для новой попытки нужен новый ключ.\nСрок хранения файлов результата — `retention.files_days` из `GET /v1/key`; повтор его не продлевает.\nПоддерживается для генерации изображений, видео и музыки, транскрибации, синтеза речи и\nчата. У чата сравнивается тело запроса целиком; повтор дожидается идущего вызова и\nполучает тот же ответ (и поток), что первый; ответ хранится сутки.\n",
        "in": "header",
        "name": "Idempotency-Key",
        "required": false,
        "schema": {
          "maxLength": 255,
          "type": "string"
        }
      },
      "JobId": {
        "description": "Id задачи — `job_…`; у чата — `chatcmpl-…` из ответа.",
        "example": "job_1a2b3c4d5e6f",
        "in": "path",
        "name": "id",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "Limit": {
        "in": "query",
        "name": "limit",
        "required": false,
        "schema": {
          "default": 20,
          "maximum": 100,
          "minimum": 1,
          "type": "integer"
        }
      },
      "ModelId": {
        "description": "Id модели из каталога.",
        "example": "nano-banana-pro",
        "in": "path",
        "name": "id",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "Prefer": {
        "description": "RFC 7240. Понимаем `respond-async` — не ждать результат, сразу ответить `202` с\nзадачей; остальные предпочтения игнорируются. Долгим моделям — вместе с\n`Idempotency-Key` и вебхуком (`callback_url`): ответ всегда `202`, один путь кода.\n",
        "example": "respond-async",
        "in": "header",
        "name": "Prefer",
        "required": false,
        "schema": {
          "type": "string"
        }
      },
      "WebhookID": {
        "description": "Id доставки — один у всех её повторов.",
        "in": "header",
        "name": "webhook-id",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "WebhookSignature": {
        "description": "`v1,\u003cbase64 HMAC-SHA256\u003e` от `\u003cwebhook-id\u003e.\u003cwebhook-timestamp\u003e.\u003cтело\u003e`.",
        "in": "header",
        "name": "webhook-signature",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "WebhookTimestamp": {
        "description": "Unix-секунды отправки; старые доставки отбрасывайте (защита от повтора).",
        "in": "header",
        "name": "webhook-timestamp",
        "required": true,
        "schema": {
          "type": "string"
        }
      }
    },
    "responses": {
      "BadRequest": {
        "content": {
          "application/json": {
            "examples": {
              "unsupported_value": {
                "value": {
                  "error": {
                    "code": "capability_mismatch",
                    "detail": [
                      {
                        "allowed": [
                          "1:1",
                          "16:9",
                          "9:16"
                        ],
                        "path": "aspect_ratio",
                        "reason": "unsupported_value"
                      }
                    ],
                    "message": "the model does not support this value",
                    "type": "invalid_request_error"
                  }
                }
              },
              "wrong_endpoint": {
                "value": {
                  "error": {
                    "code": "invalid_request",
                    "detail": [
                      {
                        "allowed": [
                          "/v1/videos"
                        ],
                        "path": "model",
                        "reason": "wrong_endpoint"
                      }
                    ],
                    "message": "this model is served by another endpoint",
                    "type": "invalid_request_error"
                  }
                }
              }
            },
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "description": "Запрос отклонён; `error.detail[]` называет поля и допустимые значения."
      },
      "Conflict": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "description": "Тот же `Idempotency-Key` с другим телом."
      },
      "Forbidden": {
        "content": {
          "application/json": {
            "examples": {
              "management_key": {
                "value": {
                  "error": {
                    "code": "forbidden",
                    "detail": [
                      {
                        "reason": "requires_api_key"
                      }
                    ],
                    "message": "this endpoint takes an API key; a management key manages the account only",
                    "type": "permission_error"
                  }
                }
              }
            },
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "description": "Нельзя: у ключа не тот вид (модели запускает API-ключ, аккаунт — ключ управления), у роли\nучастника нет права или подпись ссылки на файл не сходится. `detail[].reason` говорит,\nчто именно: `requires_api_key`, `requires_management_key`, `cabinet_only` (только в\nкабинете), `insufficient_role` (в `allowed` — роли, которым можно), `not_key_author`\n(секрет ключа открывает только тот, кто его создал).\n"
      },
      "GenerationFailed": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "description": "Модель не справилась или исход вызова неизвестен; ничего не списано."
      },
      "Gone": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "description": "Срок жизни файла вышел, байты удалены."
      },
      "JobAccepted": {
        "content": {
          "application/json": {
            "examples": {
              "queued": {
                "value": {
                  "attempt_count": 0,
                  "completed_at": null,
                  "created": 1758801600,
                  "created_at": "2026-09-25T12:00:00Z",
                  "currency": "RUB",
                  "data": [],
                  "error": null,
                  "id": "job_1a2b3c4d5e6f",
                  "max_price_multiplier": null,
                  "modality": "video",
                  "model": "seedance-2",
                  "object": "job",
                  "price": null,
                  "routing": "cheap",
                  "routing_options": null,
                  "status": "queued",
                  "usage": null
                }
              }
            },
            "schema": {
              "$ref": "#/components/schemas/Job"
            }
          }
        },
        "description": "Задача принята и выполняется.",
        "headers": {
          "Location": {
            "$ref": "#/components/headers/Location"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        }
      },
      "JobCompleted": {
        "content": {
          "application/json": {
            "examples": {
              "image": {
                "value": {
                  "attempt_count": 1,
                  "completed_at": "2026-09-25T12:00:09Z",
                  "created": 1758801600,
                  "created_at": "2026-09-25T12:00:00Z",
                  "currency": "RUB",
                  "data": [
                    {
                      "bytes": 618240,
                      "content_type": "image/jpeg",
                      "created_at": "2026-09-25T12:00:09Z",
                      "expired": false,
                      "expires_at": "2026-10-02T12:00:09Z",
                      "filename": "souz_nano-banana-pro_9f8e7d6c.jpg",
                      "height": 1024,
                      "id": "file_9f8e7d6c5b4a",
                      "kind": "result",
                      "object": "file",
                      "role": "result",
                      "type": "image",
                      "url": "https://media.souz.ai/v1/files/file_9f8e7d6c5b4a/souz_nano-banana-pro_9f8e7d6c.jpg?exp=1759406400\u0026sig=abc",
                      "width": 1024
                    }
                  ],
                  "error": null,
                  "id": "job_1a2b3c4d5e6f",
                  "max_price_multiplier": 2,
                  "modality": "image",
                  "model": "nano-banana-pro",
                  "object": "job",
                  "price": 5000000,
                  "routing": "cheap",
                  "routing_options": null,
                  "status": "completed",
                  "usage": null
                }
              }
            },
            "schema": {
              "$ref": "#/components/schemas/Job"
            }
          }
        },
        "description": "Задача завершена, результат в `data`."
      },
      "JobOK": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Job"
            }
          }
        },
        "description": "Задача."
      },
      "JobOrError": {
        "content": {
          "application/json": {
            "schema": {
              "anyOf": [
                {
                  "$ref": "#/components/schemas/Job"
                },
                {
                  "$ref": "#/components/schemas/Error"
                }
              ]
            }
          }
        },
        "description": "Запрос не принят — `Error`; задача провалилась во время ожидания — объект задачи с\n`error` (то же поле, что у `Error`, поэтому разбирается одним кодом). `503` на\nплановых работах — `Error` с кодом `maintenance` (ответ `Maintenance`).\n",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        }
      },
      "Maintenance": {
        "content": {
          "application/json": {
            "examples": {
              "maintenance": {
                "value": {
                  "error": {
                    "code": "maintenance",
                    "ends_at": "2026-10-04T14:15:00+03:00",
                    "message": "scheduled maintenance: new requests are paused until ends_at; retry after it, accepted jobs finish afterwards and nothing needs to change on your side",
                    "reason": "Обновление сервиса",
                    "type": "model_error"
                  }
                }
              }
            },
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "description": "Плановые работы (`maintenance`): новые запросы приостановлены до `error.ends_at`,\nпричина — в `error.reason`. Повторите после этого времени (или через `Retry-After`\nсекунд, чтобы узнать, не закончились ли работы раньше); принятые задачи доделываются,\nпереключаться никуда не нужно. Состояние — `GET /v1/status`.\n",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        }
      },
      "ModelUnavailable": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "description": "Модель сейчас некому исполнить — повторите через `Retry-After`. На плановых работах —\n`maintenance` (ответ `Maintenance`).\n",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        }
      },
      "NotFound": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "description": "Нет такого объекта у этого аккаунта."
      },
      "NotModified": {
        "description": "Не изменилось с прошлого раза: `If-None-Match` совпал с `ETag`."
      },
      "Overloaded": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "description": "Сервер занят большими запросами (`overloaded`) — повторите через `Retry-After`. На\nплановых работах — `maintenance` (ответ `Maintenance`).\n",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        }
      },
      "PaymentRequired": {
        "content": {
          "application/json": {
            "examples": {
              "balance": {
                "summary": "Не хватает баланса",
                "value": {
                  "error": {
                    "code": "insufficient_balance",
                    "message": "insufficient balance",
                    "type": "billing_error"
                  }
                }
              },
              "key_spend_limit": {
                "summary": "Исчерпан потолок трат ключа",
                "value": {
                  "error": {
                    "code": "key_spend_limit_exceeded",
                    "message": "this api key has reached its configured spend limit",
                    "type": "billing_error"
                  }
                }
              },
              "member_spend_limit": {
                "summary": "Исчерпан лимит участника, которому выдан ключ",
                "value": {
                  "error": {
                    "code": "member_spend_limit_exceeded",
                    "message": "the member this api key is issued to has reached their spend limit",
                    "type": "billing_error"
                  }
                }
              }
            },
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "description": "Баланса не хватает на самый дешёвый канал с учётом запросов, которые ещё\nвыполняются (`insufficient_balance`), или исчерпан лимит трат ключа\n(`key_spend_limit_exceeded`) либо участника, которому он выдан\n(`member_spend_limit_exceeded`). Повтор не поможет, пока баланс не пополнят, а лимит не\nначнётся заново или его не поднимут: потолок ключа со `spend_limit_reset: none` — на\nвсё время ключа.\n"
      },
      "RateLimited": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "description": "Слишком часто — повторите через `Retry-After` секунд. Запуск моделей, задачи и файлы результатов частотой не ограничены (их ограничивают баланс и лимиты трат); здесь 429 — на поток запросов с ключом, который сервер не знает, с одного адреса, и на потоки сверх 1000 одновременных на аккаунт (события задачи, чат с `stream: true`). Пределы — раздел «Лимиты» руководства.",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        }
      },
      "TooLarge": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "description": "Тело или файл больше предела (`invalid_input`, `detail[].reason: too_large`) или — только у `POST /v1/files` — загрузки аккаунта заняли квоту (`storage_limit_exceeded`)."
      },
      "Unauthorized": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "description": "Нет ключа или ключ недействителен."
      },
      "UnsupportedMediaType": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "description": "Тип тела не тот, что принимает метод: `Content-Type: application/json` (у загрузки файла и транскрибации — `multipart/form-data`). В `detail[]` — `{\"path\": \"body\", \"reason\": \"unsupported_format\"}` и принимаемые типы."
      }
    },
    "schemas": {
      "APIKey": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "currency": {
            "$ref": "#/components/schemas/Currency"
          },
          "expires_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "examples": [
              "key_1a2b3c4d5e6f7890"
            ],
            "type": "string"
          },
          "kind": {
            "description": "`management` — ключ управления: модели не запускает, у него нет трат.",
            "enum": [
              "user",
              "playground",
              "agent",
              "management"
            ],
            "type": "string"
          },
          "last_used_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "max_price_multiplier": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/MaxPriceMultiplier"
              },
              {
                "type": "null"
              }
            ]
          },
          "name": {
            "type": "string"
          },
          "no_store": {
            "description": "Режим без хранения аккаунта (`no_store` в `GET /v1/settings`): тексты запросов не\nсохраняются; файлы живут обычный срок.",
            "type": "boolean"
          },
          "object": {
            "const": "api_key",
            "type": "string"
          },
          "retention": {
            "properties": {
              "chat_content_days": {
                "type": "integer"
              },
              "files_days": {
                "type": "integer"
              }
            },
            "required": [
              "files_days",
              "chat_content_days"
            ],
            "type": "object"
          },
          "routing": {
            "$ref": "#/components/schemas/Routing"
          },
          "routing_options": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ModelRoutingOptions"
              },
              {
                "type": "null"
              }
            ]
          },
          "spend_limit": {
            "description": "Потолок трат ключа; `null` — без потолка.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "spend_limit_reset": {
            "description": "Как обновляется потолок: `none` — потолок на всё время ключа, сам не обновляется;\n`daily` / `monthly` — `spent` считается с 00:00 UTC текущего дня / с 1-го числа\nтекущего месяца. У ключа без потолка (`spend_limit: null`) — тоже `none`.\n",
            "enum": [
              "none",
              "daily",
              "monthly"
            ],
            "type": "string"
          },
          "spent": {
            "description": "Потрачено в текущем окне потолка (при `none` — за всё время ключа), только завершённые\nсписания.\n",
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "object",
          "id",
          "kind",
          "created_at",
          "expires_at",
          "last_used_at",
          "spend_limit",
          "spend_limit_reset",
          "spent",
          "currency",
          "no_store",
          "routing",
          "max_price_multiplier",
          "retention"
        ],
        "type": "object"
      },
      "APIKeyEntry": {
        "properties": {
          "blocked": {
            "description": "Ключ заблокирован службой поддержки — отдельно от `enabled`: включить его снова\nнельзя, запросы по нему получают `403 key_blocked`. Снять блокировку — через\nподдержку.",
            "examples": [
              false
            ],
            "type": "boolean"
          },
          "created_at": {
            "examples": [
              "2026-08-21T12:00:00Z"
            ],
            "type": "string"
          },
          "created_by": {
            "description": "Автор ключа — только он открывает секрет (`GET /v1/keys/{id}/secret`); null — автор\nнеизвестен или удалён из аккаунта, секрет не открыть.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/MemberRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "enabled": {
            "examples": [
              true
            ],
            "type": "boolean"
          },
          "expires_at": {
            "description": "RFC 3339; null — ключ бессрочный.",
            "examples": [
              "2026-12-31T00:00:00Z"
            ],
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "examples": [
              "key_1a2b3c4d5e6f7890"
            ],
            "type": "string"
          },
          "kind": {
            "description": "`user` — обычный ключ, `management` — ключ управления: модели не запускает, потолка трат нет.",
            "enum": [
              "user",
              "management"
            ],
            "type": "string"
          },
          "last_used_at": {
            "description": "Когда ключ последний раз прошёл проверку; null — ещё ни разу.",
            "type": [
              "string",
              "null"
            ]
          },
          "member": {
            "description": "Держатель ключа — его автор: траты ключа идут в его лимит, при его удалении ключ\nотзывается; null — ключ аккаунта, выданный до того, как ключи стали личными.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/MemberRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "name": {
            "examples": [
              "production"
            ],
            "type": "string"
          },
          "secret_available": {
            "description": "Можно ли показать секрет снова (`GET /v1/keys/{id}/secret`); false — показать нельзя\n(ответ `409 secret_unavailable`), создайте новый ключ.",
            "examples": [
              true
            ],
            "type": "boolean"
          },
          "secret_hint": {
            "description": "Подсказка секрета: приставка, первые 4 и последние 4 знака — узнать ключ, не открывая\nего; null — секрет не сохранён.",
            "examples": [
              "sk_9f3a…c1d2"
            ],
            "type": [
              "string",
              "null"
            ]
          },
          "spend_limit_micro": {
            "description": "Потолок трат ключа в микроединицах валюты; null — без потолка.",
            "examples": [
              1000000
            ],
            "type": [
              "integer",
              "null"
            ]
          },
          "spend_limit_reset": {
            "description": "Как часто обновляется потолок: `none` — на весь срок ключа; `daily` / `monthly` —\n`spent_micro` считается с 00:00 UTC текущего дня / с 1-го числа текущего месяца.",
            "enum": [
              "none",
              "daily",
              "monthly"
            ],
            "examples": [
              "monthly"
            ],
            "type": "string"
          },
          "spent_micro": {
            "description": "Списано по запросам ключа в текущем окне потолка (при `none` — за весь срок), в\nмикроединицах; только завершённые запросы.",
            "examples": [
              250000
            ],
            "type": "integer"
          }
        },
        "required": [
          "blocked",
          "created_at",
          "created_by",
          "enabled",
          "expires_at",
          "id",
          "kind",
          "last_used_at",
          "member",
          "secret_available",
          "secret_hint",
          "spend_limit_micro",
          "spend_limit_reset",
          "spent_micro"
        ],
        "type": "object"
      },
      "APIKeysResponse": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/APIKeyEntry"
            },
            "type": "array"
          }
        },
        "required": [
          "items"
        ],
        "type": "object"
      },
      "AccountRef": {
        "properties": {
          "blocked": {
            "description": "Аккаунт заблокирован службой поддержки: новые запросы его ключей и плейграунда\nполучают `403 account_blocked`; вход, баланс, история и уже принятые запросы\nостаются. Снять блокировку — через поддержку.",
            "examples": [
              false
            ],
            "type": "boolean"
          },
          "has_balance": {
            "description": "false — у аккаунта нет баланса, расход учитывается по факту; пополнение, оплата, бонусы и история баланса недоступны (403 account_without_balance).",
            "examples": [
              true
            ],
            "type": "boolean"
          },
          "id": {
            "examples": [
              "user_1a2b3c4d5e6f7890"
            ],
            "type": "string"
          },
          "name": {
            "examples": [
              "Acme"
            ],
            "type": "string"
          },
          "number": {
            "description": "Номер аккаунта в виде автомобильного номера: буква, три цифры, две буквы и код\nрегиона РФ из двух или трёх цифр — «К 482 МТ · 77», «Р 105 ОС · 761». Случайный и\nуникальный; по нему поддержка находит\nаккаунт. Буквы — только А В Е К М Н О Р С Т У Х, у которых одно начертание в\nкириллице и латинице, поэтому номер принимается в любой раскладке, с пробелами и\nбез.",
            "examples": [
              "К 482 МТ · 77"
            ],
            "type": "string"
          }
        },
        "required": [
          "blocked",
          "has_balance",
          "id",
          "name",
          "number"
        ],
        "type": "object"
      },
      "AccountSettingsPatch": {
        "properties": {
          "max_price_multiplier": {
            "description": "Потолок цены; null снимает потолок, без поля — не меняется.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/MaxPriceMultiplier"
              },
              {
                "type": "null"
              }
            ]
          },
          "no_store": {
            "description": "Режим без хранения для всех ключей аккаунта; без поля — не меняется.",
            "type": "boolean"
          },
          "routing": {
            "$ref": "#/components/schemas/Routing"
          },
          "routing_options": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ModelRoutingOptions"
              },
              {
                "type": "null"
              }
            ]
          },
          "webhook": {
            "$ref": "#/components/schemas/WebhookSettingsPatch"
          }
        },
        "type": "object"
      },
      "AccountSettingsResponse": {
        "properties": {
          "max_price_multiplier": {
            "description": "Потолок цены для всех ключей аккаунта, когда запрос его не задаёт;\nnull — без потолка.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/MaxPriceMultiplier"
              },
              {
                "type": "null"
              }
            ]
          },
          "no_store": {
            "description": "Режим без хранения для всех ключей аккаунта, включая плейграунд. По умолчанию\nвыключен: тексты запросов — промпт, сообщения и ответ чата, текст речи, расшифровка —\nхранятся до `retention.chat_content_days` дней, файлы — `retention.files_days`. Включён —\nтексты запросов и ответов не сохраняются; файлы живут `retention.files_days`, как\nбез режима. `store: false` в запросе включает то же для одного вызова.",
            "type": "boolean"
          },
          "retention": {
            "description": "Сроки хранения, те же, что в `GET /v1/key`.",
            "properties": {
              "chat_content_days": {
                "type": "integer"
              },
              "files_days": {
                "type": "integer"
              }
            },
            "required": [
              "files_days",
              "chat_content_days"
            ],
            "type": "object"
          },
          "routing": {
            "$ref": "#/components/schemas/Routing",
            "description": "Пресет роутинга для всех ключей аккаунта, включая встроенный ключ\nплейграунда, когда запрос его не называет."
          },
          "routing_options": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ModelRoutingOptions"
              },
              {
                "type": "null"
              }
            ]
          },
          "webhook": {
            "$ref": "#/components/schemas/WebhookSettings"
          }
        },
        "required": [
          "max_price_multiplier",
          "routing",
          "webhook",
          "no_store",
          "retention"
        ],
        "type": "object"
      },
      "AttemptCount": {
        "description": "Сколько раз запрос отправлялся каналам, по порядку роутинга: `1` —\nвыполнен с первого раза, больше — запрос переходил к следующему каналу; `0` — ещё не\nотправлялся.\n",
        "minimum": 0,
        "type": "integer"
      },
      "BalanceHistoryResponse": {
        "properties": {
          "currency": {
            "examples": [
              "RUB"
            ],
            "type": "string"
          },
          "items": {
            "items": {
              "$ref": "#/components/schemas/BalanceOperation"
            },
            "type": "array"
          },
          "next_before": {
            "description": "Курсор следующей (более старой) страницы для `before`; null — страниц больше нет.",
            "examples": [
              "1758600000123456.4211"
            ],
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "currency",
          "items",
          "next_before"
        ],
        "type": "object"
      },
      "BalanceOperation": {
        "description": "Операция по балансу: пополнение (deposit), списание за успешный запрос (charge), возврат остатка через поддержку (refund) или отмена начисления службой поддержки (reversal). Суммы без знака в микроединицах currency ответа; направление задаёт kind: пополнение прибавляет, списание, возврат и отмена вычитают.",
        "properties": {
          "amount_micro": {
            "examples": [
              10000000
            ],
            "format": "int64",
            "type": "integer"
          },
          "api_key_kind": {
            "enum": [
              "user",
              "playground",
              "agent"
            ],
            "examples": [
              "user"
            ],
            "type": "string"
          },
          "api_key_name": {
            "examples": [
              "production"
            ],
            "type": "string"
          },
          "canonical_model": {
            "examples": [
              "gpt-5-nano"
            ],
            "type": "string"
          },
          "created_at": {
            "examples": [
              "2026-08-21T12:00:00Z"
            ],
            "type": "string"
          },
          "id": {
            "description": "dep_N у пополнения, rfd_N у возврата, rev_N у отмены, id запроса у списания.",
            "examples": [
              "dep_42"
            ],
            "type": "string"
          },
          "job_id": {
            "description": "У списания — запрос, за который оно; у компенсации (label compensation) — запрос, за который она начислена. Поля ниже — только у списания.",
            "examples": [
              "job_abc123"
            ],
            "type": "string"
          },
          "kind": {
            "$ref": "#/components/schemas/BalanceOperationKind"
          },
          "label": {
            "description": "Только у бонуса от службы поддержки: topup_bonus — бонус к пополнению, compensation — компенсация за запрос (job_id), bonus — бонус. Нет поля — приветственный бонус или бонус по приглашению.",
            "enum": [
              "topup_bonus",
              "compensation",
              "bonus"
            ],
            "examples": [
              "compensation"
            ],
            "type": "string"
          },
          "modality": {
            "enum": [
              "chat",
              "image",
              "video",
              "transcription",
              "speech",
              "music"
            ],
            "examples": [
              "chat"
            ],
            "type": "string"
          },
          "source": {
            "description": "У пополнения: payment — оплата, bonus — бонус (приветственный, по приглашению или от поддержки). У отмены — что отменено: оплата или бонус.",
            "enum": [
              "payment",
              "bonus"
            ],
            "examples": [
              "payment"
            ],
            "type": "string"
          },
          "topup": {
            "$ref": "#/components/schemas/BalanceTopup"
          }
        },
        "required": [
          "amount_micro",
          "created_at",
          "id",
          "kind"
        ],
        "type": "object"
      },
      "BalanceOperationKind": {
        "description": "deposit — пополнение, charge — списание за успешный запрос, refund — возврат остатка, reversal — отмена начисления службой поддержки.",
        "enum": [
          "deposit",
          "charge",
          "refund",
          "reversal"
        ],
        "type": "string"
      },
      "BalanceResponse": {
        "properties": {
          "available_micro": {
            "examples": [
              10000000
            ],
            "type": "integer"
          },
          "currency": {
            "examples": [
              "RUB"
            ],
            "type": "string"
          },
          "mock_topup": {
            "description": "Есть ли на этом сервере тестовое пополнение баланса; в рабочем API всегда `false`.",
            "examples": [
              false
            ],
            "type": "boolean"
          },
          "overdraft_limit_micro": {
            "description": "Разрешённая сумма минуса в микроединицах валюты аккаунта.",
            "format": "int64",
            "minimum": 0,
            "type": "integer"
          },
          "spendable_micro": {
            "description": "Сумма, доступная для новых запросов с учётом овердрафта и текущих обязательств.",
            "format": "int64",
            "minimum": 0,
            "type": "integer"
          },
          "spent_total_micro": {
            "description": "Сколько аккаунт потратил за всё время: сумма списаний за успешные запросы в\nмикроединицах `currency`. Обновляется в течение минуты после завершения запроса.",
            "examples": [
              125000000
            ],
            "format": "int64",
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "available_micro",
          "overdraft_limit_micro",
          "spendable_micro",
          "spent_total_micro",
          "currency",
          "mock_topup"
        ],
        "type": "object"
      },
      "BalanceTopup": {
        "description": "Остаток конкретного пополнения. Только у deposit с доступным учётом:\nу старых оплат без распределения поле отсутствует. Суммы в микроединицах\ncurrency ответа. Бонусы расходуются первыми; внутри каждого источника —\nсначала более ранние пополнения. Нулевой остаток не подтверждает выдачу чека.",
        "properties": {
          "method": {
            "description": "Способ оплаты пополнения: card — банковская карта, sbp — Система быстрых\nплатежей, other — другой способ платёжной страницы. Отсутствует у бонуса\nи пока платёжная система не сообщила способ (обычно в течение минуты после оплаты).",
            "enum": [
              "card",
              "sbp",
              "other"
            ],
            "type": "string"
          },
          "receipt_url": {
            "description": "HTTPS-ссылка на чек покупки, если документ доступен. Отсутствует у бонуса и при отсутствии ссылки; не является подтверждением доставки письма.",
            "format": "uri",
            "pattern": "^https://",
            "type": "string"
          },
          "refund_pending_micro": {
            "description": "Часть remaining_micro, удержанная для возврата; у бонуса всегда 0.",
            "format": "int64",
            "minimum": 0,
            "type": "integer"
          },
          "refunded_micro": {
            "description": "Уже возвращено из этого пополнения; у бонуса всегда 0.",
            "format": "int64",
            "minimum": 0,
            "type": "integer"
          },
          "remaining_micro": {
            "description": "Неизрасходованный остаток, включая сумму ожидающего возврата.",
            "format": "int64",
            "minimum": 0,
            "type": "integer"
          },
          "reversed_micro": {
            "description": "Сколько из этого пополнения отменила служба поддержки (операции reversal); это не расход и не возврат.",
            "format": "int64",
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "remaining_micro",
          "refunded_micro",
          "refund_pending_micro",
          "reversed_micro"
        ],
        "type": "object"
      },
      "Capabilities": {
        "description": "Только у чата — что модель действительно учитывает.",
        "properties": {
          "audio_input": {
            "description": "Звук в `messages[].content` (`input_audio`).",
            "type": "boolean"
          },
          "file_input": {
            "description": "Файл, например PDF, в `messages[].content` (`file`).",
            "type": "boolean"
          },
          "streaming": {
            "type": "boolean"
          },
          "structured_output": {
            "type": "boolean"
          },
          "supported_parameters": {
            "description": "Параметры запроса, которые учитывает хотя бы один канал модели. Нет поля — список опубликован не у всех каналов.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "tools": {
            "type": "boolean"
          },
          "video_input": {
            "description": "Видео в `messages[].content` (`video_url`).",
            "type": "boolean"
          },
          "vision": {
            "description": "Картинка в `messages[].content` (`image_url`).",
            "type": "boolean"
          }
        },
        "required": [
          "tools",
          "vision",
          "structured_output",
          "streaming",
          "file_input",
          "audio_input",
          "video_input"
        ],
        "type": "object"
      },
      "ChannelHistory": {
        "description": "Как канал работал последние 7 дней по вызовам всех клиентов и проверкам Союза: 28\nинтервалов по 6 часов. Считаются отправленные вызовы с успехом или отказом по вине\nканала; ошибки во входных данных и правила модели стабильность не портят. Это наблюдение,\nа не обещание: один цвет может стать медленнее или дороже.\n",
        "properties": {
          "attempts": {
            "description": "Вызовов канала за 7 дней.",
            "minimum": 0,
            "type": "integer"
          },
          "bucket": {
            "const": "6h",
            "type": "string"
          },
          "points": {
            "description": "Ровно 28 интервалов по возрастанию; последний — текущий, ещё не закрытый.",
            "items": {
              "$ref": "#/components/schemas/ChannelHistoryPoint"
            },
            "type": "array"
          },
          "success_rate": {
            "description": "Доля успешных за 7 дней, от 0 до 1. `null` — меньше двадцати вызовов.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "bucket",
          "attempts",
          "success_rate",
          "points"
        ],
        "type": "object"
      },
      "ChannelHistoryPoint": {
        "properties": {
          "at": {
            "description": "Начало интервала, UTC (00:00, 06:00, 12:00 или 18:00).",
            "format": "date-time",
            "type": "string"
          },
          "attempts": {
            "minimum": 0,
            "type": "integer"
          },
          "latency_p50_ms": {
            "description": "Медиана задержки успешных вызовов, мс (±10 %) — у чата до первого содержимого, у остальных до результата.",
            "type": [
              "number",
              "null"
            ]
          },
          "success_rate": {
            "description": "Доля успешных вызовов интервала, от 0 до 1. `null` — меньше пяти вызовов; это не ноль.",
            "type": [
              "number",
              "null"
            ]
          },
          "throughput_p50": {
            "description": "Только чат — медиана скорости выдачи, токенов в секунду.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "at",
          "attempts",
          "success_rate",
          "latency_p50_ms",
          "throughput_p50"
        ],
        "type": "object"
      },
      "ChannelId": {
        "description": "Постоянный идентификатор цветового канала. Цвет обозначает одно исполнение и не переназначается.",
        "pattern": "^[a-z][a-z0-9-]{0,47}$",
        "type": "string"
      },
      "ChannelMetrics": {
        "description": "Измерения успешных запросов канала и доля успешных выполнений. Задержка и скорость выдачи имеют отдельные числа замеров и окна. Для задержки берутся последние 50 подходящих успехов чата или 20 у остальных модальностей за сутки; для скорости выдачи — последние 20 за сутки. Если для метрики меньше трёх свежих замеров — данные за 7 дней. Без трёх замеров за неделю соответствующие значения — null, число замеров и окно — 0. Порядок пресетов дополнительно учитывает цену, ожидаемое время полного выполнения и устойчивость канала. `measured_at` — время последнего успешного замера канала.",
        "properties": {
          "latency_p50_ms": {
            "description": "Медиана времени успешного выполнения, мс; у чата — до первого содержимого ответа.",
            "type": [
              "number",
              "null"
            ]
          },
          "latency_p90_ms": {
            "description": "90-й процентиль времени успешного выполнения, мс; у чата — до первого содержимого ответа.",
            "type": [
              "number",
              "null"
            ]
          },
          "latency_samples": {
            "description": "Число успешных замеров, использованных для latency_p50_ms и latency_p90_ms; 0, если оценки нет.",
            "minimum": 0,
            "type": "integer"
          },
          "latency_window_seconds": {
            "description": "Окно замеров задержки в секундах — сутки или 7 дней; 0, если оценки нет.",
            "enum": [
              0,
              86400,
              604800
            ],
            "type": "integer"
          },
          "measured_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "samples": {
            "description": "Число успешных запросов и сбоев исполнения за сутки, по которым считается success_rate. Не число замеров задержки или скорости выдачи.",
            "minimum": 0,
            "type": "integer"
          },
          "success_rate": {
            "description": "Доля успешных среди успешных запросов и сбоев исполнения за сутки, от нуля до единицы. Публикуется от двадцати таких запросов. Ошибки параметров, отказы по содержимому, отмены, ограничения канала, перегрузка и неотправленные запросы исключены.",
            "type": [
              "number",
              "null"
            ]
          },
          "success_samples": {
            "description": "Успешные запросы среди samples за сутки.",
            "minimum": 0,
            "type": "integer"
          },
          "throughput_p50": {
            "description": "Чат — медиана скорости выдачи содержимого, токенов в секунду, после первого токена.",
            "type": [
              "number",
              "null"
            ]
          },
          "throughput_p90": {
            "description": "Чат — 90-й процентиль скорости выдачи содержимого, токенов в секунду. У остальных модальностей null.",
            "type": [
              "number",
              "null"
            ]
          },
          "throughput_samples": {
            "description": "Число успешных замеров выдачи, использованных для throughput_p50 и throughput_p90; 0, если оценки нет или это не чат.",
            "minimum": 0,
            "type": "integer"
          },
          "throughput_window_seconds": {
            "description": "Окно замеров скорости выдачи в секундах — сутки или 7 дней; 0, если оценки нет или это не чат.",
            "enum": [
              0,
              86400,
              604800
            ],
            "type": "integer"
          },
          "window_seconds": {
            "description": "Общее окно времени и скорости для существующих клиентов — 86400 или 604800; если хотя бы одна оценка взята за неделю, 604800. Для каждой метрики используйте её latency_window_seconds или throughput_window_seconds.",
            "type": "integer"
          }
        },
        "required": [
          "samples",
          "window_seconds",
          "measured_at",
          "latency_p50_ms",
          "latency_p90_ms",
          "latency_samples",
          "latency_window_seconds",
          "throughput_p50",
          "throughput_p90",
          "throughput_samples",
          "throughput_window_seconds",
          "success_rate",
          "success_samples"
        ],
        "type": "object"
      },
      "ChannelPalette": {
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/PaletteColor"
            },
            "type": "array"
          }
        },
        "required": [
          "data"
        ],
        "type": "object"
      },
      "ChannelParameter": {
        "additionalProperties": false,
        "properties": {
          "default": {
            "type": "string"
          },
          "enum": {
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "enum",
          "default"
        ],
        "type": "object"
      },
      "ChannelPrice": {
        "description": "Цена одного канала для сценария. Итог запроса — по факту выполнения.",
        "properties": {
          "amount_micro": {
            "description": "Остальные единицы — сумма сценария (в строке `options` — за её сочетание параметров).",
            "format": "int64",
            "type": "integer"
          },
          "cache_read_micro": {
            "description": "`per_1m_tokens` — вход из кэша за 1M токенов, если у канала отдельная ставка.",
            "format": "int64",
            "type": "integer"
          },
          "dynamic": {
            "description": "`true` — динамическая цена канала: сумма — оценка сценария, итог — по фактическому расходу.",
            "type": "boolean"
          },
          "id": {
            "$ref": "#/components/schemas/ChannelId"
          },
          "input_micro": {
            "description": "`per_1m_tokens` — вход за 1M токенов.",
            "format": "int64",
            "type": "integer"
          },
          "output_micro": {
            "description": "`per_1m_tokens` — выход за 1M токенов.",
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "id"
        ],
        "type": "object"
      },
      "ChatChoice": {
        "properties": {
          "finish_reason": {
            "examples": [
              "stop"
            ],
            "type": [
              "string",
              "null"
            ]
          },
          "index": {
            "type": "integer"
          },
          "logprobs": {
            "type": [
              "object",
              "null"
            ]
          },
          "message": {
            "$ref": "#/components/schemas/ChatResponseMessage"
          }
        },
        "required": [
          "index",
          "message",
          "finish_reason"
        ],
        "type": "object"
      },
      "ChatChunkChoice": {
        "properties": {
          "delta": {
            "$ref": "#/components/schemas/ChatResponseMessage"
          },
          "finish_reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "index": {
            "type": "integer"
          },
          "logprobs": {
            "type": [
              "object",
              "null"
            ]
          }
        },
        "required": [
          "index",
          "delta"
        ],
        "type": "object"
      },
      "ChatCompletion": {
        "properties": {
          "channel": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ChannelId"
              }
            ],
            "description": "Фактический цвет канала, который дал этот ответ. Название и HEX — `GET /v1/channels`."
          },
          "choices": {
            "items": {
              "$ref": "#/components/schemas/ChatChoice"
            },
            "type": "array"
          },
          "created": {
            "format": "int64",
            "type": "integer"
          },
          "id": {
            "description": "`chatcmpl-…`; тот же id открывает `GET /v1/jobs/{id}`.",
            "type": "string"
          },
          "model": {
            "type": "string"
          },
          "object": {
            "const": "chat.completion",
            "type": "string"
          },
          "usage": {
            "$ref": "#/components/schemas/ChatUsage"
          }
        },
        "required": [
          "id",
          "object",
          "created",
          "model",
          "choices",
          "usage"
        ],
        "type": "object"
      },
      "ChatCompletionChunk": {
        "description": "Одно событие потока; `usage` приходит в последнем.",
        "properties": {
          "channel": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ChannelId"
              }
            ],
            "description": "Фактический цвет канала, который дал этот ответ. Название и HEX — `GET /v1/channels`."
          },
          "choices": {
            "items": {
              "$ref": "#/components/schemas/ChatChunkChoice"
            },
            "type": "array"
          },
          "created": {
            "format": "int64",
            "type": "integer"
          },
          "id": {
            "type": "string"
          },
          "model": {
            "type": "string"
          },
          "object": {
            "const": "chat.completion.chunk",
            "type": "string"
          },
          "usage": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ChatUsage"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "object",
          "created",
          "model",
          "choices"
        ],
        "type": "object"
      },
      "ChatCompletionRequest": {
        "additionalProperties": true,
        "description": "Запрос OpenAI Chat Completions. Поля, которых здесь нет, передаются модели как есть.\n`routing`, `max_price_multiplier` и `store` — наши; модели не передаются.\nВеб-поиск — `web_search_options` или плагин `{\"id\": \"web\"}` в `plugins` — `400 capability_mismatch`;\n`service_tier`, `provider`, `models`, `route`, `transforms` и остальные `plugins` игнорируются.\n",
        "properties": {
          "max_completion_tokens": {
            "minimum": 1,
            "type": "integer"
          },
          "max_price_multiplier": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/MaxPriceMultiplier"
              },
              {
                "type": "null"
              }
            ]
          },
          "max_tokens": {
            "description": "Граница ответа (или `max_completion_tokens`). Без поля — предел модели. Если баланса\nхватает не на весь ответ, модели передаётся граница по оплачиваемому (не меньше\n1000 токенов).\n",
            "minimum": 1,
            "type": "integer"
          },
          "messages": {
            "items": {
              "$ref": "#/components/schemas/ChatMessage"
            },
            "minItems": 1,
            "type": "array"
          },
          "model": {
            "examples": [
              "gpt-5-nano"
            ],
            "type": "string"
          },
          "n": {
            "minimum": 1,
            "type": "integer"
          },
          "reasoning_effort": {
            "examples": [
              "medium"
            ],
            "type": "string"
          },
          "response_format": {
            "description": "`{\"type\": \"json_schema\", …}` — у моделей с `capabilities.structured_output`.",
            "type": "object"
          },
          "routing": {
            "$ref": "#/components/schemas/Routing"
          },
          "routing_options": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/RoutingOptions"
              },
              {
                "type": "null"
              }
            ]
          },
          "store": {
            "description": "`false` — запрос без хранения: тексты запроса и ответа не сохраняются; файлы живут обычный срок. По умолчанию тексты хранятся; `true` не отменяет режим без хранения аккаунта.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "stream": {
            "default": false,
            "type": "boolean"
          },
          "temperature": {
            "format": "double",
            "type": "number"
          },
          "tool_choice": {
            "description": "`auto`, `none`, `required` или конкретная функция. `required` и конкретную функцию исполняют не все каналы; если ни один — `400 capability_mismatch` с путём `tool_choice`.",
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "object"
              }
            ]
          },
          "tools": {
            "description": "Инструменты OpenAI; модель без `capabilities.tools` — `400 capability_mismatch`.",
            "items": {
              "type": "object"
            },
            "type": "array"
          }
        },
        "required": [
          "model",
          "messages"
        ],
        "type": "object"
      },
      "ChatContentPart": {
        "additionalProperties": true,
        "description": "Часть сообщения. `type` выбирает поле с содержимым:\n\n- `text` — `{\"type\": \"text\", \"text\": \"…\"}`;\n- `image_url` — `{\"type\": \"image_url\", \"image_url\": {\"url\": \"https://… | data:image/png;base64,…\"}}`;\n- `file` — `{\"type\": \"file\", \"file\": {\"filename\": \"doc.pdf\", \"file_data\": \"data:application/pdf;base64,…\"}}`;\n- `input_audio` — `{\"type\": \"input_audio\", \"input_audio\": {\"data\": \"\u003cbase64\u003e\", \"format\": \"wav\"}}`;\n- `video_url` — `{\"type\": \"video_url\", \"video_url\": {\"url\": \"https://… | data:video/mp4;base64,…\"}}`.\n",
        "properties": {
          "file": {
            "additionalProperties": true,
            "properties": {
              "file_data": {
                "description": "Файл data URL в base64.",
                "type": "string"
              },
              "filename": {
                "type": "string"
              }
            },
            "type": "object"
          },
          "image_url": {
            "additionalProperties": true,
            "properties": {
              "url": {
                "type": "string"
              }
            },
            "type": "object"
          },
          "input_audio": {
            "additionalProperties": true,
            "properties": {
              "data": {
                "description": "Звук в base64, без префикса `data:`.",
                "type": "string"
              },
              "format": {
                "examples": [
                  "wav",
                  "mp3"
                ],
                "type": "string"
              }
            },
            "type": "object"
          },
          "text": {
            "type": "string"
          },
          "type": {
            "examples": [
              "text",
              "image_url",
              "file",
              "input_audio",
              "video_url"
            ],
            "type": "string"
          },
          "video_url": {
            "additionalProperties": true,
            "properties": {
              "url": {
                "description": "Ссылка на ролик или data URL в base64.",
                "type": "string"
              }
            },
            "type": "object"
          }
        },
        "required": [
          "type"
        ],
        "type": "object"
      },
      "ChatMessage": {
        "additionalProperties": true,
        "properties": {
          "content": {
            "description": "Текст или части — как у OpenAI: `text`, `image_url`, `file`, `input_audio`,\n`video_url`. Картинка, файл, звук и видео уходят только в каналы, которые их\nпринимают (`capabilities` модели); если таких нет — `400 capability_mismatch`.\n",
            "oneOf": [
              {
                "type": "string"
              },
              {
                "items": {
                  "$ref": "#/components/schemas/ChatContentPart"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ]
          },
          "role": {
            "enum": [
              "system",
              "developer",
              "user",
              "assistant",
              "tool"
            ],
            "type": "string"
          }
        },
        "required": [
          "role"
        ],
        "type": "object"
      },
      "ChatResponseMessage": {
        "description": "Сообщение ответа (в потоке — его часть `delta`).",
        "properties": {
          "annotations": {
            "items": {
              "type": "object"
            },
            "type": "array"
          },
          "audio": {
            "type": [
              "object",
              "null"
            ]
          },
          "content": {
            "type": [
              "string",
              "null"
            ]
          },
          "images": {
            "description": "Картинки мультимодальной модели — data-URI, не сохраняются.",
            "items": {
              "type": "object"
            },
            "type": "array"
          },
          "reasoning": {
            "type": [
              "string",
              "null"
            ]
          },
          "reasoning_details": {
            "items": {
              "type": "object"
            },
            "type": "array"
          },
          "refusal": {
            "type": [
              "string",
              "null"
            ]
          },
          "role": {
            "type": "string"
          },
          "tool_calls": {
            "items": {
              "type": "object"
            },
            "type": "array"
          }
        },
        "type": "object"
      },
      "ChatUsage": {
        "properties": {
          "completion_tokens": {
            "type": "integer"
          },
          "completion_tokens_details": {
            "properties": {
              "audio_tokens": {
                "type": "integer"
              },
              "reasoning_tokens": {
                "type": "integer"
              }
            },
            "type": "object"
          },
          "cost": {
            "description": "Сколько списано за вызов, микроединицы `currency` — в итоговом ответе и последнем чанке потока.",
            "format": "int64",
            "type": "integer"
          },
          "currency": {
            "$ref": "#/components/schemas/Currency"
          },
          "prompt_tokens": {
            "type": "integer"
          },
          "prompt_tokens_details": {
            "properties": {
              "audio_tokens": {
                "type": "integer"
              },
              "cached_tokens": {
                "type": "integer"
              }
            },
            "type": "object"
          },
          "total_tokens": {
            "type": "integer"
          }
        },
        "required": [
          "prompt_tokens",
          "completion_tokens",
          "total_tokens"
        ],
        "type": "object"
      },
      "CreateAPIKeyRequest": {
        "properties": {
          "kind": {
            "default": "user",
            "description": "`user` — обычный ключ, запускает модели; `management` — ключ управления: создают\nвладелец и администратор и только в кабинете, трат и потолка у него нет.",
            "enum": [
              "user",
              "management"
            ],
            "type": "string"
          },
          "name": {
            "examples": [
              "production"
            ],
            "type": "string"
          },
          "spend_limit_micro": {
            "description": "Потолок трат ключа в микроединицах валюты; без поля — без потолка. У ключа\nуправления потолка нет: с полем — 400.",
            "examples": [
              5000000000
            ],
            "type": "integer"
          },
          "spend_limit_reset": {
            "description": "Как часто обновляется потолок: `none` (по умолчанию, на весь срок), `daily`,\n`monthly` — по UTC.",
            "enum": [
              "none",
              "daily",
              "monthly"
            ],
            "examples": [
              "monthly"
            ],
            "type": "string"
          }
        },
        "type": "object"
      },
      "CreateAPIKeyResponse": {
        "properties": {
          "created_at": {
            "examples": [
              "2026-08-21T12:00:00Z"
            ],
            "type": "string"
          },
          "id": {
            "examples": [
              "key_1a2b3c4d5e6f7890"
            ],
            "type": "string"
          },
          "key": {
            "examples": [
              "sk_9f8e7d6c5b4a39281706f5e4d3c2b1a0"
            ],
            "type": "string"
          },
          "name": {
            "examples": [
              "production"
            ],
            "type": "string"
          }
        },
        "required": [
          "created_at",
          "id",
          "key"
        ],
        "type": "object"
      },
      "Currency": {
        "description": "Валюта сумм рядом, ISO 4217.",
        "enum": [
          "RUB"
        ],
        "type": "string"
      },
      "DailyUsageEntry": {
        "properties": {
          "by_model": {
            "description": "Тот же день в разрезе моделей, по расходу вниз; сумма по моделям равна итогам дня.",
            "items": {
              "$ref": "#/components/schemas/ModelUsageEntry"
            },
            "type": "array"
          },
          "date": {
            "examples": [
              "2026-09-01"
            ],
            "type": "string"
          },
          "requests": {
            "description": "Завершённые запросы дня (успех, провал, отмена); `succeeded` — из них успешные.",
            "examples": [
              7
            ],
            "type": "integer"
          },
          "spend_micro": {
            "examples": [
              125000
            ],
            "type": "integer"
          },
          "succeeded": {
            "examples": [
              6
            ],
            "type": "integer"
          }
        },
        "required": [
          "by_model",
          "date",
          "requests",
          "spend_micro",
          "succeeded"
        ],
        "type": "object"
      },
      "DetailReason": {
        "enum": [
          "required",
          "unsupported_field",
          "unsupported_value",
          "incompatible_value",
          "duplicate",
          "mutually_exclusive",
          "out_of_range",
          "too_long",
          "too_many_items",
          "exceeds_duration",
          "requires_first_frame",
          "requires_visual_reference",
          "text_to_video_only",
          "unsupported_format",
          "animated_not_supported",
          "undecodable",
          "too_large",
          "too_many_pixels",
          "too_small",
          "unreachable",
          "invalid_source",
          "unknown_file",
          "file_expired",
          "content_policy_category",
          "price_cap",
          "wrong_endpoint",
          "insufficient_role",
          "requires_api_key",
          "requires_management_key",
          "cabinet_only",
          "not_key_author",
          "not_selected",
          "above_max_price",
          "fallback_disabled"
        ],
        "type": "string"
      },
      "Error": {
        "description": "Тело любой ошибки.",
        "properties": {
          "error": {
            "$ref": "#/components/schemas/ErrorBody"
          }
        },
        "required": [
          "error"
        ],
        "type": "object"
      },
      "ErrorBody": {
        "properties": {
          "code": {
            "$ref": "#/components/schemas/ErrorCode"
          },
          "detail": {
            "description": "Что именно не так — когда это известно.",
            "items": {
              "$ref": "#/components/schemas/ErrorDetail"
            },
            "type": "array"
          },
          "ends_at": {
            "description": "Только у `maintenance` — до какого времени приостановлены новые запросы.",
            "format": "date-time",
            "type": "string"
          },
          "message": {
            "description": "Короткая фраза для человека и лога; ветвиться по ней не нужно.",
            "type": "string"
          },
          "reason": {
            "description": "Только у `maintenance` — причина плановых работ, для людей.",
            "type": "string"
          },
          "type": {
            "$ref": "#/components/schemas/ErrorType"
          }
        },
        "required": [
          "type",
          "code",
          "message"
        ],
        "type": "object"
      },
      "ErrorCode": {
        "description": "Что случилось — закрытый словарь. `no_channel_matches` (400) — `routing_options` отсекли\nвсе каналы модели; что именно — в `detail[].reason` (`not_selected`, `above_max_price`,\n`fallback_disabled`). Повтор того же запроса не поможет: измените настройки.\n`account_blocked` (403) — аккаунт заблокирован службой поддержки: новые запросы не\nпринимаются, чтение задач и результатов работает; `key_blocked` (403) — этот ключ\nзаблокирован службой поддержки. Повтор не поможет — напишите в поддержку.\n`account_without_balance` (403) — у аккаунта нет баланса (`has_balance: false`): расход\nучитывается по факту, баланс, его история, пополнение и оплата недоступны.\n`overloaded` (503) — сервер занят большими запросами; повторите через `Retry-After`\nсекунд. `maintenance` (503) — плановые работы: новые запросы приостановлены до\n`ends_at`, принятые задачи доделываются; повторите после него, переключаться не нужно.\n`unknown_error` (502) — неизвестная ошибка, без подробностей и без списания: повторите\nзапрос, мы разбираем такие случаи.\n`storage_limit_exceeded` (413) — загрузки `POST /v1/files`, срок которых ещё не вышел,\nзаняли квоту (10 ГБ, после первого пополнения — 50 ГБ): удалите ненужные\n`DELETE /v1/files/{id}` или дождитесь их срока.\n",
        "enum": [
          "invalid_request",
          "invalid_input",
          "capability_mismatch",
          "content_policy",
          "invalid_api_key",
          "account_blocked",
          "key_blocked",
          "account_without_balance",
          "insufficient_balance",
          "key_spend_limit_exceeded",
          "member_spend_limit_exceeded",
          "invalid_signature",
          "unauthorized",
          "forbidden",
          "not_found",
          "model_not_found",
          "job_not_found",
          "file_not_found",
          "file_expired",
          "idempotency_key_conflict",
          "secret_unavailable",
          "rate_limited",
          "generation_failed",
          "unknown_error",
          "model_unavailable",
          "no_channel_matches",
          "storage_limit_exceeded",
          "overloaded",
          "maintenance",
          "internal_error"
        ],
        "type": "string"
      },
      "ErrorDetail": {
        "description": "Одно поле запроса и что с ним не так. `path` — как в запросе (`aspect_ratio`,\n`references[1]`, `elements[0].images[1]`); `allowed` — что было бы принято. У\n`content_policy_category` в `allowed` — найденная категория.\n",
        "properties": {
          "allowed": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "path": {
            "examples": [
              "aspect_ratio"
            ],
            "type": "string"
          },
          "reason": {
            "$ref": "#/components/schemas/DetailReason"
          }
        },
        "required": [
          "reason"
        ],
        "type": "object"
      },
      "ErrorType": {
        "description": "Класс ошибки, следует из HTTP-статуса: `invalid_request_error` (400, 405, 413) —\nисправить запрос; `authentication_error` (401); `billing_error` (402) — пополнить баланс\nили поднять лимит, повтор не поможет; `permission_error` (403); `not_found_error` (404, 410);\n`conflict_error` (409); `rate_limit_error` (429) и `model_error` (502, 503, 504) — повторить\nпозже; `server_error` (500).\n",
        "enum": [
          "invalid_request_error",
          "authentication_error",
          "billing_error",
          "permission_error",
          "not_found_error",
          "conflict_error",
          "rate_limit_error",
          "model_error",
          "server_error"
        ],
        "type": "string"
      },
      "File": {
        "description": "Файл — результат, референс из запроса или загрузка. Живёт 1 день (`expires_at`);\n`url` подписан ровно до этого срока и одинаков при каждом чтении. После срока —\n`expired: true` без `url`.\n",
        "properties": {
          "bytes": {
            "format": "int64",
            "type": "integer"
          },
          "content_type": {
            "examples": [
              "image/png"
            ],
            "type": "string"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "expired": {
            "type": "boolean"
          },
          "expires_at": {
            "format": "date-time",
            "type": "string"
          },
          "filename": {
            "type": "string"
          },
          "height": {
            "description": "Только у картинок.",
            "type": "integer"
          },
          "id": {
            "examples": [
              "file_9f8e7d6c5b4a"
            ],
            "type": "string"
          },
          "kind": {
            "enum": [
              "upload",
              "reference",
              "result"
            ],
            "type": "string"
          },
          "object": {
            "const": "file",
            "type": "string"
          },
          "url": {
            "format": "uri",
            "type": "string"
          },
          "width": {
            "description": "Только у картинок.",
            "type": "integer"
          }
        },
        "required": [
          "id",
          "object",
          "kind",
          "content_type",
          "bytes",
          "filename",
          "created_at",
          "expires_at",
          "expired"
        ],
        "type": "object"
      },
      "FileDeleted": {
        "description": "Как у `files.delete` SDK OpenAI.",
        "properties": {
          "deleted": {
            "const": true,
            "type": "boolean"
          },
          "id": {
            "type": "string"
          },
          "object": {
            "const": "file",
            "type": "string"
          }
        },
        "required": [
          "id",
          "object",
          "deleted"
        ],
        "type": "object"
      },
      "FileList": {
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/File"
            },
            "type": "array"
          },
          "has_more": {
            "type": "boolean"
          },
          "object": {
            "const": "list",
            "type": "string"
          }
        },
        "required": [
          "object",
          "data",
          "has_more"
        ],
        "type": "object"
      },
      "FileUploadRequest": {
        "properties": {
          "file": {
            "contentMediaType": "application/octet-stream",
            "description": "Файл; имя берётся из части формы.",
            "type": "string"
          },
          "purpose": {
            "description": "Поле SDK OpenAI; принимается и ни на что не влияет.",
            "type": "string"
          }
        },
        "required": [
          "file"
        ],
        "type": "object"
      },
      "GenerationParamsEntry": {
        "properties": {
          "aspect_ratio": {
            "examples": [
              "16:9"
            ],
            "type": "string"
          },
          "duration_seconds": {
            "examples": [
              5
            ],
            "type": "integer"
          },
          "first_frame": {
            "examples": [
              false
            ],
            "type": "boolean"
          },
          "instrumental": {
            "description": "Музыка — трек без вокала.",
            "examples": [
              false
            ],
            "type": "boolean"
          },
          "last_frame": {
            "examples": [
              false
            ],
            "type": "boolean"
          },
          "lyrics": {
            "description": "Музыка — свой текст песни из запроса; стирается вместе с промптом.",
            "examples": [
              "[Verse] Утро светит в окно"
            ],
            "type": "string"
          },
          "prompt": {
            "examples": [
              "a red bicycle on a beach"
            ],
            "type": "string"
          },
          "references": {
            "examples": [
              0
            ],
            "type": "integer"
          },
          "resolution": {
            "examples": [
              "1K"
            ],
            "type": "string"
          },
          "stored": {
            "description": "Хранился ли текст запроса. `false` — запрос без хранения (`store: false` или режим\nаккаунта), и после завершения промпт стёрт: пустой `prompt` тогда значит «не\nсохранён», а не «не отправлен».",
            "examples": [
              true
            ],
            "type": "boolean"
          },
          "title": {
            "description": "Музыка — название трека из запроса; стирается вместе с промптом.",
            "examples": [
              "Утро"
            ],
            "type": "string"
          }
        },
        "required": [
          "first_frame",
          "last_frame",
          "prompt",
          "references",
          "stored"
        ],
        "type": "object"
      },
      "HourlyUsageEntry": {
        "properties": {
          "by_model": {
            "description": "Тот же час в разрезе моделей, все модели часа, по расходу вниз;\nсумма по моделям равна итогам часа. Всегда массив.",
            "items": {
              "$ref": "#/components/schemas/ModelUsageEntry"
            },
            "type": "array"
          },
          "hour": {
            "description": "Начало часа завершения запросов, UTC.",
            "examples": [
              "2026-09-23T14:00:00Z"
            ],
            "format": "date-time",
            "type": "string"
          },
          "requests": {
            "description": "Завершённые запросы часа (успех, провал, отмена); `succeeded` — из них успешные.",
            "examples": [
              7
            ],
            "type": "integer"
          },
          "spend_micro": {
            "examples": [
              125000
            ],
            "type": "integer"
          },
          "succeeded": {
            "examples": [
              6
            ],
            "type": "integer"
          }
        },
        "required": [
          "by_model",
          "hour",
          "requests",
          "spend_micro",
          "succeeded"
        ],
        "type": "object"
      },
      "ImageGenerationRequest": {
        "additionalProperties": false,
        "description": "Какие поля и значения принимает конкретная модель — её `input_schema`.\n",
        "properties": {
          "aspect_ratio": {
            "description": "Соотношение сторон или `auto` — умолчание модели.",
            "examples": [
              "16:9"
            ],
            "pattern": "^(auto|[0-9]+:[0-9]+)$",
            "type": "string"
          },
          "background": {
            "enum": [
              "auto",
              "transparent",
              "opaque"
            ],
            "type": "string"
          },
          "callback_url": {
            "description": "Куда прислать вебхук — https на публичный хост; без поля — адрес по умолчанию из настроек аккаунта.",
            "format": "uri",
            "type": "string"
          },
          "max_price_multiplier": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/MaxPriceMultiplier"
              },
              {
                "type": "null"
              }
            ]
          },
          "model": {
            "examples": [
              "nano-banana-pro"
            ],
            "type": "string"
          },
          "moderation": {
            "description": "Поле OpenAI; принимается, модель отвечает со своей модерацией.",
            "enum": [
              "auto",
              "low"
            ],
            "type": "string"
          },
          "n": {
            "default": 1,
            "description": "Поле OpenAI — сколько картинок; больше одной — у моделей, чья карточка это объявляет.",
            "minimum": 1,
            "type": "integer"
          },
          "output_compression": {
            "description": "Поле OpenAI; принимается, сжатие файла — как у модели.",
            "maximum": 100,
            "minimum": 0,
            "type": "integer"
          },
          "output_format": {
            "description": "Формат файла; переводим сами, у любой модели.",
            "enum": [
              "png",
              "jpeg",
              "webp"
            ],
            "type": "string"
          },
          "partial_images": {
            "description": "Поле OpenAI; промежуточных кадров нет — в потоке приходит только итог.",
            "maximum": 3,
            "minimum": 0,
            "type": "integer"
          },
          "prompt": {
            "minLength": 1,
            "type": "string"
          },
          "quality": {
            "description": "Конкретный уровень качества по схеме модели. Без поля используется medium; auto — только при явном выборе.\nЯвный уровень ограничивает каналы, которые гарантируют его выполнение.\nДопустимые значения канала — parameters.quality в GET /v1/models/{id}/channels.\n",
            "enum": [
              "auto",
              "low",
              "medium",
              "high",
              "xhigh",
              "max"
            ],
            "type": "string"
          },
          "references": {
            "description": "Референсы — картинки.",
            "items": {
              "$ref": "#/components/schemas/MediaSource"
            },
            "type": "array"
          },
          "resolution": {
            "examples": [
              "2K"
            ],
            "type": "string"
          },
          "response_format": {
            "default": "url",
            "description": "Поле OpenAI; `b64_json` — картинка ещё и base64 в `data[].b64_json`.",
            "enum": [
              "url",
              "b64_json"
            ],
            "type": "string"
          },
          "routing": {
            "$ref": "#/components/schemas/Routing"
          },
          "routing_options": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/RoutingOptions"
              },
              {
                "type": "null"
              }
            ]
          },
          "size": {
            "description": "Поле OpenAI: размер `ШxВ` или `auto`. Переводится в `aspect_ratio` и `resolution`\nмодели; вместе с ними не присылается (`mutually_exclusive`).\n",
            "examples": [
              "1024x1024"
            ],
            "pattern": "^(auto|[0-9]+x[0-9]+)$",
            "type": "string"
          },
          "store": {
            "description": "`false` — запрос без хранения: тексты запроса и ответа не сохраняются; файлы живут обычный срок. По умолчанию тексты хранятся; `true` не отменяет режим без хранения аккаунта.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "stream": {
            "description": "Поле OpenAI; `true` — ответ `text/event-stream`: событие `image_generation.completed`\nс картинкой base64 на каждую картинку, затем поток закрывается. Ошибка и задача, не\nуспевшая за 9 минут, — обычным JSON со статусом.\n",
            "type": [
              "boolean",
              "null"
            ]
          },
          "style": {
            "description": "Поле OpenAI; принимается, стиль задаёт промпт.",
            "enum": [
              "vivid",
              "natural"
            ],
            "type": "string"
          },
          "user": {
            "description": "Поле OpenAI (id конечного пользователя); принимается, ни на что не влияет и не хранится.",
            "type": "string"
          },
          "web_search": {
            "description": "Модель может сверяться с интернетом.",
            "type": [
              "boolean",
              "null"
            ]
          }
        },
        "required": [
          "model",
          "prompt"
        ],
        "type": "object"
      },
      "ImageGenerationStreamEvent": {
        "description": "Событие потока картинки, как у `images.generate` SDK OpenAI с `stream:true`.",
        "properties": {
          "b64_json": {
            "type": "string"
          },
          "background": {
            "type": "string"
          },
          "created_at": {
            "type": "integer"
          },
          "output_format": {
            "examples": [
              "png"
            ],
            "type": "string"
          },
          "quality": {
            "type": "string"
          },
          "size": {
            "examples": [
              "1024x1024"
            ],
            "type": "string"
          },
          "type": {
            "const": "image_generation.completed",
            "type": "string"
          }
        },
        "required": [
          "type",
          "b64_json",
          "created_at",
          "size",
          "quality",
          "background",
          "output_format"
        ],
        "type": "object"
      },
      "ImageLayer": {
        "additionalProperties": false,
        "description": "Метаданные фона или прозрачного слоя; порядок наложения снизу вверх.",
        "properties": {
          "bounding_box": {
            "additionalProperties": false,
            "properties": {
              "absolute": {
                "description": "Левый, верхний, правый и нижний края в пикселях исходного изображения.",
                "items": {
                  "type": "integer"
                },
                "maxItems": 4,
                "minItems": 4,
                "type": "array"
              },
              "normalized": {
                "items": {
                  "maximum": 1000,
                  "minimum": 0,
                  "type": "integer"
                },
                "maxItems": 4,
                "minItems": 4,
                "type": "array"
              }
            },
            "required": [
              "absolute",
              "normalized"
            ],
            "type": "object"
          },
          "description": {
            "type": "string"
          },
          "height": {
            "minimum": 1,
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "width": {
            "minimum": 1,
            "type": "integer"
          },
          "z_index": {
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "z_index",
          "width",
          "height"
        ],
        "type": "object"
      },
      "Index": {
        "properties": {
          "auth": {
            "examples": [
              "Authorization: Bearer \u003capi-key\u003e"
            ],
            "type": "string"
          },
          "base_url": {
            "format": "uri",
            "type": "string"
          },
          "docs": {
            "properties": {
              "llms": {
                "format": "uri",
                "type": "string"
              },
              "llms_full": {
                "format": "uri",
                "type": "string"
              },
              "models": {
                "format": "uri",
                "type": "string"
              },
              "openapi": {
                "format": "uri",
                "type": "string"
              },
              "site": {
                "format": "uri",
                "type": "string"
              }
            },
            "required": [
              "openapi",
              "llms",
              "llms_full",
              "models",
              "site"
            ],
            "type": "object"
          },
          "name": {
            "type": "string"
          },
          "object": {
            "const": "api",
            "type": "string"
          }
        },
        "required": [
          "object",
          "name",
          "base_url",
          "auth",
          "docs"
        ],
        "type": "object"
      },
      "Job": {
        "description": "Задача — один объект для картинок, видео, музыки, транскрибации, речи и итога чата. Его отдают\nответы на запросы, `GET /v1/jobs/{id}`, поток событий и вебхук. У картинок это ещё и\nответ `images.generate` SDK OpenAI (`created`, `data[].url`, `data[].b64_json`), у\nтранскрибации — ответ `audio.transcriptions.create` (`text`).\n",
        "properties": {
          "action": {
            "description": "Выполненное действие с аудио.",
            "type": "string"
          },
          "attempt_count": {
            "$ref": "#/components/schemas/AttemptCount"
          },
          "channel": {
            "description": "Фактический цвет канала запроса: при успехе — канал, который выполнил запрос; пока\nзапрос идёт — канал, которому он уже отправлен; при ошибке — последний вызванный канал.\n`null` — запрос ещё не отправлялся ни одному каналу или запись старше каналов.\nНазвание и HEX цвета — `GET /v1/channels`.\n",
            "oneOf": [
              {
                "$ref": "#/components/schemas/ChannelId"
              },
              {
                "type": "null"
              }
            ]
          },
          "completed_at": {
            "description": "Когда задача завершилась; `null`, пока идёт.",
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "created": {
            "description": "То же время, что `created_at`, в unix-секундах — как `created` у OpenAI.",
            "format": "int64",
            "type": "integer"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "currency": {
            "$ref": "#/components/schemas/Currency"
          },
          "data": {
            "description": "Файлы результата; `data[0]` — сам результат. У музыкальной модели, которая за запрос даёт\nдва варианта трека, оба — `role: result`, по порядку. Пустой, пока задача не завершена, и\nу чата.\n",
            "items": {
              "$ref": "#/components/schemas/OutputFile"
            },
            "type": "array"
          },
          "duration": {
            "description": "Транскрибация — длительность звука в секундах.",
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "error": {
            "description": "Почему задача не удалась; `null`, если не провалилась.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/ErrorBody"
              },
              {
                "type": "null"
              }
            ]
          },
          "id": {
            "description": "`job_…`; у чата — `chatcmpl-…` из его ответа.",
            "examples": [
              "job_1a2b3c4d5e6f"
            ],
            "type": "string"
          },
          "language": {
            "description": "Транскрибация — язык записи, код ISO 639-1 (`ru`, `en`) у любой модели: названный\nмоделью или, если она его не назвала, из подсказки `language` запроса. Язык неизвестен\n— поля нет.\n",
            "oneOf": [
              {
                "$ref": "#/components/schemas/LanguageCode"
              },
              {
                "type": "null"
              }
            ]
          },
          "max_price_multiplier": {
            "description": "Потолок цены, с которым задача принята: из запроса или из настроек аккаунта на момент\nприёма. `null` — без потолка.\n",
            "oneOf": [
              {
                "$ref": "#/components/schemas/MaxPriceMultiplier"
              },
              {
                "type": "null"
              }
            ]
          },
          "modality": {
            "$ref": "#/components/schemas/Modality"
          },
          "model": {
            "examples": [
              "nano-banana-pro"
            ],
            "type": "string"
          },
          "model_version": {
            "description": "Версия музыкальной модели; используйте её при продолжении исходного трека.",
            "type": "string"
          },
          "object": {
            "const": "job",
            "type": "string"
          },
          "persona_id": {
            "description": "ID этой задачи для повторного использования созданной персоны.",
            "type": "string"
          },
          "price": {
            "description": "Итог в микроединицах `currency` — фактический объём × цены сработавшего канала\nна момент приёма; `null`, пока задача не завершена. У проваленной — `0`.\n",
            "format": "int64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          },
          "result": {
            "$ref": "#/components/schemas/MusicResult"
          },
          "routing": {
            "$ref": "#/components/schemas/Routing"
          },
          "routing_options": {
            "description": "Настройки каналов, с которыми задача принята: из запроса или из настроек аккаунта на\nмомент приёма. `null` — каналы выбирает Авто-роутинг.\n",
            "oneOf": [
              {
                "$ref": "#/components/schemas/RoutingOptions"
              },
              {
                "type": "null"
              }
            ]
          },
          "segments": {
            "description": "Транскрибация, `verbose_json` у модели с таймкодами — фразы: предложение или отрезок\nречи до паузы в секунду и дольше, не длиннее 30 с. Начало фразы — начало её первого\nслова, конец — конец последнего; одинаково у всех моделей.\n",
            "items": {
              "$ref": "#/components/schemas/TranscriptionSegment"
            },
            "type": "array"
          },
          "status": {
            "$ref": "#/components/schemas/JobStatus"
          },
          "text": {
            "description": "Транскрибация — расшифровка; у остальных задач поля нет.",
            "type": [
              "string",
              "null"
            ]
          },
          "usage": {
            "description": "Объём выполненного — токены, символы, секунды; `null`, где мерить нечего.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/JobUsage"
              },
              {
                "type": "null"
              }
            ]
          },
          "voice_id": {
            "description": "ID этой задачи для повторного использования созданного голоса.",
            "type": "string"
          },
          "webhook": {
            "$ref": "#/components/schemas/JobWebhook"
          },
          "words": {
            "description": "Транскрибация — слова с таймкодами, если запрошена детализация по словам.",
            "items": {
              "$ref": "#/components/schemas/TranscriptionWord"
            },
            "type": "array"
          }
        },
        "required": [
          "id",
          "object",
          "created",
          "created_at",
          "completed_at",
          "model",
          "modality",
          "status",
          "routing",
          "max_price_multiplier",
          "routing_options",
          "attempt_count",
          "price",
          "currency",
          "usage",
          "data",
          "error"
        ],
        "type": "object"
      },
      "JobContentEntry": {
        "properties": {
          "request": {
            "additionalProperties": true,
            "description": "Что ушло в модель: сообщения и параметры, модель — по id каталога.",
            "type": "object"
          },
          "response": {
            "additionalProperties": true,
            "description": "Ответ модели — `content`, `finish_reason`, `tool_calls`; поля нет, если ответа не\nбыло.",
            "type": "object"
          },
          "truncated": {
            "description": "Сохранённая копия неполная: длинные строки обрезаны до 256 КиБ на поле или поток\nоборвался раньше конца ответа.",
            "examples": [
              false
            ],
            "type": "boolean"
          }
        },
        "required": [
          "request",
          "truncated"
        ],
        "type": "object"
      },
      "JobDetailResponse": {
        "properties": {
          "action": {
            "description": "Действие музыкального запроса. У старых запросов на создание песни — generate; у других типов запросов поля нет.",
            "examples": [
              "lyrics"
            ],
            "type": "string"
          },
          "api_key_id": {
            "examples": [
              "key_1a2b3c4d5e6f7890"
            ],
            "type": "string"
          },
          "api_key_kind": {
            "enum": [
              "user",
              "playground",
              "agent"
            ],
            "examples": [
              "user"
            ],
            "type": "string"
          },
          "api_key_name": {
            "examples": [
              "production"
            ],
            "type": "string"
          },
          "attempt_count": {
            "$ref": "#/components/schemas/AttemptCount"
          },
          "canonical_model": {
            "examples": [
              "gpt-5-nano"
            ],
            "type": "string"
          },
          "channel": {
            "description": "Фактический цвет канала запроса: при успехе — канал, который выполнил запрос; пока\nзапрос идёт — канал, которому он уже отправлен; при ошибке — последний вызванный канал.\n`null` — запрос ещё не отправлялся ни одному каналу или запись старше каналов.\nНазвание и HEX цвета — `GET /v1/channels`.\n",
            "oneOf": [
              {
                "$ref": "#/components/schemas/ChannelId"
              },
              {
                "type": "null"
              }
            ]
          },
          "content": {
            "allOf": [
              {
                "$ref": "#/components/schemas/JobContentEntry"
              }
            ],
            "description": "Содержимое чата, пока оно хранится."
          },
          "created_at": {
            "examples": [
              "2026-08-21T12:00:00Z"
            ],
            "type": "string"
          },
          "duration_ms": {
            "description": "Сколько шёл запрос целиком, от приёма до итога, — та же цифра, что в списке; есть у\nзавершённого запроса.",
            "examples": [
              12400
            ],
            "type": "integer"
          },
          "error": {
            "allOf": [
              {
                "$ref": "#/components/schemas/JobErrorEntry"
              }
            ],
            "description": "Есть у не удавшегося запроса."
          },
          "extra_results": {
            "description": "Другие файлы той же генерации, по порядку, тем же описанием, что `result`: второй\nмузыкальный вариант, дополнительные дорожки или изображения.",
            "items": {
              "$ref": "#/components/schemas/File"
            },
            "type": "array"
          },
          "id": {
            "examples": [
              "job_abc123"
            ],
            "type": "string"
          },
          "input_file": {
            "allOf": [
              {
                "$ref": "#/components/schemas/File"
              }
            ],
            "description": "Запись, отправленная на расшифровку; после срока хранения — описание без ссылки."
          },
          "input_text": {
            "description": "Текст запроса на озвучку; хранится тот же срок, что содержимое чата. Голос и\nсведения о результате остаются в карточке.",
            "examples": [
              "Привет!"
            ],
            "type": "string"
          },
          "input_tokens": {
            "examples": [
              1978
            ],
            "type": "integer"
          },
          "last_frame": {
            "$ref": "#/components/schemas/File"
          },
          "modality": {
            "$ref": "#/components/schemas/Modality"
          },
          "model_version": {
            "description": "Выбранная версия музыкальной модели, если она была указана в запросе.",
            "examples": [
              "v6"
            ],
            "type": "string"
          },
          "output_tokens": {
            "examples": [
              88
            ],
            "type": "integer"
          },
          "params": {
            "allOf": [
              {
                "$ref": "#/components/schemas/GenerationParamsEntry"
              }
            ],
            "description": "Параметры генерации — у изображений, видео, музыки и расшифровки."
          },
          "price": {
            "examples": [
              5000
            ],
            "type": [
              "integer",
              "null"
            ]
          },
          "request_id": {
            "examples": [
              "req_1a2b3c"
            ],
            "type": "string"
          },
          "result": {
            "allOf": [
              {
                "$ref": "#/components/schemas/File"
              }
            ],
            "description": "Результат успешной генерации — то же описание файла, что в `GET /v1/jobs/{id}`:\nподписанная ссылка, пока файл хранится, после — `expired: true`. `last_frame` —\nвторой файл, если видео его вернуло."
          },
          "routing": {
            "$ref": "#/components/schemas/Routing"
          },
          "routing_source": {
            "description": "Откуда пресет `routing`, в котором шёл запрос, — из запроса (`request`) или из настройки аккаунта (`account`).",
            "enum": [
              "request",
              "account"
            ],
            "examples": [
              "account"
            ],
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/UsageStatus"
          },
          "terminal_code": {
            "$ref": "#/components/schemas/TerminalCode"
          },
          "text": {
            "description": "Расшифровка успешного запроса на транскрибацию; хранится тот же срок, что содержимое\nчата, потом поля нет.",
            "examples": [
              "привет, это расшифровка"
            ],
            "type": "string"
          },
          "updated_at": {
            "examples": [
              "2026-08-21T12:00:02Z"
            ],
            "type": "string"
          },
          "usage": {
            "allOf": [
              {
                "$ref": "#/components/schemas/JobUsageEntry"
              }
            ],
            "description": "Объём расшифровки; остаётся и после того, как текст перестал храниться."
          },
          "voice": {
            "examples": [
              "eve"
            ],
            "type": "string"
          }
        },
        "required": [
          "api_key_id",
          "api_key_kind",
          "attempt_count",
          "canonical_model",
          "created_at",
          "id",
          "modality",
          "price",
          "request_id",
          "routing",
          "routing_source",
          "status",
          "updated_at"
        ],
        "type": "object"
      },
      "JobEntry": {
        "properties": {
          "action": {
            "description": "Действие музыкального запроса. У старых запросов на создание песни — generate; у других типов запросов поля нет.",
            "examples": [
              "lyrics"
            ],
            "type": "string"
          },
          "api_key_id": {
            "examples": [
              "key_1a2b3c4d5e6f7890"
            ],
            "type": "string"
          },
          "api_key_kind": {
            "description": "Вид ключа запроса: `user` — обычный ключ, `playground` — встроенный ключ плейграунда\n(в списке ключей его нет), `agent` — ключ агента.",
            "enum": [
              "user",
              "playground",
              "agent"
            ],
            "examples": [
              "user"
            ],
            "type": "string"
          },
          "api_key_name": {
            "examples": [
              "production"
            ],
            "type": "string"
          },
          "attempt_count": {
            "$ref": "#/components/schemas/AttemptCount"
          },
          "canonical_model": {
            "examples": [
              "gpt-5-nano"
            ],
            "type": "string"
          },
          "channel": {
            "description": "Фактический цвет канала запроса: при успехе — канал, который выполнил запрос; пока\nзапрос идёт — канал, которому он уже отправлен; при ошибке — последний вызванный канал.\n`null` — запрос ещё не отправлялся ни одному каналу или запись старше каналов.\nНазвание и HEX цвета — `GET /v1/channels`.\n",
            "oneOf": [
              {
                "$ref": "#/components/schemas/ChannelId"
              },
              {
                "type": "null"
              }
            ]
          },
          "characters": {
            "description": "Сколько символов (Unicode) дала расшифровка — то же число, что `usage.characters` в\nеё ответе; только у транскрибации.",
            "examples": [
              420
            ],
            "type": "integer"
          },
          "created_at": {
            "examples": [
              "2026-08-21T12:00:00Z"
            ],
            "type": "string"
          },
          "detail": {
            "description": "На каком параметре не удался запрос и что было бы принято — в той же форме, что\n`error.detail`. Обычно поля нет; у удавшегося запроса его нет никогда.",
            "items": {
              "$ref": "#/components/schemas/ErrorDetail"
            },
            "type": "array"
          },
          "duration_ms": {
            "description": "Сколько шёл запрос целиком, от приёма до итога; есть у завершённого запроса.",
            "examples": [
              12400
            ],
            "type": "integer"
          },
          "error_code": {
            "description": "Почему запрос не удался — код закрытого словаря; есть только в статусе `failed`.\nНеизвестная ошибка — `unknown_error`, без подробностей.",
            "examples": [
              "content_policy"
            ],
            "type": "string"
          },
          "id": {
            "examples": [
              "job_abc123"
            ],
            "type": "string"
          },
          "input_tokens": {
            "description": "Токены чата — входные (`input_tokens`) и выходные (`output_tokens`); у картинок и\nвидео их нет.",
            "examples": [
              1978
            ],
            "type": "integer"
          },
          "modality": {
            "$ref": "#/components/schemas/Modality"
          },
          "model_version": {
            "description": "Выбранная версия музыкальной модели, если она была указана в запросе.",
            "examples": [
              "v6"
            ],
            "type": "string"
          },
          "output_tokens": {
            "examples": [
              88
            ],
            "type": "integer"
          },
          "price": {
            "description": "Итоговая цена завершённого запроса в микроединицах (у не удавшегося — `0`); `null` —\nзапрос ещё идёт.",
            "examples": [
              5000
            ],
            "type": [
              "integer",
              "null"
            ]
          },
          "result": {
            "allOf": [
              {
                "$ref": "#/components/schemas/File"
              }
            ],
            "description": "Файл результата удавшейся генерации — то же описание, что `result` в\n`GET /v1/usage/{id}`: подписанная ссылка, пока файл жив, `expired: true` после. У\nчата и незавершённых запросов поля нет."
          },
          "routing": {
            "$ref": "#/components/schemas/Routing"
          },
          "routing_source": {
            "description": "Откуда пресет `routing`, в котором шёл запрос, — из запроса (`request`) или из настройки аккаунта (`account`).",
            "enum": [
              "request",
              "account"
            ],
            "examples": [
              "account"
            ],
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/UsageStatus"
          },
          "terminal_code": {
            "$ref": "#/components/schemas/TerminalCode"
          }
        },
        "required": [
          "api_key_id",
          "api_key_kind",
          "attempt_count",
          "canonical_model",
          "created_at",
          "id",
          "modality",
          "price",
          "routing",
          "routing_source",
          "status"
        ],
        "type": "object"
      },
      "JobErrorEntry": {
        "properties": {
          "code": {
            "$ref": "#/components/schemas/TerminalCode"
          },
          "detail": {
            "description": "На каком параметре не удался запрос и что было бы принято — в той же форме, что\n`error.detail` в `GET /v1/jobs/{id}`.",
            "items": {
              "$ref": "#/components/schemas/ErrorDetail"
            },
            "type": "array"
          },
          "message": {
            "examples": [
              "the model failed to process this request; retry it, a failed request is not charged"
            ],
            "type": "string"
          }
        },
        "required": [
          "code"
        ],
        "type": "object"
      },
      "JobStatus": {
        "description": "`queued` → `in_progress` → `completed` или `failed`.",
        "enum": [
          "queued",
          "in_progress",
          "completed",
          "failed"
        ],
        "type": "string"
      },
      "JobUsage": {
        "properties": {
          "billed_characters": {
            "description": "У речи с посимвольной оплатой — символов по счёту этой модели; у посекундной речи поля нет.",
            "type": "integer"
          },
          "characters": {
            "description": "Речь — символов на входе; транскрибация — в расшифровке.",
            "type": "integer"
          },
          "completion_tokens": {
            "description": "Чат.",
            "type": "integer"
          },
          "prompt_tokens": {
            "description": "Чат.",
            "type": "integer"
          },
          "seconds": {
            "description": "Речь — длительность звука.",
            "format": "double",
            "type": "number"
          },
          "total_tokens": {
            "description": "Чат.",
            "type": "integer"
          }
        },
        "type": "object"
      },
      "JobUsageEntry": {
        "properties": {
          "billed_characters": {
            "examples": [
              421
            ],
            "type": "integer"
          },
          "characters": {
            "description": "Символы (Unicode) расшифровки — то же число, что вернул `POST\n/v1/audio/transcriptions`.",
            "examples": [
              420
            ],
            "type": "integer"
          },
          "seconds": {
            "examples": [
              3.42
            ],
            "type": "number"
          }
        },
        "required": [
          "characters"
        ],
        "type": "object"
      },
      "JobWebhook": {
        "description": "Доставка вебхука — только у задачи с `callback_url`.",
        "properties": {
          "attempts": {
            "type": "integer"
          },
          "delivered_at": {
            "format": "date-time",
            "type": "string"
          },
          "error": {
            "description": "Почему последняя попытка доставки не засчитана.",
            "type": "string"
          },
          "last_status_code": {
            "description": "Последний HTTP-статус получателя.",
            "type": "integer"
          },
          "next_attempt_at": {
            "format": "date-time",
            "type": "string"
          },
          "status": {
            "enum": [
              "pending",
              "delivered",
              "failed"
            ],
            "type": "string"
          },
          "url": {
            "format": "uri",
            "type": "string"
          }
        },
        "required": [
          "url",
          "status",
          "attempts"
        ],
        "type": "object"
      },
      "LanguageCode": {
        "description": "Язык — код ISO 639-1: две строчные латинские буквы (`ru`, `en`), один вид у всех моделей.\n",
        "enum": [
          "af",
          "am",
          "ar",
          "as",
          "az",
          "ba",
          "be",
          "bg",
          "bn",
          "bo",
          "br",
          "bs",
          "ca",
          "cs",
          "cy",
          "da",
          "de",
          "el",
          "en",
          "es",
          "et",
          "eu",
          "fa",
          "fi",
          "fo",
          "fr",
          "gl",
          "gu",
          "ha",
          "he",
          "hi",
          "hr",
          "ht",
          "hu",
          "hy",
          "id",
          "is",
          "it",
          "ja",
          "jv",
          "ka",
          "kk",
          "km",
          "kn",
          "ko",
          "la",
          "lb",
          "ln",
          "lo",
          "lt",
          "lv",
          "mg",
          "mi",
          "mk",
          "ml",
          "mn",
          "mr",
          "ms",
          "mt",
          "my",
          "ne",
          "nl",
          "nn",
          "no",
          "oc",
          "pa",
          "pl",
          "ps",
          "pt",
          "ro",
          "ru",
          "sa",
          "sd",
          "si",
          "sk",
          "sl",
          "sn",
          "so",
          "sq",
          "sr",
          "su",
          "sv",
          "sw",
          "ta",
          "te",
          "tg",
          "th",
          "tk",
          "tl",
          "tr",
          "tt",
          "uk",
          "ur",
          "uz",
          "vi",
          "yi",
          "yo",
          "zh"
        ],
        "examples": [
          "ru"
        ],
        "type": "string"
      },
      "Limits": {
        "description": "Опубликованные пределы; нет поля — число не публикуется (а не ноль).",
        "properties": {
          "context_tokens": {
            "type": "integer"
          },
          "max_output_seconds": {
            "description": "Наибольшая длительность готового звука в секундах, если известна.",
            "type": "integer"
          },
          "max_output_tokens": {
            "type": "integer"
          },
          "max_references": {
            "type": "integer"
          }
        },
        "type": "object"
      },
      "MCPRequest": {
        "additionalProperties": false,
        "description": "Сообщение JSON-RPC 2.0 клиента MCP — запрос (с `id`) или уведомление (без `id`).",
        "properties": {
          "id": {
            "description": "Номер запроса; ответ вернёт его же. Без `id` — уведомление.",
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              }
            ]
          },
          "jsonrpc": {
            "const": "2.0",
            "type": "string"
          },
          "method": {
            "examples": [
              "tools/call"
            ],
            "type": "string"
          },
          "params": {
            "additionalProperties": true,
            "description": "Параметры метода; у `tools/call` — `name` инструмента и `arguments` по его `inputSchema`.",
            "type": "object"
          }
        },
        "required": [
          "jsonrpc",
          "method"
        ],
        "type": "object"
      },
      "MCPResponse": {
        "description": "Ответ JSON-RPC 2.0 — ровно одно из `result` и `error`.",
        "properties": {
          "error": {
            "description": "Ошибка протокола JSON-RPC.",
            "properties": {
              "code": {
                "description": "`-32700` — не JSON, `-32600` — не запрос JSON-RPC, `-32601` — нет метода, `-32602` — неверные параметры или неизвестный инструмент, `-32603` — сбой сервера.",
                "type": "integer"
              },
              "data": {
                "description": "Подробности у неверных аргументов инструмента (`-32602`).",
                "properties": {
                  "errors": {
                    "items": {
                      "properties": {
                        "allowed": {
                          "items": {
                            "type": "string"
                          },
                          "type": "array"
                        },
                        "path": {
                          "description": "JSON Pointer внутри `arguments`.",
                          "examples": [
                            "/model"
                          ],
                          "type": "string"
                        },
                        "reason": {
                          "$ref": "#/components/schemas/DetailReason"
                        }
                      },
                      "required": [
                        "path",
                        "reason"
                      ],
                      "type": "object"
                    },
                    "type": "array"
                  },
                  "tool": {
                    "type": "string"
                  }
                },
                "type": "object"
              },
              "message": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ],
            "type": "object"
          },
          "id": {
            "description": "`id` запроса; `null` — запрос не удалось разобрать.",
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "jsonrpc": {
            "const": "2.0",
            "type": "string"
          },
          "result": {
            "additionalProperties": true,
            "description": "Итог метода. У `tools/call` — `content` (текст с таблицей), `structuredContent`\n(те же данные объектом) и `isError`.\n",
            "type": "object"
          }
        },
        "required": [
          "jsonrpc",
          "id"
        ],
        "type": "object"
      },
      "MaxPriceMultiplier": {
        "description": "Потолок цены: каналы дороже первого канала плана больше чем во столько раз не\nпробуются. Без `routing_options` первый канал — канал пресета, и цена отсчёта — как в\n`pricing.presets` карточки модели, для параметров запроса; с `routing_options` отсчёт\nидёт от первого канала, который остался после ваших настроек. Первый канал под потолок\nпопадает всегда. Если не ответили все\nканалы в пределах потолка, задача проваливается, как при отказе всех каналов, с\nдеталью `{\"path\": \"max_price_multiplier\", \"reason\": \"price_cap\"}`. `null` — без потолка.\nБез поля в запросе — настройка аккаунта (`GET /v1/key` → `max_price_multiplier`);\nзначение не из списка — `400` со списком допустимых.\n",
        "enum": [
          1.5,
          2,
          3,
          5,
          10
        ],
        "type": "number"
      },
      "MeResponse": {
        "properties": {
          "account": {
            "$ref": "#/components/schemas/AccountRef"
          },
          "avatar_url": {
            "description": "Картинка участника — адрес в кабинете (`?v=` меняется вместе с картинкой) — или\n`null`.",
            "examples": [
              "/v1/members/mem_1a2b3c4d5e6f7890/avatar?v=1758300000"
            ],
            "type": [
              "string",
              "null"
            ]
          },
          "email": {
            "description": "Почта участника; пустая строка — участник приглашён только по username Telegram.\n`telegram_username` — username Telegram (строчными, без @) или пустая строка; хотя\nбы одно из двух есть.",
            "examples": [
              "dev@example.com"
            ],
            "type": "string"
          },
          "id": {
            "examples": [
              "mem_1a2b3c4d5e6f7890"
            ],
            "type": "string"
          },
          "name": {
            "description": "Имя; пустая строка, пока участник не вошёл через провайдера входа и не задал имя в\nпрофиле.",
            "examples": [
              "Dev User"
            ],
            "type": "string"
          },
          "role": {
            "description": "Роль участника в аккаунте: `owner`, `admin`, `developer` или `viewer`.",
            "enum": [
              "owner",
              "admin",
              "developer",
              "viewer"
            ],
            "examples": [
              "owner"
            ],
            "type": "string"
          },
          "spend_limit": {
            "description": "Собственный лимит трат участника — с расходом и остатком в текущем окне; `null` —\nлимита нет (владелец, администратор, наблюдатель, разработчик без лимита).",
            "oneOf": [
              {
                "$ref": "#/components/schemas/SpendLimitEntry"
              },
              {
                "type": "null"
              }
            ]
          },
          "telegram_username": {
            "examples": [
              "durov"
            ],
            "type": "string"
          }
        },
        "required": [
          "account",
          "avatar_url",
          "email",
          "id",
          "name",
          "role",
          "spend_limit",
          "telegram_username"
        ],
        "type": "object"
      },
      "MediaSource": {
        "description": "`data:\u003cmime\u003e;base64,…`, `https://…` или `file_…` (`POST /v1/files`).",
        "examples": [
          "https://example.com/cat.png"
        ],
        "type": "string"
      },
      "MemberRef": {
        "properties": {
          "id": {
            "examples": [
              "mem_1a2b3c4d5e6f7890"
            ],
            "type": "string"
          },
          "name": {
            "examples": [
              "Иван Петров"
            ],
            "type": "string"
          }
        },
        "required": [
          "id",
          "name"
        ],
        "type": "object"
      },
      "Modality": {
        "enum": [
          "chat",
          "image",
          "video",
          "transcription",
          "speech",
          "music"
        ],
        "type": "string"
      },
      "Model": {
        "properties": {
          "added_at": {
            "format": "date",
            "type": "string"
          },
          "capabilities": {
            "$ref": "#/components/schemas/Capabilities"
          },
          "created": {
            "description": "Unix-время появления модели в каталоге (`added_at`) — поле `models.list` SDK OpenAI.",
            "examples": [
              1758758400
            ],
            "format": "int64",
            "type": "integer"
          },
          "description": {
            "type": "string"
          },
          "display_name": {
            "type": "string"
          },
          "id": {
            "description": "То, что идёт в поле `model` запроса.",
            "examples": [
              "nano-banana-pro"
            ],
            "type": "string"
          },
          "input_schema": {
            "additionalProperties": true,
            "description": "JSON Schema 2020-12 тела запроса к этой модели, включая условные пределы текста музыки: какие поля и значения она\nпринимает. Годится как `parameters` инструмента и `inputSchema` MCP. Значения,\nкоторые у модели ничего не меняют, в ней тоже есть — они принимаются.\n",
            "type": "object"
          },
          "limits": {
            "$ref": "#/components/schemas/Limits"
          },
          "modality": {
            "$ref": "#/components/schemas/Modality"
          },
          "object": {
            "const": "model",
            "type": "string"
          },
          "owned_by": {
            "description": "Автор модели — `vendor.id` (пусто, если автор не указан); поле `models.list` SDK OpenAI.",
            "examples": [
              "google"
            ],
            "type": "string"
          },
          "params": {
            "description": "Те же поля для витрины — с подписями и подсказками.",
            "items": {
              "$ref": "#/components/schemas/ParamSpec"
            },
            "type": "array"
          },
          "pricing": {
            "$ref": "#/components/schemas/Pricing"
          },
          "released_at": {
            "format": "date",
            "type": [
              "string",
              "null"
            ]
          },
          "rules": {
            "description": "Какие сочетания значений допустимы — то, что не выражает `params`.",
            "items": {
              "$ref": "#/components/schemas/ParamRule"
            },
            "type": "array"
          },
          "stats_7d": {
            "$ref": "#/components/schemas/ModelStatsSummary"
          },
          "status": {
            "enum": [
              "active"
            ],
            "type": "string"
          },
          "tags": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          },
          "vendor": {
            "description": "Автор модели; `null`, если не указан.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/Vendor"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "object",
          "id",
          "created",
          "owned_by",
          "display_name",
          "vendor",
          "modality",
          "description",
          "tags",
          "pricing",
          "stats_7d",
          "input_schema",
          "params",
          "rules",
          "limits",
          "status",
          "released_at",
          "added_at",
          "updated_at"
        ],
        "type": "object"
      },
      "ModelChannel": {
        "properties": {
          "available": {
            "type": "boolean"
          },
          "capabilities": {
            "properties": {
              "audio_input": {
                "type": "boolean"
              },
              "file_input": {
                "type": "boolean"
              },
              "streaming": {
                "type": "boolean"
              },
              "structured_output": {
                "type": "boolean"
              },
              "supported_parameters": {
                "description": "Параметры запроса, которые учитывает канал. Параметр не из списка этим каналом игнорируется; `tools`, `tool_choice`, `response_format` и `verbosity` идут только к каналам, которые их учитывают. Нет поля — список канала не опубликован.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "tools": {
                "type": "boolean"
              },
              "video_input": {
                "type": "boolean"
              },
              "vision": {
                "type": "boolean"
              }
            },
            "required": [
              "tools",
              "vision",
              "structured_output",
              "streaming",
              "file_input",
              "audio_input",
              "video_input"
            ],
            "type": "object"
          },
          "color": {
            "pattern": "^#[0-9A-Fa-f]{6}$",
            "type": "string"
          },
          "history": {
            "$ref": "#/components/schemas/ChannelHistory"
          },
          "id": {
            "$ref": "#/components/schemas/ChannelId"
          },
          "limits": {
            "additionalProperties": false,
            "description": "Пределы конкретного канала в токенах; null означает, что предел неизвестен.",
            "properties": {
              "context_tokens": {
                "minimum": 1,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "max_input_tokens": {
                "minimum": 1,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "max_output_tokens": {
                "minimum": 1,
                "type": [
                  "integer",
                  "null"
                ]
              }
            },
            "required": [
              "context_tokens",
              "max_input_tokens",
              "max_output_tokens"
            ],
            "type": "object"
          },
          "metrics": {
            "$ref": "#/components/schemas/ChannelMetrics"
          },
          "name": {
            "type": "string"
          },
          "parameters": {
            "additionalProperties": {
              "$ref": "#/components/schemas/ChannelParameter"
            },
            "description": "Параметры, выполнение которых гарантирует канал; отсутствие поля означает отсутствие подтверждённой поддержки.",
            "type": "object"
          },
          "rates": {
            "$ref": "#/components/schemas/ModelChannelRates"
          }
        },
        "required": [
          "id",
          "name",
          "color",
          "available",
          "rates",
          "metrics",
          "capabilities",
          "limits",
          "history"
        ],
        "type": "object"
      },
      "ModelChannelRates": {
        "additionalProperties": false,
        "properties": {
          "basis": {
            "enum": [
              "tokens",
              "default_request",
              "second",
              "character"
            ],
            "type": "string"
          },
          "cache_read": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "currency": {
            "$ref": "#/components/schemas/Currency"
          },
          "dynamic": {
            "description": "`true` — динамическая цена: `request` — оценка для параметров по умолчанию, итог считается по фактическому расходу у канала и может отличаться от оценки.",
            "type": "boolean"
          },
          "input": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "output": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "request": {
            "description": "Сумма в микроединицах currency за единицу basis. Для default_request — оценка запроса с указанными параметрами; у динамической цены она может уточняться по сопоставимым выполненным запросам. Токеновые ставки остаются в tokens.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "tokens": {
            "additionalProperties": false,
            "description": "Цены, по которым считается итог канала с динамической ценой (`dynamic`), в микроединицах `currency` за 1M токенов. `null` у канала с ценой, известной заранее.",
            "properties": {
              "image_input": {
                "description": "Изображения на входе (референсы); `null` у речи.",
                "format": "int64",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "input": {
                "description": "Текст на входе.",
                "format": "int64",
                "type": "integer"
              },
              "output": {
                "description": "Результат на выходе — изображение или звук.",
                "format": "int64",
                "type": "integer"
              },
              "reference_image": {
                "description": "Оценка одного референса в микроединицах `currency` — не за 1M токенов; `null` у речи.",
                "format": "int64",
                "type": [
                  "integer",
                  "null"
                ]
              }
            },
            "required": [
              "input",
              "output",
              "image_input",
              "reference_image"
            ],
            "type": [
              "object",
              "null"
            ]
          }
        },
        "required": [
          "currency",
          "basis",
          "input",
          "output",
          "cache_read",
          "request"
        ],
        "type": "object"
      },
      "ModelChannels": {
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/ModelChannel"
            },
            "type": "array"
          },
          "generated_at": {
            "format": "date-time",
            "type": "string"
          },
          "model": {
            "type": "string"
          }
        },
        "required": [
          "model",
          "data",
          "generated_at"
        ],
        "type": "object"
      },
      "ModelList": {
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/Model"
            },
            "type": "array"
          },
          "generated_at": {
            "description": "Когда собран каталог (до часа).",
            "format": "date-time",
            "type": "string"
          },
          "object": {
            "const": "list",
            "type": "string"
          }
        },
        "required": [
          "object",
          "data",
          "generated_at"
        ],
        "type": "object"
      },
      "ModelRoutingOptions": {
        "additionalProperties": {
          "$ref": "#/components/schemas/RoutingOptions"
        },
        "description": "Настройки по id модели. Объект заменяет сохранённый словарь целиком (сначала GET, затем\nслить и отправить PATCH); null очищает его. Ключ — существующая модель или «*»; каждый\nцвет `only`/`ignore`/`order` — канал этой модели (`GET /v1/models/{id}/channels`), иначе\n`400` с `detail[].path` вида `routing_options.\u003cмодель\u003e.only[0]`. Ключ «*» задаёт общие\nпредпочтения без списков цветов; поля только для чата (`sort: throughput`,\n`preferred_min_throughput`) у не-чат модели из «*» молча не применяются, а под ключом\nне-чат модели — `400`. session_id в настройках не сохраняется.\n",
        "maxProperties": 64,
        "type": "object"
      },
      "ModelStats": {
        "description": "Статистика модели за 7 дней по запросам всех клиентов — за окно и по часам.\nПересчитывается раз в минуту. Объёмы и доли точные; доля успешных — среди завершённых\nзапросов, отказы по вине запроса не считаются. Время ответа — только по успешным\nзапросам; медиана и p95 округлены до ступени шкалы (±10 %), поэтому одинаковые числа у\nразных моделей — следствие округления, а не общий предел времени.\n",
        "properties": {
          "bucket": {
            "const": "1h",
            "type": "string"
          },
          "latency_p50_ms": {
            "description": "Медиана времени ответа успешных запросов, мс (±10 %); `null` — успешных нет.",
            "type": [
              "integer",
              "null"
            ]
          },
          "latency_p95_ms": {
            "description": "95 % успешных запросов отвечают быстрее, мс (±10 %); `null` — успешных нет.",
            "type": [
              "integer",
              "null"
            ]
          },
          "model_id": {
            "type": "string"
          },
          "requests": {
            "type": "integer"
          },
          "series": {
            "description": "Ровно 168 часов по возрастанию.",
            "items": {
              "$ref": "#/components/schemas/ModelStatsHour"
            },
            "type": "array"
          },
          "speed": {
            "description": "Скорость опций пресетов роутинга за 7 дней: по ряду на опцию — те же опции и в том же\nпорядке, что `pricing.presets` карточки модели (параметры по умолчанию). От одного до\nтрёх рядов; пусто, когда цены нет. Точка ряда — медиана успешных запросов первого\nканала опции за 6 часов, с любым пресетом. Ряды разных опций могут\nчисленно совпадать.\n",
            "items": {
              "$ref": "#/components/schemas/ModelStatsSpeed"
            },
            "type": "array"
          },
          "success_rate": {
            "description": "Доля успешных среди завершённых запросов, от 0 до 1; отказы по вине запроса (ошибка\nво входных данных, правила модели, нехватка баланса, несовместимые параметры) не\nсчитаются. `null` — считать не из чего.\n",
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "tokens_out": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "updated_at": {
            "description": "Когда числа пересчитаны.",
            "format": "date-time",
            "type": "string"
          },
          "window": {
            "const": "7d",
            "type": "string"
          }
        },
        "required": [
          "model_id",
          "window",
          "bucket",
          "requests",
          "success_rate",
          "latency_p50_ms",
          "latency_p95_ms",
          "tokens_out",
          "updated_at",
          "series",
          "speed"
        ],
        "type": "object"
      },
      "ModelStatsHour": {
        "properties": {
          "at": {
            "description": "Начало часа, UTC.",
            "format": "date-time",
            "type": "string"
          },
          "failed": {
            "description": "Не выполнены; отказы по вине запроса не считаются, как и в `success_rate`.",
            "type": "integer"
          },
          "latency_max_ms": {
            "description": "Самый долгий успешный запрос часа, мс; `null` — успешных нет.",
            "type": [
              "integer",
              "null"
            ]
          },
          "latency_min_ms": {
            "description": "Самый быстрый успешный запрос часа, мс; `null` — успешных нет.",
            "type": [
              "integer",
              "null"
            ]
          },
          "latency_p05_ms": {
            "description": "5 % успешных запросов часа отвечают быстрее, мс (±10 %); `null` — успешных нет. Вместе\nс `latency_p95_ms` — полоса обычного времени ответа без редких крайних значений.\n",
            "type": [
              "integer",
              "null"
            ]
          },
          "latency_p50_ms": {
            "description": "Медиана времени ответа успешных запросов часа, мс (±10 %); `null` — успешных нет.",
            "type": [
              "integer",
              "null"
            ]
          },
          "latency_p95_ms": {
            "description": "95 % успешных запросов часа отвечают быстрее, мс (±10 %); `null` — успешных нет.",
            "type": [
              "integer",
              "null"
            ]
          },
          "requests": {
            "type": "integer"
          },
          "succeeded": {
            "type": "integer"
          },
          "success_rate": {
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "at",
          "requests",
          "succeeded",
          "failed",
          "success_rate",
          "latency_p50_ms",
          "latency_p05_ms",
          "latency_p95_ms",
          "latency_min_ms",
          "latency_max_ms"
        ],
        "type": "object"
      },
      "ModelStatsSpeed": {
        "description": "Скорость одной опции пресетов роутинга за 7 дней.",
        "properties": {
          "points": {
            "description": "Ровно 28 интервалов по 6 часов по возрастанию; последний — текущий, ещё не закрытый.",
            "items": {
              "$ref": "#/components/schemas/ModelStatsSpeedPoint"
            },
            "type": "array"
          },
          "routing": {
            "description": "Пресеты опции — как `routing` опции в `pricing.presets`.",
            "items": {
              "$ref": "#/components/schemas/Routing"
            },
            "minItems": 1,
            "type": "array"
          },
          "unit": {
            "description": "Единица `value`: `seconds` — время выполнения запроса, секунды; `tokens_per_second` —\nу чата: скорость ответа, выходных токенов в секунду за всё время ответа (время ответа\nчата зависит от его длины).\n",
            "enum": [
              "seconds",
              "tokens_per_second"
            ],
            "type": "string"
          }
        },
        "required": [
          "routing",
          "unit",
          "points"
        ],
        "type": "object"
      },
      "ModelStatsSpeedPoint": {
        "properties": {
          "at": {
            "description": "Начало интервала, UTC (00:00, 06:00, 12:00 или 18:00).",
            "format": "date-time",
            "type": "string"
          },
          "value": {
            "description": "Медиана успешных запросов за интервал в единице `unit`, приближённая (ошибка до\n20 %); `null` — успешных запросов не было.\n",
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "at",
          "value"
        ],
        "type": "object"
      },
      "ModelStatsSummary": {
        "description": "Итоги статистики модели за 7 дней по запросам всех клиентов — те же числа, что в\n`GET /v1/models/{id}/stats` на начало часа, без почасового ряда. Обновляются раз в час;\n`null` — за окно нет данных, а не ноль.\n",
        "properties": {
          "failed": {
            "description": "Из них не выполнены; отказы по вине запроса не считаются, как и в `success_rate`.\nСумма `failed` по часам `GET /v1/models/{id}/stats`.\n",
            "type": "integer"
          },
          "latency_p50_ms": {
            "description": "Медиана времени ответа успешных запросов, мс (±10 %).",
            "type": [
              "integer",
              "null"
            ]
          },
          "latency_p95_ms": {
            "description": "95 % успешных запросов отвечают быстрее, мс (±10 %).",
            "type": [
              "integer",
              "null"
            ]
          },
          "requests": {
            "description": "Запросы за окно в любом статусе.",
            "type": "integer"
          },
          "succeeded": {
            "description": "Из них завершились успешно.",
            "type": "integer"
          },
          "success_rate": {
            "description": "Доля успешных среди завершённых запросов, `succeeded / (succeeded + failed)`, от 0\nдо 1; отказы по вине запроса (ошибка во входных данных, правила модели, нехватка\nбаланса, несовместимые параметры) не считаются.\n",
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "tokens_out": {
            "description": "Сколько токенов выдала модель — только у чата.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "updated_at": {
            "description": "Когда числа пересчитаны.",
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "requests",
          "succeeded",
          "failed",
          "success_rate",
          "latency_p50_ms",
          "latency_p95_ms",
          "tokens_out",
          "updated_at"
        ],
        "type": "object"
      },
      "ModelUsageEntry": {
        "properties": {
          "canonical_model": {
            "examples": [
              "gpt-5-nano"
            ],
            "type": "string"
          },
          "requests": {
            "examples": [
              5
            ],
            "type": "integer"
          },
          "spend_micro": {
            "examples": [
              90000
            ],
            "type": "integer"
          }
        },
        "required": [
          "canonical_model",
          "requests",
          "spend_micro"
        ],
        "type": "object"
      },
      "MusicGenerationRequest": {
        "additionalProperties": false,
        "description": "Какие поля и значения принимает конкретная модель — её `input_schema`.\n",
        "properties": {
          "action": {
            "description": "Действие с музыкой или звуком; без поля — создание музыки.",
            "enum": [
              "generate",
              "sounds",
              "cover",
              "extend",
              "add_vocals",
              "add_instrumental",
              "mashup",
              "replace_section",
              "separate_vocals",
              "split_stems",
              "isolate_stem",
              "wav",
              "midi",
              "video",
              "cover_image",
              "lyrics",
              "boost_style",
              "timestamps",
              "persona",
              "voice_validate",
              "voice_generate",
              "voice_regenerate",
              "voice_check"
            ],
            "type": "string"
          },
          "audio_weight": {
            "description": "Влияние аудиоэлементов; доступно и при создании в custom_mode.",
            "maximum": 1,
            "minimum": 0,
            "type": "number"
          },
          "author": {
            "description": "Автор.",
            "type": "string"
          },
          "callback_url": {
            "description": "Куда прислать вебхук — https на публичный хост; без поля — адрес по умолчанию из настроек аккаунта.",
            "format": "uri",
            "type": "string"
          },
          "continue_at": {
            "description": "С какой секунды продолжить исходный трек.",
            "minimum": 0.01,
            "type": "number"
          },
          "custom_mode": {
            "description": "Создание по своему стилю и тексту; для инструментала текст не нужен.",
            "type": "boolean"
          },
          "description": {
            "description": "Описание.",
            "type": "string"
          },
          "domain_name": {
            "description": "Подпись сайта.",
            "type": "string"
          },
          "duration_seconds": {
            "description": "Желаемая длительность в режиме своего текста или стиля.",
            "maximum": 360,
            "minimum": 10,
            "type": "integer"
          },
          "end_seconds": {
            "description": "Конец фрагмента.",
            "type": "number"
          },
          "full_lyrics": {
            "description": "Полный текст после замены.",
            "type": "string"
          },
          "grab_lyrics": {
            "description": "Сохранить текст звука.",
            "type": "boolean"
          },
          "instrumental": {
            "description": "Трек без вокала.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "language": {
            "description": "Язык проверки голоса.",
            "type": "string"
          },
          "lyrics": {
            "description": "Текст песни — модель споёт его как написан; разделы размечаются `[Verse]`, `[Chorus]`,\n`[Bridge]`. Без поля текст пишет модель. Вместе с `instrumental` не присылается.\n",
            "type": "string"
          },
          "max_price_multiplier": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/MaxPriceMultiplier"
              },
              {
                "type": "null"
              }
            ]
          },
          "model": {
            "examples": [
              "suno-v6"
            ],
            "type": "string"
          },
          "name": {
            "description": "Имя.",
            "type": "string"
          },
          "negative_tags": {
            "description": "Какие стили и элементы исключить.",
            "maxLength": 200,
            "type": "string"
          },
          "persona_id": {
            "description": "ID задачи Союза, создавшей персону или голос.",
            "type": "string"
          },
          "persona_model": {
            "description": "Тип сохранённой персоны.",
            "enum": [
              "style_persona",
              "voice_persona"
            ],
            "type": "string"
          },
          "prompt": {
            "description": "Описание трека: жанр, настроение, инструменты, темп, голос. Язык текста песни, который\nнапишет модель, — язык описания. В custom_mode и при lyrics это музыкальный стиль.\n",
            "type": "string"
          },
          "reference_audio": {
            "description": "Входные аудиофайлы — ссылки https или идентификаторы загруженных файлов.",
            "items": {
              "type": "string"
            },
            "maxItems": 2,
            "type": "array"
          },
          "routing": {
            "$ref": "#/components/schemas/Routing"
          },
          "routing_options": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/RoutingOptions"
              },
              {
                "type": "null"
              }
            ]
          },
          "singer_skill_level": {
            "description": "Уровень вокала.",
            "type": "string"
          },
          "sound_key": {
            "description": "Тональность звука из схемы параметров модели.",
            "type": "string"
          },
          "sound_loop": {
            "description": "Зацикленный звук.",
            "type": "boolean"
          },
          "sound_tempo": {
            "description": "Темп звука в ударах в минуту.",
            "maximum": 300,
            "minimum": 1,
            "type": "integer"
          },
          "source_file": {
            "description": "ID аудиофайла из data исходной задачи.",
            "type": "string"
          },
          "source_job": {
            "description": "ID готовой задачи Союза, принадлежащей вашему аккаунту.",
            "type": "string"
          },
          "start_seconds": {
            "description": "Начало фрагмента.",
            "type": "number"
          },
          "stem_name": {
            "description": "Дорожка или инструмент.",
            "type": "string"
          },
          "store": {
            "description": "`false` — запрос без хранения: тексты запроса и ответа не сохраняются; файлы живут обычный срок. По умолчанию тексты хранятся; `true` не отменяет режим без хранения аккаунта.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "style_weight": {
            "description": "Точность следования стилю.",
            "maximum": 1,
            "minimum": 0,
            "type": "number"
          },
          "title": {
            "description": "Название в режиме своего текста или стиля и при переработке аудио. Без него —\nпервая строка текста песни или описания. В простом режиме название выбирает модель.\n",
            "type": "string"
          },
          "user": {
            "description": "Поле OpenAI (id конечного пользователя); принимается, ни на что не влияет и не хранится.",
            "type": "string"
          },
          "version": {
            "description": "Версия модели из её схемы параметров.",
            "type": "string"
          },
          "vocal_gender": {
            "description": "Предпочтительный вокал; результат не гарантирован.",
            "enum": [
              "m",
              "f"
            ],
            "type": "string"
          },
          "weirdness": {
            "description": "Степень экспериментальности.",
            "maximum": 1,
            "minimum": 0,
            "type": "number"
          }
        },
        "required": [
          "model"
        ],
        "type": "object"
      },
      "MusicResult": {
        "description": "Структурированный результат аудиооперации. Доступен до истечения срока файла JSON из data; отсутствующие поля не относятся к выбранному действию.",
        "properties": {
          "aligned_words": {
            "description": "Слова и их таймкоды в секундах; success показывает, удалось ли выровнять слово.",
            "items": {
              "properties": {
                "endS": {
                  "type": "number"
                },
                "palign": {
                  "type": "number"
                },
                "startS": {
                  "type": "number"
                },
                "success": {
                  "type": "boolean"
                },
                "word": {
                  "type": "string"
                }
              },
              "required": [
                "word",
                "success",
                "startS",
                "endS",
                "palign"
              ],
              "type": "object"
            },
            "type": "array"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "hoot_cer": {
            "description": "Оценка ошибки выравнивания текста.",
            "type": [
              "number",
              "null"
            ]
          },
          "is_available": {
            "description": "Готов ли проверяемый голос к использованию.",
            "type": "boolean"
          },
          "is_streamed": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "lyrics": {
            "items": {
              "properties": {
                "text": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                }
              },
              "type": "object"
            },
            "type": "array"
          },
          "midi": {
            "description": "Нотные партии; pitch — MIDI-номер ноты, start/end — секунды, velocity — сила от 0 до 1.",
            "properties": {
              "instruments": {
                "items": {
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "notes": {
                      "items": {
                        "properties": {
                          "end": {
                            "type": "number"
                          },
                          "pitch": {
                            "maximum": 127,
                            "minimum": 0,
                            "type": "integer"
                          },
                          "start": {
                            "type": "number"
                          },
                          "velocity": {
                            "maximum": 1,
                            "minimum": 0,
                            "type": "number"
                          }
                        },
                        "required": [
                          "pitch",
                          "start",
                          "end",
                          "velocity"
                        ],
                        "type": "object"
                      },
                      "type": "array"
                    }
                  },
                  "type": "object"
                },
                "type": "array"
              },
              "state": {
                "type": "string"
              }
            },
            "type": "object"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "result": {
            "description": "Улучшенное описание музыкального стиля.",
            "type": "string"
          },
          "status": {
            "description": "Состояние проверки голоса.",
            "type": "string"
          },
          "validate_info": {
            "description": "Фраза для записи подтверждения голоса.",
            "type": "string"
          },
          "waveform_data": {
            "description": "Амплитуды для визуализации звука, сохранённые вместе с результатом.",
            "items": {
              "type": "number"
            },
            "type": [
              "array",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "OutputFile": {
        "allOf": [
          {
            "$ref": "#/components/schemas/File"
          },
          {
            "properties": {
              "actions": {
                "description": "Доступные действия с этим треком; принимают source_job и source_file.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "b64_json": {
                "description": "Картинка в base64 — при `response_format=b64_json`.",
                "type": "string"
              },
              "cover_id": {
                "description": "ID файла обложки из data с role=cover.",
                "type": "string"
              },
              "duration_seconds": {
                "description": "Фактическая длительность трека.",
                "type": "number"
              },
              "label": {
                "description": "Название выделенной дорожки.",
                "type": "string"
              },
              "layer": {
                "$ref": "#/components/schemas/ImageLayer"
              },
              "lyrics": {
                "description": "Текст песни.",
                "type": "string"
              },
              "role": {
                "description": "`result` — сам результат (у музыки их бывает два — варианты трека), `last_frame` — последний кадр ролика по `return_last_frame`.",
                "enum": [
                  "result",
                  "last_frame",
                  "cover",
                  "layer"
                ],
                "type": "string"
              },
              "tags": {
                "description": "Стиль трека.",
                "type": "string"
              },
              "title": {
                "description": "Название трека.",
                "type": "string"
              },
              "type": {
                "description": "Что это за файл (не что за задача — у видео бывает и кадр).",
                "enum": [
                  "image",
                  "video",
                  "audio",
                  "json"
                ],
                "type": "string"
              }
            },
            "required": [
              "type",
              "role"
            ],
            "type": "object"
          }
        ],
        "description": "Файл результата задачи."
      },
      "PaletteColor": {
        "properties": {
          "color": {
            "pattern": "^#[0-9A-Fa-f]{6}$",
            "type": "string"
          },
          "id": {
            "$ref": "#/components/schemas/ChannelId"
          },
          "name": {
            "examples": [
              "Синий"
            ],
            "type": "string"
          }
        },
        "required": [
          "id",
          "name",
          "color"
        ],
        "type": "object"
      },
      "ParamRule": {
        "description": "`when` / `when_present` → `allow` или `deny`.",
        "properties": {
          "allow": {
            "additionalProperties": {
              "items": {
                "type": "string"
              },
              "type": "array"
            },
            "type": "object"
          },
          "deny": {
            "additionalProperties": {
              "items": {
                "type": "string"
              },
              "type": "array"
            },
            "type": "object"
          },
          "when": {
            "additionalProperties": {
              "items": {
                "type": "string"
              },
              "type": "array"
            },
            "type": "object"
          },
          "when_present": {
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "type": "object"
      },
      "ParamSpec": {
        "description": "Одно поле запроса к модели — для API, витрины и плейграунда.",
        "properties": {
          "api_only": {
            "description": "Поле API и документации; плейграунд не показывает и не отправляет его.",
            "type": "boolean"
          },
          "default": {
            "description": "Значение по умолчанию — строка, число или логическое."
          },
          "fields": {
            "items": {
              "$ref": "#/components/schemas/ParamSpec"
            },
            "type": "array"
          },
          "formats": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "hint": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "max": {
            "format": "double",
            "type": "number"
          },
          "max_bytes": {
            "format": "int64",
            "type": "integer"
          },
          "max_distinct": {
            "description": "Перечисление внутри списка — сколько разных значений поле принимает во всём списке (голоса диалога речи).",
            "type": "integer"
          },
          "max_items": {
            "type": "integer"
          },
          "max_length": {
            "type": "integer"
          },
          "max_pixels": {
            "format": "int64",
            "type": "integer"
          },
          "min": {
            "format": "double",
            "type": "number"
          },
          "min_items": {
            "type": "integer"
          },
          "name": {
            "examples": [
              "aspect_ratio"
            ],
            "type": "string"
          },
          "required": {
            "type": "boolean"
          },
          "step": {
            "format": "double",
            "type": "number"
          },
          "type": {
            "enum": [
              "string",
              "enum",
              "integer",
              "number",
              "boolean",
              "image",
              "video",
              "audio",
              "list"
            ],
            "type": "string"
          },
          "values": {
            "items": {
              "$ref": "#/components/schemas/ParamValue"
            },
            "type": "array"
          }
        },
        "required": [
          "name",
          "label",
          "type"
        ],
        "type": "object"
      },
      "ParamValue": {
        "properties": {
          "label": {
            "type": "string"
          },
          "value": {
            "description": "Строка или число — то, что уходит в запрос."
          }
        },
        "required": [
          "value",
          "label"
        ],
        "type": "object"
      },
      "PresetOption": {
        "description": "Опция пресетов роутинга: цена и типичное время запроса в пресетах `routing`. Суммы — в\nединице `unit` карточки модели, как у `Pricing`; в строке `options` — как у\n`amount_micro` этой строки.\n",
        "properties": {
          "amount_micro": {
            "description": "Остальные единицы — за генерацию, секунду звука или 1M символов. В строке `options` — в\nтой же единице, что `amount_micro` строки (у видео — цена сценария строки, за её\n`billed_seconds` секунд; ставка за секунду — деление на `billed_seconds`).\n",
            "format": "int64",
            "type": "integer"
          },
          "cache_read_micro": {
            "description": "`per_1m_tokens` — вход из кэша за 1M токенов, если у этой опции есть отдельная ставка.",
            "format": "int64",
            "type": "integer"
          },
          "dynamic": {
            "description": "`true` — динамическая цена первого канала опции: сумма — оценка, итог — по фактическому расходу.",
            "type": "boolean"
          },
          "input_micro": {
            "description": "`per_1m_tokens` — вход за 1M токенов.",
            "format": "int64",
            "type": "integer"
          },
          "output_micro": {
            "description": "`per_1m_tokens` — выход за 1M токенов.",
            "format": "int64",
            "type": "integer"
          },
          "routing": {
            "description": "Пресеты, которые покрывает опция, по порядку `cheap`, `balanced`, `fast`.",
            "items": {
              "$ref": "#/components/schemas/Routing"
            },
            "minItems": 1,
            "type": "array"
          },
          "typical_seconds": {
            "description": "Типичное время выполнения первого канала опции, секунды: медиана последних успешных\nзапросов за сутки, если их меньше трёх — типичное за 7 дней (та же оценка, что в\n`metrics` каналов), округлённая: до 10 с — до секунды, 10–60 с — до 5 с, дольше —\nдо 10 с; `null` — замеров нет. У чата всегда `null`: время ответа зависит от\nего длины.\n",
            "minimum": 1,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "routing",
          "typical_seconds"
        ],
        "type": "object"
      },
      "PriceOption": {
        "properties": {
          "amount_micro": {
            "format": "int64",
            "type": "integer"
          },
          "billed_seconds": {
            "description": "Посекундное видео — сколько секунд тарифицируется в этом сочетании.",
            "type": "integer"
          },
          "channels": {
            "description": "Цена каждого канала для этого сочетания параметров — как `pricing.channels`.",
            "items": {
              "$ref": "#/components/schemas/ChannelPrice"
            },
            "type": "array"
          },
          "max_amount_micro": {
            "description": "Верх полной цены того же сочетания параметров по всем пригодным каналам, включая запасные; у видео это цена ролика указанной длительности, а не ставка за секунду. `null`, если единицы расчёта различаются, длительность видео-входа неизвестна или у части каналов динамическая цена.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "presets": {
            "description": "Опции пресетов роутинга для этого сочетания параметров — как `pricing.presets`.",
            "items": {
              "$ref": "#/components/schemas/PresetOption"
            },
            "type": "array"
          },
          "when": {
            "additionalProperties": {
              "type": "string"
            },
            "type": "object"
          }
        },
        "required": [
          "when",
          "amount_micro",
          "max_amount_micro",
          "presets"
        ],
        "type": "object"
      },
      "Pricing": {
        "description": "Цена «от» — наименьшая по всем каналам и параметрам, одна для всех. Цены и\nтипичное время пресетов роутинга — `presets` (параметры по умолчанию) и\n`options[].presets` (каждое сочетание параметров). Итог запроса — фактический объём ×\nцены сработавшего канала на момент приёма; если отвечал следующий канал, итог может\nбыть выше цены пресета. Поля `max_*` — верх опубликованной ставки пригодных каналов\nдля указанной единицы, включая запасные, но не предел итоговой стоимости\nзапроса: объём и фактическое списание могут отличаться. `null` означает, что общий\nверх в этой единице по всем допустимым параметрам не доказан. Какие суммы есть, решает `unit`.\n",
        "properties": {
          "amount_micro": {
            "description": "Для изображений — минимальная цена каналов за генерацию с параметрами по умолчанию, как в каталоге каналов; другие сочетания представлены в `options`. Остальные единицы — за генерацию, секунду звука или 1M символов.",
            "format": "int64",
            "type": "integer"
          },
          "available": {
            "description": "`false` — цены сейчас нет, сумм тоже нет.",
            "type": "boolean"
          },
          "cache_read_micro": {
            "description": "`per_1m_tokens` — вход из кэша за 1M токенов, если есть отдельная ставка.",
            "format": "int64",
            "type": "integer"
          },
          "channels": {
            "description": "Цена каждого канала для параметров по умолчанию — в порядке палитры модели, как\n`GET /v1/models/{id}/channels`. Суммы — в единице `unit`: у чата ставки за 1M токенов,\nу остальных — сумма сценария. Канал, которому параметры не подходят, отсутствует.\nПусто, когда цены нет.\n",
            "items": {
              "$ref": "#/components/schemas/ChannelPrice"
            },
            "type": "array"
          },
          "currency": {
            "$ref": "#/components/schemas/Currency"
          },
          "dynamic": {
            "description": "`true` — у части каналов динамическая цена: их суммы — оценка, итог считается по фактическому расходу у канала и может отличаться от оценки. Верх `max_amount_micro` тогда `null`.",
            "type": "boolean"
          },
          "input_micro": {
            "description": "`per_1m_tokens` — вход за 1M токенов.",
            "format": "int64",
            "type": "integer"
          },
          "max_amount_micro": {
            "description": "Верх ставки по всем пригодным каналам и доказуемо полному набору допустимых параметров в единице `unit`. Для видео `null`, поскольку полную цену генерации нельзя выдавать за секундную ставку; используйте верх конкретной строки `options[].max_amount_micro`. Также `null`, если единицы каналов различаются, полный охват не доказан или у части каналов динамическая цена (`dynamic`).",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "max_cache_read_micro": {
            "description": "Верх ставки чтения кэша за 1M токенов; канал без отдельной ставки тарифицирует такой вход по обычной ставке.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "max_input_micro": {
            "description": "Верх ставки входа за 1M токенов с учётом запасных каналов и ступени длинного контекста.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "max_output_micro": {
            "description": "Верх ставки выхода за 1M токенов с учётом запасных каналов и ступени длинного контекста.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "options": {
            "description": "Стартовые цены отдельных сочетаний параметров.",
            "items": {
              "$ref": "#/components/schemas/PriceOption"
            },
            "type": "array"
          },
          "output_micro": {
            "description": "`per_1m_tokens` — выход за 1M токенов.",
            "format": "int64",
            "type": "integer"
          },
          "presets": {
            "description": "Цены и типичное время пресетов роутинга для параметров по умолчанию — от одной до трёх\nопций. Одна опция может покрывать несколько пресетов: «Баланс» может входить в опцию\n«Дешевле» или «Быстрее». У разных опций цена и типичное время могут совпадать, хотя\nих поведение в Авто-роутинге различается. Переданный в запросе `routing` сохраняет\nвыбранный порядок исполнения. Пусто, когда цены нет.\n",
            "items": {
              "$ref": "#/components/schemas/PresetOption"
            },
            "type": "array"
          },
          "unit": {
            "enum": [
              "per_1m_tokens",
              "per_generation",
              "per_second",
              "per_1m_characters"
            ],
            "type": "string"
          }
        },
        "required": [
          "unit",
          "available",
          "currency",
          "presets",
          "max_input_micro",
          "max_output_micro",
          "max_cache_read_micro",
          "max_amount_micro"
        ],
        "type": "object"
      },
      "QuoteElement": {
        "additionalProperties": false,
        "properties": {
          "description": {
            "type": "string"
          },
          "images": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "QuoteGenerationParams": {
        "additionalProperties": false,
        "properties": {
          "action": {
            "description": "Музыка — действие (`generate`, `cover`, …), от него зависит цена.",
            "type": "string"
          },
          "aspect_ratio": {
            "type": "string"
          },
          "audio": {
            "type": "boolean"
          },
          "background": {
            "type": "string"
          },
          "background_source": {
            "type": "string"
          },
          "character_orientation": {
            "type": "string"
          },
          "duration_seconds": {
            "type": "integer"
          },
          "elements": {
            "items": {
              "$ref": "#/components/schemas/QuoteElement"
            },
            "type": "array"
          },
          "first_frame": {
            "type": "boolean"
          },
          "last_frame": {
            "type": "boolean"
          },
          "output_format": {
            "type": "string"
          },
          "quality": {
            "enum": [
              "auto",
              "low",
              "medium",
              "high",
              "xhigh",
              "max"
            ],
            "type": "string"
          },
          "reference_audio": {
            "type": "integer"
          },
          "reference_videos": {
            "type": "integer"
          },
          "references": {
            "type": "integer"
          },
          "resolution": {
            "type": "string"
          },
          "return_last_frame": {
            "type": "boolean"
          },
          "shots": {
            "items": {
              "$ref": "#/components/schemas/VideoShot"
            },
            "type": "array"
          },
          "version": {
            "description": "Музыка — версия модели, от неё зависит цена.",
            "type": "string"
          },
          "web_search": {
            "type": "boolean"
          }
        },
        "type": "object"
      },
      "RevealAPIKeyResponse": {
        "properties": {
          "key": {
            "examples": [
              "sk_9f8e7d6c5b4a39281706f5e4d3c2b1a0"
            ],
            "type": "string"
          }
        },
        "required": [
          "key"
        ],
        "type": "object"
      },
      "Routing": {
        "description": "Пресет роутинга — порядок, в котором Авто-роутинг пробует каналы модели. `cheap` —\n«Дешевле»: самый дешёвый канал, даже если он медленнее; скорость решает только при\nравной цене. `balanced` — «Баланс», по умолчанию: заметно быстрее за небольшую\nдоплату; если такого канала нет — как «Дешевле». `fast` — «Быстрее»: самый быстрый\nканал; при близкой скорости — дешевле. Скорость измеряется по реальным запросам.\nПресет — пожелание: принимается для любой модели, даже если у неё один канал. Канал не\nответил — запрос переходит к следующему по порядку пресета; следующий канал может\nстоить дороже, и итог может превысить цену пресета — насколько, ограничивает\n`max_price_multiplier`. Без поля в запросе сервер применяет настройку аккаунта; другое\nзначение — `400` со списком допустимых.\n",
        "enum": [
          "cheap",
          "balanced",
          "fast"
        ],
        "type": "string"
      },
      "RoutingMaxPrice": {
        "additionalProperties": false,
        "description": "Абсолютные потолки опубликованных ставок в микроединицах RUB: input/output/cache_read\nза миллион токенов, request за конкретный запрос с его параметрами. Ноль допускает только\nбесплатную ставку. Неизвестная ставка не проходит заданный потолок. Потолки за токены\nдействуют только на каналы с ценой за токены: каналы с ценой за запрос (картинка, видео,\nсекунда или символ звука) они не отсекают — их цену ограничивает request. Это фильтр\nтарифов, а не гарантия итоговой суммы при иной фактической стоимости. Для неизвестной\nдлительности аудио request сравнивается с оценкой; окончательная длительность может\nотличаться.\n",
        "properties": {
          "cache_read": {
            "format": "int64",
            "minimum": 0,
            "type": "integer"
          },
          "input": {
            "format": "int64",
            "minimum": 0,
            "type": "integer"
          },
          "output": {
            "format": "int64",
            "minimum": 0,
            "type": "integer"
          },
          "request": {
            "format": "int64",
            "minimum": 0,
            "type": "integer"
          }
        },
        "type": "object"
      },
      "RoutingOptions": {
        "additionalProperties": false,
        "description": "Настройки каналов. Без поля действует настройка аккаунта; объект заменяет её целиком,\nnull сбрасывает на автоматический выбор. Ограничения никогда не ослабляются при отказах.\nonly и ignore ограничивают допустимые каналы; order задаёт предпочтительный порядок и\nобязан быть подмножеством допустимых: цвет из order вне only или из ignore — `400`.\nОстальные допустимые каналы следуют по пресету. allow_fallbacks=false оставляет только\norder, а без order — первый выбранный канал. Закрепление диалога не отменяет ограничений.\nЦвет, которого у модели нет, — `400 invalid_request`. Если настройки отсекли все каналы\n(ни один разрешённый цвет не исполняет модель, все дороже max_price, запасные запрещены),\nответ — `400 no_channel_matches` с `detail[{path: \"routing_options\", reason}]`, а не\n`503`: повтор того же запроса не поможет. Пауза канала после сбоев смотрится только среди\nканалов, которые вы разрешили: если на паузе все они, запрос всё равно пробует их.\n",
        "properties": {
          "allow_fallbacks": {
            "default": true,
            "type": "boolean"
          },
          "ignore": {
            "items": {
              "$ref": "#/components/schemas/ChannelId"
            },
            "maxItems": 64,
            "type": "array",
            "uniqueItems": true
          },
          "max_price": {
            "$ref": "#/components/schemas/RoutingMaxPrice"
          },
          "only": {
            "items": {
              "$ref": "#/components/schemas/ChannelId"
            },
            "maxItems": 64,
            "type": "array",
            "uniqueItems": true
          },
          "order": {
            "items": {
              "$ref": "#/components/schemas/ChannelId"
            },
            "maxItems": 64,
            "type": "array",
            "uniqueItems": true
          },
          "preferred_max_latency_ms": {
            "description": "Мягкое предпочтение по p50 задержки. Неизмеренные и более медленные каналы остаются запасными.",
            "format": "int64",
            "minimum": 1,
            "type": "integer"
          },
          "preferred_min_throughput": {
            "description": "Мягкое предпочтение по p50 токенов в секунду; только чат (в запросе к другой модальности — `400`).",
            "exclusiveMinimum": 0,
            "type": "number"
          },
          "session_id": {
            "description": "Идентификатор диалога чата в пределах аккаунта и модели. Сохраняется только хеш.",
            "maxLength": 256,
            "minLength": 1,
            "type": "string"
          },
          "sort": {
            "description": "Явная сортировка заменяет пресет; порядок цветов имеет приоритет. latency — время первого содержимого чата или всего результата; throughput — токены в секунду, только чат (в запросе к другой модальности — `400`).",
            "enum": [
              "price",
              "latency",
              "throughput"
            ],
            "type": "string"
          },
          "sticky": {
            "default": true,
            "description": "Закреплять успешное исполнение диалога на десять минут бездействия. Явный order имеет приоритет.",
            "type": "boolean"
          }
        },
        "type": "object"
      },
      "RoutingPreview": {
        "properties": {
          "channels": {
            "description": "Каналы плана в порядке попыток: первый — тот, с которого начнётся запрос, следующие —\nзапасные. Пустой список — запрос с этими условиями сейчас выполнить нельзя; почему —\nв `excluded`.\n",
            "items": {
              "$ref": "#/components/schemas/RoutingPreviewChannel"
            },
            "type": "array"
          },
          "currency": {
            "$ref": "#/components/schemas/Currency"
          },
          "estimated_price": {
            "description": "Оценка суммы первого канала цепочки для этих параметров. Может уточняться по\nсопоставимым выполненным запросам; итог зависит от фактического объёма\nи ставок на момент приёма. Запасной канал может стоить дороже. `null` — план пуст. План ознакомительный: при создании\nзапроса он рассчитывается заново.\n",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "excluded": {
            "description": "Каналы модели, которые в план не вошли, и почему. Каждый цвет — один раз.",
            "items": {
              "$ref": "#/components/schemas/RoutingPreviewExclusion"
            },
            "type": "array"
          },
          "generated_at": {
            "format": "date-time",
            "type": "string"
          },
          "model": {
            "type": "string"
          }
        },
        "required": [
          "model",
          "channels",
          "excluded",
          "estimated_price",
          "currency",
          "generated_at"
        ],
        "type": "object"
      },
      "RoutingPreviewChannel": {
        "properties": {
          "estimated_price": {
            "description": "Оценка суммы этого канала для параметров превью, в микроединицах `currency`; итог определяется фактическим объёмом и ставками на момент приёма запроса.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "id": {
            "$ref": "#/components/schemas/ChannelId"
          },
          "rates": {
            "$ref": "#/components/schemas/ModelChannelRates"
          }
        },
        "required": [
          "id",
          "estimated_price"
        ],
        "type": "object"
      },
      "RoutingPreviewExclusion": {
        "properties": {
          "id": {
            "$ref": "#/components/schemas/ChannelId"
          },
          "reason": {
            "description": "`not_selected` — цвет не прошёл `only`/`ignore`; `above_max_price` — дороже\n`max_price` или потолка `max_price_multiplier`; `unsupported` — канал не берёт эти\nпараметры, возможности (инструменты, картинка, JSON-схема, поток) или пределы\nтокенов; `unavailable` — канал сейчас не исполняет (пауза после сбоев, выключен);\n`fallback_disabled` — запасные каналы запрещены (`allow_fallbacks: false`).\n",
            "enum": [
              "not_selected",
              "above_max_price",
              "unsupported",
              "unavailable",
              "fallback_disabled"
            ],
            "type": "string"
          }
        },
        "required": [
          "id",
          "reason"
        ],
        "type": "object"
      },
      "RoutingPreviewRequest": {
        "additionalProperties": false,
        "properties": {
          "audio_input": {
            "description": "Чат — в `messages` будет звук.",
            "type": "boolean"
          },
          "billed_seconds": {
            "maximum": 86400,
            "minimum": 1,
            "type": "integer"
          },
          "file_input": {
            "description": "Чат — в `messages` будет файл (PDF).",
            "type": "boolean"
          },
          "input_tokens": {
            "maximum": 16777216,
            "minimum": 0,
            "type": "integer"
          },
          "max_price_multiplier": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/MaxPriceMultiplier"
              },
              {
                "type": "null"
              }
            ]
          },
          "n": {
            "description": "Чат — сколько вариантов ответа; пределы выхода каналов и оценка считаются на все.",
            "maximum": 128,
            "minimum": 1,
            "type": "integer"
          },
          "output_tokens": {
            "maximum": 16777216,
            "minimum": 1,
            "type": "integer"
          },
          "params": {
            "$ref": "#/components/schemas/QuoteGenerationParams"
          },
          "routing": {
            "$ref": "#/components/schemas/Routing"
          },
          "routing_options": {
            "$ref": "#/components/schemas/RoutingOptions"
          },
          "speech_characters": {
            "maximum": 1000000,
            "minimum": 1,
            "type": "integer"
          },
          "speech_dialogue": {
            "description": "Речь — запрос с `dialogue` вместо `input`.",
            "type": "boolean"
          },
          "speech_instructions": {
            "description": "Речь — запрос с полем `instructions`.",
            "type": "boolean"
          },
          "speech_output_seconds": {
            "maximum": 86400,
            "minimum": 1,
            "type": "integer"
          },
          "speech_utf16_characters": {
            "maximum": 2000000,
            "minimum": 1,
            "type": "integer"
          },
          "stream": {
            "type": "boolean"
          },
          "structured_output": {
            "type": "boolean"
          },
          "tools": {
            "type": "boolean"
          },
          "video_input": {
            "description": "Чат — в `messages` будет видео.",
            "type": "boolean"
          },
          "vision": {
            "type": "boolean"
          }
        },
        "type": "object"
      },
      "ServiceStatus": {
        "description": "Состояние сервиса (`GET /v1/status`). У `maintenance` — причина и срок плановых работ.\n",
        "properties": {
          "ends_at": {
            "description": "До какого времени приостановлены новые запросы.",
            "format": "date-time",
            "type": "string"
          },
          "reason": {
            "description": "Причина плановых работ, для людей.",
            "type": "string"
          },
          "started_at": {
            "description": "Когда начались плановые работы.",
            "format": "date-time",
            "type": "string"
          },
          "status": {
            "description": "`ok` — работает; `maintenance` — плановые работы, новые запросы до `ends_at` получают\n`503 maintenance`; `unavailable` — сервис не отвечает вне плановых работ.\n",
            "enum": [
              "ok",
              "maintenance",
              "unavailable"
            ],
            "type": "string"
          }
        },
        "required": [
          "status"
        ],
        "type": "object"
      },
      "SpeechRequest": {
        "additionalProperties": false,
        "description": "Текст — `input` или `dialogue`, одно из двух; без обоих — `400` с `input` `required`.",
        "properties": {
          "callback_url": {
            "format": "uri",
            "type": "string"
          },
          "dialogue": {
            "description": "Реплики по порядку вместо `input` — диалог разными голосами. Только у моделей, в карточке которых есть это поле; число разных голосов, реплик и общий предел текста — там же.",
            "items": {
              "additionalProperties": false,
              "properties": {
                "text": {
                  "description": "Текст реплики.",
                  "minLength": 1,
                  "type": "string"
                },
                "voice": {
                  "description": "Голос реплики из карточки модели.",
                  "type": "string"
                }
              },
              "required": [
                "voice",
                "text"
              ],
              "type": "object"
            },
            "minItems": 1,
            "type": "array"
          },
          "input": {
            "description": "Текст или описание звуковой сцены; предел длины — у модели, если указан. Обязателен, если нет `dialogue`; вместе с `dialogue` не присылается.",
            "minLength": 1,
            "type": "string"
          },
          "instructions": {
            "description": "Как говорить — тон, темп и эмоция словами. Только у моделей, в карточке которых есть это поле; предел длины — там же.",
            "minLength": 1,
            "type": "string"
          },
          "max_price_multiplier": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/MaxPriceMultiplier"
              },
              {
                "type": "null"
              }
            ]
          },
          "model": {
            "examples": [
              "qwen-audio-3.0-tts-plus"
            ],
            "type": "string"
          },
          "response_format": {
            "description": "Формат звука; без поля — родной формат модели.",
            "enum": [
              "mp3",
              "opus",
              "aac",
              "flac",
              "wav",
              "pcm"
            ],
            "type": "string"
          },
          "routing": {
            "$ref": "#/components/schemas/Routing"
          },
          "routing_options": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/RoutingOptions"
              },
              {
                "type": "null"
              }
            ]
          },
          "speed": {
            "description": "Поле OpenAI; принимается, темп речи — как у модели.",
            "maximum": 4,
            "minimum": 0.25,
            "type": "number"
          },
          "store": {
            "description": "`false` — запрос без хранения: тексты запроса и ответа не сохраняются; файлы живут обычный срок. По умолчанию тексты хранятся; `true` не отменяет режим без хранения аккаунта.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "stream_format": {
            "default": "audio",
            "description": "Поле OpenAI; `sse` — звук событиями `text/event-stream`: `speech.audio.delta` с base64\nзвука, затем `speech.audio.done`.\n",
            "enum": [
              "audio",
              "sse"
            ],
            "type": "string"
          },
          "user": {
            "description": "Поле OpenAI (id конечного пользователя); принимается, ни на что не влияет и не хранится.",
            "type": "string"
          },
          "voice": {
            "description": "Голос из карточки модели, если она предлагает выбор; без поля — умолчание модели.",
            "type": "string"
          }
        },
        "required": [
          "model"
        ],
        "type": "object"
      },
      "SpeechStreamEvent": {
        "description": "Событие потока речи, как у `audio.speech.create` SDK OpenAI со `stream_format:\"sse\"`.",
        "properties": {
          "audio": {
            "description": "Звук base64 — у `speech.audio.delta`.",
            "type": "string"
          },
          "type": {
            "enum": [
              "speech.audio.delta",
              "speech.audio.done"
            ],
            "type": "string"
          }
        },
        "required": [
          "type"
        ],
        "type": "object"
      },
      "SpendLimitEntry": {
        "properties": {
          "amount_micro": {
            "examples": [
              5000000000
            ],
            "type": "integer"
          },
          "remaining_micro": {
            "examples": [
              3750000000
            ],
            "type": "integer"
          },
          "reset": {
            "enum": [
              "none",
              "daily",
              "monthly"
            ],
            "examples": [
              "monthly"
            ],
            "type": "string"
          },
          "spent_micro": {
            "examples": [
              1250000000
            ],
            "type": "integer"
          }
        },
        "required": [
          "amount_micro",
          "remaining_micro",
          "reset",
          "spent_micro"
        ],
        "type": "object"
      },
      "TerminalCode": {
        "description": "Почему задача не удалась — закрытый словарь, тот же, что у `error.code` задачи в\nпубличном API: `invalid_input` — модель отвергла входные данные (параметр или файл;\nчто именно — в `detail`, если известно), исправьте запрос; `content_policy` — сработал\nконтентный фильтр, перепишите описание; `capability_mismatch` — модель не принимает\nпараметры; `insufficient_balance` — не хватило баланса или лимита; `model_unavailable`\n— модель сейчас некому исполнить, повторите позже или выберите другую модель;\n`generation_failed` — модель приняла запрос и не справилась, повторите; `unknown_error` —\nнеизвестная ошибка, без подробностей: повторите, мы разбираем такие случаи. Проваленная\nзадача стоит `0`.",
        "enum": [
          "invalid_input",
          "content_policy",
          "capability_mismatch",
          "insufficient_balance",
          "model_unavailable",
          "generation_failed",
          "unknown_error"
        ],
        "examples": [
          "model_unavailable"
        ],
        "type": "string"
      },
      "TranscriptionRequest": {
        "additionalProperties": false,
        "properties": {
          "callback_url": {
            "format": "uri",
            "type": "string"
          },
          "chunking_strategy": {
            "description": "Поле OpenAI (`auto` или объект `server_vad`); принимается, запись делит модель. В multipart также принимаются поля chunking_strategy[…].",
            "oneOf": [
              {
                "const": "auto",
                "type": "string"
              },
              {
                "properties": {
                  "type": {
                    "const": "server_vad",
                    "type": "string"
                  }
                },
                "required": [
                  "type"
                ],
                "type": "object"
              }
            ]
          },
          "file": {
            "contentMediaType": "audio/*",
            "description": "`wav`, `mp3`, `flac`, `m4a`, `ogg`, `webm`, `aac`, до 25 МиБ; формат определяется по байтам.",
            "type": "string"
          },
          "include": {
            "description": "Поле OpenAI; принимается, вероятностей токенов в ответе нет. В multipart также принимается запись include[].",
            "items": {
              "enum": [
                "logprobs"
              ],
              "type": "string"
            },
            "type": "array"
          },
          "language": {
            "$ref": "#/components/schemas/LanguageCode",
            "description": "Язык записи, код ISO 639-1 (`ru`, `en`); без поля язык определяет модель. Другое\nнаписание (`RU`, `ru-RU`, `russian`) — `400` со списком кодов в `allowed`.\n"
          },
          "max_price_multiplier": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/MaxPriceMultiplier"
              },
              {
                "type": "null"
              }
            ]
          },
          "model": {
            "examples": [
              "whisper-large-v3-turbo"
            ],
            "type": "string"
          },
          "prompt": {
            "description": "Поле OpenAI; принимается, модель расшифровывает без подсказки.",
            "type": "string"
          },
          "response_format": {
            "default": "json",
            "enum": [
              "json",
              "verbose_json",
              "text",
              "srt"
            ],
            "type": "string"
          },
          "routing": {
            "$ref": "#/components/schemas/Routing"
          },
          "routing_options": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/RoutingOptions"
              },
              {
                "type": "null"
              }
            ]
          },
          "store": {
            "description": "`false` — запрос без хранения: тексты запроса и ответа не сохраняются; файлы живут обычный срок. По умолчанию тексты хранятся; `true` не отменяет режим без хранения аккаунта.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "stream": {
            "description": "Поле OpenAI; `true` — ответ `text/event-stream`: `transcript.text.delta` с текстом, затем\n`transcript.text.done`.\n",
            "type": "boolean"
          },
          "temperature": {
            "description": "Поле OpenAI; принимается, ни на что не влияет.",
            "maximum": 1,
            "minimum": 0,
            "type": "number"
          },
          "timestamp_granularities": {
            "description": "Таймкоды фраз и слов; только вместе с verbose_json у моделей, которые их поддерживают. В multipart также принимается запись timestamp_granularities[].",
            "items": {
              "enum": [
                "segment",
                "word"
              ],
              "type": "string"
            },
            "maxItems": 2,
            "minItems": 1,
            "type": "array",
            "uniqueItems": true
          },
          "user": {
            "description": "Поле OpenAI (id конечного пользователя); принимается, ни на что не влияет и не хранится.",
            "type": "string"
          }
        },
        "required": [
          "file",
          "model"
        ],
        "type": "object"
      },
      "TranscriptionSegment": {
        "properties": {
          "end": {
            "format": "double",
            "type": "number"
          },
          "id": {
            "type": "integer"
          },
          "start": {
            "description": "Начало, секунды от начала записи.",
            "format": "double",
            "type": "number"
          },
          "text": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "start",
          "end",
          "text"
        ],
        "type": "object"
      },
      "TranscriptionStreamEvent": {
        "description": "Событие потока расшифровки, как у `audio.transcriptions.create` SDK OpenAI со `stream:true`.",
        "properties": {
          "delta": {
            "description": "Текст — у `transcript.text.delta`.",
            "type": "string"
          },
          "text": {
            "description": "Вся расшифровка — у `transcript.text.done`.",
            "type": "string"
          },
          "type": {
            "enum": [
              "transcript.text.delta",
              "transcript.text.done"
            ],
            "type": "string"
          }
        },
        "required": [
          "type"
        ],
        "type": "object"
      },
      "TranscriptionWord": {
        "properties": {
          "end": {
            "format": "double",
            "type": "number"
          },
          "start": {
            "description": "Начало, секунды от начала записи.",
            "format": "double",
            "type": "number"
          },
          "word": {
            "type": "string"
          }
        },
        "required": [
          "word",
          "start",
          "end"
        ],
        "type": "object"
      },
      "UpdateAPIKeyRequest": {
        "properties": {
          "expires_at": {
            "description": "RFC 3339; null — ключ бессрочный.",
            "examples": [
              "2026-12-31T00:00:00Z"
            ],
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "examples": [
              "production"
            ],
            "type": "string"
          },
          "spend_limit_micro": {
            "description": "null — без потолка.",
            "examples": [
              1000000
            ],
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "spend_limit_reset": {
            "description": "`none` | `daily` | `monthly`; без поля — `none`.",
            "enum": [
              "none",
              "daily",
              "monthly"
            ],
            "examples": [
              "monthly"
            ],
            "type": "string"
          }
        },
        "type": "object"
      },
      "UsageResponse": {
        "properties": {
          "currency": {
            "examples": [
              "RUB"
            ],
            "type": "string"
          },
          "items": {
            "items": {
              "$ref": "#/components/schemas/JobEntry"
            },
            "type": "array"
          },
          "next_before": {
            "description": "Курсор следующей (более старой) страницы для before; null — страниц больше нет.",
            "examples": [
              "1758283200000000000_job_1a2b3c4d5e6f7890"
            ],
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "currency",
          "items",
          "next_before"
        ],
        "type": "object"
      },
      "UsageStatus": {
        "description": "Статус запроса: queued — в очереди, running — выполняется, succeeded — готов, failed — не удался, unknown — исход ещё выясняется, cancelled — отменён.",
        "enum": [
          "queued",
          "running",
          "succeeded",
          "failed",
          "unknown",
          "cancelled"
        ],
        "type": "string"
      },
      "UsageSummaryResponse": {
        "properties": {
          "by_model": {
            "items": {
              "$ref": "#/components/schemas/ModelUsageEntry"
            },
            "type": "array"
          },
          "currency": {
            "examples": [
              "RUB"
            ],
            "type": "string"
          },
          "daily": {
            "description": "Ряд по UTC-дням; дней без запросов в нём нет. С bucket=hour — пустой, ряд в hourly.",
            "items": {
              "$ref": "#/components/schemas/DailyUsageEntry"
            },
            "type": "array"
          },
          "hourly": {
            "description": "Ряд по UTC-часам — только с bucket=hour; часов без запросов в нём нет, по часу вверх.",
            "items": {
              "$ref": "#/components/schemas/HourlyUsageEntry"
            },
            "type": "array"
          },
          "period_days": {
            "examples": [
              30
            ],
            "type": "integer"
          },
          "total_requests": {
            "examples": [
              42
            ],
            "type": "integer"
          },
          "total_spend_micro": {
            "examples": [
              1250000
            ],
            "type": "integer"
          },
          "total_succeeded": {
            "examples": [
              40
            ],
            "type": "integer"
          }
        },
        "required": [
          "by_model",
          "currency",
          "daily",
          "period_days",
          "total_requests",
          "total_spend_micro",
          "total_succeeded"
        ],
        "type": "object"
      },
      "Vendor": {
        "properties": {
          "id": {
            "examples": [
              "bytedance"
            ],
            "type": "string"
          },
          "name": {
            "examples": [
              "ByteDance"
            ],
            "type": "string"
          }
        },
        "required": [
          "id",
          "name"
        ],
        "type": "object"
      },
      "VideoElement": {
        "additionalProperties": false,
        "properties": {
          "description": {
            "type": "string"
          },
          "images": {
            "items": {
              "$ref": "#/components/schemas/MediaSource"
            },
            "type": "array"
          },
          "name": {
            "examples": [
              "element_dog"
            ],
            "type": "string"
          }
        },
        "required": [
          "name",
          "images"
        ],
        "type": "object"
      },
      "VideoGenerationForm": {
        "additionalProperties": true,
        "description": "Форма `videos.create` SDK OpenAI. `input_reference` — первый кадр: файл картинки,\n`input_reference[image_url]` или `input_reference[file_id]`. Остальные поля\n`VideoGenerationRequest` — полями формы: числа и флаги текстом, списки повтором поля или\nJSON-массивом, объекты (`routing_options`, `shots`, `elements`) — JSON-строкой.\n",
        "properties": {
          "input_reference": {
            "format": "binary",
            "type": "string"
          },
          "model": {
            "type": "string"
          },
          "prompt": {
            "type": "string"
          },
          "seconds": {
            "examples": [
              "8"
            ],
            "type": "string"
          },
          "size": {
            "examples": [
              "1280x720"
            ],
            "type": "string"
          }
        },
        "required": [
          "model",
          "prompt"
        ],
        "type": "object"
      },
      "VideoGenerationRequest": {
        "additionalProperties": false,
        "description": "Какие поля и значения принимает конкретная модель — её `input_schema`. Кадры\n(`first_frame`, `last_frame`) и набор референсов взаимоисключающие.\n",
        "properties": {
          "aspect_ratio": {
            "examples": [
              "16:9"
            ],
            "pattern": "^(auto|[0-9]+:[0-9]+)$",
            "type": "string"
          },
          "audio": {
            "description": "Сгенерировать звуковую дорожку.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "background_source": {
            "examples": [
              "input_image"
            ],
            "type": "string"
          },
          "callback_url": {
            "format": "uri",
            "type": "string"
          },
          "character_orientation": {
            "examples": [
              "video"
            ],
            "type": "string"
          },
          "duration_seconds": {
            "examples": [
              5
            ],
            "minimum": 1,
            "type": "integer"
          },
          "elements": {
            "description": "Именованные сущности, на которые промпт ссылается как `@name`.",
            "items": {
              "$ref": "#/components/schemas/VideoElement"
            },
            "type": "array"
          },
          "first_frame": {
            "$ref": "#/components/schemas/MediaSource"
          },
          "last_frame": {
            "$ref": "#/components/schemas/MediaSource"
          },
          "max_price_multiplier": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/MaxPriceMultiplier"
              },
              {
                "type": "null"
              }
            ]
          },
          "model": {
            "examples": [
              "seedance-2"
            ],
            "type": "string"
          },
          "output_format": {
            "enum": [
              "mp4",
              "mov"
            ],
            "type": "string"
          },
          "prompt": {
            "minLength": 1,
            "type": "string"
          },
          "reference_audio": {
            "description": "Звук — `https://…` или `file_…`.",
            "items": {
              "$ref": "#/components/schemas/MediaSource"
            },
            "type": "array"
          },
          "reference_videos": {
            "description": "Клипы — `https://…` или `file_…`.",
            "items": {
              "$ref": "#/components/schemas/MediaSource"
            },
            "type": "array"
          },
          "references": {
            "items": {
              "$ref": "#/components/schemas/MediaSource"
            },
            "type": "array"
          },
          "resolution": {
            "examples": [
              "720p"
            ],
            "type": "string"
          },
          "return_last_frame": {
            "description": "Вернуть последний кадр вторым файлом (`role: last_frame`).",
            "type": [
              "boolean",
              "null"
            ]
          },
          "routing": {
            "$ref": "#/components/schemas/Routing"
          },
          "routing_options": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/RoutingOptions"
              },
              {
                "type": "null"
              }
            ]
          },
          "seconds": {
            "description": "Длительность в секундах, как в `videos.create` SDK OpenAI (`\"8\"`); то же, что `duration_seconds`.",
            "oneOf": [
              {
                "pattern": "^[0-9]+$",
                "type": "string"
              },
              {
                "minimum": 1,
                "type": "integer"
              }
            ]
          },
          "shots": {
            "description": "Сцены вместо одного промпта; сумма длительностей — в пределах ролика.",
            "items": {
              "$ref": "#/components/schemas/VideoShot"
            },
            "type": "array"
          },
          "size": {
            "description": "`ШxВ`, как в `videos.create` SDK OpenAI (`1280x720`): соотношение сторон — ближайшее из\n`aspect_ratio` модели, разрешение — по короткой стороне. Вместе с `aspect_ratio` или\n`resolution` не передаётся.\n",
            "examples": [
              "1280x720"
            ],
            "pattern": "^([0-9]+x[0-9]+|auto)$",
            "type": "string"
          },
          "store": {
            "description": "`false` — запрос без хранения: тексты запроса и ответа не сохраняются; файлы живут обычный срок. По умолчанию тексты хранятся; `true` не отменяет режим без хранения аккаунта.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "user": {
            "description": "Поле OpenAI (id конечного пользователя); принимается, ни на что не влияет и не хранится.",
            "type": "string"
          },
          "web_search": {
            "type": [
              "boolean",
              "null"
            ]
          }
        },
        "required": [
          "model",
          "prompt"
        ],
        "type": "object"
      },
      "VideoShot": {
        "additionalProperties": false,
        "properties": {
          "duration_seconds": {
            "minimum": 1,
            "type": "integer"
          },
          "prompt": {
            "type": "string"
          }
        },
        "required": [
          "prompt"
        ],
        "type": "object"
      },
      "WebhookEvent": {
        "description": "Тело вебхука по Standard Webhooks.",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Job"
          },
          "timestamp": {
            "format": "date-time",
            "type": "string"
          },
          "type": {
            "enum": [
              "job.completed",
              "job.failed"
            ],
            "type": "string"
          }
        },
        "required": [
          "type",
          "timestamp",
          "data"
        ],
        "type": "object"
      },
      "WebhookSecret": {
        "properties": {
          "object": {
            "const": "webhook_secret",
            "type": "string"
          },
          "secret": {
            "description": "`whsec_\u003cbase64\u003e` — ключ Standard Webhooks.",
            "pattern": "^whsec_",
            "type": "string"
          }
        },
        "required": [
          "object",
          "secret"
        ],
        "type": "object"
      },
      "WebhookSettings": {
        "properties": {
          "url": {
            "description": "URL is where a job without callback_url of its own reports to,\nincluding jobs started with the playground key; empty — nowhere.",
            "examples": [
              "https://example.com/hooks/souz"
            ],
            "type": "string"
          }
        },
        "type": "object"
      },
      "WebhookSettingsPatch": {
        "properties": {
          "url": {
            "description": "null или пустая строка снимает адрес.",
            "examples": [
              "https://example.com/hooks/souz"
            ],
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      }
    },
    "securitySchemes": {
      "BearerAuth": {
        "description": "API-ключ из кабинета souz.ai — запускает модели. Ключ управления здесь не подходит: `403\nforbidden` с `detail[].reason: requires_api_key`.\n",
        "scheme": "bearer",
        "type": "http"
      },
      "ClientSession": {
        "description": "Сессия кабинета souz.ai в браузере — те же ручки, что у ключа управления.",
        "in": "cookie",
        "name": "client_session",
        "type": "apiKey"
      },
      "ManagementKey": {
        "description": "Ключ управления из кабинета souz.ai (выдают владелец и администратор аккаунта — себе или\nучастнику). Даёт ровно то, что его держатель видит и может в кабинете: баланс, историю\nопераций и запросов, расходы, обычные ключи, настройки аккаунта — с той же ролью, лимитами\nи цифрами. Модели\nне запускает. Обычный API-ключ здесь не подходит: `403 forbidden` с\n`detail[].reason: requires_management_key`.\n",
        "scheme": "bearer",
        "type": "http"
      }
    }
  },
  "info": {
    "description": "Базовый адрес — `https://api.souz.ai`, ключ — `Authorization: Bearer \u003cключ\u003e` (выдаётся в\nкабинете souz.ai). SDK OpenAI работает с `base_url = \"https://api.souz.ai/v1\"`. Ключ —\nтолько на сервере: CORS у API нет, из браузера запрос не пройдёт.\n\n**Смена модели — смена имени.** У каждой модели есть карточка (`GET /v1/models/{id}`) с\nJSON Schema тела запроса (`input_schema`). Значение, которое у модели ничего не меняет\n(её умолчание, `auto`, параметр, которого у модели нет, со значением, которое она и так\nдаёт), принимается без ошибки. Значение, которое изменило бы результат или цену, но модели\nнедоступно, — `400 capability_mismatch` со списком допустимых в `error.detail[].allowed`.\n\n**Поля.** `null` в необязательном поле значит то же, что его отсутствие: умолчание модели\nили настройка ключа.\n\n**Задача.** Всё, кроме чата, — задача (`Job`) с одним объектом. Картинки, музыка,\nтранскрибация и речь отвечают результатом сразу (`200`; не успели за 9 минут — `202`), видео — `202` с задачей\nв работе. Заголовок `Prefer: respond-async` делает любой такой запрос асинхронным: `202`,\nзаголовок `Location` с адресом задачи. Результат — `GET /v1/jobs/{id}`, поток событий\n`GET /v1/jobs/{id}/events` или вебхук на `callback_url`. Отменить принятую задачу нельзя:\nобрыв соединения и прекращение опроса её не останавливают. Повтор с тем же\n`Idempotency-Key` вернёт ту же задачу.\n\n**Деньги.** Суммы — целые микроединицы (`1 000 000` = 1 ₽), рядом всегда `currency`.\nИтог запроса — фактический объём × цены сработавшего канала на момент приёма запроса.\nСписывается только успешный запрос и только после завершения; до этого `price` — `null`.\nЦена «от» и цены пресетов роутинга — в карточке модели. Запрос принимается, если баланса\nхватает на самый дешёвый канал с учётом запросов, которые ещё выполняются.\n\n**Каналы.** К модели можно обратиться через один или несколько каналов. Канал обозначен\nцветом (`red`, `orange`, …), цвет постоянен внутри модели и не переходит другому исполнению.\nСтавки, пределы, измеренные скорость и стабильность каждого цвета —\n`GET /v1/models/{id}/channels`; фактический цвет запроса — `channel` в ответе, задаче,\nвебхуке и истории. Цвет не означает класс цены или скорости: у разных моделей один цвет —\nразные исполнения.\n\n**Роутинг.** Без настроек канал выбирает Авто-роутинг по пресету (`routing`):\n`cheap` — «Дешевле», `balanced` — «Баланс» (по умолчанию), `fast` — «Быстрее». Пресет —\nпожелание: у модели может быть меньше каналов, чем пресетов, и запрос принимается всегда.\nЦена и типичное время пресета для параметров запроса — в карточке модели\n(`pricing.presets`). Канал не ответил — запрос переходит к следующему по порядку пресета;\nследующий канал может стоить дороже, и итог может превысить цену пресета. Потолок\n`max_price_multiplier` не даёт пробовать каналы дороже цены пресета больше чем во столько\nраз. Точнее управляет `routing_options` — настройки по цветам каналов: `only` — только\nэти цвета (`{\"only\": [\"blue\"]}` — всегда синий), `ignore` — кроме\nэтих, `order` — сначала эти по порядку, `allow_fallbacks: false` — без запасных каналов,\n`sort`, `max_price`, мягкие предпочтения скорости и закрепление диалога. Бесплатная\nпроверка настройки — `POST /v1/models/{id}/routing/preview`. Сколько раз запрос\nотправлялся каналам — `attempt_count` задачи.\n\n**Ключ управления.** Отдельный ключ из кабинета для агентов и скриптов, которые ведут\nаккаунт: баланс, история операций и запросов, расходы, обычные ключи и секрет вебхуков — ровно\nто, что его держатель видит и может в кабинете, с той же ролью и цифрами. Выдают его\nвладелец и администратор — себе. Модели он не запускает, а API-ключ\nне управляет аккаунтом: ключ не того вида — `403 forbidden` с `detail[].reason`\n`requires_api_key` или `requires_management_key`; участники, профиль и выпуск ключей\nуправления — только в кабинете (`cabinet_only`). Настройки аккаунта\n(`GET`/`PATCH /v1/settings`, в том числе закрепление канала), секрет вебхуков и его смена\nдоступны по ключу управления держателя с ролью разработчика или выше.\n\n**Ошибки.** Любая ошибка — `{\"error\": {\"type\", \"code\", \"message\", \"detail\"?}}`. `type`\nследует из HTTP-статуса, `code` — из закрытого словаря, `detail[]` называет поля запроса\n(`path` — как в запросе) и допустимые значения.\n",
    "summary": "Один API к моделям чата, картинок, видео, музыки, транскрибации и синтеза речи.",
    "title": "Souz API",
    "version": "2026-09-23"
  },
  "openapi": "3.1.1",
  "paths": {
    "/": {
      "get": {
        "description": "Индекс для агента, который знает только хост.",
        "operationId": "getIndex",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Index"
                }
              }
            },
            "description": "Индекс."
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          }
        },
        "security": [],
        "summary": "Где что лежит",
        "tags": [
          "docs"
        ]
      }
    },
    "/llms-full.txt": {
      "get": {
        "operationId": "getLLMsFullTxt",
        "responses": {
          "200": {
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Markdown."
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          }
        },
        "security": [],
        "summary": "Руководство и эта спецификация одним файлом",
        "tags": [
          "docs"
        ]
      }
    },
    "/llms.txt": {
      "get": {
        "operationId": "getLLMsTxt",
        "responses": {
          "200": {
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Markdown по llmstxt.org."
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          }
        },
        "security": [],
        "summary": "Короткий индекс для языковых моделей",
        "tags": [
          "docs"
        ]
      }
    },
    "/mcp": {
      "post": {
        "description": "Сервер Model Context Protocol, транспорт Streamable HTTP, версия протокола `2025-06-18`.\nМетоды: `initialize`, `ping`, `tools/list`, `tools/call`; уведомление (сообщение без\n`id`) — `202` без тела. Ответ всегда JSON, потока и сессий нет; `GET /mcp` — `405`.\n\nКаждый инструмент вызывает ту же ручку API, что описана здесь, с тем же заголовком\n`Authorization`: каталог, каналы и превью — без ключа, чат и задачи — API-ключ,\nнастройки каналов аккаунта — ключ управления. Отказ ручки (нет ключа, не тот ключ,\nбаланс) — `result.isError: true` с кодом ошибки API в `structuredContent.error`;\nошибка протокола (нет метода, неверные аргументы) — `error` JSON-RPC.\n",
        "operationId": "sendMCPMessage",
        "parameters": [
          {
            "description": "Версия протокола, согласованная в `initialize`: `2025-06-18`, `2025-03-26` или\n`2024-11-05`; без заголовка — `2025-03-26`. Другая — `400`.\n",
            "in": "header",
            "name": "MCP-Protocol-Version",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "examples": {
                "compare": {
                  "summary": "Сравнить каналы модели по стабильности",
                  "value": {
                    "id": 2,
                    "jsonrpc": "2.0",
                    "method": "tools/call",
                    "params": {
                      "arguments": {
                        "by": "stability",
                        "model": "gpt-5-nano"
                      },
                      "name": "compare_channels"
                    }
                  }
                },
                "tools": {
                  "summary": "Список инструментов",
                  "value": {
                    "id": 1,
                    "jsonrpc": "2.0",
                    "method": "tools/list"
                  }
                }
              },
              "schema": {
                "$ref": "#/components/schemas/MCPRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "examples": {
                  "ping": {
                    "value": {
                      "id": 1,
                      "jsonrpc": "2.0",
                      "result": {}
                    }
                  },
                  "unknown_method": {
                    "value": {
                      "error": {
                        "code": -32601,
                        "message": "method not found"
                      },
                      "id": 1,
                      "jsonrpc": "2.0"
                    }
                  }
                },
                "schema": {
                  "$ref": "#/components/schemas/MCPResponse"
                }
              }
            },
            "description": "Ответ JSON-RPC — `result` или `error`."
          },
          "202": {
            "description": "Уведомление или ответ клиента принят; тела нет."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Maintenance"
          }
        },
        "security": [
          {},
          {
            "BearerAuth": []
          },
          {
            "ManagementKey": []
          }
        ],
        "summary": "Сообщение MCP-серверу",
        "tags": [
          "mcp"
        ]
      }
    },
    "/openapi.json": {
      "get": {
        "operationId": "getOpenAPIJSON",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            },
            "description": "OpenAPI 3.1."
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          }
        },
        "security": [],
        "summary": "Эта спецификация (JSON)",
        "tags": [
          "docs"
        ]
      }
    },
    "/openapi.yaml": {
      "get": {
        "description": "Тот же документ, короче для языковых моделей.",
        "operationId": "getOpenAPIYAML",
        "responses": {
          "200": {
            "content": {
              "application/yaml": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OpenAPI 3.1."
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          }
        },
        "security": [],
        "summary": "Эта спецификация (YAML)",
        "tags": [
          "docs"
        ]
      }
    },
    "/v1/audio/generations": {
      "post": {
        "description": "Трек по описанию — с текстом песни, который напишет модель, со своим текстом (`lyrics`)\nили без вокала (`instrumental`). Ждёт результат и отвечает `200` с завершённой задачей:\nзвук — в `data[]`, у моделей, которые за один запрос дают два варианта трека, — оба, по\nпорядку. Не успело за 9 минут или прислан `Prefer: respond-async` — `202` с задачей в\nработе.\n\nЗадача, провалившаяся во время ожидания, отвечает статусом по причине (`400`\n`invalid_input`/`content_policy`/`capability_mismatch`, `502 generation_failed` или\n`unknown_error`, `503 model_unavailable`) и телом — объектом задачи с `error`.\n",
        "operationId": "createMusic",
        "parameters": [
          {
            "$ref": "#/components/parameters/Prefer"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "examples": {
                "instrumental": {
                  "summary": "Без вокала",
                  "value": {
                    "instrumental": true,
                    "model": "lyria-3-clip-preview",
                    "prompt": "Спокойный лоуфай на пианино для учёбы"
                  }
                },
                "lyrics": {
                  "summary": "Свой текст песни",
                  "value": {
                    "lyrics": "[Verse]\nУтро светит в окно, город ещё не проснулся\n[Chorus]\nСолнце, солнце, мы снова живём",
                    "model": "suno-v6",
                    "prompt": "инди-поп, женский вокал, 110 bpm",
                    "title": "Утро"
                  }
                },
                "song": {
                  "summary": "Песня, текст пишет модель",
                  "value": {
                    "model": "suno-v6",
                    "prompt": "Бодрый инди-поп о солнечном утре в городе, женский вокал"
                  }
                }
              },
              "schema": {
                "$ref": "#/components/schemas/MusicGenerationRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/JobCompleted"
          },
          "202": {
            "$ref": "#/components/responses/JobAccepted"
          },
          "400": {
            "$ref": "#/components/responses/JobOrError"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "$ref": "#/components/responses/JobOrError"
          },
          "503": {
            "$ref": "#/components/responses/JobOrError"
          }
        },
        "summary": "Сгенерировать музыку",
        "tags": [
          "audio"
        ]
      }
    },
    "/v1/audio/speech": {
      "post": {
        "description": "Текст в звук, результат сразу — как у SDK OpenAI: тело ответа — байты аудио, id задачи\n— в заголовке `X-Job-Id`. С `Accept: application/json` — объект задачи (звук в\n`data[0]`), с `Prefer: respond-async` — `202`.\n",
        "operationId": "createSpeech",
        "parameters": [
          {
            "$ref": "#/components/parameters/Prefer"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "examples": {
                "dialogue": {
                  "value": {
                    "dialogue": [
                      {
                        "text": "Ты готов?",
                        "voice": "Kore"
                      },
                      {
                        "text": "Почти. [sighs] Дай мне минуту.",
                        "voice": "Charon"
                      }
                    ],
                    "instructions": "Спокойный вечерний разговор, говорят негромко.",
                    "model": "gemini-3.1-flash-tts-preview"
                  }
                },
                "simple": {
                  "value": {
                    "input": "Добро пожаловать в СОЮЗ.",
                    "model": "qwen-audio-3.0-tts-plus",
                    "voice": "longanlingxin"
                  }
                }
              },
              "schema": {
                "$ref": "#/components/schemas/SpeechRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              },
              "audio/mpeg": {
                "schema": {
                  "contentMediaType": "audio/mpeg",
                  "description": "MP3 — у моделей, чей формат звука mp3.",
                  "type": "string"
                }
              },
              "audio/wav": {
                "schema": {
                  "contentMediaType": "audio/wav",
                  "description": "WAV — у моделей, чей формат звука wav.",
                  "type": "string"
                }
              },
              "text/event-stream": {
                "schema": {
                  "$ref": "#/components/schemas/SpeechStreamEvent"
                }
              }
            },
            "description": "Звук (по умолчанию) или объект задачи (`Accept: application/json`).",
            "headers": {
              "X-Job-Id": {
                "$ref": "#/components/headers/JobId"
              }
            }
          },
          "202": {
            "$ref": "#/components/responses/JobAccepted"
          },
          "400": {
            "$ref": "#/components/responses/JobOrError"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "$ref": "#/components/responses/JobOrError"
          },
          "503": {
            "$ref": "#/components/responses/JobOrError"
          }
        },
        "summary": "Озвучить текст",
        "tags": [
          "audio"
        ]
      }
    },
    "/v1/audio/transcriptions": {
      "post": {
        "description": "Звук в текст, результат сразу. `response_format`: `json` (по умолчанию) и\n`verbose_json` — объект задачи (надмножество ответа OpenAI: `text`, `language` — если он\nизвестен, `duration`, `segments` и `words` — если модель даёт таймкоды); `text` и `srt` — текст, id\nзадачи — в заголовке `X-Job-Id`. `srt` — у моделей, чья карточка его объявляет. Присланный файл сохраняется как загрузка аккаунта (`GET /v1/files`).\n",
        "operationId": "createTranscription",
        "parameters": [
          {
            "$ref": "#/components/parameters/Prefer"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "encoding": {
                "file": {
                  "contentType": "audio/*"
                }
              },
              "schema": {
                "$ref": "#/components/schemas/TranscriptionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              },
              "text/event-stream": {
                "schema": {
                  "$ref": "#/components/schemas/TranscriptionStreamEvent"
                }
              },
              "text/plain": {
                "schema": {
                  "description": "Текст (`response_format=text`) или субтитры SRT (`response_format=srt`).",
                  "type": "string"
                }
              }
            },
            "description": "Расшифровка.",
            "headers": {
              "X-Job-Id": {
                "$ref": "#/components/headers/JobId"
              }
            }
          },
          "202": {
            "$ref": "#/components/responses/JobAccepted"
          },
          "400": {
            "$ref": "#/components/responses/JobOrError"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "$ref": "#/components/responses/JobOrError"
          },
          "503": {
            "$ref": "#/components/responses/JobOrError"
          }
        },
        "summary": "Расшифровать звук",
        "tags": [
          "audio"
        ]
      }
    },
    "/v1/auth/me": {
      "get": {
        "description": "Текущий участник: id участника (не аккаунта), почта и/или username Telegram, имя,\nкартинка, роль, собственный лимит трат с расходом и остатком (`spend_limit`) и аккаунт\n(id, название и номер). С ключом управления — его держатель: та же роль и тот же лимит, что в\nкабинете. Ответ не кешируется (`Cache-Control: private, no-store`).",
        "operationId": "getMe",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeResponse"
                }
              }
            },
            "description": "OK"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "ManagementKey": []
          },
          {
            "ClientSession": []
          }
        ],
        "summary": "Кто я",
        "tags": [
          "account"
        ]
      }
    },
    "/v1/balance": {
      "get": {
        "description": "Зачисленные средства за вычетом списаний за завершённые запросы, в микроединицах валюты из поля currency; не меньше нуля. Превышение расчётной цены запроса над остатком покрывает Союз. У аккаунта без баланса (has_balance: false в /v1/auth/me) — 403 account_without_balance.",
        "operationId": "getBalance",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BalanceResponse"
                }
              }
            },
            "description": "OK"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "ManagementKey": []
          },
          {
            "ClientSession": []
          }
        ],
        "summary": "Баланс аккаунта",
        "tags": [
          "account"
        ]
      }
    },
    "/v1/balance/history": {
      "get": {
        "description": "Пополнения, списания за завершённые запросы, возвраты остатка и отмены начислений, новые первыми, прямо из журнала операций. У пополнения source: payment — оплата, bonus — бонус; у бонуса от службы поддержки — label (бонус к пополнению, компенсация за запрос, бонус). Списание — одно на успешный запрос, по фактической цене; провалившийся запрос не стоит ничего. Возврат остатка (refund) отмечает служба поддержки, когда вернула остаток по обращению клиента; он уменьшает баланс. Отмена (reversal) — служба поддержки отменила начисление или его часть; она уменьшает баланс, у пополнения растёт topup.reversed_micro. Страницы — по курсору: next_before из ответа передаётся в before следующего запроса, пока он не станет null. kind оставляет один вид операций. У аккаунта без баланса (has_balance: false в /v1/auth/me) — 403 account_without_balance.",
        "operationId": "listBalanceHistory",
        "parameters": [
          {
            "description": "По умолчанию 100, максимум 1000",
            "in": "query",
            "name": "limit",
            "schema": {
              "type": "integer"
            }
          },
          {
            "description": "Один вид операций; по умолчанию все",
            "in": "query",
            "name": "kind",
            "schema": {
              "$ref": "#/components/schemas/BalanceOperationKind"
            }
          },
          {
            "description": "Курсор next_before предыдущей страницы",
            "in": "query",
            "name": "before",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BalanceHistoryResponse"
                }
              }
            },
            "description": "OK"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "ManagementKey": []
          },
          {
            "ClientSession": []
          }
        ],
        "summary": "История операций по балансу",
        "tags": [
          "account"
        ]
      }
    },
    "/v1/channels": {
      "get": {
        "description": "Все цвета каналов — идентификатор, название и HEX, включая закрытые каналы. Нужна, чтобы\nпоказать в своём интерфейсе название и цвет `channel` из ответа и истории. Каналы\nконкретной модели — `GET /v1/models/{id}/channels`; один цвет у разных моделей — разные\nканалы. `Cache-Control: public, max-age=3600` и `ETag`: с `If-None-Match` — `304`.\n",
        "operationId": "listChannelPalette",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChannelPalette"
                }
              }
            },
            "description": "Палитра."
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [],
        "summary": "Палитра цветов каналов",
        "tags": [
          "models"
        ]
      }
    },
    "/v1/chat/completions": {
      "post": {
        "description": "Контракт OpenAI Chat Completions. Поля, которых нет в схеме, передаются модели как есть;\nчто модель читает — её карточка (`params`, `capabilities`). С `\"stream\": true` ответ —\n`text/event-stream`: чанки `chat.completion.chunk`, у каждого есть `choices[0]`; с\n`stream_options.include_usage` последний чанк — пустой `choices` и `usage` с `cost`; в\nконце `data: [DONE]`.\n\nЕсли исход вызова установить нельзя (модель не ответила вовремя, поток оборвался до\nитога), ответ — `502 generation_failed`, ничего не списано. Неизвестная ошибка —\n`502 unknown_error`, тоже без списания. Обрыв соединения с вашей\nстороны вызов не отменяет: ответ дочитывается и списывается по факту — итог виден в\n`GET /v1/jobs/{id}` по `id` ответа. Повтор с тем же `Idempotency-Key` и тем же телом\nдожидается первого вызова и получает его ответ без второго списания; тот же ключ с\nдругим телом — `409`.\n",
        "operationId": "createChatCompletion",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "examples": {
                "simple": {
                  "summary": "Один вопрос",
                  "value": {
                    "messages": [
                      {
                        "content": "Привет!",
                        "role": "user"
                      }
                    ],
                    "model": "gpt-5-nano"
                  }
                }
              },
              "schema": {
                "$ref": "#/components/schemas/ChatCompletionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "examples": {
                  "answer": {
                    "value": {
                      "choices": [
                        {
                          "finish_reason": "stop",
                          "index": 0,
                          "message": {
                            "content": "Привет! Чем помочь?",
                            "role": "assistant"
                          }
                        }
                      ],
                      "created": 1758801600,
                      "id": "chatcmpl-1a2b3c4d5e6f",
                      "model": "gpt-5-nano",
                      "object": "chat.completion",
                      "usage": {
                        "completion_tokens": 24,
                        "cost": 3000,
                        "currency": "RUB",
                        "prompt_tokens": 10,
                        "total_tokens": 34
                      }
                    }
                  }
                },
                "schema": {
                  "$ref": "#/components/schemas/ChatCompletion"
                }
              },
              "text/event-stream": {
                "schema": {
                  "$ref": "#/components/schemas/ChatCompletionChunk"
                }
              }
            },
            "description": "Ответ модели целиком или потоком."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "$ref": "#/components/responses/GenerationFailed"
          },
          "503": {
            "$ref": "#/components/responses/ModelUnavailable"
          }
        },
        "summary": "Ответ чат-модели",
        "tags": [
          "chat"
        ]
      }
    },
    "/v1/files": {
      "get": {
        "description": "Новые сверху; удалённые и истёкшие — с `expired: true` и без `url`.",
        "operationId": "listFiles",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/After"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileList"
                }
              }
            },
            "description": "Страница списка."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "summary": "Файлы аккаунта",
        "tags": [
          "files"
        ]
      },
      "post": {
        "description": "Референс для генераций: картинка (`png`/`jpeg`/`webp`, до 50 МиБ, JPEG до 300 Мп), ролик\n(`mp4`/`mov`, до 200 МиБ), звук (`wav`/`mp3`, до 15 МиБ). Полученный `file_…`\nподставляется в поля запросов вместо байтов. Файл живёт 1 день. Тяжёлые\nкартинки-референсы загружайте так заранее: тело запроса генерации остаётся маленьким, и\nзапрос принимается сразу. Загрузки аккаунта, срок которых ещё не вышел, — не больше\n10 ГБ, после первого пополнения — не больше 50 ГБ; сверх — `413 storage_limit_exceeded`.\nФайлы, присланные в самом запросе, в квоту не входят.\n",
        "operationId": "uploadFile",
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/FileUploadRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/File"
                }
              }
            },
            "description": "Файл сохранён."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Overloaded"
          }
        },
        "summary": "Загрузить файл",
        "tags": [
          "files"
        ]
      }
    },
    "/v1/files/{id}": {
      "delete": {
        "description": "Досрочно; ссылка после этого отвечает `410`.",
        "operationId": "deleteFile",
        "parameters": [
          {
            "$ref": "#/components/parameters/FileId"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileDeleted"
                }
              }
            },
            "description": "Файл удалён."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Maintenance"
          }
        },
        "summary": "Удалить файл",
        "tags": [
          "files"
        ]
      },
      "get": {
        "operationId": "getFile",
        "parameters": [
          {
            "$ref": "#/components/parameters/FileId"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/File"
                }
              }
            },
            "description": "Описание файла."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "summary": "Файл по id",
        "tags": [
          "files"
        ]
      }
    },
    "/v1/files/{id}/{filename}": {
      "get": {
        "description": "Ссылка из `url` файла; ключ не нужен — подпись и есть авторизация. Работают `HEAD`,\n`Range`, `If-None-Match`; `?download=1` отдаёт как вложение. Хост — `media.souz.ai`,\nCORS `*`: файл можно встраивать на любые страницы.\n",
        "operationId": "downloadFile",
        "parameters": [
          {
            "$ref": "#/components/parameters/FileId"
          },
          {
            "in": "path",
            "name": "filename",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "До какого момента (unix-секунды) действует ссылка.",
            "in": "query",
            "name": "exp",
            "required": true,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          },
          {
            "description": "Подпись ссылки.",
            "in": "query",
            "name": "sig",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "`1` — отдать как вложение (`Content-Disposition: attachment`).",
            "in": "query",
            "name": "download",
            "required": false,
            "schema": {
              "enum": [
                "1"
              ],
              "type": "string"
            }
          },
          {
            "description": "Часть файла, `bytes=начало-конец` — ответ `206`.",
            "in": "header",
            "name": "Range",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              },
              "application/octet-stream": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              },
              "audio/mpeg": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              },
              "audio/wav": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              },
              "image/jpeg": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              },
              "image/png": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              },
              "image/webp": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              },
              "video/mp4": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              },
              "video/quicktime": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              }
            },
            "description": "Байты файла; тип — тот, что в `content_type` файла."
          },
          "206": {
            "content": {
              "application/json": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              },
              "application/octet-stream": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              },
              "audio/mpeg": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              },
              "audio/wav": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              },
              "image/jpeg": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              },
              "image/png": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              },
              "image/webp": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              },
              "video/mp4": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              },
              "video/quicktime": {
                "schema": {
                  "format": "binary",
                  "type": "string"
                }
              }
            },
            "description": "Запрошенный `Range`."
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "410": {
            "$ref": "#/components/responses/Gone"
          }
        },
        "security": [],
        "summary": "Байты файла по подписанной ссылке",
        "tags": [
          "files"
        ]
      }
    },
    "/v1/images/generations": {
      "post": {
        "description": "Ждёт результат и отвечает `200` с завершённой задачей — это же ответ `images.generate`\nSDK OpenAI (`created`, `data[].url`, `data[].b64_json`). Не успело за 9 минут или прислан\n`Prefer: respond-async` — `202` с задачей в работе.\n\nЗадача, провалившаяся во время ожидания, отвечает статусом по причине (`400`\n`invalid_input`/`content_policy`/`capability_mismatch`, `502 generation_failed` или\n`unknown_error`, `503 model_unavailable`) и телом — объектом задачи с `error`.\n",
        "operationId": "createImage",
        "parameters": [
          {
            "$ref": "#/components/parameters/Prefer"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "examples": {
                "minimal": {
                  "summary": "Только обязательное",
                  "value": {
                    "model": "nano-banana-pro",
                    "prompt": "Кот-космонавт на Луне"
                  }
                },
                "openai": {
                  "summary": "Поля SDK OpenAI",
                  "value": {
                    "model": "nano-banana-pro",
                    "n": 1,
                    "prompt": "Кот-космонавт на Луне",
                    "response_format": "b64_json",
                    "size": "1024x1024"
                  }
                }
              },
              "schema": {
                "$ref": "#/components/schemas/ImageGenerationRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              },
              "text/event-stream": {
                "schema": {
                  "$ref": "#/components/schemas/ImageGenerationStreamEvent"
                }
              }
            },
            "description": "Задача завершена, результат в `data`; с `stream:true` — поток событий."
          },
          "202": {
            "$ref": "#/components/responses/JobAccepted"
          },
          "400": {
            "$ref": "#/components/responses/JobOrError"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "$ref": "#/components/responses/JobOrError"
          },
          "503": {
            "$ref": "#/components/responses/JobOrError"
          }
        },
        "summary": "Сгенерировать картинку",
        "tags": [
          "images"
        ]
      }
    },
    "/v1/jobs/{id}": {
      "get": {
        "description": "Текущее состояние любой задачи — и ответа чата по его `chatcmpl-…` (итог и цена, без\nтекста). Опрашивать не чаще `Retry-After` из ответа `202`.\n",
        "operationId": "getJob",
        "parameters": [
          {
            "$ref": "#/components/parameters/JobId"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/JobOK"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "summary": "Задача по id",
        "tags": [
          "jobs"
        ]
      }
    },
    "/v1/jobs/{id}/events": {
      "get": {
        "description": "`text/event-stream`: первым событием — текущее состояние, дальше — новый снимок при\nкаждом изменении, в конце `data: [DONE]`; к завершённой задаче — снимок и сразу\n`[DONE]`. Раз в 15 с — комментарий `: ping`. Переподключаться можно в любой момент.\nСхема ниже описывает одно событие `data:` — объект задачи.\n",
        "operationId": "streamJobEvents",
        "parameters": [
          {
            "$ref": "#/components/parameters/JobId"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "text/event-stream": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            },
            "description": "Поток снимков задачи."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "summary": "Поток событий задачи",
        "tags": [
          "jobs"
        ]
      }
    },
    "/v1/key": {
      "get": {
        "description": "Сам ключ: его потолок трат (`spend_limit`), как потолок обновляется\n(`spend_limit_reset`) и сколько потрачено (`spent`), пресет роутинга и потолок цены по\nумолчанию и сроки хранения — то, что агенту полезно знать до первого запроса. Баланс и история аккаунта —\n`GET /v1/balance` и `GET /v1/balance/history` ключом управления (тег `account`); не\nхватает баланса или исчерпан лимит — запрос получит `402`. Ключи создаются и\nнастраиваются в кабинете или ключом управления.\n",
        "operationId": "getKey",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIKey"
                }
              }
            },
            "description": "Ключ."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "summary": "Ключ, которым сделан запрос",
        "tags": [
          "key"
        ]
      }
    },
    "/v1/keys": {
      "get": {
        "description": "Ключи аккаунта, новые первыми: без секретов, с подсказкой секрета (secret_hint), автором (created_by), держателем (member), потолком и периодом его сброса; spent_micro — расход в текущем окне потолка. Владелец, администратор и наблюдатель видят все ключи, разработчик — только свои. Ключи управления — в том же списке, kind: management.",
        "operationId": "listAPIKeys",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIKeysResponse"
                }
              }
            },
            "description": "OK"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "ManagementKey": []
          },
          {
            "ClientSession": []
          }
        ],
        "summary": "Список своих API-ключей",
        "tags": [
          "account"
        ]
      },
      "post": {
        "description": "Возвращает сырой ключ; он же сохраняется в зашифрованном виде, и автор может получить его снова через GET /v1/keys/{id}/secret. Ключ создаёт участник, который вызывает метод (через ключ управления — его держатель), и он же держатель: траты ключа идут в его лимит, при его удалении ключ отзывается. Необязательно: spend_limit_micro и spend_limit_reset (none | daily | monthly) — потолок трат ключа сразу при создании. Разработчик и выше. kind: management — ключ управления: создают владелец и администратор и только в кабинете (ключом управления — 403 cabinet_only); потолка трат у него нет — он не тратит.",
        "operationId": "createAPIKey",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAPIKeyRequest"
              }
            }
          },
          "description": "Имя и потолок — все поля необязательны",
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateAPIKeyResponse"
                }
              }
            },
            "description": "Created"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Maintenance"
          }
        },
        "security": [
          {
            "ManagementKey": []
          },
          {
            "ClientSession": []
          }
        ],
        "summary": "Создать API-ключ",
        "tags": [
          "account"
        ]
      }
    },
    "/v1/keys/{id}": {
      "delete": {
        "description": "Ключ перестаёт работать сразу и навсегда. Разработчик — только свои ключи (чужой — 404), администратор и владелец — любые. Ключ управления отзывается только в кабинете.",
        "operationId": "revokeAPIKey",
        "parameters": [
          {
            "description": "Id ключа",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Maintenance"
          }
        },
        "security": [
          {
            "ManagementKey": []
          },
          {
            "ClientSession": []
          }
        ],
        "summary": "Отозвать свой API-ключ",
        "tags": [
          "account"
        ]
      },
      "patch": {
        "description": "Полная замена редактируемых полей — null у spend_limit_micro/expires_at снимает ограничение, пропущенный spend_limit_reset — none. Держатель ключа не меняется. Разработчик — только свои ключи (чужой — 404), администратор и владелец — любые. Разработчик и выше. Ключ управления не меняется: его отзывают и создают новый.",
        "operationId": "updateAPIKey",
        "parameters": [
          {
            "description": "Id ключа",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAPIKeyRequest"
              }
            }
          },
          "description": "Новые значения",
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/APIKeyEntry"
                }
              }
            },
            "description": "OK"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Maintenance"
          }
        },
        "security": [
          {
            "ManagementKey": []
          },
          {
            "ClientSession": []
          }
        ],
        "summary": "Изменить свой API-ключ",
        "tags": [
          "account"
        ]
      }
    },
    "/v1/keys/{id}/secret": {
      "get": {
        "description": "Отдаёт сырой ключ, чтобы скопировать его повторно, — только автору ключа (created_by), в кабинете или его ключом управления. Остальным — 403 с detail[].reason not_key_author; разработчику чужой ключ — 404, как несуществующий; наблюдателю — 403 по роли. Секрет, который показать нельзя, — 409 secret_unavailable: создайте новый ключ. Секрет ключа управления — только в кабинете.",
        "operationId": "revealAPIKey",
        "parameters": [
          {
            "description": "Id ключа",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RevealAPIKeyResponse"
                }
              }
            },
            "description": "OK"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "ManagementKey": []
          },
          {
            "ClientSession": []
          }
        ],
        "summary": "Секрет своего API-ключа",
        "tags": [
          "account"
        ]
      }
    },
    "/v1/models": {
      "get": {
        "description": "Совместим с `models.list` SDK OpenAI. У каждой модели — итоги статистики за 7 дней\n(`stats_7d`), почасовой ряд — в `GET /v1/models/{id}/stats`; итоги обновляются раз в час.\nГостевой ответ — `Cache-Control: public, max-age=30, stale-while-revalidate=300` и `ETag`:\nс `If-None-Match` того же `ETag` — `304` без тела. С авторизацией возвращает цены текущего\nаккаунта; такой ответ — `Cache-Control: private, no-cache` с тем же `ETag`.\n",
        "operationId": "listModels",
        "parameters": [
          {
            "description": "Только модели этой модальности.",
            "in": "query",
            "name": "modality",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/Modality"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModelList"
                }
              }
            },
            "description": "Все модели каталога."
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {},
          {
            "BearerAuth": []
          },
          {
            "ManagementKey": []
          },
          {
            "ClientSession": []
          }
        ],
        "summary": "Каталог моделей",
        "tags": [
          "models"
        ]
      }
    },
    "/v1/models/{id}": {
      "get": {
        "description": "Что модель принимает (`input_schema`, `params`, `rules`), сколько стоит «от»\n(`pricing`), пределы и возможности. Стройте запрос по карточке, а не по памяти.\nКеширование — как у `GET /v1/models`. С авторизацией возвращает цены текущего аккаунта;\nтакой ответ — `Cache-Control: private, no-cache`.\n",
        "operationId": "getModel",
        "parameters": [
          {
            "$ref": "#/components/parameters/ModelId"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Model"
                }
              }
            },
            "description": "Карточка."
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {},
          {
            "BearerAuth": []
          },
          {
            "ManagementKey": []
          },
          {
            "ClientSession": []
          }
        ],
        "summary": "Карточка модели",
        "tags": [
          "models"
        ]
      }
    },
    "/v1/models/{id}/channels": {
      "get": {
        "description": "Каналы, через которые сейчас можно обратиться к модели: постоянный цвет, базовые ставки,\nпределы, измерения последнего часа и история стабильности за 7 дней (`history`). Канал,\nзакрытый навсегда, здесь не показывается; его цвет остаётся в истории запросов, название\nи HEX — в `GET /v1/channels`. Для конкретных параметров используйте предварительный план.\nКеширование — как у `GET /v1/models`. С авторизацией возвращает цены текущего аккаунта;\nтакой ответ — `Cache-Control: private, no-cache`.\n",
        "operationId": "getModelChannels",
        "parameters": [
          {
            "$ref": "#/components/parameters/ModelId"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModelChannels"
                }
              }
            },
            "description": "Каналы."
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {},
          {
            "BearerAuth": []
          },
          {
            "ManagementKey": []
          },
          {
            "ClientSession": []
          }
        ],
        "summary": "Цветовые каналы модели",
        "tags": [
          "models"
        ]
      }
    },
    "/v1/models/{id}/routing/preview": {
      "post": {
        "description": "Проверяет параметры и настройки выбора без создания платного запроса. Настройки роутинга аккаунта и закреплённые диалоги не используются: передайте нужные настройки явно. Отказ — тем же конвертом, что у запуска: `capability_mismatch` или `invalid_request` с `detail[]` (`path`, `reason`, `allowed`); путь параметра из `params` — как в запросе запуска.",
        "operationId": "previewModelRouting",
        "parameters": [
          {
            "$ref": "#/components/parameters/ModelId"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RoutingPreviewRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RoutingPreview"
                }
              }
            },
            "description": "Предварительный план."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {},
          {
            "BearerAuth": []
          },
          {
            "ManagementKey": []
          },
          {
            "ClientSession": []
          }
        ],
        "summary": "Предварительный выбор каналов",
        "tags": [
          "models"
        ]
      }
    },
    "/v1/models/{id}/stats": {
      "get": {
        "description": "Как модель работала последние 7 дней по запросам всех клиентов: число запросов, доля\nуспешных, медиана и p95 времени ответа — за окно и по часам (168 точек), а в `speed` —\nскорость каждой опции пресетов роутинга по 6 часов. Время ответа — по успешным\nзапросам, медиана и p95 округлены (±10 %). Помогает выбрать модель и понять, почему\nзапросы идут медленно; ускорить — пресет роутинга `balanced` или `fast` (быстрые\nканалы обычно дороже — см. схему `Routing`). `ETag` и `Cache-Control` на каждом\nответе.\n",
        "operationId": "getModelStats",
        "parameters": [
          {
            "$ref": "#/components/parameters/ModelId"
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModelStats"
                }
              }
            },
            "description": "Статистика."
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [],
        "summary": "Статистика модели за 7 дней",
        "tags": [
          "models"
        ]
      }
    },
    "/v1/settings": {
      "get": {
        "description": "Умолчания для всех ключей аккаунта, включая встроенный ключ плейграунда: пресет роутинга\n(`routing`), потолок цены (`max_price_multiplier`), настройки каналов по моделям\n(`routing_options`), адрес вебхука по умолчанию (`webhook.url` — задача без своего\n`callback_url` стучится сюда) и режим без хранения (`no_store`, по умолчанию\nвыключен). Поля запроса перекрывают их на один вызов. Своих настроек у\nключей нет; обычный API-ключ видит действующие умолчания в `GET /v1/key`. Доступно\nключу управления и сессии кабинета любого участника.\n",
        "operationId": "getSettings",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountSettingsResponse"
                }
              }
            },
            "description": "OK"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "ManagementKey": []
          },
          {
            "ClientSession": []
          }
        ],
        "summary": "Настройки аккаунта",
        "tags": [
          "account"
        ]
      },
      "patch": {
        "description": "Каждое поле необязательно; отсутствующее не меняется. `routing` — `cheap`, `balanced` или\n`fast`. `max_price_multiplier` — 1.5, 2, 3, 5 или 10; `null` снимает потолок. `webhook.url`\n— абсолютный https-адрес на публичный хост (та же проверка, что у `callback_url`), `null`\nили пустая строка снимает адрес. `no_store` — `true` или `false`.\n\n`routing_options` — словарь целиком: PATCH заменяет весь сохранённый словарь, поэтому\nсначала прочитайте его (`GET /v1/settings`), добавьте или измените ключ своей модели и\nотправьте словарь обратно; `null` очищает его. Ключ — существующая модель или `*`; каждый\nцвет в `only`/`ignore`/`order` — канал этой модели из `GET /v1/models/{id}/channels`. Так\nагент закрепляет выбранный цвет для всего аккаунта:\n`{\"routing_options\": {\"gpt-5-nano\": {\"only\": [\"blue\"]}}}`.\n\nНеверное значение — `400` со списком допустимых или с путём поля\n(`routing_options.\u003cмодель\u003e.only[0]`); ничего не меняется. Нужен ключ управления или сессия\nучастника с ролью разработчика или выше. Отвечает полными настройками после изменения.\n",
        "operationId": "updateSettings",
        "requestBody": {
          "content": {
            "application/json": {
              "examples": {
                "pin": {
                  "summary": "Закрепить синий канал модели для аккаунта",
                  "value": {
                    "routing_options": {
                      "gpt-5-nano": {
                        "only": [
                          "blue"
                        ]
                      }
                    }
                  }
                }
              },
              "schema": {
                "$ref": "#/components/schemas/AccountSettingsPatch"
              }
            }
          },
          "description": "Что изменить",
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountSettingsResponse"
                }
              }
            },
            "description": "OK"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Maintenance"
          }
        },
        "security": [
          {
            "ManagementKey": []
          },
          {
            "ClientSession": []
          }
        ],
        "summary": "Изменить настройки аккаунта",
        "tags": [
          "account"
        ]
      }
    },
    "/v1/status": {
      "get": {
        "description": "Без ключа. `ok` — сервис работает; `maintenance` — плановые работы: новые запросы\n(`POST`, `PUT`, `PATCH`, `DELETE`) до `ends_at` получают `503 maintenance`, принятые\nзадачи доделываются после, чтение и опрос задач работают. Отвечает и тогда, когда сам\nAPI остановлен на время работ.\n",
        "operationId": "getServiceStatus",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "examples": {
                  "maintenance": {
                    "value": {
                      "ends_at": "2026-10-04T14:15:00+03:00",
                      "reason": "Обновление сервиса",
                      "started_at": "2026-10-04T14:00:00+03:00",
                      "status": "maintenance"
                    }
                  },
                  "ok": {
                    "value": {
                      "status": "ok"
                    }
                  }
                },
                "schema": {
                  "$ref": "#/components/schemas/ServiceStatus"
                }
              }
            },
            "description": "Состояние; не кешируется (`Cache-Control: no-store`)."
          },
          "503": {
            "content": {
              "application/json": {
                "examples": {
                  "unavailable": {
                    "value": {
                      "status": "unavailable"
                    }
                  }
                },
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/ServiceStatus"
                    },
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ]
                }
              }
            },
            "description": "Сервис не отвечает, а плановых работ нет — `{\"status\": \"unavailable\"}`: сбой, мы\nуже чиним; повторите позже.\n"
          }
        },
        "security": [],
        "summary": "Идут ли плановые работы",
        "tags": [
          "status"
        ]
      }
    },
    "/v1/usage": {
      "get": {
        "description": "Страница истории запросов, новые первыми; фильтры и страницы — на сервере. since ограничивает период снизу, status, modality, model и api_key_id оставляют одно значение, q — точный id запроса (job_…, chatcmpl-…) или ключ идемпотентности; фильтры действуют вместе. Модель без запросов, чужой или несуществующий ключ — пустая страница, а не ошибка. Страницы — по курсору: next_before из ответа передаётся в before, пока он не станет null. Разработчик видит только запросы по выданным ему ключам (включая его ключ плейграунда), остальные роли — все запросы аккаунта. Итоги и график периода — GET /v1/usage/summary.",
        "operationId": "listUsage",
        "parameters": [
          {
            "description": "По умолчанию 100, максимум 1000",
            "in": "query",
            "name": "limit",
            "schema": {
              "maximum": 1000,
              "minimum": 1,
              "type": "integer"
            }
          },
          {
            "description": "Нижняя граница периода, RFC3339",
            "in": "query",
            "name": "since",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "description": "Курсор next_before предыдущей страницы",
            "in": "query",
            "name": "before",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Только запросы в этом статусе",
            "in": "query",
            "name": "status",
            "schema": {
              "$ref": "#/components/schemas/UsageStatus"
            }
          },
          {
            "description": "Только запросы этой модальности",
            "in": "query",
            "name": "modality",
            "schema": {
              "$ref": "#/components/schemas/Modality"
            }
          },
          {
            "description": "Только запросы к этой модели — её id, как canonical_model у строки истории",
            "in": "query",
            "name": "model",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Только запросы по этому ключу — его id (key_…), как api_key_id у строки истории",
            "in": "query",
            "name": "api_key_id",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Точный id запроса (job_…, chatcmpl-…) или ключ идемпотентности",
            "in": "query",
            "name": "q",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Только запросы из плейграунда (ключом плейграунда)",
            "in": "query",
            "name": "source",
            "schema": {
              "enum": [
                "playground"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UsageResponse"
                }
              }
            },
            "description": "OK"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "ManagementKey": []
          },
          {
            "ClientSession": []
          }
        ],
        "summary": "Свои запросы",
        "tags": [
          "account"
        ]
      }
    },
    "/v1/usage/summary": {
      "get": {
        "description": "Расход за период + ряд по дням (у каждого дня — разрез по моделям by_model) + топ моделей по расходу. Только завершённые запросы и их списания, по дню завершения (UTC); суммы — в микроединицах валюты из поля currency. С bucket=hour ряд — по часам завершения (UTC) за последние days × 24 часа, включая текущий час, в поле hourly; итоги и топ моделей — за те же часы. Не пагинировано — для детальной таблицы см. GET /v1/usage.",
        "operationId": "listUsageSummary",
        "parameters": [
          {
            "description": "Период в днях назад, по умолчанию 30, максимум 365; с bucket=hour — по умолчанию 1, максимум 2",
            "in": "query",
            "name": "days",
            "schema": {
              "type": "integer"
            }
          },
          {
            "description": "Шаг ряда — day (по умолчанию) или hour. Ряд по часам — только за окно до 48 часов (days не больше 2), иначе 400",
            "in": "query",
            "name": "bucket",
            "schema": {
              "enum": [
                "day",
                "hour"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UsageSummaryResponse"
                }
              }
            },
            "description": "OK"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "ManagementKey": []
          },
          {
            "ClientSession": []
          }
        ],
        "summary": "Сводная аналитика использования",
        "tags": [
          "account"
        ]
      }
    },
    "/v1/usage/{id}": {
      "get": {
        "description": "Итог запроса: цена `price`, параметры генерации, подписанная ссылка на результат и ошибка — что применимо. У чат-задач ещё и content: что ушло в модель и что она ответила (хранится до `retention.chat_content_days` дней из GET /v1/key; нет поля — содержимого нет). Читается и обычным API-ключом — только запросы, отправленные этим ключом, без предела частоты. Разработчику доступны только запросы по его ключам. Чужой id отвечает 404.",
        "operationId": "getUsageJob",
        "parameters": [
          {
            "description": "Id запроса — `job_…` или, у чата, `chatcmpl-…` из его ответа.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobDetailResponse"
                }
              }
            },
            "description": "OK"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "BearerAuth": []
          },
          {
            "ManagementKey": []
          },
          {
            "ClientSession": []
          }
        ],
        "summary": "Детали своего запроса",
        "tags": [
          "account"
        ]
      }
    },
    "/v1/videos": {
      "post": {
        "description": "Ролик — минуты, поэтому ответ всегда `202` с задачей в работе. Результат —\n`GET /v1/jobs/{id}` (или `GET /v1/videos/{id}`), поток событий или вебхук.\n",
        "operationId": "createVideo",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "examples": {
                "text_to_video": {
                  "summary": "Из текста, с вебхуком",
                  "value": {
                    "callback_url": "https://example.com/hooks/souz",
                    "duration_seconds": 5,
                    "model": "seedance-2",
                    "prompt": "Рассвет над морем, камера медленно поднимается"
                  }
                }
              },
              "schema": {
                "$ref": "#/components/schemas/VideoGenerationRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/VideoGenerationForm"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "$ref": "#/components/responses/JobAccepted"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/ModelUnavailable"
          }
        },
        "summary": "Сгенерировать видео",
        "tags": [
          "videos"
        ]
      }
    },
    "/v1/videos/{id}": {
      "get": {
        "description": "То же, что `GET /v1/jobs/{id}`, — по пути SDK OpenAI.",
        "operationId": "getVideo",
        "parameters": [
          {
            "$ref": "#/components/parameters/JobId"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/JobOK"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "summary": "Видео-задача по id",
        "tags": [
          "videos"
        ]
      }
    },
    "/v1/webhooks/secret": {
      "get": {
        "description": "Один на аккаунт; выдаётся при первом обращении. Нужен ключ управления\nили сессия кабинета участника с ролью разработчика или выше. Обычный\nAPI-ключ получает 403.\n",
        "operationId": "getWebhookSecret",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookSecret"
                }
              }
            },
            "description": "Секрет."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "ManagementKey": []
          },
          {
            "ClientSession": []
          }
        ],
        "summary": "Секрет подписи вебхуков",
        "tags": [
          "webhooks"
        ]
      }
    },
    "/v1/webhooks/secret/rotate": {
      "post": {
        "description": "Следующие доставки подписываются уже новым секретом. Нужен ключ управления\nили сессия кабинета участника с ролью разработчика или выше. Обычный\nAPI-ключ получает 403.\n",
        "operationId": "rotateWebhookSecret",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookSecret"
                }
              }
            },
            "description": "Новый секрет."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Maintenance"
          }
        },
        "security": [
          {
            "ManagementKey": []
          },
          {
            "ClientSession": []
          }
        ],
        "summary": "Выпустить новый секрет",
        "tags": [
          "webhooks"
        ]
      }
    }
  },
  "security": [
    {
      "BearerAuth": []
    }
  ],
  "servers": [
    {
      "url": "https://api.souz.ai"
    }
  ],
  "tags": [
    {
      "description": "Чат, совместимый с OpenAI Chat Completions.",
      "name": "chat"
    },
    {
      "description": "Картинки.",
      "name": "images"
    },
    {
      "description": "Видео.",
      "name": "videos"
    },
    {
      "description": "Транскрибация и синтез речи.",
      "name": "audio"
    },
    {
      "description": "Задачи — состояние, результат, поток событий.",
      "name": "jobs"
    },
    {
      "description": "Файлы — загрузка референсов и результаты со сроком жизни.",
      "name": "files"
    },
    {
      "description": "Каталог моделей — без ключа.",
      "name": "models"
    },
    {
      "description": "Ключ, которым сделан запрос.",
      "name": "key"
    },
    {
      "description": "Состояние сервиса и плановые работы — без ключа.",
      "name": "status"
    },
    {
      "description": "Секрет подписи вебхуков.",
      "name": "webhooks"
    },
    {
      "description": "Аккаунт по ключу управления: кто я, баланс, история операций и запросов, расходы, обычные\nключи, настройки аккаунта (в том числе закрепление каналов) — то же, что держатель ключа\nвидит и может в кабинете.\n",
      "name": "account"
    },
    {
      "description": "Документация для людей и агентов — без ключа.",
      "name": "docs"
    },
    {
      "description": "Сервер Model Context Protocol для агентов: те же ручки API инструментами — каталог, каналы\nи их сравнение, превью выбора, закрепление канала, чат и задачи.\n",
      "name": "mcp"
    }
  ],
  "webhooks": {
    "job.completed": {
      "post": {
        "description": "Приходит на `callback_url` запроса (или адрес по умолчанию из настроек аккаунта).\nПодпись — [Standard Webhooks](https://www.standardwebhooks.com): готовые библиотеки\nпроверки есть для любого языка; ключ — секрет `whsec_…` из `GET /v1/webhooks/secret`.\nОтветьте `2xx` за 10 секунд; иначе повтор через 30 с, 2 мин, 10 мин и 1 ч, после пятой\nнеудачи доставка — `failed` (поле `webhook` задачи). Повтор приходит с тем же\n`webhook-id` — по нему отбрасывайте дубли.\n",
        "operationId": "jobCompletedWebhook",
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookID"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestamp"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Любой ответ `2xx` подтверждает доставку."
          }
        },
        "summary": "Задача завершилась",
        "tags": [
          "webhooks"
        ]
      }
    },
    "job.failed": {
      "post": {
        "description": "То же, что `job.completed`, для проваленной задачи (у неё заполнен `error`).",
        "operationId": "jobFailedWebhook",
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookID"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestamp"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Любой ответ `2xx` подтверждает доставку."
          }
        },
        "summary": "Задача не удалась",
        "tags": [
          "webhooks"
        ]
      }
    }
  }
}