Сверяйте ожидаемую сумму токена с полученной и подтверждённой суммами на адресе, который контролируете вы, включая частичную оплату и переплату. Vilna наблюдает за входящими транзакциями и обновляет суммы и статус счёта. Плательщик подписывает и отправляет транзакцию из своего кошелька прямо на ваш. См. сценарии интеграции и уведомление о работе без хранения средств.
Нужен ключ проекта с api:invoice:read и api:invoice:write. Сначала зарегистрируйте адрес, который контролируете вы.
5 состояний жизненного цикла Получено + подтверждено Публичное представление счёта Граница expires_at не включена
status описывает жизненный цикл. Суммы независимо отражают текущие факты о платежах:
| Статус | Значение |
|---|---|
| open | Окно оплаты открыто. Счёт может подтвердиться до окончания срока. |
| processing | Окно закрыто; ещё ожидаются проверки платежей, подтверждения или действия оператора. |
| confirmed | Подтверждена достаточная сумма ожидаемого токена. Конечное состояние. |
| cancelled | Отменён по правилам ниже. Конечное состояние. |
| expired | Окно закрыто, проверки завершены, действительных платежей нет. Конечное состояние. |
Возможен переход прямо из open, если достаточная сумма подтверждена до окончания срока.
Нужны проверки отмены, описанные ниже; частичные платежи остаются связаны со счётом.
Переход из processing после завершения проверок при отсутствии действительных платежей.
Окно оплаты начинается в created_at и заканчивается непосредственно перед expires_at либо раньше при переходе в confirmed или cancelled. Учитывается время включения транзакции в блок по данным сети, а не время получения webhook. Подходящий платёж может набрать подтверждения уже после срока. Наступление срока само по себе не означает expired; частичная оплата может оставить счёт в processing.
amount - запрошенная сумма, received_amount - сумма текущих действительных платежей ожидаемым токеном, попавших в окно, confirmed_amount - её подтверждённая часть. В аутентифицированном API все три поля являются строками с целым числом базовых единиц. Реорганизация может уменьшить суммы. Конечное решение жизненного цикла сохраняется даже при изменении данных сети; перед дальнейшими действиями приложения сверяйте текущие суммы и связи с транзакциями.
Создайте счёт через POST /invoices. Передайте зарегистрированный адрес, CAIP-19 asset_gid, сумму в базовых единицах и будущий expires_at.
Окна оплаты счетов на одном адресе не могут пересекаться. Если на адресе уже есть счёт с открытым окном оплаты, тот же актив и сумма вернут существующий счёт с 200; другие актив или сумма вернут 409 Conflict. При 200 срок и metadata существующего счёта не меняются. Проверьте возвращённые ID, срок и metadata, прежде чем связывать счёт с заказом.
Создайте Idempotency-Key и срок один раз, затем сохраните их вместе с полным телом запроса. Повторы используют тот же ключ и тело. Для токена с 6 десятичными знаками 42.5 единицы передаются как "42500000". Перед расчётом суммы прочитайте метаданные точной сети и контракта; символ не определяет число знаков.
При неизвестном результате повторяйте с тем же ключом и телом. Если ID счёта известен, прочитайте его текущее состояние; иначе поиск результата ограничен доступными списками и фильтрами. Не создавайте новый ключ автоматически. См. Идемпотентность.
Сохраните возвращённый item.id, чтобы проверять счёт и связывать его с заказом.
status_logs содержит переходы жизненного цикла: status, допускающий null comment и changed_at. Это не история каждого изменения сумм. metadata видит только мерчант; декодированные ключи и значения вместе могут занимать не более 4096 байт UTF-8.
Публичное представление API не требует аутентификации. Счёт может прочитать любой, у кого есть его UUID, поэтому передавайте ссылку только предполагаемым получателям. Для своей информационной страницы оплаты используйте GET /public/invoices/{invoice_id} - публичный счёт.
Ответ использует PublicInvoice: поля amount, received_amount и confirmed_amount содержат base и необязательную строку formatted. Показывайте форматированное значение, если оно есть; иначе явно обозначайте базовые единицы. Не подставляйте фиксированный символ токена. Публичное представление скрывает metadata и комментарии истории. Оно отличается от аутентифицированного Invoice, где три поля сумм являются строками.
Читайте GET /invoices/{invoice_id} - сведения о счёте. О завершении судите по самому счёту. Уведомление о транзакции - повод перечитать его, а не доказательство статуса confirmed.
Форматируйте неотрицательные суммы по decimals из метаданных токена. Сохраняйте точность целого значения, в том числе выше безопасного целого JavaScript. Если метаданных нет, показывайте базовые единицы и идентификатор актива, не угадывайте число знаков.
Проверяйте связи в item.transactions вместе с суммами. is_active означает, что транзакция ещё актуальна в сети, но не доказывает оплату счёта. Кандидат Bitcoin из мемпула может быть активен без учтённой суммы. Депозиты отражают чистый положительный вклад по активу; is_matched отмечает ожидаемый токен. Другие активы не входят в запрошенную сумму.
При реорганизации или замене сохранённая связь становится неактивной, её депозиты пустеют. Связь остаётся, поэтому тот же перевод не оплатит другой счёт. Сводки активных транзакций находятся в references.transactions[chain_gid][txid]; у неактивной связи сводки там нет. Сводки используют details.family и поля своего семейства.
Сравнивайте базовые единицы через BigInt. Для запроса "42500000" с 6 знаками полученные "20000000" - частичная оплата 20 единиц, а "45000000" - 45 единиц с превышением на 2.5. Достаточная полученная сумма ещё не означает достаточную подтверждённую, а отменённый или просроченный счёт не завершён оплатой.
Публичного действия ручного подтверждения нет. Читайте текущие status, received_amount, confirmed_amount и связи с транзакциями; не переносите категории оплаты из приложения в ответ API.
Подпишитесь на транзакции адреса счёта и перечитывайте счёт при уведомлении. Подписки не присылают исправления при реорганизации. См. События; при перебоях доставки используйте существующий сценарий сверки.
Используйте GET /invoices - список счетов. Фильтруйте по status жизненного цикла; повторяйте параметр для альтернативных значений (до 10). Чтобы выделить частичную оплату или превышение, сравнивайте суммы в приложении.
Список возвращает InvoiceSummary без status_logs и transactions. Для подробностей перечитайте отдельный счёт.
Счёт в статусе open или processing можно отменить, если среди уже учтённых действительных платежей нет неподтверждённых, а подтверждённая сумма меньше amount. Полностью подтверждённая частичная оплата не препятствует отмене. Если условие отмены не выполнено, API возвращает 422.
Вызовите POST /invoices/{invoice_id}/actions/cancel - отмена счёта. Используйте отдельный ключ отмены и сохраните его, идентификатор счёта и необязательное тело для повторов.
Успех возвращает 204 No Content; повторная отмена уже отменённого счёта тоже возвращает 204. Комментарий необязателен, до 64 символов; тело можно оставить пустым или не передавать. Отмена меняет жизненный цикл мониторинга и не перемещает и не возвращает средства.
После отмены новые платежи не связываются со счётом, даже если время их включения в блок попадает в его прежнее окно оплаты. Существующие связи с платежами сохраняются, а received_amount и confirmed_amount могут меняться при изменении данных сети. Статус остаётся cancelled. Связанные платежи не переносятся в новый счёт, а адрес можно использовать снова.
Чтобы использовать адрес снова, создайте новый счёт, соблюдая требования к созданию и используя новый Idempotency-Key. У нового счёта будет собственное окно оплаты.