Вебхуки
Coinetic сообщает вашему серверу об изменениях счёта POST-запросом. Вебхук — сигнал «посмотри счёт», а не доказательство оплаты.
Настройка
- Кабинет → «Ключи и вебхуки» → «Добавить». URL — только
https://на публичный адрес и порт 443 (в песочнице — ещёhttp://localhost). - Секрет endpoint-а показывается один раз. До 5 активных endpoint-ов: каждое событие уходит на все.
Запрос
POST /webhooks/coinetic HTTP/1.1
Content-Type: application/json
User-Agent: cryptopay-webhooks/1
X-Webhook-Id: evt_3f9c…
X-Webhook-Timestamp: 1760000000
X-Webhook-Signature: v1=5d1e…
{"id":"evt_3f9c…","type":"invoice.paid","created_at":"2026-10-12T15:04:05Z","livemode":true,"data":{"invoice_id":"inv_x7k2…","order_id":"ORDER-1001","status":"paid","paid_amount":"49990000"}}X-Webhook-Id одинаков при повторах. При ротации секрета в X-Webhook-Signature две подписи через запятую. Технические имена (cryptopay-webhooks/1) — исторические, менять их у себя не нужно.
Проверка подписи
expected = "v1=" + hex(HMAC-SHA256(webhook_secret, X-Webhook-Timestamp + "." + raw_body))- Возьмите сырое тело — байты до JSON-парсинга.
- Проверьте, что
X-Webhook-Timestampотличается от текущего времени не больше чем на 5 минут. - Разбейте
X-Webhook-Signatureпо запятой. Подпись верна, если любая часть совпадает с ожидаемой (сравнение за постоянное время). - Не совпало — ответьте
401и ничего не делайте.
Эталон: секрет whsec-0123456789abcdef0123456789abcdef, timestamp 1760000000, тело {"id":"evt_1","type":"invoice.paid"} → v1=aceeb56215ba09e7a2923d48f89afb8331f422f2d0a8cf60f76fef69fe06a6a4.
Обработка
проверить подпись → дедупликация по X-Webhook-Id → GET /v1/invoices/{invoice_id}
→ обновить заказ по статусу из API (выдача — один раз) → ответить 2xx- Дедупликация. Одно событие может прийти несколько раз. Храните обработанные
X-Webhook-Id; флаг «выдано» ставьте в той же транзакции, что и выдачу. - Отвечайте быстро — до 10 секунд. Долгую работу отправьте в очередь.
- Коды ответа:
2xx— принято;410 Gone— эту доставку не повторять; любой другой код (включая3xx— редиректы не выполняются) или таймаут — повтор. - Игнорируйте незнакомые поля и типы событий — список будет расти.
Готовые обработчики на четырёх языках — в быстром старте.
Повторы
10 с → 30 с → 2 мин → 10 мин → 30 мин → 1 ч → 3 ч ×7 → 1 ч, с небольшим разбросом. Последняя попытка — примерно через сутки. Неудачную доставку можно отправить снова: кабинет → «Вебхуки» → «Переотправить».
Порядок
События одного счёта доставляются на endpoint по порядку: следующее не уходит, пока предыдущая доставка ещё ждёт повтора. Завершилась она успешно или нет — дальше идут следующие. Поэтому опирайтесь на статус из GET /v1/invoices/{id}, а не на последовательность событий. События разных счетов независимы.
Типы событий
| Событие | Когда |
|---|---|
invoice.detected | Платёж виден в сети |
invoice.confirming | Платёж в блоке, идут подтверждения |
invoice.paid | Оплачено и подтверждено — можно выдавать (после перепроверки). data.late: true — стейблкоин пришёл после срока и зачтён автоматически |
invoice.overpaid | Оплачено с излишком |
invoice.underpaid | Подтверждено меньше нужного |
invoice.awaiting_payment | Счёт снова ждёт оплату (например, после реорга единственного платежа) |
invoice.expired | Срок вышел без оплаты |
invoice.late_payment | Оплата волатильным активом после срока |
invoice.manual_review | Платёж на проверке AML |
invoice.payment_held | Платёж задержан AML (карантин) |
invoice.reorged | Блок с платежом откатился, статус пересчитан (например, paid → confirming) |
invoice.payment_after_close | Платёж пришёл на уже закрытый счёт: заказ не оплачивает, доступен к возврату |
invoice.cancelled | Счёт закрыт без оплаты исполнением возврата |
refund.sent | Возврат исполнен, в data.refund — сумма, адрес и tx_hash |
События биллинга (billing.*) — о счетах на комиссию платформы: выставлен, оплачен, просрочен, приостановка и её снятие.
invoice.reorgedРеорг после paid редок, но бывает. Если товар выдаётся мгновенно — подпишитесь на это событие и передавайте такие случаи в поддержку.Ротация секрета
Кабинет → «Сменить секрет»: Coinetic начинает подписывать обоими секретами.
- Добавьте новый секрет на сервер (принимайте оба).
- Нажмите «Завершить ротацию» — старый удалится.
- Уберите старый секрет с сервера.