Перейти к основному содержимому

HTML формы

Один из способов добавить оплату криптовалютой на сайт, в интернет-магазин или в бота. Покупатель нажимает кнопку, открывается платежная страница со счетом.

Форма отправляется только методом POST на https://dash.bitsby.app/invoices/form и содержит два поля:

ПолеЧто в нем
database64url от JSON с полями счета
signatureHMAC-SHA256 от строки data, 64 знака hex

Одновременно у проекта может быть не более 50 неоплаченных счетов, созданных этим способом.

Пример формы

<form method="post" action="https://dash.bitsby.app/invoices/form" target="_blank">
<input type="hidden" name="data" value="eyJwcm9qZWN0SWQiOiJhMWIyYzNkNC01ZTZm...">
<input type="hidden" name="signature" value="f77d6da1be35bd2900e0bfed9f202b04...">
<button type="submit">Pay</button>
</form>

Оба значения подставляет сервер магазина при отрисовке страницы. Секрет в разметку не попадает.

Атрибут target="_blank" необязателен: с ним корзина остается открытой в исходной вкладке.

Как собирается контейнер

  1. Собрать JSON с полями счета.
  2. Закодировать его в base64url. Это строка data.
  3. Посчитать signature = HMAC-SHA256(data, formSecret).

Подписывается строка data целиком, поэтому порядок ключей в JSON, отступы и способ экранирования юникода значения не имеют. Стандартный base64 приемник тоже принимает, с паддингом или без.

Пересобирать data после подписи нельзя: изменился хоть байт — подпись считается заново.

Как считать подпись и готовые примеры на четырех языках — в разделе «Подпись HTML-формы».

Ключи внутри data

КлючОбязательныйЧто в нем
projectIdдаID проекта из настроек в личном кабинете, uuid
amountFiatдаСумма от 1 до 100000, не более двух знаков после точки. Строкой "10.50" или числом 10.5
currencyFiatдаВалюта фиата: USD, EUR или RUB
timeToPayдаСрок оплаты в часах: 0.5, 1, 3, 6, 12. Строкой или числом
descriptionнетОписание для покупателя, до 1000 знаков
serviceDataнетИдентификатор заказа на стороне магазина, до 1000 знаков. Покупателю не показывается, но виден в исходном коде формы — не передавайте здесь ничего чувствительного
outputнетerrors — показывать подробности ошибок заполнения

Необязательный ключ можно не класть в JSON — это то же самое, что пустая строка. Порядок ключей любой, незнакомые ключи приемник не читает.

Значения — строки или числа JSON. Логические значения, массивы и вложенные объекты значениями полей не считаются и приходят как пустая строка.

Пример содержимого data:

{
"projectId": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"amountFiat": 10.5,
"currencyFiat": "USD",
"timeToPay": 1,
"description": "Order #7, delivery",
"serviceData": "order-7"
}

Здесь сумма и срок оплаты переданы числами, строкой они тоже принимаются. Необязательный output не задан вовсе.

Формат суммы

Только цифры и точка, не более двух знаков после точки: 10, 10.00, 1000.50. Пробелы по краям обрезаются.

Любой другой формат отклоняется — разделители тысяч, запятая вместо точки, экспоненциальная запись, знак перед числом, символ валюты. Округления нет: третий знак после точки не отбрасывается, а дает отказ.

Секрет формы

Секрет лежит в настройках проекта в личном кабинете, строка «Секрет формы». Его выдает сервер при создании проекта. Задать свое значение нельзя, секрет можно только перевыпустить — например, если он скомпрометирован.

Секрет должен оставаться на сервере магазина. Если он попадет в HTML витрины, подпись потеряет смысл.

Секрет формы и секрет вебхука — разные ключи, смешивать их нельзя.

Идентификатор заказа

Заполняйте serviceData всегда: кладите туда идентификатор заказа на своей стороне. Значение приходит обратно в уведомлении об оплате — по нему магазин находит заказ.

Заполненный serviceData защищает от дублей. Повторная отправка формы и двойной клик по кнопке не создают второй счет: покупателя направит на уже существующий неоплаченный. Совпадение ищется по полям заказа — проекту, сумме, валюте, описанию и serviceData, а не по байтам data.

Значение должно быть уникальным для каждого заказа. При одинаковом значении второй покупатель попадет на неоплаченный счет первого.

Пустой serviceData этой защиты лишает: распознать повтор нечем, каждая отправка создает новый счет. Дубли расходуют лимит в 50 неоплаченных счетов, а при оплате магазину нечем связать платеж с заказом.

Ошибки и режим отладки

Форма проходит две проверки: сначала подпись и контейнер, потом заполнение полей.

Что произошлоЧто покажет сервис
Подпись не сошлась, контейнер не читается, проект чужой или не существуетОбщая ошибка, без причины
Подпись сошлась, но поле заполнено неверноОбщая ошибка. С "output":"errors" — детализация ошибок
Обе проверки пройденыПлатежная страница со счетом

На первой проверке причина не называется никогда и ни при каких настройках.

Пара "output":"errors" в JSON включает подробности второй проверки: сервис назовет поле, перечислит допустимые значения и сообщит, если достигнут потолок в 50 неоплаченных счетов. Ключ живет внутри подписанного контейнера, поэтому подставить его снаружи нельзя.

На время настройки формы кладите "output":"errors" в JSON, после настройки уберите ключ и пересоберите контейнер.

Если не сходится сама подпись, сверьте свои data и подпись с эталонным набором в разделе «Подпись HTML-формы».

Что дальше

Счет, созданный формой, дальше обрабатывается так же, как счет из API или личного кабинета: