# Коды ошибок

> Обрабатывайте ошибки Merchant API по стабильным машинным кодам, деталям валидации полей и документированным сценариям восстановления.

## Каталог кодов

Стабильные машинно-читаемые идентификаторы возвращаются в `code` (а при ошибке по конкретному полю — в `errors[].code`). Список — **фактически выдаваемый набор**: каждый код ниже реально отдаёт хотя бы один обработчик, валидатор или middleware в API. Семантика существующих кодов не меняется, новые коды добавляются под новые сценарии. Переименование кода — редкий случай, и о каждом мы пишем в чейнджлоге.

Используйте `code` для программной обработки. `detail` приходит только на английском — для логов и запасного UI; локализуйте на клиенте по `code`.

`401` и `403` — не две ступени одной ошибки. `401` значит, что запрос не прошёл проверку учётных данных: заголовка нет, он повреждён, подпись сделана не тем секретом или слишком давно. Повторить тот же запрос — получить тот же ответ. Чинить нужно на стороне ключа: сам ключ, его настройки в дашборде или часы, по которым вы подписываете.

`403` значит, что ключ приняли, а дальше запрос не пропустили. Под одним статусом живут две несвязанные ситуации:

- **Ключ не тот** — `forbidden`, `payment_key_required`, `payout_key_required`. Это настройка интеграции: подпишите запрос ключом нужного типа и окружения, и вызов пройдёт.
- **Ключ в порядке, дело в состоянии аккаунта или проекта** — `whitelist_required`, `merchant_suspended`, `widget_inactive`, `terminal_not_enabled`, `embed_not_enabled`, `not_sandbox`, `payment_channel_simulation_sandbox_only`. Ключ исправен, менять его бесполезно. Самый частый случай — `whitelist_required`: адрес получателя ещё не добавлен в белый список для выводов. Покажите это тому, кто ждёт вывод, вместо того чтобы поднимать дежурного из-за рабочего ключа.

`ip_allowlist_required` стоит между ними. Тип ключа правильный, но у мерчанта отключён белый список адресов вывода, а в этом режиме рабочий ключ Payout выводит, только когда у него задан список разрешённых IP. Чинить нужно в настройках ключа в дашборде: добавьте туда IP своих серверов.

HTTP-статус говорит только о том, на каком уровне запрос остановили. Что делать — смотрите в `code`: ни он сам, ни класс ошибки из вашего SDK этого не скажут.

### Коды поля

Возвращаются при валидации запроса. У кодов уровня поля (ниже) `field` содержит имя поля, не прошедшего проверку, в snake_case. Когда сразу несколько полей не проходят проверку, код верхнего уровня — `validation_failed`, а разбивка по полям лежит в `errors[]`.

| Code | Когда | Что делать |
|------|-------|-----------|
| `validation_failed` | Сразу несколько полей не прошли валидацию. Это код верхнего уровня; разбивка по полям — у каждого свой `code` и `field` — лежит в `errors[]`. | Разберите `errors[]` и поправьте каждое перечисленное `field`. |
| `field_required` | Обязательное поле пустое, `null` или состоит только из пробелов. | Передайте значение в `field`. |
| `field_too_long` | Поле длиннее допустимого максимума. | Обрежьте до лимита, указанного для этого эндпоинта. |
| `field_out_of_range` | Числовое значение вне допустимого диапазона. | Приведите значение к документированному диапазону. |
| `field_invalid_enum` | Значение не входит в набор допустимых значений enum (например, незнакомая `currency` / `network`, токен не включён в проекте или сеть выключена на вкладке «Валюты» проекта). | Сверьтесь со справочником допустимых значений; для токенов — убедитесь, что пара токен+сеть включена в проекте. |
| `field_invalid_format` | Значение не соответствует формату поля: либо не разбирается как id (например, `invoice_id` без префикса `inv_…`), либо `amount` передан не простой decimal-строкой вида `"10.00"`. | Передавайте поле в документированном формате; id — ровно в том виде, в каком их вернул API. |
| `entity_id_empty` | Переданный id — это нулевой (пустой) GUID (`00000000-0000-…`). `field` указывает на конкретный id — например, `invoice_id` или `withdrawal_id`. | Передавайте id ровно в том виде, в каком его вернул API; не отправляйте пустой или обнулённый id. |
| `field_must_be_positive` | Десятичное или целое число должно быть больше 0. | Передайте положительное значение. |
| `field_percentage_out_of_range` | Процент должен быть в диапазоне `[0, 100]` включительно. | Приведите значение к диапазону `[0, 100]`. |
| `query_parameter_unknown` | В запросе списка передан параметр строки запроса, которого нет у этого эндпоинта. | Удалите параметр или используйте его документированное имя в snake_case. |
| `pagination_cursor_invalid` | Курсор повреждён, истёк, подделан, относится к другому ресурсу или совмещён с другими фильтрами. | Начните пагинацию без `cursor`, затем сохраняйте фильтры при переходе по `next_cursor`. |
| `amount_too_many_decimals` | В `amount` больше знаков после запятой, чем допустимо. У инвойса с суммой в фиатной валюте предел — минимальная единица валюты (например, `23.345` для `USD`, `23.01` для `JPY`), у вывода — число знаков токена в выбранной сети (например, `100.0000004` для `USDT` в `TRC20`, где их шесть). API такую сумму отклоняет, а не округляет. | Округлите до минимальной единицы валюты или до числа знаков токена в этой сети. |
| `amount_too_large` | `amount` при создании инвойса или вывода выходит за поддерживаемый диапазон — выше потолка в 20 целых знаков, который хранит API. | Передайте сумму в пределах поддерживаемого диапазона. |

