# Ошибки

Каждый эндпоинт завершается одинаково: HTTP-статусом и одним JSON-конвертом.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_input",
    "message": "duration must be one of 5, 10.",
    "param": "duration",
    "details": [ { "param": "duration", "message": "duration must be one of 5, 10." } ],
    "request_id": null,
    "doc_url": "https://doitong.com/developers/docs/errors#invalid_input"
  }
}
```

| Поле | Значение |
|---|---|
| `type` | Общий класс ошибки. По нему определяется дальнейшее действие. |
| `code` | Точная причина, стабильная и машиночитаемая. Для каждого кода ниже есть отдельный раздел; `doc_url` ведёт на него. |
| `message` | Понятное человеку объяснение, безопасное для записи в журнал или показа разработчику. |
| `param` | Проблемный входной параметр или заголовок, если он есть. |
| `details` | Для ошибок входных данных — все найденные проблемы: `[{ "param", "message" }]`. |
| `request_id` | Запрос, к которому относится ошибка, если он существует. |

За вызов, вернувший ошибку, плата не взимается. Запрос, завершившийся ошибкой *после* принятия, сохраняет статус
`failed`, содержит `error: { "type", "code", "message" }` в объекте запроса и автоматически возвращается.

## Типы

| Тип | HTTP-статус | Действие |
|---|---|---|
| `invalid_request` | 400, 413 или 422 | Исправьте запрос. Повторная отправка того же вызова снова завершится ошибкой. |
| `authentication_error` | 401 | Передайте действительный ключ в `Authorization: Bearer <key>`. |
| `permission_error` | 403 | Используйте ключ с необходимой областью доступа. |
| `not_found` | 404 | Проверьте идентификатор модели или запроса. |
| `insufficient_credits` | 402 | Пополните баланс API (`top_up_url` в ошибке). |
| `budget_exceeded` | 402 | Собственный бюджет ключа исчерпан. Окончательное решение: попросите владельца ключа увеличить его. |
| `conflict` | 409 | Ресурс находится в состоянии, не допускающем этот вызов. |
| `rate_limited` | 429 | Подождите `Retry-After` секунд, затем повторите запрос. |
| `upstream_error` | 502 | Сервер модели завершился с ошибкой. Безопасно повторить с тем же `Idempotency-Key`: операция запустится снова, плата не взималась. |
| `service_unavailable` | 503 | API приостановлен или недоступна зависимость. Повторите позже. |
| `internal_error` | 500 | Ошибка на нашей стороне. Повторите запрос; если ошибка сохраняется, обратитесь в поддержку, указав время и `request_id`. |

## Коды

### `invalid_request`

Общий некорректно сформированный запрос (400).

### `invalid_json`

Тело не является допустимым JSON (400).

### `invalid_body`

Тело является допустимым JSON, но не объектом; входные данные модели должны быть JSON-объектом (400).

### `body_too_large`

Тело больше 16 MB (413). Загрузите большие файлы и передайте вместо них URL (см. [Файлы](https://doitong.com/developers/docs/files)).

### `invalid_parameter`

Параметр запроса содержит недопустимое значение: например, `limit` вне диапазона от 1 до 100, `wait` не является числом, неизвестны
`status` или `category`, либо `storage` отличается от `permanent` / `temporary` (400). Имя параметра указано в `param`.

### `invalid_category`

`GET /openapi.json?category=` указывает несуществующую категорию (400). Запрос `GET https://api.doitong.ru/v1/categories` выводит их список.

### `invalid_cursor`

`cursor` вызова списка не относится к этому списку (400). Начните заново без курсора.

### `invalid_idempotency_key`

Заголовок `Idempotency-Key` пуст или содержит более 255 символов (400).

### `invalid_arguments`

Вызову инструмента MCP не хватает аргумента или он некорректно сформирован (только MCP). Имя аргумента указано в `param`.

### `invalid_input`

Входные данные модели не прошли проверку (422): неизвестный параметр (сообщение предлагает ближайшее допустимое имя),
отсутствующий обязательный параметр, неверный тип, значение вне разрешённого списка или диапазона либо одновременно
указанные каноническое и нативное имена с разными значениями. `param` содержит первый проблемный параметр, а `details` — все такие параметры.
Плата не взимается.

### `unsupported_file`

Файл имеет неподдерживаемый тип (422): например, загружен файл с неподдерживаемым расширением или `content_type`,
не соответствующий расширению.

