# Invoise documentation (ru) API: https://platform.invoise.me/api/v1 OpenAPI: https://docs.invoise.me/openapi.json # Справочник входа агента Эндпоинты, которыми автоматический агент входит по EVM-кошельку и управляет сессией. Source: https://docs.invoise.me/ru/agents/auth-reference/ Все пути ниже используют `https://platform.invoise.me/api/v1`. Для JSON передавайте `Content-Type: application/json`. Запросам входа не нужен ключ идемпотентности. Вход по кошельку — только для агентов. Запрос с заголовком `Origin`, как любой запрос из браузера, вернёт `403 wallet_sign_in_agents_only`. Вызывайте эти эндпоинты с сервера или из скрипта. ## POST /auth/wallet/challenge Запросить сообщение для подписи. Авторизация не нужна. | Поле | Тип | Значение | | --- | --- | --- | | `address` | string, обязательно | Адрес вашего EVM-кошелька. | | `chain_id` | integer, обязательно | ID доступной EVM-сети из [API](https://docs.invoise.me/ru/payments/networks/). | **Ответ 200:** `challenge_id` и `message`, оба — строки. Подпишите сообщение как есть через EIP-191 personal-message signing. Не отправляйте приватный ключ. Истёкший или использованный челлендж нужно запросить заново. ## POST /auth/wallet/verify Обменять подписанный челлендж на сессию. Bearer-токен не нужен. | Поле | Тип | Значение | | --- | --- | --- | | `challenge_id` | string, обязательно | ID из ответа на запрос сообщения. | | `signature` | string, обязательно | Подпись исходного сообщения, hex-строка. | ```json {"challenge_id":"","signature":"<0x-signature>"} ``` **Ответ 200** с примерными значениями: ```json { "token": "", "expires_at": "2026-09-21T10:00:00Z", "user": { "user_id": "", "onboarding_required": true, "mfa_required": false } } ``` Передавайте `token` как `Authorization: Bearer `. Срок действия — `expires_at`. Cookie не устанавливается, поэтому bearer-запросам не нужен CSRF-заголовок. Неверное или использованное доказательство может вернуть `401 unauthorized`. Если после отправки одноразовой подписи случился таймаут, начните новый челлендж вместо бесконечного повтора подписи. ## MFA, если включено Вход по кошельку не обходит второй фактор. Если `user.mfa_required` равен `true`, подтвердите настроенный фактор с этой сессией до бизнес-запросов. Для аккаунта с TOTP: ```http POST /api/v1/auth/totp/verify Authorization: Bearer Content-Type: application/json {"code":""} ``` Чувствительное изменение также может вернуть `403 mfa_required`, если нужно свежее подтверждение. Коды восстановления работают только с основной сессией, а не как отдельный вход. Остальные факторы описаны в [входе в аккаунт](https://docs.invoise.me/ru/integration/dashboard-sign-in/). ## POST /onboarding Если `user.onboarding_required` равен `true`, создайте первого мерчанта. Аккаунт, вошедший только кошельком, должен передать рядом с `name` email владельца-человека, поэтому сначала спросите его: ```json {"name":"My merchant","email":"owner@example.com"} ``` Отправьте запрос с bearer-сессией и `Idempotency-Key`. Email становится способом входа в этот же аккаунт. Invoise отправляет человеку уведомление: он открывает интерфейс, входит с этим email по одноразовому коду и попадает в аккаунт, созданный агентом. | Ошибка | Что означает | | --- | --- | | `400 email_required` | Нет `email`. Спросите его у своего человека. | | `400 invalid_email` | Некорректный адрес. | | `400 disposable_email` | Одноразовые почтовые адреса не принимаются. Укажите постоянный адрес. | | `400 identity_already_linked` | Этот email уже принадлежит другому аккаунту. Попросите другой. | Дальнейшие шаги — в [сценарии агента](https://docs.invoise.me/ru/agents/integration/). ## POST /auth/logout Завершить текущую сессию. Передайте её bearer-токен. Успешный запрос возвращает `200`; отозванная сессия больше не работает. Для постоянной работы с платежами используйте [API-ключ магазина](https://docs.invoise.me/ru/integration/api-keys/). После входа продолжайте по [сценарию агента](https://docs.invoise.me/ru/agents/integration/). --- # Сценарий для агента Путь от входа кошельком до оплаченного инвойса для автоматического агента. Source: https://docs.invoise.me/ru/agents/integration/ Это настройка для агента с [сессией кошелька](https://docs.invoise.me/ru/agents/sign-in/). Если ID магазина и API-ключ уже есть, переходите сразу к шагу 4. Каждому JSON-запросу на изменение ниже нужны `Content-Type: application/json`, bearer-токен сессии и сохранённый `Idempotency-Key`, уникальный для действия. ## 1. Выберите мерчанта Прочитайте `GET /api/v1/me`. Если `user.onboarding_required` равен `true`, сначала спросите у своего человека его email, затем завершите настройку: ```http POST /api/v1/onboarding Content-Type: application/json {"name":"My merchant","email":"owner@example.com"} ``` Аккаунт, вошедший только кошельком, должен передать `email`; без него ответ — `400 email_required`. Некорректный адрес вернёт `invalid_email`, одноразовый — `disposable_email`, а email, который уже принадлежит другому аккаунту, — `identity_already_linked`. Email становится способом входа в этот же аккаунт. Invoise отправляет человеку уведомление: он открывает интерфейс, входит с этим email по одноразовому коду и попадает в созданный вами аккаунт. Ответ `{"completed":true}` не содержит ID мерчанта. После него вызовите `GET /api/v1/merchants` и сохраните `id` нужного мерчанта. У существующего аккаунта их может быть несколько. Выберите нужного явно, а не берите первый элемент. Не используйте `POST /merchants` для первичной настройки: он возвращает `forbidden`. ## 2. Создайте магазин ```http POST /api/v1/merchants/{merchant_id}/shops Content-Type: application/json { "name": "Agent payments", "sandbox": true, "recipient": "" } ``` Сохраните `id` ответа как `shop_id`. Для теста начните с Sandbox; затем создайте отдельный боевой магазин с `sandbox: false`. Необязательный EVM-делегат `delegate` нужен только для независимого завершения инвойса вашим кошельком. Адрес биржи для этой роли не подходит. Получателя и делегата можно изменить позже через `PATCH /api/v1/shops/{shop_id}`. Уже созданные инвойсы и адреса сохраняют значения на момент создания. Боевой магазин может вместо этого платить в [кошелёк Invoise](https://docs.invoise.me/ru/payments/wallet/) аккаунта: передайте `"payout_target":"wallet"` без `recipient`. Кошелёк настраивает ваш человек в интерфейсе; до этого создание инвойса вернёт `400 wallet_not_ready`. Для Solana и Tron нужен отдельный получатель; см. [Solana и Tron](https://docs.invoise.me/ru/payments/solana-and-tron/). ## 3. Выпустите API-ключ магазина С токеном сессии [создайте ключ](https://docs.invoise.me/ru/integration/api-keys/) с `read` и `write`. Сохраните `ivk_`-токен в хранилище секретов и используйте его для дальнейших платёжных запросов. ## 4. Создайте инвойс 1. Прочитайте `GET /api/v1/networks`. Выберите включённую сеть и готовый токен с его настоящим адресом и числом знаков. 2. Сохраните ключ идемпотентности рядом с инвойсом в вашей системе до отправки запроса. 3. Вызовите `POST /api/v1/shops/{shop_id}/invoices`: | Поле | Значение | | --- | --- | | `chain_id` | ID выбранной сети из API; целое число. | | `token` | Адрес выбранного токена из API. | | `amount` | Сумма инвойса в минимальных единицах токена; строка целого числа. | | `external_id` | Необязательная ссылка на запись в вашей системе. | Для многоразового адреса пополнения вызовите `/deposits` без `amount`. Чтобы плательщик выбрал один из нескольких токенов или сетей, передайте `assets` вместо `chain_id` и `token`; см. [Депозиты и инвойсы](https://docs.invoise.me/ru/payments/deposits-and-invoices/#несколько-токенов-или-сетей). После таймаута повторяйте тот же запрос с тем же ключом. Один `external_id` не защищает от дублей. ## 5. Дождитесь адреса и оплаты Сохраните `id` из ответа `202`. Опрашивайте: ```bash curl 'https://platform.invoise.me/api/v1/shops/{shop_id}/issuances/{issuance_id}' \ -H 'Authorization: Bearer ivk_...' ``` Дождитесь непустого `address`, затем передайте `payment_url`. Продолжайте читать `status` и `received` через тот же endpoint. Получайте уведомления об изменениях через [вебхуки](https://docs.invoise.me/ru/integration/webhooks/). Перед учётом оплаты инвойса прочитайте [Статус инвойса и депозита](https://docs.invoise.me/ru/payments/status/): `funded`, `settled`, отмена и многоразовые депозиты имеют разный смысл. Каждое изменение бизнес-данных сохраняйте один раз. ## Читайте документацию без браузера [llms.txt](https://docs.invoise.me/llms.txt) содержит индекс страниц, [OpenAPI](https://docs.invoise.me/openapi.json) — формальные контракты. Markdown и полный текст описаны в [чтении документации](https://docs.invoise.me/ru/agents/reading/). --- # Читать без браузера Markdown-страницы, llms.txt и OpenAPI для агентов и инструментов. Source: https://docs.invoise.me/ru/agents/reading/ Вся документация публичная. Для чтения не нужны аккаунт, автоматизация браузера или JavaScript. ## Начните с индекса ```bash curl 'https://docs.invoise.me/llms.txt' ``` В нём перечислены английские и русские страницы с прямыми Markdown-ссылками. Загружайте только то, что нужно для задачи. ## Прочитайте одну страницу Замените последний `/` в адресе документации на `.md`: ```bash curl 'https://docs.invoise.me/payments/status.md' curl 'https://docs.invoise.me/ru/payments/status.md' ``` Начните с `/start/quickstart.md` или `/ru/start/quickstart.md`. `/index.md` и `/ru/index.md` возвращают тот же текст быстрого старта. Markdown содержит заголовок, адрес оригинала и тот же текст, что сайт. ## Получите весь текст | Язык | Полный текст | | --- | --- | | Английский | [Полный текст на английском](https://docs.invoise.me/llms-full.txt) | | Русский | [Полный текст на русском](https://docs.invoise.me/ru/llms-full.txt) | Файлы собираются из тех же исходных страниц при каждой сборке. В них находятся инструкции без разметки навигации. Контракты API доступны отдельно в OpenAPI и Scalar. ## Загрузите контракт API [openapi.json](https://docs.invoise.me/openapi.json) описывает методы интеграции, авторизацию, поля, ответы и ошибки. Объяснения — в [справочнике API](https://docs.invoise.me/api-reference/). Адреса токенов и число знаков берите из живого каталога сетей. Адреса, ID и секреты в примерах документации не являются рабочими настройками. ## Короткий маршрут чтения 1. Ключ уже есть: [создание инвойса](https://docs.invoise.me/ru/start/quickstart.md), затем [его статус](https://docs.invoise.me/ru/payments/status.md). 2. Нужна настройка аккаунта: [вход по кошельку](https://docs.invoise.me/ru/agents/sign-in.md), затем [сценарий агента](https://docs.invoise.me/ru/agents/integration.md). 3. Перед повторами запросов и приёмом событий: [идемпотентность](https://docs.invoise.me/ru/integration/idempotency-and-errors.md) и [вебхуки](https://docs.invoise.me/ru/integration/webhooks.md). --- # Вход агента Аутентификация автоматического агента EVM-кошельком, без браузера. Source: https://docs.invoise.me/ru/agents/sign-in/ Уже есть API-ключ магазина? Вход не нужен — используйте [платёжное API](https://docs.invoise.me/api-reference/). Вход по кошельку нужен агенту для настройки аккаунта и управления им. Вход по кошельку — только для агентов. Отправляйте эти запросы с сервера или из скрипта: запрос с заголовком `Origin`, который добавляет любой браузер, отклоняется с `403 wallet_sign_in_agents_only`. В интерфейсе нет входа и привязки по кошельку. ## 1. Запросите сообщение Используйте свой EVM-кошелёк. Приватный ключ остаётся в вашем инструменте подписи и никогда не отправляется в Invoise. ```bash curl -X POST 'https://platform.invoise.me/api/v1/auth/wallet/challenge' \ -H 'Content-Type: application/json' \ -d "{\"address\":\"${WALLET_ADDRESS:?}\",\"chain_id\":${CHAIN_ID:?}}" ``` Задайте `WALLET_ADDRESS` своим EVM-адресом и `CHAIN_ID` — ID доступной EVM-сети из [API](https://docs.invoise.me/ru/payments/networks/). В ответе придут `challenge_id` и `message`. ## 2. Подпишите сообщение Используйте EIP-191 personal-message signing в своём кошельке. Подпишите `message` точно как пришёл, включая пробелы и переносы. Это подпись сообщения, а не транзакции. Челлендж одноразовый и действует недолго. Если он истёк или уже использован, запросите новый. ## 3. Получите сессию ```bash curl -X POST 'https://platform.invoise.me/api/v1/auth/wallet/verify' \ -H 'Content-Type: application/json' \ -d '{"challenge_id":"","signature":"<0x-signature>"}' ``` Надёжно сохраните `token`. Проверьте `expires_at`, `user.mfa_required` и `user.onboarding_required` в ответе. Invoise не устанавливает cookie. Передавайте сессию как `Authorization: Bearer `; CSRF-заголовок не нужен. ## 4. Завершите настройку | Условие | Следующий шаг | | --- | --- | | `user.mfa_required: true` | Подтвердите настроенный второй фактор до бизнес-запросов. Вход по кошельку не обходит MFA. | | `user.onboarding_required: true` | Спросите у своего человека его email, затем создайте первого мерчанта через `/onboarding` с `name` и `email`. Без email ответ — `400 email_required`; одноразовый адрес вернёт `400 disposable_email`. | | Вход завершён | Продолжите по [сценарию агента](https://docs.invoise.me/ru/agents/integration/): выберите мерчанта, создайте магазин и выпустите API-ключ. | Сессия нужна для настройки, ключ магазина — для платежей. Истекла сессия — войдите заново. Поля запросов и ответов описаны в [справочнике входа](https://docs.invoise.me/ru/agents/auth-reference/). --- # API-ключи Создание ключа магазина, выбор прав и ограничение по IP. Source: https://docs.invoise.me/ru/integration/api-keys/ API-ключ даёт вашему бэкенду доступ к одному магазину. Создайте его в интерфейсе, сохраните на сервере и передавайте как bearer-токен. ## Создать ключ В магазине создайте ключ с правами `read` и `write`. Токен начинается с `ivk_` и показывается один раз — сохраните его сразу. У магазина может быть до 10 неотозванных ключей; см. [Лимиты](https://docs.invoise.me/ru/integration/idempotency-and-errors/#лимиты). Агент может создать такой же ключ с помощью своей сессии: ```bash curl -X POST 'https://platform.invoise.me/api/v1/shops/{shop_id}/keys' \ -H 'Authorization: Bearer ' \ -H 'Idempotency-Key: ' \ -H 'Content-Type: application/json' \ -d '{"name":"backend","scopes":["read","write"]}' ``` Создавать и менять ключи нужно через сессию. API-ключ не может создать другой ключ. Если включено MFA, может потребоваться свежее подтверждение. ## Вызвать API ```bash curl 'https://platform.invoise.me/api/v1/shops/{shop_id}/payments?limit=50' \ -H 'Authorization: Bearer ivk_...' ``` | Разрешение | Назначение | | --- | --- | | `read` | чтение инвойсов и депозитов. | | `write` | создание инвойсов и депозитов, управление вебхуками. | Если бэкенд создаёт инвойсы и проверяет их оплату, выдайте оба права. Не считайте, что `write` автоматически включает `read`. Ключ действует только в пределах своего магазина. Он не управляет аккаунтами и командой мерчанта. Не помещайте его в браузерный код, платёжную ссылку или общий чат. ## Ограничить IP При создании или изменении ключа можно указать `allowed_ips`: ```json {"allowed_ips":["203.0.113.10","2001:db8::/32"]} ``` Это примеры: замените их реальными исходящими адресами вашего бэкенда. Для одного ключа допустимо до 10 IP-адресов или CIDR-диапазонов; при большем числе придёт `400 too_many_allowed_ips`. Пустой список снимает ограничение. ## Заменить или отозвать Создайте новый ключ, обновите бэкенд и отзовите старый через `DELETE /api/v1/shops/{shop_id}/keys/{key_id}`. `PATCH` по тому же пути меняет `name`, `enabled`, `scopes` и `allowed_ips`. Пропущенные поля не меняются. Редактирование не показывает токен заново и не выпускает новый. Ключ работает, пока его не отключили или не отозвали и пока сохраняется доступ к аккаунту и магазину. Это не бессрочная гарантия доступа. Поля запросов — в [справочнике API](https://docs.invoise.me/api-reference/). --- # Вход в аккаунт Вход в интерфейс и безопасность аккаунта отдельно от платёжного API. Source: https://docs.invoise.me/ru/integration/dashboard-sign-in/ Люди входят на [platform.invoise.me](https://platform.invoise.me) через почту или Google. После настройки выдайте бэкенду [API-ключ магазина](https://docs.invoise.me/ru/integration/api-keys/). Агент, которому нужна сессия аккаунта, использует [вход по кошельку](https://docs.invoise.me/ru/agents/sign-in/). Он только для агентов: в интерфейсе его нет, а запрос из браузера отклоняется. Для приёма платежей не нужно реализовывать все методы входа ниже. ## Почта и Google Эти маршруты обслуживают интерфейс. Все пути начинаются с `/api/v1`: | Запрос | Назначение | | --- | --- | | `POST /auth/email/start` | запрашивает код с телом `{"email":"you@example.com"}` и возвращает `challenge_id`. | | `POST /auth/email/verify` | обменивает `challenge_id` и `code` на сессию. | | `GET /auth/google` | начинает переход через браузер. `/auth/google/callback` принимает ответ провайдера. | Ответ сессии содержит `token`, `expires_at`, `csrf` и `user`. Перед продолжением проверьте `user.mfa_required` и `user.onboarding_required`. Адрес на домене одноразовой почты отклоняется с `400 disposable_email`, если для него ещё нет аккаунта, в том числе при привязке email к аккаунту. Существующие аккаунты входят как прежде. ## MFA и безопасность Управлять вторыми факторами удобнее в интерфейсе. Эти маршруты требуют сессии: | Запрос | Назначение | | --- | --- | | `POST /auth/totp/enroll` | начинает подключение и возвращает URI настройки. | | `POST /auth/totp/verify` | принимает `code`; `"enroll":true` нужно только для подтверждения подключения. | | `POST /auth/recovery` | принимает код восстановления вместе с основной сессией. | | `POST /auth/passkeys/begin` | Начать регистрацию или проверку passkey. | | `POST /auth/passkeys/finish/{id}` | Завершить регистрацию или проверку passkey. | | `PATCH /auth/passkeys/{id}` | Переименовать passkey. | | `DELETE /auth/passkeys/{id}` | Удалить passkey. | | `POST /auth/confirm` | проверяет достаточность свежей авторизации, но сам по себе не подтверждает MFA. | | `POST /auth/logout` | отзывает сессию. | Сессии кошелька подчиняются настроенному MFA. API-ключ не может подключать, удалять или обходить факторы аккаунта. ## Cookie браузера и bearer-токен Интерфейс использует cookie сессии. Запросам на изменение с cookie нужны корректные `Origin` и `X-CSRF-Token`. Серверная интеграция передаёт bearer-токен, поэтому cookie-проверка CSRF ей не нужна. Держите секреты на сервере. Методы работы с аккаунтом и командой — в [справочнике API](https://docs.invoise.me/api-reference/). --- # Идемпотентность, ошибки и лимиты Как безопасно повторять изменяющие запросы Invoise, что означают коды ошибок и какие действуют лимиты. Source: https://docs.invoise.me/ru/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/ru/payments/deposits-and-invoices/#несколько-токенов-или-сетей). | | `solana_setup_required` / `tron_setup_required` | Сначала задать [получателя Solana или Tron](https://docs.invoise.me/ru/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/ru/integration/team-and-access/#заблокированные-аккаунты). | | `rate_limited` | Подождать столько секунд, сколько указано в `Retry-After`, и повторить. | ## Лимиты Если запрос превышает лимит, Invoise отклоняет его с обычным телом ошибки и кодом из таблицы. | Лимит | Значение | Ошибка | | --- | --- | --- | | Сумма одного инвойса | 1 000 000 токенов | `400 invoice_amount_limit` | | Сумма одного инвойса или имитированного перевода в Sandbox | 10 000 токенов | `400 sandbox_amount_limit` | | Активные инвойсы мерчанта | 2 000 | `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` | | Запросы в минуту | 1 200, из них не больше 120 не-GET | `429 rate_limited` | Лимиты сумм указаны в целых токенах, а не в минимальных единицах. Все поддерживаемые токены — долларовые стейблкоины, поэтому 1 000 000 токенов — это около $1 000 000. Инвойс активен, пока он не оплачен, не отменён и не истёк. Инвойс с несколькими сетями считается один раз. Депозитный адрес активен, пока его не отключили; каждая сеть депозита — отдельный адрес. Sandbox и боевой режим считаются отдельно для обоих лимитов. Сотрудники Invoise могут изменить для мерчанта лимиты инвойсов, депозитных адресов и команды. Лимит команды проверяется и при приглашении, и при его принятии. URL адреса вебхука можно изменить, поэтому существующий адрес можно использовать вместо нового. Запросы считаются по API-ключу, по сессии в интерфейсе или, без авторизации, по IP клиента. Ответ `429` содержит `Retry-After: 60`. ## Повторяйте без дублей При таймаутах и временных серверных ошибках сохраняйте **тот же ключ** и увеличивайте задержку. При `429` подождите столько секунд, сколько указано в `Retry-After`. Ошибки входных данных и доступа сначала исправьте. Повторную доставку вебхуков делает Invoise. Надёжно сохраните событие, ответьте 2xx и обработайте его. Дубли отсеивайте по `Invoise-Event-ID`. Старые маршруты `/projects` — аналоги `/shops` с общей областью идемпотентности. Для новых интеграций используйте `/shops`. В старых кодах ошибок может встречаться `project_*`. --- # Команда и доступы Приглашение команды, выбор прав и выгрузка истории платежей. Source: https://docs.invoise.me/ru/integration/team-and-access/ Участника можно пригласить во весь аккаунт мерчанта или только в один магазин. Для управления командой нужна сессия владельца мерчанта; API-ключ магазина не подходит. ## Пригласить участника ```bash curl -X POST 'https://platform.invoise.me/api/v1/merchants/{merchant_id}/invites' \ -H 'Authorization: Bearer ' \ -H 'Idempotency-Key: ' \ -H 'Content-Type: application/json' \ -d '{"provider":"email","subject":"teammate@example.com","role":"developer","shop_id":""}' ``` Роль `viewer` нужна для чтения, `developer` — для интеграции, `owner` — для управления. `shop_id` ограничивает приглашение одним магазином. Если не передать поле или указать `null`, доступ будет на уровне всего мерчанта. Проверьте роль и область доступа перед отправкой. Магазин должен быть активным и принадлежать этому мерчанту. Ошибка в ID не выдаст доступ ко всем магазинам. Получатель входит в аккаунт и принимает приглашение через `POST /api/v1/invites/{id}/accept`. Этому запросу тоже нужен ключ идемпотентности. По умолчанию у мерчанта может быть до 10 участников и ожидающих приглашений вместе. Сверх этого и приглашение, и его принятие вернут `400 team_limit_reached`; сотрудники Invoise могут поднять лимит. См. [Лимиты](https://docs.invoise.me/ru/integration/idempotency-and-errors/#лимиты). ## Посмотреть или отозвать доступ | Запрос | Назначение | | --- | --- | | `GET /api/v1/merchants/{merchant_id}/team` | список выданных доступов и приглашений. | | `DELETE /api/v1/merchants/{merchant_id}/invites/{id}` | отозвать приглашение. | | `DELETE /api/v1/merchants/{merchant_id}/grants/{id}` | отозвать существующий доступ. | Изменения требуют прав владельца и ключа идемпотентности. Если включено MFA, чувствительное действие может попросить свежий код. ## Заблокированные аккаунты Если сотрудники Invoise блокируют мерчанта, его неоплаченные инвойсы отменяются с причиной `merchant_blocked`, депозитные адреса отключаются, а API-ключи перестают работать. Участники видят причину в интерфейсе. Запросы заблокированного пользователя, кроме запросов кошелька и карты, возвращают `403 account_disabled`; причина — в `error.details`. ## Выгрузить историю `GET /api/v1/shops/{shop_id}/export.csv` возвращает CSV для бухгалтерии. Нужен доступ на чтение магазина. Для уведомления об оплате используйте статус или вебхуки. --- # Вебхуки Уведомления о платежах, проверка подписи и обработка повторов. Source: https://docs.invoise.me/ru/integration/webhooks/ Вебхук — HTTP-запрос от Invoise на ваш сервер при событии входящего перевода, инвойса или пейаута. Используйте [GET состояния инвойса или депозита](https://docs.invoise.me/ru/payments/status/) для проверки его текущего состояния. ## 1. Зарегистрируйте адрес ```bash curl -X POST 'https://platform.invoise.me/api/v1/shops/{shop_id}/webhooks' \ -H 'Authorization: Bearer ivk_...' \ -H 'Idempotency-Key: ' \ -H 'Content-Type: application/json' \ -d '{"url":"https://example.com/invoise","filters":["transfer","invoice","payout"]}' ``` Укажите свой публичный HTTPS-адрес. Локальные и приватные адреса не принимаются. Сохраните `secret` из ответа на создание — им проверяется подпись запросов. У магазина может быть до 10 адресов. URL существующего адреса можно изменить, поэтому используйте его вместо нового. См. [Лимиты](https://docs.invoise.me/ru/integration/idempotency-and-errors/#лимиты). ## 2. Выберите события | Событие | Что означает | | --- | --- | | `transfer.observed` | Перевод замечен, но ещё не подтверждён. | | `transfer.confirmed` | Входящий перевод получил достаточно подтверждений. Это может быть лишь частичная оплата инвойса. | | `transfer.reverted` | Предыдущее событие перевода отменено. | | `invoice.closed` | Инвойс закрыт в блокчейне. | | `invoice.cancelled` | Checkout отменён или срок инвойса истёк; это не возврат денег. | | `payout.sent` | Пейаут отправлен в сеть или замечен исходящий перевод. | | `payout.confirmed` | Полный учёт пейаута подтверждён. | | `payout.reverted` | Предыдущее подтверждение пейаута отменено. | | `payout.failed` | Окончательная ошибка пейаута требует вмешательства. | У `invoice.cancelled` поле `data.reason` объясняет причину: `expired` — истёк [срок действия инвойса](https://docs.invoise.me/ru/payments/deposits-and-invoices/#срок-действия-инвойса), `merchant_blocked` — сотрудники Invoise заблокировали мерчанта. При отмене самим мерчантом `reason` нет. Подписывайтесь по группам: `transfer`, `invoice`, `payout`. Входящая оплата и исходящий пейаут — разные события. Временная ошибка RPC или ожидание газа не означают `payout.failed`. `gas.wait` и `sweep.failed` принимаются как фильтры, но Invoise не отправляет их на ваш адрес. Это внутренние сигналы: `gas.wait` — пейаут ждёт средств на комиссию сети и продолжится сам; `sweep.failed` — попытка перевести средства получателю не удалась. Ни то, ни другое не требует от вас действий. Пейаут, который не может завершиться, придёт как `payout.failed`. В sandbox-магазине оба сигнала можно симулировать через `POST /shops/{shop_id}/sandbox/simulate`, чтобы проверить, что задержка пейаута не ломает ваш сценарий. Они меняют только состояние пейаута и не отправляют вебхук. ## 3. Проверьте подпись Заголовок `Invoise-Signature` имеет вид `t=,v1=`. Подпись — HMAC-SHA256 строки `timestamp + "." + raw_body` с секретом вебхука. Пример для Node.js также отклоняет время с расхождением более пяти минут. Часы сервера должны быть синхронизированы; допустимое расхождение выбирайте осознанно. ```js import { createHmac, timingSafeEqual } from 'node:crypto'; export function verify(rawBody, header, secret) { const match = /^t=(\d+),v1=([a-f0-9]{64})$/.exec(header ?? ''); if (!match) return false; const [, timestamp, signature] = match; const age = Math.abs(Date.now() / 1000 - Number(timestamp)); if (!Number.isFinite(age) || age > 300) return false; const expected = createHmac('sha256', secret) .update(timestamp + '.') .update(rawBody) .digest(); return timingSafeEqual(Buffer.from(signature, 'hex'), expected); } ``` В `rawBody` передавайте исходные байты запроса. Нельзя сначала разобрать JSON, собрать его заново и проверять подпись уже над ним. Неверную подпись отклоняйте до сохранения и обработки содержимого. ## 4. Обработайте событие один раз Сокращённый пример: ```json { "id": "", "type": "transfer.confirmed", "created_at": "2026-09-19T10:00:00Z", "data": { "issuance_id": "", "shop_id": "", "external_id": "order-123", "type": "invoice", "invoice_cancelled": false } } ``` | Ситуация | Обработка | | --- | --- | | Дубли | Дубли определяйте по `Invoise-Event-ID`, совпадающему с `id` конверта. Сохраняйте ID и изменение бизнес-данных в одной транзакции. | | Приём события | Надёжно сохраните принятое событие, быстро ответьте 2xx и выполняйте остальную работу из очереди. | | Повторная доставка | Повторы и ручная доставка сохраняют ID события. `Invoise-Attempt-ID` меняется и не подходит для защиты от дублей. | | Порядок событий | Порядок прихода не гарантируется. Смотрите на содержимое и при необходимости сверяйтесь с [текущим статусом](https://docs.invoise.me/ru/payments/status/). | При отмене `chain_event.reference_event_id` ссылается на предыдущее событие сети. Пейауты содержат стабильный `payout_id`, хэш транзакции, суммы и комиссию; неизвестные суммы равны `null`. Список ID входящих переводов ограничен 100 записями и помечает усечение. В старых сохранённых событиях может быть `project_id`: сначала читайте `shop_id`, а при его отсутствии — `project_id`. Повторная доставка сохраняет исходные байты. ## Проверить доставку История доступна через `GET /api/v1/shops/{shop_id}/deliveries`. Повторить доставку можно через `POST /api/v1/shops/{shop_id}/deliveries/{id}/replay` с сохранённым ключом идемпотентности. Нового бизнес-события от этого не появляется. --- # Платёжная страница Ссылка оплаты, название и логотип магазина, проверка платежа. Source: https://docs.invoise.me/ru/payments/checkout/ У каждого инвойса и депозита есть готовая страница оплаты. Когда адрес готов, передайте клиенту `payment_url` из ответа API. На странице уже есть токен, сеть, адрес, QR-код и статус. Делать собственный checkout не нужно. ## Передайте ссылку Используйте `payment_url` как есть. Не собирайте ссылку из `issuance_id` и не полагайтесь на фиксированный формат `public_id`. Клиент должен отправить указанный токен в указанной сети. Перевод другого токена или в другой сети не оплачивает инвойс. ## Настройте название и логотип Измените оформление в интерфейсе или через API с сессией владельца: ```http PATCH /api/v1/shops/{shop_id}/branding Authorization: Bearer Idempotency-Key: Content-Type: application/json {"name":"My shop"} ``` Оформление задаёт название магазина и логотип. Ссылку `return_url` укажите при создании инвойса или депозита. Адрес получателя от этого не меняется. ## Подтвердите оплату на сервере Ссылка возврата нужна для навигации. Сам переход по ней **не доказывает оплату**. Проверьте [статус инвойса и депозита](https://docs.invoise.me/ru/payments/status/) с вашего бэкенда или подпись [вебхука](https://docs.invoise.me/ru/integration/webhooks/). API-ключ должен оставаться на сервере: не вставляйте его в ссылку или код браузера. --- # Депозиты и инвойсы Создание разового инвойса или многоразового депозитного адреса. Source: https://docs.invoise.me/ru/payments/deposits-and-invoices/ Для заказа с фиксированной ценой создайте **инвойс**. Для баланса клиента, который можно пополнять много раз, — **депозит**. ## Создать инвойс ```bash curl -X POST 'https://platform.invoise.me/api/v1/shops/{shop_id}/invoices' \ -H 'Authorization: Bearer ivk_...' \ -H 'Idempotency-Key: ' \ -H 'Content-Type: application/json' \ -d "{\"chain_id\":${CHAIN_ID:?},\"token\":\"${TOKEN_ADDRESS:?}\",\"amount\":\"${AMOUNT:?}\",\"external_id\":\"order-123\"}" ``` Замените `{shop_id}` на ID магазина. Задайте `CHAIN_ID` и `TOKEN_ADDRESS` по [ответу API](https://docs.invoise.me/ru/payments/networks/), а `AMOUNT` — в минимальных единицах выбранного токена. `external_id` связывает инвойс с заказом в вашей системе и не заменяет ключ идемпотентности. Ответ — `202 Accepted`. Сохраните `id` и опрашивайте [статус инвойса](https://docs.invoise.me/ru/payments/status/), пока не появится `address`. Затем передайте плательщику вернувшийся `payment_url`. Частичные оплаты складываются. Когда подтверждённых средств достаточно, Invoise отправляет пейаут и закрывает инвойс. Получателю уходит сумма инвойса минус комиссия. **Переплата уходит Invoise**, а не получателю. Инвойс одноразовый: автоматического продления нет. ## Срок действия инвойса По умолчанию инвойс открыт 30 дней. Чтобы выбрать другой срок, добавьте в тело запроса `expires_in`, например `"expires_in":"7d"`. Допустимые значения: `1d`, `7d`, `30d`, `180d` и `365d`. Ответы с инвойсом, в том числе публичный checkout, содержат `expires_at`. Когда срок истекает, неоплаченный инвойс закрывается: заполняется `cancelled_at` и отправляется вебхук `invoice.cancelled` с `data.reason`, равным `expired`. Оплата, пришедшая позже, всё равно учитывается и может уйти в пейаут, как у отменённого инвойса. У депозитов срока нет. Если передать `expires_in` при создании депозита, придёт `400 invalid_expires_in`. ## Создать депозитный адрес С теми же заголовками отправьте запрос на другой путь: ```bash curl -X POST 'https://platform.invoise.me/api/v1/shops/{shop_id}/deposits' \ -H 'Authorization: Bearer ivk_...' \ -H 'Idempotency-Key: ' \ -H 'Content-Type: application/json' \ -d "{\"chain_id\":${CHAIN_ID:?},\"token\":\"${TOKEN_ADDRESS:?}\",\"external_id\":\"customer-123\"}" ``` Фиксированный `amount` не нужен. Дождитесь адреса так же, как для инвойса. На него можно многократно отправлять выбранный токен в выбранной сети. Небольшие переводы накапливаются до порога пейаута магазина. Получите его через `GET /api/v1/shops/{shop_id}/terms`. ## Несколько токенов или сетей Передайте `assets` вместо `chain_id` и `token`, чтобы плательщик сам выбрал, чем платить. Это работает для инвойсов и депозитов: ```bash curl -X POST 'https://platform.invoise.me/api/v1/shops/{shop_id}/invoices' \ -H 'Authorization: Bearer ivk_...' \ -H 'Idempotency-Key: ' \ -H 'Content-Type: application/json' \ -d '{"assets":[{"chain_id":,"token":""},{"chain_id":,"token":""}],"amount":"10.5","external_id":"order-124"}' ``` С `assets` сумма инвойса `amount` — **десятичная сумма в токенах**, например `"10.5"`, а не минимальные единицы: у токенов может быть разное число знаков. Каждый вариант должен достигать `minimum_payment` своей сети. Ответ — группа. Каждый вариант — отдельный инвойс или депозитный адрес со своим `address`, суммой в минимальных единицах и статусом: ```json { "id": "", "group": true, "shop_id": "", "public_id": "", "status": "registering", "payment_url": "https://pay.invoise.me/", "options": [ { "id": "", "public_id": "", "chain_id": 12345, "token": "", "token_decimals": 6, "family": "evm", "amount": "10500000", "address": null, "status": "registering" } ], "expires_at": "2026-10-19T09:00:00Z" } ``` Сохраните `id` группы. `GET /api/v1/shops/{shop_id}/issuances/{id}` возвращает группу со всеми вариантами; опрашивайте его, пока у вариантов не появятся адреса, затем передайте плательщику `payment_url` группы — там он выберет вариант. Группа-инвойс оплачивается один раз. Её `status` берётся у оплаченного варианта, а `paid_issuance_id` указывает на него. Вебхуки приходят по каждому варианту и содержат `group_id` и `group_public_id`. `duplicate: true` означает, что группа уже оплачена другим вариантом: не засчитывайте заказ дважды. У группы-депозита остаётся по одному многоразовому адресу на вариант. Отменяйте группу-инвойс или отключайте группу-депозит по `id` группы: все варианты меняются вместе. `id` отдельного варианта вернёт `400 issuance_in_group`. Если хотя бы один вариант создать нельзя, не создаётся ничего, а `error.details` указывает вариант как `{chain_id, token}`. Пустая или повторённая пара, а также `assets` вместе с `chain_id` или `token` вернут `400 invalid_assets`. ## Лимиты Сумма одного инвойса — не больше 1 000 000 токенов. У мерчанта может быть до 2 000 активных инвойсов и ограниченное число активных депозитных адресов в каждом семействе сетей. Чтобы освободить место, отмените ненужные инвойсы или отключите ненужные депозиты. Точные значения и коды ошибок — в разделе [Лимиты](https://docs.invoise.me/ru/integration/idempotency-and-errors/#лимиты). ## Отключить депозит или отменить инвойс | Действие | Запрос | | --- | --- | | Отключить страницу депозита | `PATCH /api/v1/shops/{shop_id}/deposits/{id}` с `{"enabled":false}`. Для включения передайте `true`. | | Отменить страницу инвойса | `POST /api/v1/shops/{shop_id}/invoices/{id}/cancel`. | Для обоих действий нужны авторизация и сохранённый `Idempotency-Key`. Эти действия закрывают страницу оплаты. **Они не возвращают деньги и не прекращают наблюдение за адресом.** Средства на отменённом инвойсе всё ещё могут уйти в пейаут; его события содержат `invoice_cancelled: true`. Переводы после завершения инвойса учитываются как поздние и автоматически не выплачиваются. Их восстановление, как и восстановление ошибочно отправленного токена, требует отдельной ручной операции. Все поля запросов и ответов — в [справочнике API](https://docs.invoise.me/api-reference/). --- # Сети и токены Выбор сети и токена, формат сумм и комиссии магазина. Source: https://docs.invoise.me/ru/payments/networks/ Перед созданием инвойса или депозита выберите сеть и токен из API. Одного названия токена недостаточно: нужен его адрес в выбранной сети. ## Получите доступные сети ```bash curl 'https://platform.invoise.me/api/v1/networks' ``` В ответе вам нужны: | Поле | Назначение | | --- | --- | | `chain_id` | ID сети. | | `family` | `solana` или `tron` для этих сетей; у EVM-сетей поля нет или оно равно `evm`. | | `tokens[].address` | адрес токена: контракт в EVM и Tron, mint в Solana. | | `tokens[].decimals` | число знаков после запятой. | | `tokens[].status` | готовность токена, если поле есть. Для реальных платежей используйте `ready`. | | `minimum_payment` | наименьшая сумма инвойса в этой сети, в целых токенах. | Публичный каталог описывает настроенные сети. У мерчанта может быть включена только часть из них: при настройке проверьте `GET /api/v1/merchants/{merchant_id}/networks` с токеном сессии. API отклонит создание инвойса или депозита, если сеть или токен недоступны. Для Solana и Tron до первого инвойса у магазина нужно задать получателя. См. [Solana и Tron](https://docs.invoise.me/ru/payments/solana-and-tron/). Набор сетей и токенов меняется через настройки платформы. Получайте доступность, адреса и `decimals` из API при выборе актива; не храните собственный фиксированный список. ## Минимальный платёж `minimum_payment` — целое число токенов, например `"1"`. Инвойс меньше этой суммы вернёт `400 amount_below_minimum`. Поле есть в обоих списках сетей. Значение отличается между сетями и может меняться, поэтому читайте его из API, а не храните в коде. ## Укажите сумму Сумма инвойса — **строка с целым числом в минимальных единицах токена**: | Знаков у токена | 10 токенов в запросе | | --- | --- | | 6 | `"10000000"` | | 18 | `"10000000000000000000"` | Не отправляйте `"10.5"`. При 6 знаках 10,5 токена — это `"10500000"`. Для расчётов используйте целые числа (`BigInt` в JavaScript): обычные числа с плавающей точкой могут терять точность. Исключение — инвойс с несколькими токенами или сетями: ему передают десятичную сумму в токенах, например `"10.5"`. См. [несколько токенов или сетей](https://docs.invoise.me/ru/payments/deposits-and-invoices/#несколько-токенов-или-сетей). ## Получите комиссию и порог пейаута ```bash curl 'https://platform.invoise.me/api/v1/shops/{shop_id}/terms' \ -H 'Authorization: Bearer ivk_...' ``` Ответ содержит условия по каждой сети: | Поле | Назначение | | --- | --- | | `invoice` и `deposit` | комиссия: `bps`, `minimum`, `maximum`. | | `sweep_threshold` | сколько нужно накопить на депозитном адресе перед пейаутом. | | `minimum_sweep` и `maximum_sweep` | указанный API диапазон этого параметра. | `bps` — сотые доли процента: 50 bps = 0,5%. `minimum` и `maximum` комиссии выражены в единицах с восемнадцатью знаками независимо от токена: `10000000000000000` означает комиссию 0,01 токена. `sweep_threshold` — обычная сумма в токенах, например `"1"`. **Максимальная комиссия — не максимальная сумма платежа.** Не смешивайте её с суммой инвойса и порогом пейаута депозитов. --- # Sandbox Проверка платёжных событий без реальной криптовалюты. Source: https://docs.invoise.me/ru/payments/sandbox/ В Sandbox можно проверить приём платежей без отправки криптовалюты. У каждого мерчанта может быть один sandbox-магазин. Создайте отдельный магазин с `"sandbox": true`. Переключить существующий боевой магазин в Sandbox нельзя. ## Проверить инвойс 1. Создайте инвойс в sandbox-магазине по [быстрому старту](https://docs.invoise.me/ru/start/quickstart/). 2. Сохраните его `id` как `issuance_id`. 3. Имитируйте подтверждённый входящий перевод: ```bash curl -X POST 'https://platform.invoise.me/api/v1/shops/{shop_id}/sandbox/simulate' \ -H 'Authorization: Bearer ivk_...' \ -H 'Idempotency-Key: ' \ -H 'Content-Type: application/json' \ -d '{"issuance_id":"","kind":"transfer.confirmed","amount":"10000000"}' ``` Укажите настоящую сумму инвойса в минимальных единицах. Пустое тело `{}` не указывает платёж и приведёт к ошибке. В Sandbox один инвойс или имитированный перевод — не больше 10 000 токенов; бо́льшая сумма вернёт `400 sandbox_amount_limit`. Инвойсы и депозитные адреса Sandbox считаются отдельно от боевых. См. [Лимиты](https://docs.invoise.me/ru/integration/idempotency-and-errors/#лимиты). Снова запросите [статус](https://docs.invoise.me/ru/payments/status/). Полностью оплаченный инвойс получит `funded`, а подписчики вебхуков — событие `transfer.confirmed`. Этот вызов добавляет конкретное событие, а не воспроизводит весь блокчейн-платёж. Чтобы после оплаты имитировать закрытие инвойса, отправьте **новый** ключ идемпотентности и тело: ```json {"issuance_id":"","kind":"invoice.closed","amount":"0"} ``` Так проверяется состояние `settled`. Для проверки корректировок можно отправить `transfer.reverted`, указав в `reference_event_id` ID предыдущего события. Каждому новому событию нужен свой сохранённый ключ. ## Начать тест заново `POST /api/v1/shops/{shop_id}/sandbox/reset` удаляет историю операций Sandbox. Нужны сессия владельца, свежее подтверждение MFA, если оно включено, и `Idempotency-Key`. После сброса старые ключи идемпотентности сохраняют прежние результаты. Для новых тестов используйте новые ключи. ## Перед реальными платежами Sandbox проверяет работу с API и событиями. Она не проверяет реальные подтверждения сети, стоимость газа и зачисление на биржу. Для этого отдельно проверьте небольшой реальный платёж. --- # Solana и Tron Как задать получателя в Solana или Tron и чем эти платежи отличаются от EVM. Source: https://docs.invoise.me/ru/payments/solana-and-tron/ Сети Solana и Tron есть в `GET /api/v1/networks` рядом с EVM-сетями, у них `family` равно `solana` или `tron`. Токены, `decimals` и `minimum_payment` получайте из API, а не храните свой список. Адреса в этих сетях записываются в их собственном формате base58 — в запросах, ответах и вебхуках. ## Чем они отличаются от EVM | | EVM | Solana | Tron | | --- | --- | --- | --- | | Адрес для оплаты | Адрес контракта. Получатель закрепляется в блокчейне при создании адреса. | Отдельный ключ на каждый платёж, его хранит подписывающий сервис Invoise. | Отдельный ключ на каждый платёж, его хранит подписывающий сервис Invoise. | | Хранение средств | Средства могут уйти только получателю, закреплённому в блокчейне, за вычетом комиссии. | Invoise держит платёж, только пока не перешлёт его вашему получателю. | Invoise держит платёж, пока не перешлёт его. Платёжного контракта нет. | | Получатель | `recipient` магазина | `PUT /shops/{shop_id}/solana-recipient` | `PUT /shops/{shop_id}/tron-recipient` | | Делегат | Необязателен | Нет | Нет | | Sandbox-магазин | Да | Нет: `400 solana_sandbox_unavailable` | Да | Tron включается для мерчанта по запросу — напишите в поддержку. Его `minimum_payment` выше, чем в других сетях. ## Задайте получателя Чтобы выпускать платежи в Solana или Tron, магазину нужен получатель в этой сети. Без него создание инвойса или депозита вернёт `400 solana_setup_required` или `400 tron_setup_required`. ```bash curl -X PUT 'https://platform.invoise.me/api/v1/shops/{shop_id}/solana-recipient' \ -H 'Authorization: Bearer ' \ -H 'Idempotency-Key: ' \ -H 'Content-Type: application/json' \ -d '{"address":""}' ``` Для Tron используйте `/tron-recipient`. Задать получателя может только сессия владельца; API-ключ магазина может его только прочитать. `GET` по тому же пути возвращает `{"address":"..."}`, пока получатель не задан — с пустым адресом. Получатель задаётся один раз. Тот же адрес повторно принимается, другой вернёт `400 shop_addresses_immutable`. Проверьте адрес до сохранения. | Сеть | Правила | | --- | --- | | Solana | Нужен обычный кошелёк, не program-derived address и не адрес Invoise: иначе `invalid_solana_address`. У кошелька уже должен быть аккаунт для токена, иначе создание инвойса или депозита вернёт `solana_recipient_token_account_required`. Сначала один раз получите на него этот токен. | | Tron | Некорректный адрес вернёт `invalid_tron_address` или `invalid_tron_checksum`, адрес Invoise — `invalid_tron_recipient`. У мерчанта должен быть включён Tron, иначе `merchant_network_disabled`. | ## Выплаты в кошелёк Invoise [Кошелёк Invoise](https://docs.invoise.me/ru/payments/wallet/) работает в EVM-сетях. Магазин с целью выплат `wallet` отправляет туда и платежи в Solana: Invoise переводит их в кошелёк в EVM-сети через мост. Если мост недоступен, выпуск в Solana вернёт `400 solana_bridge_unavailable`. `GET /merchants/{merchant_id}/networks` показывает `wallet_bridge: true` у сети Solana, где мост работает. Платежи в Tron не попадают в кошелёк. Выбрать кошелёк для Tron нельзя, пока мост для Tron не готов, а выпуск в Tron у магазина, чьи выплаты в Tron идут в кошелёк, вернёт `400 tron_bridge_unavailable`. Оставьте для Tron собственный адрес. Выбор задаётся для каждого семейства сетей через `PATCH /shops/{shop_id}`: `solana_payout_target` и `tron_payout_target` принимают `address` или `wallet`. См. [справочник API](https://docs.invoise.me/api-reference/). --- # Статус инвойса и депозита Проверка инвойса или депозита через API — с вебхуками или без них. Source: https://docs.invoise.me/ru/payments/status/ Запрашивайте состояние инвойса или депозита через GET. Вебхуки уведомляют об изменениях автоматически. ## Получите инвойс или депозит Используйте `id` из ответа на создание инвойса или депозита: ```bash curl 'https://platform.invoise.me/api/v1/shops/{shop_id}/issuances/{issuance_id}' \ -H 'Authorization: Bearer ivk_...' ``` Важные поля примера ответа (остальные опущены): ```json { "id": "f06b8a31-19c7-4687-ade3-1c09466d2751", "kind": "invoice", "status": "funded", "amount": "10000000", "received": "10000000", "token_decimals": 6, "expires_at": "2026-10-19T10:00:00Z", "cancelled_at": null, "disabled_at": null, "payout_tx_hash": null } ``` Обе суммы — целочисленные строки в минимальных единицах. Здесь пришло 10 токенов, но подтверждённой транзакции пейаута ещё нет. ## Как читать статус инвойса | `status` | Что делать | | --- | --- | | `registering` | Дождитесь непустого `address`. Не вычисляйте адрес сами. | | `open` | Ждите оплату. В `received` уже может быть частичная сумма. | | `funded` | Подтверждённых средств достаточно для пейаута. | | `settled` | Инвойс закрыт в блокчейне. | | `reconciling` | Дождитесь сверки; не считайте платёж успешным. | Отдельно проверяйте `cancelled_at`: это дата или `null`, а не значение статуса. Поле заполняется, когда вы отменяете инвойс, когда неоплаченный инвойс доходит до `expires_at` или когда сотрудники Invoise блокируют мерчанта; вебхук `invoice.cancelled` различает эти случаи по [`data.reason`](https://docs.invoise.me/ru/integration/webhooks/#2-выберите-события). Отмена скрывает checkout, но не останавливает переводы и пейаут. Заранее решите, что делать с оплаченным отменённым инвойсом. `funded` означает получение оплаты, а не завершение пейаута. `settled` фиксирует закрытие инвойса. Полный учёт пейаута подтверждает `payout.confirmed`; `payout_tx_hash`, если он есть, указывает на последний подтверждённый перевод получателю. Если получен `transfer.reverted`, Invoise сообщает об отмене конкретного входящего перевода в сети. Найдите его по `chain_event.reference_event_id`, запросите актуальное состояние инвойса и скорректируйте учёт этого перевода один раз. Формат события описан в [вебхуках](https://docs.invoise.me/ru/integration/webhooks/). ## Как следить за депозитом Депозитный адрес многоразовый. После пейаута он может вернуться в `open`, поэтому не ждите постоянного `settled`. `received` — **вся подтверждённая входящая сумма**, а не остаток. Пейаут её не уменьшает. Отмена перевода при реорганизации может уменьшить. Зачисляйте каждый входящий платёж один раз; для этого удобны вебхуки со стабильным ID события. `disabled_at` управляет доступностью checkout. Отключение депозита не прекращает наблюдение за адресом. ## Получите список инвойсов и депозитов ```bash curl 'https://platform.invoise.me/api/v1/shops/{shop_id}/payments?limit=50' \ -H 'Authorization: Bearer ivk_...' ``` С `limit` от 1 до 100 ответ имеет вид `{"items":[...],"next_cursor":"..."}`. Для следующей страницы передайте `cursor`; пустой `next_cursor` означает конец. Без параметров пагинации приходит ограниченный массив, а не вся история. Есть фильтры `kind`, `status` и `q`. Фильтр списка `status=paid` выбирает `funded` и `settled`. Сам GET инвойса или депозита не возвращает статус `paid`. Поле `transfers` в ответе инвойса или депозита содержит только десять последних подтверждённых входящих переводов и пейаутов. Это не полный журнал. ## Публичный статус checkout `GET /api/v1/checkout/{public_id}` работает без ключа. Он отдаёт состояние страницы оплаты, в том числе `status`, `received`, `amount` и `expires_at`. Для записей магазина на вашем бэкенде используйте авторизованный GET инвойса или депозита. Автоматические уведомления и проверка подписи описаны в [вебхуках](https://docs.invoise.me/ru/integration/webhooks/). --- # Кошелёк Invoise Куда поступают платежи магазина, кто управляет кошельком и что Invoise может и не может с ним сделать. Source: https://docs.invoise.me/ru/payments/wallet/ Магазин выплачивает средства либо на ваш собственный адрес, либо в **кошелёк Invoise** участника аккаунта. Кошелёк — смарт-аккаунт [Safe](https://safe.global) с тремя владельцами и порогом 2 из 3: | Владелец | У кого | Роль | | --- | --- | --- | | Ключ мерчанта | У вас, только в браузере | Подписывает каждый вывод и изменение настроек. Не покидает устройство в открытом виде. | | Со-подписант Invoise | Сервис подписи Invoise | Добавляет вторую подпись к тому, что подписали вы. Один не может двигать средства. | | Делегат (по желанию) | Ваш собственный холодный кошелёк | Вместе с вами: выход без Invoise. Один: постановка вывода в очередь через модуль задержки. | Один кошелёк на аккаунт, один адрес во всех поддерживаемых EVM-сетях; в сети он разворачивается при первом выводе. Средства остаются в той сети и том токене, в которых пришли; при получении ничего не конвертируется. ## Настройка 1. Создайте магазин с выплатами в **кошелёк Invoise**. Настройка откроется сразу, и её нельзя пропустить, пока магазин ждёт кошелёк. 2. Выберите, чем разблокировать ключ: код из шести символов, пароль (от 10 символов) или passkey. Код и пароль усиливаются на стороне сервиса подписи (OPRF) и блокируются после десяти неверных попыток; passkey использует расширение PRF, где оно поддерживается. 3. Без делегата вы дополнительно сохраняете **ключ восстановления** — единственный способ вернуть средства при утере кода или пароля. Делегата можно добавить позже на вкладке кошелька. ## Вывод Выводите любой поддерживаемый токен в любую поддерживаемую сеть с одним подтверждением. Invoise собирает USDC из других сетей через CCTP Circle, обменивает в сети назначения, если токен выплаты другой, и переводит получателю. Комиссия — удвоенный газ каждого шага по текущей цене, списывается в токене каждой сети; за невыполненные шаги ничего не списывается. Если последний шаг не удался, средства остаются на кошельке в сети назначения. Защита по желанию: дневной лимит в USD, охлаждение, которое приостанавливает вывод после изменений безопасности и заставляет новые адреса ждать, и второй фактор на каждую операцию. Ослабление защиты вступает в силу только после текущего периода охлаждения. ## Если Invoise недоступен - **Делегат один:** ставит перевод в очередь через модуль Zodiac Delay; он исполняется после трёх дней ожидания и истекает ещё через неделю. Вы получаете письмо и уведомление в кабинете и можете отменить запрос до исполнения. - **Вы и делегат:** подписываете транзакцию Safe напрямую ключом восстановления и кошельком делегата; она исполняется сразу. Оба способа работают на автономной аварийной странице (`/emergency.html`), которой нужны только публичный узел сети и ваш кошелёк. Скачайте памятку с адресами кошелька и модуля на вкладке безопасности и храните её вместе с ключом восстановления. ## Что Invoise не может Invoise не может двигать средства без вашей подписи, не знает ваш код или пароль, не может открыть ваши конверты без ключа сервиса подписи и не может остановить путь делегата. --- # Основные понятия Мерчант, магазин, инвойс, депозит и пейаут — сущности Invoise. Source: https://docs.invoise.me/ru/start/concepts/ Invoise выдаёт клиенту адрес для оплаты и отправляет полученные средства на ваш кошелёк за вычетом комиссии. | Понятие | Значение | | --- | --- | | Аккаунт | Пользователь, который входит в платформу и получает доступ к мерчантам и магазинам. | | Мерчант | Бизнес в Invoise со своими магазинами, командой и условиями. | | Магазин | Место создания инвойсов и депозитов. У него свои настройки получателя, API-ключи и история операций. | | Инвойс | Запрос на разовую оплату фиксированной суммы. Создаётся через `/invoices`. | | Депозит | Многоразовый адрес для пополнений без фиксированной суммы. Создаётся через `/deposits`. | | Входящий перевод | Средства, отправленные плательщиком на адрес инвойса или депозита. Один инвойс можно оплатить несколькими переводами. | | Пейаут | Перевод полученных средств получателю магазина за вычетом комиссии. | `issuance` — общее имя ресурса API для инвойса и депозита. Сохраняйте `id` из ответа на создание как `issuance_id` для последующих запросов. Заказ в вашей системе можно связать с инвойсом через `external_id`. Сам инвойс в Invoise всегда называется инвойсом. ## Как проходит платёж 1. Создайте инвойс или депозит. 2. Дождитесь `address` и передайте клиенту вернувшийся `payment_url`. 3. Клиент отправит выбранный токен в выбранной сети. 4. Invoise подтвердит входящий перевод. Когда суммы достаточно, отправит пейаут получателю. Проверять результат можно GET-запросом или через вебхуки. См. [Статус инвойса и депозита](https://docs.invoise.me/ru/payments/status/). Инвойс становится `funded`, когда получена достаточная подтверждённая сумма. Завершение пейаута подтверждается отдельно событием `payout.confirmed`. ## Куда идут пейауты | Настройка | Для чего нужна | | --- | --- | | Адрес получателя | Кошелёк для EVM-пейаутов. Проверьте, что он поддерживает выбранные сети. | | Кошелёк Invoise | Вместо адреса магазин может платить в [кошелёк Invoise](https://docs.invoise.me/ru/payments/wallet/) участника аккаунта. | | Делегат | Необязательный кошелёк под вашим управлением для самостоятельного завершения EVM-инвойсов с оплатой газа. Адрес биржи для этой роли не подходит. | Получателя, делегата и выбор между адресом и кошельком Invoise можно изменить позже через `PATCH /shops/{shop_id}`. Каждый инвойс и депозит сохраняет получателя и делегата на момент создания, поэтому изменение касается только инвойсов и адресов, созданных после него. У Solana и Tron свои получатели. См. [Solana и Tron](https://docs.invoise.me/ru/payments/solana-and-tron/). ## Комиссия и небольшие платежи Комиссия удерживается из пейаута. Получайте актуальные [комиссии и лимиты](https://docs.invoise.me/ru/payments/networks/) магазина из API. Переводы на депозитный адрес накапливаются до порога автоматического перевода. Частичные оплаты инвойса — до его суммы. Переплата по инвойсу уходит Invoise вместе с комиссией, а не получателю. Попробовать интеграцию без реальных средств можно в [Sandbox](https://docs.invoise.me/ru/payments/sandbox/). --- # Быстрый старт Создайте магазин, создайте инвойс и примите платёж через REST API Invoise. Source: https://docs.invoise.me/ru/start/quickstart/ **Быстрый онбординг с агентом** Хотите подключиться быстрее? Скопируйте промпт и передайте своему агенту — он поможет настроить магазин и проверить первый инвойс. ```text wrap Помоги подключить Invoise к моему проекту. Прочитай https://docs.invoise.me/llms.txt, https://docs.invoise.me/openapi.json и https://docs.invoise.me/ru/agents/integration.md. Используй существующий доступ или помоги пройти вход, создать мерчанта, магазин и API-ключ. Если входишь кошельком, спроси мой email до создания мерчанта. Уточни у меня адрес получателя до создания магазина. Получай доступные сети, токены, decimals и комиссии из API. Начни с Sandbox: создай инвойс, получи payment_url, подключи вебхуки с проверкой подписи и защитой от повторов, проверь оплату через GET. Сохраняй Idempotency-Key до запросов. В конце покажи результат проверки и что нужно для приёма реальных платежей. ``` Это обычный способ подключить Invoise к сайту или бэкенду: человек входит в интерфейс, настраивает магазин, а сервер дальше работает с API по ключу. Делаете агента, который работает без браузера и без почты? Вам в раздел [Вход агента](https://docs.invoise.me/ru/agents/sign-in/). Эта страница исходит из того, что настройку делает человек. ## 1. Войдите и создайте магазин Откройте [platform.invoise.me](https://platform.invoise.me) и войдите по коду на почту или через Google. При первом входе создаётся мерчант; магазинов у него ещё нет, поэтому создайте один. Магазину нужен **получатель** — кошелёк, на который приходят деньги, — либо магазин платит в ваш [кошелёк Invoise](https://docs.invoise.me/ru/payments/wallet/). Получателя и необязательного делегата можно изменить позже; уже созданные инвойсы и адреса сохраняют значения на момент создания. Хотите потренироваться без реальных средств — создайте sandbox-магазин. См. [Sandbox](https://docs.invoise.me/ru/payments/sandbox/). ## 2. Создайте API-ключ В магазине создайте ключ с правами `read` и `write`. Он начинается с `ivk_` и показывается один раз, поэтому сохраните его сразу. Сервер передаёт его в каждом запросе: ```text Authorization: Bearer ivk_... ``` Ключ работает только для одного магазина и не может тронуть аккаунт или команду. См. [API-ключи](https://docs.invoise.me/ru/integration/api-keys/). ## 3. Выберите сеть и токен ```bash curl https://platform.invoise.me/api/v1/networks ``` Возьмите `chain_id`, адрес токена и `decimals` из ответа. Выберите сеть, включённую для мерчанта, и готовый токен. Доступные активы меняются; не зашивайте их список в код. См. [Сети и токены](https://docs.invoise.me/ru/payments/networks/). ## 4. Создайте инвойс Суммы — целочисленные строки в минимальных единицах токена. При 6 знаках `10000000` — это 10 токенов. Перед запросом задайте переменные окружения: | Переменная | Значение | | --- | --- | | `CHAIN_ID` | `chain_id` выбранной сети из API. | | `TOKEN_ADDRESS` | `tokens[].address` выбранного токена в этой сети. | | `AMOUNT` | Сумма инвойса в минимальных единицах, рассчитанная по `tokens[].decimals`. | ```bash curl -X POST https://platform.invoise.me/api/v1/shops/{shop_id}/invoices \ -H 'Authorization: Bearer ivk_...' \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: 2a8b1f47-6d0c-4a1f-8f0b-4f2c9f3a77d2' \ -d "{\"chain_id\":${CHAIN_ID:?},\"token\":\"${TOKEN_ADDRESS:?}\",\"amount\":\"${AMOUNT:?}\"}" ``` Замените `{shop_id}` на ID магазина. Создайте и сохраните уникальный `Idempotency-Key` для этого инвойса; ключ в примере — только образец. В ответе `202 Accepted` сохраните `id` как `issuance_id`. Код `202` означает принятие запроса на создание, а не оплату клиентом. Нужен многоразовый адрес для пополнений без фиксированной суммы? Вызовите `/deposits`. См. [Депозиты и инвойсы](https://docs.invoise.me/ru/payments/deposits-and-invoices/). ## 5. Дождитесь адреса ```bash curl https://platform.invoise.me/api/v1/shops/{shop_id}/issuances/{issuance_id} \ -H 'Authorization: Bearer ivk_...' ``` Опрашивайте, пока не вернётся адрес, и отправьте плательщика на `payment_url` из этого ответа. Это [готовая платёжная страница](https://docs.invoise.me/ru/payments/checkout/) — адрес, QR-код и статус там уже есть. ## 6. Проверьте оплату **Инвойс оплачен, когда его `status` — `funded` или `settled`.** При `funded` нужная сумма уже подтверждена, при `settled` инвойс закрыт в блокчейне. Статус можно получить через API, а об изменении узнать через вебхук. ### Через вебхук До первого платежа зарегистрируйте адрес вашего сервера: ```bash curl -X POST 'https://platform.invoise.me/api/v1/shops/{shop_id}/webhooks' \ -H 'Authorization: Bearer ivk_...' \ -H 'Idempotency-Key: ' \ -H 'Content-Type: application/json' \ -d '{"url":"https://example.com/invoise","filters":["transfer","invoice","payout"]}' ``` Замените URL на свой публичный HTTPS-адрес и сохраните `secret` из ответа. 1. При получении события проверьте `Invoise-Signature` с этим секретом и отсейте повторы по `Invoise-Event-ID`. [Пример проверки подписи](https://docs.invoise.me/ru/integration/webhooks/#3-проверьте-подпись). 2. `transfer.confirmed` сообщает о подтверждённом входящем переводе. Возьмите `data.issuance_id` и запросите статус инвойса через GET ниже: один перевод может покрывать лишь часть суммы. 3. Если `status` — `funded` или `settled` и `cancelled_at` равен `null`, учтите оплату инвойса в вашей системе один раз. Событие `payout.confirmed` отдельно подтверждает полный учёт пейаута получателю. ### Через API Запросите состояние инвойса с вашего сервера: ```bash curl 'https://platform.invoise.me/api/v1/shops/{shop_id}/issuances/{issuance_id}' \ -H 'Authorization: Bearer ivk_...' ``` Важные поля ответа при оплате: ```json { "status": "funded", "amount": "10000000", "received": "10000000", "cancelled_at": null } ``` Здесь вся сумма инвойса подтверждена. Учтите оплату инвойса в вашей системе; повторный GET или вебхук не должен зачислить его второй раз. При `open` продолжайте ждать: оплата ещё не пришла полностью. Можно опрашивать раз в 3–5 секунд и увеличивать интервал при долгом ожидании. `registering` и `reconciling` также не означают успех. Если `cancelled_at` заполнен, обработайте оплату отменённого инвойса отдельно. Все состояния и особенности депозитов — в [статусе инвойса и депозита](https://docs.invoise.me/ru/payments/status/). ## Одно правило, которое стоит запомнить Создание инвойса или депозита требует `Idempotency-Key`. Сохраните ключ: если запрос отвалился по таймауту и непонятно, прошёл он или нет, отправьте тот же запрос с тем же ключом. Вернётся исходный результат, а не второй инвойс. См. [Идемпотентность и ошибки](https://docs.invoise.me/ru/integration/idempotency-and-errors/).