### Резервные коды по HTTP-статусу

Возвращаются, когда у ошибки нет своего бизнес-кода. Каждый код — резервный вариант для HTTP-статуса: запрос не прошёл, а описать причину точнее было нечем.

| Code | HTTP | Когда | Что делать |
|------|------|-------|-----------|
| `forbidden` | 403 | Аутентификация прошла, но этому ключу операция не разрешена: не хватает возможностей (scope) или не то окружение — например, тестовый ключ на эндпоинте только для рабочего режима. | Используйте ключ с нужными возможностями и в нужном окружении. Владение никогда не даёт `403`: чужой ресурс возвращает `not_found` (404), а не `forbidden`. |
| `payment_key_required` | 403 | Эндпоинту нужен Payment-ключ (`pk_`), а запрос пришёл с Payout-ключом (`rk_`) — например, получение списка инвойсов. | Вызовите его Payment-ключом. |
| `payout_key_required` | 403 | Эндпоинту нужен Payout-ключ (`rk_`), а запрос пришёл с Payment-ключом (`pk_`). Так отвечает любая операция с выводами и чтение балансов. | Вызовите его Payout-ключом. |
| `internal_error` | 500 | Непредвиденная ошибка или баг на нашей стороне. | Повторите один раз. Если не проходит — обратитесь в поддержку и укажите время ответа. |
| `validation_failed` | 400 | Запрос не прошёл валидацию, но кода под конкретное поле не нашлось. | Смотрите поле `detail` — там написано, что отклонено. |

### Аутентификация

Возвращается только на `401 Unauthorized` от обработчика HMAC. Каждый код указывает на конкретную точку отказа — клиент может показать осмысленное сообщение вместо общего «auth failed».

