Документация / Интеграция

Вебхуки

Coinetic сообщает вашему серверу об изменениях счёта POST-запросом. Вебхук — сигнал «посмотри счёт», а не доказательство оплаты.

Настройка

  • Кабинет → «Ключи и вебхуки» → «Добавить». URL — только https:// на публичный адрес и порт 443 (в песочнице — ещё http://localhost).
  • Секрет endpoint-а показывается один раз. До 5 активных endpoint-ов: каждое событие уходит на все.

Запрос

HTTP
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) — исторические, менять их у себя не нужно.

Проверка подписи

text
expected = "v1=" + hex(HMAC-SHA256(webhook_secret, X-Webhook-Timestamp + "." + raw_body))
  1. Возьмите сырое тело — байты до JSON-парсинга.
  2. Проверьте, что X-Webhook-Timestamp отличается от текущего времени не больше чем на 5 минут.
  3. Разбейте X-Webhook-Signature по запятой. Подпись верна, если любая часть совпадает с ожидаемой (сравнение за постоянное время).
  4. Не совпало — ответьте 401 и ничего не делайте.

Эталон: секрет whsec-0123456789abcdef0123456789abcdef, timestamp 1760000000, тело {"id":"evt_1","type":"invoice.paid"} → v1=aceeb56215ba09e7a2923d48f89afb8331f422f2d0a8cf60f76fef69fe06a6a4.

Обработка

text
проверить подпись → дедупликация по 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 начинает подписывать обоими секретами.

  1. Добавьте новый секрет на сервер (принимайте оба).
  2. Нажмите «Завершить ротацию» — старый удалится.
  3. Уберите старый секрет с сервера.