Ваш сервер получает событие.

Dedyx доставляет события PAID с подписью на обязательный HTTPS-адрес. Сначала проверьте, затем выполните заказ.

Настройка приёмника

PUT/api/v1/merchant/webhook

Ограничение частоты: 10 запросов / 60 секунд (общий счётчик настроек вебхука · на мерчанта). Общие счётчики и дополнительные лимиты по IP.

cURL
curl -X PUT https://api.dedyx.com/api/v1/merchant/webhook \
  -H 'X-API-Key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://your-company.example/webhooks/dedyx"}'

Используйте публичный HTTPS URL на порту 443 без встроенных данных доступа и фрагмента. Приватные сети, loopback, адреса метаданных, HTTP и перенаправления отклоняются. Общий список разрешённых URL не требуется.

Первый ответ содержит индивидуальный для мерчанта signing_key и key_id. Сохраните полную whsec_... строку. Следующие PUT обновляют URL, сохраняя текущий ключ.

GET/api/v1/merchant/webhook

Ограничение частоты: 120 запросов / 60 секунд (общие чтения · на мерчанта). Общие счётчики и дополнительные лимиты по IP.

Получайте настройки без раскрытия секрета подписи.

Событие платежа

POST · пример тела
{
  "event_id": "evt_example",
  "payment_id": "pay_0123456789abcdef0123456789abcdef",
  "status": "PAID",
  "expected_amount": "49.00",
  "transaction_id": "9f3c7a2e8b104d65c0a9f1726e83b4d5a7610c2f94e8b36d5a07c1e2694f83bd",
  "transaction_event_index": 0,
  "description": "Order #1024"
}

Сопоставляйте платёж со своими заказами. Несколько событий USDT Transfer могут иметь один ID транзакции; transaction_event_index указывает позицию в полном логе receipt.

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

ЗаголовокНазначение
X-Dedyx-TimestampUnix-секунды; обновляются при каждой попытке.
X-Dedyx-Signaturev1= + hex HMAC-SHA256 от timestamp + "." + исходного тела.
X-Dedyx-Event-IDПостоянный ID события при повторах.
X-Dedyx-Key-IDВыбирает сохранённый ключ подписи.
Python · проверка подписи
import hashlib
import hmac
import time

def verify_webhook(raw_body, timestamp, signature, signing_key):
    if not timestamp.isdigit() or len(timestamp) > 12:
        return False
    if abs(int(time.time()) - int(timestamp)) > 300:
        return False
    expected = "v1=" + hmac.new(
        signing_key.encode(),
        timestamp.encode() + b"." + raw_body,
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

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

Повторы и дубликаты

Только 2xx означает успешную доставку. При потере ответа запрос может повториться. Атомарно сохраняйте event_id вместе с бизнес-действием. Возвращайте 2xx без повторного выполнения уже обработанного заказа. Рабочий пример PostgreSQL.

Обычно доставка повторяется до восьми раз с увеличением задержки. Исчерпанные события доступны для защищённого повтора мерчантом или восстановления оператором. Неудачный вебхук не отменяет платёж. Сверяйте состояние через защищённый details платежа; Проверяйте доставку через GET /api/v1/payments/{payment_id}/webhooks и повторяйте исчерпанное событие через POST /api/v1/merchant/webhook/events/{event_id}/retry. Ожидающие и доставленные события повторять нельзя. Лимит — пять запросов в час на мерчанта; каждый повтор записывается в аудит и сохраняет ID и тело события.

Ротация ключа подписи

POST/api/v1/merchant/webhook/rotate-key

Ограничение частоты: 10 запросов / 60 секунд (общий счётчик настроек вебхука · на мерчанта). Общие счётчики и дополнительные лимиты по IP.

Новый секрет показывается один раз. Новые попытки доставки сразу используют новый ID ключа. Сохраняйте предыдущий ключ пять минут для запросов в пути. Эта ротация не меняет API-ключ.

Далее: Ошибки и лимиты

Диагностика и повтор доставки

Читайте события платежа через GET /api/v1/payments/{payment_id}/webhooks. Ответ содержит ограниченный список (до 100 событий): event_id, payment_id, status, attempts, временные метки и error_category. Status: pending, delivered или failed; pending включает попытку в процессе. Callback URL, тело события и секрет подписи не возвращаются. Метод делит лимит чтений мерчанта.

Используйте POST /api/v1/merchant/webhook/events/{event_id}/retry с X-API-Key и без тела для нового цикла исчерпанного недоставленного события. Pending/delivered возвращает 409; чужое или отсутствующее событие — 404. Пять запросов в фиксированном окне 3600 секунд на мерчанта (с первого запроса), включая ответы 404 и 409; 429 содержит Retry-After. Попытки нового цикла сбрасываются в ноль. ID и тело события сохраняются. Доставка использует текущие приёмник и ключ подписи. Аудит и повтор атомарны; новый платёж не создаётся и квота создания не расходуется.

Таймаут может означать, что приёмник обработал событие, но ответ потерялся. Исключайте повтор event_id и повторное выполнение заказа даже после ручного повтора.