| Code | HTTP | Когда | Что делать |
|------|------|-------|-----------|
| `unauthorized` | 401 | Запасной код, когда не подошёл ни один из кодов ниже — обычно запрос к эндпоинту с обязательной аутентификацией без заголовка `Authorization` (или с нераспознанной схемой). | Отправьте корректный заголовок HMAC `Authorization`; проверьте всю сборку подписи. |
| `authorization_missing` | 401 | Заголовок `Authorization` есть, но его значение пустое. | Отправьте полный заголовок `Authorization: HMAC-SHA256 {apiKeyId}:{base64signature}`. |
| `authorization_malformed` | 401 | Заголовок есть, но его формат нарушен: схема распознана, но в учётных данных нет двоеточия, не разбирается id API-ключа или пустая подпись. | Соберите заголовок по разделу [«Аутентификация»](/ru/docs/authentication.md); чаще всего — опечатка в id API-ключа. |
| `timestamp_missing` | 401 | Заголовка `X-Request-Timestamp` нет, или в нём не Unix-секунды десятичными цифрами: знак, пробелы и ведущие нули не принимаются. | Передайте текущее Unix-время в секундах, только цифрами. |
| `timestamp_expired` | 401 | Метка отстаёт от времени сервера больше чем на 5 минут или опережает его больше чем на 60 секунд. | Синхронизируйте часы по NTP или измерьте смещение через [`GET /v1/time`](/ru/docs/time.md); пересчитайте подпись со свежей меткой. |
| `invalid_credentials` | 401 | Ключ использовать нельзя: id не найден, ключ отозван, префикс окружения или типа не совпадает с сохранённым ключом либо подпись не сходится. Один код на все четыре случая — намеренно: разные ответы позволили бы тому, у кого нет секрета, выяснить, какие id ключей существуют. | Проверьте, что id ключа верный и ключ активен, а подпись считается секретом того же ключа. Чаще всего причина в подписи: сверьте сборку строки для подписи (`{ts}\n{METHOD}\n{path}\n{query}\n{bodyHash}`) и то, что для пустого тела `bodyHash` — пустая строка (не хешируйте пустую строку). |
| `ip_not_allowed` | 401 | В белом списке IP у Payout-ключа есть записи, и адреса клиента среди них нет. Payout-ключ с пустым списком вызывается с любого адреса, как и любой Payment-ключ; но если у мерчанта отключён белый список адресов вывода, вывод с такого ключа эту проверку пройдёт, а потом получит отказ `403 ip_allowlist_required`. Идёт после успешной подписи, поэтому корректная подпись с «не той» сети всё равно вернёт 401. | Добавьте IP клиента (или его CIDR-блок) в белый список Payout-ключа в дашборде. |

### Лимит запросов

Возвращается при `429 Too Many Requests`, когда запрос превышает лимит для мерчанта. Окно — одна секунда, и лимит общий для всех ваших API-ключей: своего бюджета у ключа нет. Перед API работает ещё одно ограничение, по IP-адресу; здесь описан лимит мерчанта.

| Code | HTTP | Когда | Что делать |
|------|------|-------|-----------|
| `rate_limited` | 429 | Превышен лимит запросов для мерчанта. Действуют два лимита: общий на все эндпоинты (по умолчанию 30 запросов в секунду) и строже — на создание инвойса, `POST /v1/invoices` (по умолчанию 5 запросов в секунду). Какой из двух лимитов сработал, ответ не сообщает — в нём приходит только пауза до следующей попытки. | Прочитайте заголовок `Retry-After` (пауза в секундах) и повторите запрос после неё. Большинство HTTP-клиентов с повторами учитывают `Retry-After` автоматически. |

### Транспорт и системные ошибки

Возвращаются системным обработчиком ошибок, когда запрос не дошёл до обработчика самого эндпоинта.

| Code | HTTP | Когда | Что делать |
|------|------|-------|-----------|
| `malformed_request` | 400 | Тело запроса не удалось разобрать — повреждённый JSON. | Проверьте, что тело — валидный JSON. |
| `payload_too_large` | 413 | Тело запроса превышает лимит в 1 MiB. | Отправьте тело меньшего размера; разбейте крупные объёмы на отдельные запросы. |
| `unsupported_media_type` | 415 | `Content-Type` не `application/json`. | Выставьте `Content-Type: application/json`. |
| `method_not_allowed` | 405 | Путь существует, но не для этого HTTP-метода. | Используйте метод, указанный для эндпоинта (например, `POST` для создания). |
| `route_not_found` | 404 | Ни один эндпоинт не подходит под этот путь. | Сверьте URL со справочником API. |

### Инвойсы

