POST на
callback_url, настроенный для вашего сайта. Это основной и самый надёжный способ
узнавать об оплате — webhook приходит сразу после изменения, без задержек polling’а.
callback_secret вашего сайта.Как это работает
Событие происходит
Платформа формирует и подписывает webhook
HMAC-SHA256 по callback_secret сайта,
добавляются заголовки X-Signature / X-Timestamp / X-Event-Type / X-Event-Id.Доставка на ваш callback_url
POST на ваш endpoint. Успех — ответ HTTP 2xx в течение 10 секунд.Вы проверяете подпись и обрабатываете
X-Signature constant-time, дедуплицируйте по X-Event-Id, ответьте 200.Заголовки доставки
Каждый webhook приходит со следующими заголовками (имена регистронезависимы):Об X-Event-Id и идемпотентности
X-Event-Id детерминирован: один логический event (тот же ресурс + тот же тип события)
всегда получает один и тот же id — стабильный между повторными попытками и даже между
перезапусками платформы. Значение в заголовке X-Event-Id совпадает с полем eventId в теле.
Используйте его как ключ дедупликации: если событие с этим id уже обработано — ответьте
200 и не выполняйте побочных эффектов повторно.
События
X-Event-Type (и поле eventType в теле) принимает значения:
deposit.status тела события (например,
deposit.finalized может нести status: "paid", "paid_over" или "wrong_amount").
Подробнее о статусах — на странице Депозиты и Выплаты.
Тестовый webhook из эндпоинта /test приходит с особым X-Event-Type: webhook.test —
это не боевое событие.Тело webhook’а
Тело — JSON c полямиeventType, eventId и вложенным объектом deposit либо payout
(в зависимости от ресурса). Поле eventId дублирует заголовок X-Event-Id.
Поля объекта deposit
order_id, переданный при создании депозита (ключ идемпотентности на стороне сайта).paid, paid_over, wrong_amount, fail, system_fail, refund_paid и др.USDT_TRC20, USDT_TON, TRX, TON.null, если приход ещё не зафиксирован.null для account-based сетей (TRON).null, если транзакция ещё не замечена.Поля объекта payout
order_id, переданный при создании выплаты.broadcasted, confirmed, failed и др.decimals актива).null для account-based.null, пока не отправлено.null, если ещё недоступна.null, пока нет on-chain транзакции.null, пока нет on-chain транзакции.payout.failed. null для успешных событий.Проверка подписи
СверяйтеX-Signature с HMAC-SHA256 от сырых байтов запроса. Прочитайте тело
как буфер до парсинга JSON — иначе повторная сериализация изменит подпись.
Политика повторных попыток
Доставка считается успешной, если ваш endpoint вернулHTTP 2xx в течение 10 секунд
(тайм-аут настраивается оператором в диапазоне 1–60 секунд). Любой другой исход — не-2xx
ответ, тайм-аут или сетевая ошибка — считается неудачей, и платформа повторяет доставку
по фиксированному расписанию с возрастающими интервалами:
Попытка 2 — через 30 секунд
Попытка 3 — через 2 минуты
Попытка 4 — через 10 минут
Попытка 5 — через 1 час
Попытка 6 — через 6 часов
Попытка 7+ — через 24 часа (далее интервал не растёт)
fail; такой webhook можно вручную переотправить через
эндпоинт resend.
allow_private_hosts, callback_url может указывать на
адрес во внутренней сети (например, CMS обменника на том же сервере). По умолчанию
внутренние/зарезервированные адреса отклоняются SSRF-защитой, и такие попытки логируются
как неудачные.Тест и переотправка
Два служебных эндпоинта Public API помогают отладить интеграцию. Оба требуют стандартной HMAC-аутентификации Public API (заголовкиX-Api-Id / X-Timestamp /
X-Signature) и возвращают результат в общем конверте ответа { "ok": true, "data": ... }.
POST /v1/public/webhooks/test
Ставит в очередь одну попытку доставки тестового webhook’а с теми же заголовками и подписью,
что и у боевых событий, но с особым типом X-Event-Type: webhook.test. Удобно проверить, что
ваш endpoint доступен, принимает POST и корректно валидирует X-Signature. Повторов нет —
ровно одна попытка.
Тело тестового webhook’а, которое получит ваш callback_url:
data:
POST /v1/public/webhooks/resend/{eventId}
Переотправляет ранее сгенерированный webhook по его X-Event-Id. Тело и URL берутся из лога
доставки, подпись пересчитывается под текущий callback_secret. Повтор использует обычное
расписание повторных попыток. Переотправлять можно только события своего сайта —
доступ к чужим eventId невозможен (вернётся 404).
data:
Частые вопросы
Подпись не сходится, хотя секрет верный
Подпись не сходится, хотя секрет верный
HMAC-SHA256 именно от этих байтов.
Повторная сериализация распарсенного объекта меняет порядок ключей и пробелы — подпись
не совпадёт. В Express используйте express.raw(), во Flask — request.get_data().Webhook не приходит совсем
Webhook не приходит совсем
callback_url для сайта; доступен ли ваш endpoint
извне (или включён ли allow_private_hosts, если он во внутренней сети); не режут ли
запрос ваш firewall/WAF. Затем вызовите POST /v1/public/webhooks/test — он поставит
тестовую доставку и вернёт url и eventId, по которым видно, куда платформа пыталась
доставить.Получаю один и тот же webhook несколько раз
Получаю один и тот же webhook несколько раз
X-Event-Id. Дедуплицируйте по нему: при уже обработанном id
отвечайте 200 без побочных эффектов.Сколько у меня времени на ответ?
Сколько у меня времени на ответ?
200, а тяжёлую логику
выполняйте асинхронно. Долгий ответ платформа считает неудачей и повторит доставку.Чем отличаются deposit.tx_detected и deposit.finalized?
Чем отличаются deposit.tx_detected и deposit.finalized?
deposit.tx_detected — первая входящая транзакция замечена, но ещё не набрала нужных
подтверждений (receivedAmount/txHash могут быть уже заполнены, но статус не финальный).
deposit.finalized — депозит достиг requiredConfirmations; смотрите deposit.status
(paid / paid_over / wrong_amount), чтобы понять исход. Зачислять средства клиенту
стоит на deposit.finalized со статусом paid/paid_over, не на tx_detected.resend вернул 404 — почему?
resend вернул 404 — почему?
eventId не найден среди событий вашего сайта. Переотправлять можно только
свои события. Проверьте, что eventId взят из реально доставлявшегося ранее webhook’а
(заголовок X-Event-Id или поле eventId тела) и принадлежит тому же сайту, чьим
ключом подписан запрос.Смежные страницы
- Аутентификация — как подписывать запросы к Public API (test/resend).
- Депозиты — статусы депозитов и поля ответа.
- Выплаты — статусы выплат и поля ответа.
- Ошибки и конверт ответа — формат
{ ok, data }/{ ok, error }и коды ошибок.