---
title: Вебхуки
description: Вебхуки Coinetic: налаштування, перевірка підпису HMAC, дедуплікація, повтори, порядок доставки, типи подій і ротація секрету для API криптоплатежів.
url: https://coinetic.money/uk/docs/webhooks/
lang: uk
---

# Вебхуки

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`) — історичні, змінювати їх у себе не потрібно.

## Перевірка підпису

```
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` — редиректи не виконуються) або тайм-аут — повтор.
- Ігноруйте незнайомі поля й типи подій — список зростатиме.

Готові обробники чотирма мовами — у [швидкому старті](https://coinetic.money/uk/docs/quickstart/#webhook).

## Повтори

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 починає підписувати **обома** секретами.

- Додайте новий секрет на сервер (приймайте обидва).
- Натисніть «Завершити ротацію» — старий буде видалено.
- Приберіть старий секрет із сервера.