| Code | HTTP | Когда | Что делать |
|------|------|-------|-----------|
| `invoice_not_found` | 404 | Инвойс с таким id не существует или принадлежит другому мерчанту. | Используйте id, возвращённый `POST /v1/invoices`, без изменений. |
| `project_not_found` | 404 | `project_id` в запросе на создание инвойса не существует или не виден вызывающему. | Используйте project id из дашборда (проект должен быть активен и принадлежать тому же мерчанту, что и API-ключ). |
| `invoice_terminal` | 410 | `confirm-payment` вызван на инвойсе со статусом `expired` или `cancelled`. (Инвойс `paid` возвращает `invoice_not_awaiting_client`, 409, а не этот код.) | Обновите статус инвойса; делать больше нечего. |
| `invoice_deadline_passed` | 410 | `confirm-payment` вызван после истечения срока инвойса. | Создайте новый инвойс. |
| `requested_amount_invalid` | 400 | `amount` в запросе на создание инвойса отсутствует, не разбирается, выходит за поддерживаемый диапазон десятичных значений или не положителен. | Передайте `amount` положительной десятичной строкой вместе с выбранной `currency` и при необходимости — `network`. |
| `invoice_amount_below_minimum` | 400 | USD-эквивалент инвойса ниже минимума для токена/сети из каталога. | Увеличьте сумму выше минимума, возвращённого для выбранного токена. |
| `deposit_amount_exceeds_limit` | 400 | Сумма превышает максимум, допустимый для этого платежа. Проверяется рассчитанная сумма инвойса в момент подтверждения токена и сети, а не фактический приход в блокчейне. | Уменьшите сумму инвойса; если так задача не решается, напишите в поддержку. |
| `currency_not_enabled_for_project` | 400 | Запрошенная криптовалюта не входит в `enabled_tokens` проекта — или входит, но все её сети выключены на вкладке «Валюты» проекта. | Включите валюту в проекте и оставьте включённой хотя бы одну её сеть либо выберите валюту из `enabled_tokens`. |
| `tokens_required` | 409 | Создание инвойса или подтверждение платежа для проекта, где не включён ни один токен. | Включите в проекте хотя бы один токен через дашборд. |
| `invoice_idempotency_conflict` | 409 | `external_order_id` уже занят инвойсом на другую сумму, валюту или сеть либо инвойсом из другого режима. Ничего не создаётся. | Отправьте исходный запрос без изменений, чтобы получить этот инвойс, или возьмите новый `external_order_id` для нового заказа. |
| `acceptance_disabled` | 503 | Запрошенный токен сейчас не принимается. | Используйте другой токен или попробуйте позже. |
| `exchange_rate_unavailable` | 503 | Нет свежего курса для пары токен/фиат. | Повторите запрос; курсы обновляются часто. |
| `network_unavailable` | 503 | При автоподтверждении не удалось использовать выбранную сеть. | Откажитесь от автоподтверждения; дайте клиенту выбрать токен на странице оплаты Paymos. |
| `payment_method_unavailable` | 503 | Выбранный токен или сеть сейчас не принимают платёж. С 23.08.2026 заменяет `no_available_address`, `address_lease_failed` и `bridge_unavailable`. | Повторите запрос или дайте клиенту выбрать другой токен либо сеть. |
| `client_confirmation_failed` | 409 | Подтверждение со стороны клиента (выбор токена, автоподтверждение) отклонено. `detail` содержит причину. | Смотрите `detail`; типично — инвойс уже не в `awaiting_client` или токен не разрешён. |
| `invoice_not_awaiting_client` | 409 | `confirm-payment` вызван на инвойсе, уже вышедшем из `awaiting_client`. | Обновите статус инвойса; клиент уже прошёл выбор. |
| `invoice_cannot_be_cancelled` | 409 | Инвойс уже не в `awaiting_client` — клиент выбрал токен либо инвойс уже `paid` или `expired`. Повторная отмена уже отменённого инвойса возвращает `200`, а не эту ошибку. | Проверьте статус; отмена работает только в `awaiting_client`. |
| `simulate_payment_failed` | 409 | Вызов `simulate_payment` для тестового режима отклонён. | Смотрите `detail`; обычно — несоответствие статуса или суммы. |
| `not_sandbox` | 403 | `simulate-payment` вызван для инвойса рабочего режима. | Симуляция доступна только для тестового инвойса. По рабочему отправьте реальный перевод в выбранной сети. |

### Инвойсы через виджет

Эти коды возвращает эндпоинт `POST /public/v1/sdk` — создание инвойса через Low-Code SDK.

