# Ідемпотентність, помилки та ліміти

Як безпечно повторювати мутації Invoise, що означають коди помилок і які ліміти застосовуються.

Source: https://docs.invoise.me/uk/integration/idempotency-and-errors/

Якщо запит завершився таймаутом, ви не знаєте, чи він виконався. Повторіть ту саму операцію з тим самим `Idempotency-Key`, щоб не створити другий платіж.

## Один ключ на дію

1. Згенеруйте унікальний ключ перед першим запитом і збережіть його разом із замовленням.
2. Надішліть його в `Idempotency-Key` під час створення або зміни бізнес-ресурсу.
3. Після таймауту повторіть той самий метод, шлях і тіло з цим ключем.
4. Для нової дії створіть новий ключ.

Ключ має бути непорожнім і не довшим за 128 байт. Повторення завершеної дії повертає збережену відповідь. Зміна тіла під тим самим ключем повертає `409 idempotency_conflict`.

Це стосується бізнес-мутацій, як-от рахунки, магазини, ключі та вебхуки. Запити GET лише для читання і виклики входу цей механізм не використовують. Дотримуйтеся вимог кожного ендпоінту.

`external_id` допомагає пов'язати платіж із вашим замовленням; це не ключ ідемпотентності.

## Читання помилок за кодом

Приклад:

```json
{"error":{"code":"idempotency_conflict","message":"idempotency_conflict"}}
```

Використовуйте `error.code` у своїй програмі. Не робіть висновок про успіх із тіла відповіді без попередньої перевірки HTTP-статусу.

| Код | Наступна дія |
| --- | --- |
| `unauthorized` | Перевірте облікові дані, права та будь-яке обмеження за IP. Увійдіть знову, якщо сесія закінчилася. |
| `mfa_required` | Пройдіть другий фактор облікового запису, використовуючи його сесію. |
| `onboarding_required` | Завершіть `/onboarding`, перш ніж працювати з магазином. |
| `idempotency_key_required` | Надайте збережений непорожній ключ, не більше 128 байт. |
| `idempotency_conflict` | Знайдіть початковий запит. Не створюйте мовчки новий платіж. |
| `json_content_type_required` / `invalid_json` | Надсилайте `Content-Type: application/json` і лише задокументовані поля. |
| `unsupported_network` / `unsupported_asset` | Оберіть підтримувану мережу й токен. |
| `network_not_ready` / `asset_not_ready` | Дочекайтеся доступності або оберіть інший готовий маршрут. |
| `amount_below_minimum` / `fee_exceeds_amount` | Перевірте суму, кількість знаків після коми та умови магазину. |
| `shop_archived` / `shop_not_found` | Перевірте магазин і доступ. |
| `invalid_expires_in` | Надсилайте `1d`, `7d`, `30d`, `180d` або `365d`, і лише під час створення рахунку. Депозити не мають терміну дії. |
| `invalid_assets` / `issuance_in_group` | Надсилайте окремі пари `{chain_id, token}` без `chain_id` і `token`; скасовуйте або призупиняйте групу за її власним `id`. Див. [кілька токенів або мереж](https://docs.invoise.me/uk/payments/deposits-and-invoices/#запропонуйте-кілька-токенів-або-мереж). |
| `solana_setup_required` / `tron_setup_required` | Спершу задайте [отримувача Solana або Tron](https://docs.invoise.me/uk/payments/solana-and-tron/) для магазину. |
| `invoice_amount_limit` / `sandbox_amount_limit` | Зменшіть суму в межах [ліміту](#ліміти). |
| `active_invoice_limit_reached` / `deposit_address_limit_reached` | Скасуйте непотрібні рахунки або вимкніть непотрібні депозити, або попросіть Invoise підняти ліміт. |
| `api_key_limit_reached` / `too_many_allowed_ips` / `webhook_limit_reached` | Відкличте невикористовувані ключі, скоротіть список IP або повторно використайте наявний ендпоінт. |
| `team_limit_reached` | Видаліть учасника або відкличте запрошення, що очікує, або попросіть Invoise підняти ліміт. |
| `account_disabled` | Персонал Invoise заблокував обліковий запис; причина — в `error.details`. Див. [заблоковані облікові записи](https://docs.invoise.me/uk/integration/team-and-access/#заблоковані-облікові-записи). |
| `rate_limited` | Дочекайтеся кількості секунд із `Retry-After`, перш ніж повторити. |

## Ліміти

Коли запит перевищив би ліміт, Invoise відхиляє його зі звичним тілом помилки й кодом нижче.

| Ліміт | Значення | Помилка |
| --- | --- | --- |
| Сума одного рахунку | 1 000 000 токенів | `400 invoice_amount_limit` |
| Сума одного рахунку пісочниці або симульованого переказу | 10 000 токенів | `400 sandbox_amount_limit` |
| Активних рахунків на мерчанта | 2000 | `400 active_invoice_limit_reached` |
| Активних депозитних адрес на мерчанта, на родину мереж | EVM 10 000, Tron 10 000, Solana 10 | `400 deposit_address_limit_reached` |
| Невідкликаних API-ключів на магазин | 10 | `400 api_key_limit_reached` |
| Дозволених IP-адрес або діапазонів CIDR на ключ | 10 | `400 too_many_allowed_ips` |
| Ендпоінтів вебхуків на магазин | 10 | `400 webhook_limit_reached` |
| Учасників команди та очікуваних запрошень на мерчанта | 10 | `400 team_limit_reached` |
| Запитів за хвилину | 1200, з яких не більше 120 не GET | `429 rate_limited` |

Ліміти сум — у цілих токенах, не в базових одиницях. Кожен підтримуваний токен — доларовий стейблкоїн, тож 1 000 000 токенів — це близько $1 000 000.

Рахунок активний, поки його не оплачено, не скасовано або не минув термін. Рахунок, запропонований у кількох мережах, рахується один раз. Депозитна адреса активна, поки її не вимкнено; кожен мережевий варіант депозиту — окрема адреса. Пісочниця й продакшен рахуються окремо для обох лімітів. Персонал Invoise може змінити ліміти рахунків, депозитних адрес і команди для мерчанта.

Ліміт команди застосовується і при запрошенні, і при прийнятті запрошення. URL ендпоінту вебхука можна змінити, тож можна повторно використати ендпоінт замість додавання нового.

Запити рахуються на API-ключ, на сесію кабінету або на IP клієнта без автентифікації. Відповідь `429` містить `Retry-After: 60`.

## Повторюйте без дублікатів

Повторюйте таймаути й тимчасові помилки сервера з **тим самим ключем**, зі зростаючими затримками. При `429` дочекайтеся кількості секунд із `Retry-After`; не надсилайте нові запити одразу. Виправте неправильні вхідні дані й помилки доступу, перш ніж повторювати.

Для вебхуків Invoise повторює доставку. Приймайте подію надійно, повертайте 2xx, потім обробляйте її. Усувайте дублікати за `Invoise-Event-ID`.

Старіші маршрути `/projects` — це псевдоніми `/shops`, зокрема їхня область ідемпотентності. Для нових інтеграцій використовуйте `/shops`. У застарілих назвах помилок може вживатися `project_*`.