### `invalid_webhook_url`

`webhook_url` не является общедоступным URL `https://` (422). Приватные, локальные и обычные адреса `http://` отклоняются.

### `missing_api_key`

Эндпоинту требуется API-ключ, но он не был передан (401).

### `invalid_api_key`

Ключ неизвестен, отозван или просрочен (401).

### `insufficient_scope`

У ключа нет области доступа, необходимой для вызова (403): например, `models:run` для запуска или `models:read` для чтения
запросов и баланса. См. [Аутентификация](https://doitong.com/developers/docs/authentication#scopes).

### `account_disabled`

Аккаунт закрыт или заблокирован (403). Его ключи больше не работают.

### `not_found`

Путь не существует (404).

### `model_not_found`

Общедоступной модели с таким идентификатором нет (404). Получите список моделей с помощью `GET https://api.doitong.ru/v1/models`.

### `request_not_found`

В вашем аккаунте нет запроса с таким идентификатором (404). Запросы других аккаунтов никогда не видны.

### `insufficient_credits`

**API-баланса** аккаунта (API-кредиты, 1 000 API-кредитов = 1 $ — не кредиты приложений Doitong) недостаточно для оплаты
этого вызова (402). Ответ отправляется до списания средств. Ошибка содержит `top_up_url`; пополните баланс по адресу
[https://doitong.ru/developers/dashboard#balance](https://doitong.ru/developers/dashboard#balance) и повторите запрос.

```json
{ "error": { "type": "insufficient_credits", "code": "insufficient_credits",
             "message": "This request costs 560 API credits ($0.56); the API balance is 120 API credits ($0.12). Top up at https://doitong.ru/developers/dashboard#balance",
             "top_up_url": "https://doitong.ru/developers/dashboard#balance", "doc_url": "https://doitong.com/developers/docs/errors#insufficient_credits" } }
```

### `budget_exceeded`

Вызов превысил бы собственный бюджет API-ключа в API-кредитах (402). Бюджет устанавливает владелец ключа; повторная отправка
не поможет, пока он не увеличит бюджет.

### `conflict`

Вызов конфликтует с текущим состоянием ресурса (409).

### `idempotency_mismatch`

`Idempotency-Key` уже использовался с другим телом запроса (409). Для новой операции используйте новый ключ.

### `idempotency_in_progress`

Прямо сейчас создаётся запрос с тем же `Idempotency-Key` (409). Повторите через мгновение, чтобы получить его.

### `request_active`

Запрос всё ещё имеет статус `queued` или `running`, поэтому удалять пока нечего (409). Удалите файлы после завершения запроса.

### `not_cancelable`

Запрос уже имеет статус `succeeded` или `failed` и не может быть отменён (409).

### `rate_limited`

Ключ отправил слишком много запросов за текущий период (429). См. заголовки `X-RateLimit-*` и `Retry-After`.

### `too_many_inflight`

В аккаунте уже есть 10 запросов со статусом `queued` или `running` (429). Запустите следующий после завершения одного из них.

### `upstream_error`

Сервер модели отклонил запрос или завершился с ошибкой (502 при запуске либо `failed` с этим кодом у запроса). API-кредиты
возвращаются. Если сервер модели сам отклонил входные данные, вызов возвращает `422 invalid_input` с соответствующим сообщением.

### `upstream_lost`

Сервер модели больше не знает об этом запросе, поэтому результат никогда не будет получен. Запрос завершается со статусом `failed`
и этим кодом (тип `upstream_error`), а средства возвращаются. Запустите его снова.

### `timeout`

Запрос выполнялся дольше установленного ограничения (15 минут для изображений, 60 для видео, 30 в остальных случаях) и был остановлен.
Он завершается со статусом `failed` с этим кодом, а средства возвращаются.

### `service_unavailable`

API временно приостановлен или недоступна зависимость, например загрузка файлов (503). Повторите позже.

### `internal_error`

На нашей стороне произошла ошибка (500). Повторите запрос; если ошибка сохраняется, обратитесь в поддержку.

### `charge_failed`

С аккаунта не удалось списать средства из-за внутренней проблемы (500). Запрос получает статус `failed`; средства не списываются.
Повторите запрос.

### `pricing_unavailable`

Цена модели не настроена, поэтому сейчас её нельзя узнать или запустить модель (500).