| Code | HTTP | Когда | Что делать |
|------|------|-------|-----------|
| `widget_key_missing` | 401 | Заголовок `X-Sdk-Key` отсутствует или пуст на эндпоинте, где нужна авторизация виджета. | Передайте публичный SDK-ключ в заголовке `X-Sdk-Key`. |
| `widget_key_invalid` | 401 | `X-Sdk-Key` передан, но не распознаётся как идентификатор ключа Paymos. | Скопируйте ключ из дашборда; проверьте префикс и что в значение не попали лишние пробелы или URL-кодирование. |
| `widget_key_not_found` | 401 | Ключ распознан, но активной записи за ним нет: он отозван, удалён или это не Payment-ключ (ключи Payout виджетом не управляют). | Возьмите активный Payment-ключ из дашборда. |
| `widget_inactive` | 403 | Виджет проекта выключен или ещё ни разу не был инициализирован. | Включите виджет в настройках проекта. |
| `terminal_not_enabled` | 403 | Запрос пришёл с `source=terminal`, но способ подключения проекта — не «Терминал». | Создайте проект типа «Терминал» либо передавайте `source=embed` из Low-Code-проекта. |
| `embed_not_enabled` | 403 | Запрос пришёл с `source=embed`, но способ подключения проекта — не Low-Code. | Используйте способ подключения самого проекта либо создайте Low-Code-проект. |
| `origin_not_allowed` | 401 | Браузерный `Origin` не входит в список разрешённых доменов. Проверок две — на уровне авторизации origin сверяется с объединённым списком всех проектов ключа с активным виджетом, затем обработчик сверяет его с конкретным проектом запроса, — и обе отвечают одинаково: тот же `401`, тот же код, тот же `detail`. Это сделано намеренно. Другой статус на второй проверке подсказал бы владельцу ключа `pk_` (он публичный, его нетрудно вытащить со страницы), что домен зарегистрирован в *другом* проекте того же мерчанта, и тестовые хосты и невыпущенные бренды можно было бы перебрать по одному запросу за раз. | Впишите домен в поле **Разрешённый origin** проекта. Значение одно, не список: под второй домен нужен второй проект. Запросы с того же домена, откуда отдаётся платёжная страница — например, с POS-терминала на том же хосте, — проверку пропускают. |

### Платёжные каналы

| Code | HTTP | Когда | Что делать |
|------|------|-------|-----------|
| `payment_channels_disabled` | 503 | Платёжные каналы не включены для вашего аккаунта в этой среде. Так отвечают все методы каналов и депозитов, включая симулятор песочницы. | Обратитесь в поддержку для подключения. Повтор запроса ответ не изменит. |
| `payment_channel_not_found` | 404 | Идентификатор `pc_` не соответствует ничему, доступному этому ключу: канала нет, он принадлежит другому мерчанту, находится в другой среде или в проекте вне области видимости ключа. Все четыре случая намеренно неразличимы. | Используйте id, возвращённый `POST /v1/payment-channels`, без изменений и подписывайте ключом той же среды и того же проекта. |
| `payment_channel_deposit_not_found` | 404 | Идентификатор `pcd_` не соответствует ничему, доступному этому ключу. Причины те же четыре. | Используйте id из payload вебхука или из ленты без изменений. |
| `payment_channel_external_id_invalid` | 400 | `external_id` пуст, состоит из пробелов или длиннее 128 символов — при создании либо как фильтр списка. | Передайте непустой идентификатор длиной не более 128 символов. |
| `payment_channel_project_has_no_supported_tokens` | 409 | В проекте не включён ни один токен, который платёжный канал мог бы принимать, поэтому у канала не будет ни одного маршрута. | Включите в проекте хотя бы один поддерживаемый токен и создайте канал заново. |
| `payment_channel_simulation_sandbox_only` | 403 | `simulate-deposit` вызван для канала рабочей среды. | Симуляция существует только для каналов песочницы. Канал рабочей среды проверяется настоящим переводом. |
| `payment_key_required` | 403 | Запрос подписан ключом выплат (`rk_`). Доступ к каналам даёт ключ `Payment` — так же, как выплаты работают через ключ `Payout`. | Подпишите запрос ключом `pk_` той же среды. |
| `pagination_cursor_invalid` | 400 | Курсор списка или ленты повреждён, старше 24 часов или выдан для других фильтров; для ленты — также для другого мерчанта, среды или набора проектов. | Начните с первой страницы. Дедупликация по `pcd_` делает полную пересинхронизацию безвредной. |
| `currency_not_enabled_for_project` | 400 | Токен, переданный в `simulate-deposit`, не включён в проекте. | Включите его в проекте или выберите тот, который канал уже возвращает в `networks[].tokens`. |
| `acceptance_disabled` | 503 | Приём указанного токена сейчас отключён на уровне платформы. | Используйте другой токен или дождитесь включения приёма. |
| `amount_too_many_decimals` | 400 | В сумме симуляции больше знаков после запятой, чем поддерживает токен. Деньги мерчанта не округляются молча до другого числа. | Округлите сумму до точности токена перед отправкой. |

### Выводы

| Code | HTTP | Когда | Что делать |
|------|------|-------|-----------|
| `withdrawal_not_found` | 404 | Вывода с таким id нет либо он принадлежит другому мерчанту. | Используйте id, который вернул `POST /v1/withdrawals`, без изменений. |
| `insufficient_balance` | 409 | Доступный баланс мерчанта ниже `amount + fee`. | Пополните баланс или уменьшите сумму вывода. |
| `whitelist_required` | 403 | Адрес назначения не добавлен в белый список для выбранной сети. (Сеть белый список поддерживает — просто этот адрес ещё не внесён.) Код приходит только при включённом белом списке мерчанта — а по умолчанию он включён. | Добавьте адрес в белый список и повторите запрос. |
| `ip_allowlist_required` | 403 | Белый список адресов вывода у мерчанта отключён, а у рабочего ключа Payout, которым подписан запрос, нет списка разрешённых IP. Без белого списка адресов ключ выводит только с IP из своего списка. Вывод не создаётся. | Добавьте IP своих серверов в список ключа Payout в дашборде и повторите запрос. |
| `destination_address_invalid` | 400 | Адрес не проходит проверку формата или контрольной суммы для этой сети. | Сверьте адрес со спецификацией сети. |
| `withdrawal_amount_below_minimum` | 400 | Сумма ниже минимума для выбранного токена. | Увеличьте сумму выше минимума (возвращается в `detail`). |
| `amount_too_many_decimals` | 400 | В `amount` больше знаков после запятой, чем у токена в выбранной сети: например, `100.0000004` для `USDT` в `TRC20`, где знаков шесть. Вывод не создаётся, сумма в резерв не уходит, и API её не округляет. | Округлите сумму до числа знаков токена в этой сети и отправьте запрос снова. |
| `withdrawal_quota_exceeded` | 409 | Достигнут лимит активных выводов. | Дождитесь завершения текущих или запросите повышение лимита. |
| `withdrawal_amount_exceeds_limit` | 400 | USD-эквивалент тела вывода превышает лимит на одну выплату по вашему аккаунту. Считается по телу вывода, комиссия сети в эту сумму не входит. | Уменьшите сумму или запросите повышение лимита в поддержке. |
| `exchange_rate_unavailable` | 503 | Чтобы сверить сумму вывода с лимитом аккаунта, нужен свежий курс токен/USD, а его в этот момент нет. Лимит не подтвердить, поэтому запрос отклоняется. | Повторите запрос; курсы обновляются часто. |
| `withdrawal_not_enabled` | 400 | Paymos не выводит запрошенную пару токен/сеть. Пара названа в `detail` — например `Withdrawals are not available for USDT on TRC20.` Набор пар, доступных для вывода, задаётся на стороне Paymos. | Выведите токен в сети, по которой Paymos делает выплаты, либо спросите в поддержке про нужную пару. |
| `withdrawal_cannot_be_cancelled` | 409 | Вывод уже вышел из состояния, в котором его можно отменить. | Проверьте текущий статус. Окно закрывается, когда начинается исполнение, — ещё внутри `created`, до всякого подписания. |
| `withdrawal_simulation_failed` | 409 | Вызов `simulate_completion` для тестового режима отклонён. | Смотрите `detail`. |
| `merchant_suspended` | 403 | Мерчант приостановлен для исходящих операций, поэтому создать вывод нельзя. | Обратитесь в поддержку, чтобы снять приостановку. |
| `outbound_frozen` | 503 | Исходящие операции заморожены — либо на всей платформе, либо для той сети и токена, в которых вы выводите. | Дождитесь снятия, попробуйте другую сеть или токен либо обратитесь в поддержку. |
| `withdrawal_network_unavailable` | 503 | Вывод этого токена в этой сети сейчас провести нельзя. | Попробуйте другую сеть назначения или повторите позже. |

### Состояние проекта

Возвращается при создании инвойса, если статус проекта не позволяет их выпускать. Подтвердить платёж по инвойсу такого проекта своим API-ключом тоже нельзя, но ответ будет другим — `404`: на запись ключ работает только с активными проектами.

| Code | HTTP | Когда | Что делать |
|------|------|-------|-----------|
| `project_state_invalid` | 409 | Проект не в статусе `Active` — он `Suspended` или `Archived`. Какой именно, ответ не сообщает. | Посмотрите статус проекта в дашборде: архивный — восстановите, приостановленный — активируйте. Либо отправьте запрос в уже активный проект. |
