Skip to content
Last updated

Webhooks

Получайте real-time уведомления о событиях через HTTP callbacks.

Настройка

Укажите webhookUrl в профиле компании:

curl -X PATCH 'https://b2b.lumowallet.io/auth/company/profile' \
  -H 'X-API-Key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "webhookUrl": "https://your-server.com/webhooks/lumo"
  }'

Формат запроса

Webhooks отправляются как POST запросы:

POST /webhooks/lumo HTTP/1.1
Host: your-server.com
Content-Type: application/json
X-Lumo-Signature: 5d41402abc4b2a76b9719d911017c592
X-Lumo-Delivery-Id: 550e8400-e29b-41d4-a716-446655440000

{...payload...}

Заголовки

ЗаголовокОписание
X-Lumo-SignatureHMAC-SHA256 подпись тела запроса
X-Lumo-Delivery-IdУникальный ID доставки
Content-Typeapplication/json

Верификация подписи

Всегда проверяйте подпись для защиты от подмены:

const crypto = require('crypto');

function verifySignature(body, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(body))
    .digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// В обработчике webhook
app.post('/webhooks/lumo', (req, res) => {
  const signature = req.headers['x-lumo-signature'];
  
  if (!verifySignature(req.body, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }
  
  // Обработка события
  handleEvent(req.body);
  res.status(200).send('OK');
});
import hmac
import hashlib

def verify_signature(body: str, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(),
        body.encode(),
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected)

События

Order Events

order.status_changed

Изменение статуса ордера.

{
  "event": "order.status_changed",
  "orderId": "550e8400-e29b-41d4-a716-446655440000",
  "walletOrderId": "660e8400-e29b-41d4-a716-446655440001",
  "status": "success",
  "amountUsdt": 52.63,
  "amountRub": 5000.00,
  "completedAt": "2026-03-10T12:00:45Z",
  "failureReason": null,
  "createdAt": "2026-03-10T12:00:00Z"
}

Deposit Events

deposit.created

Новый депозит обнаружен в сети.

{
  "event": "deposit.created",
  "depositId": "770e8400-e29b-41d4-a716-446655440002",
  "txHash": "abc123...",
  "walletAddress": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
  "fromAddress": "TXyz...",
  "amount": 100.00,
  "tokenSymbol": "USDT",
  "status": "new",
  "createdAt": "2026-03-10T12:00:00Z",
  "updatedAt": "2026-03-10T12:00:00Z"
}

deposit.completed

Депозит успешно зачислен.

{
  "event": "deposit.completed",
  "depositId": "770e8400-e29b-41d4-a716-446655440002",
  "txHash": "abc123...",
  "walletAddress": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
  "amount": 100.00,
  "status": "completed",
  "sweepTxHash": "def456...",
  "createdAt": "2026-03-10T12:00:00Z",
  "updatedAt": "2026-03-10T12:00:30Z"
}

deposit.aml_failed

AML-проверка не пройдена.

{
  "event": "deposit.aml_failed",
  "depositId": "770e8400-e29b-41d4-a716-446655440002",
  "txHash": "abc123...",
  "amount": 100.00,
  "status": "aml_failed",
  "amlCheckId": "check-123",
  "amlResult": "high_risk",
  "error": "Sanctioned address detected",
  "createdAt": "2026-03-10T12:00:00Z"
}

User Deposit Events

Для User Wallets — те же события, но с externalId:

{
  "event": "deposit.completed",
  "depositId": "880e8400-e29b-41d4-a716-446655440003",
  "externalId": "user-12345",
  "txHash": "ghi789...",
  "walletAddress": "TUserWallet...",
  "amount": 50.00,
  "status": "completed",
  "createdAt": "2026-03-10T12:05:00Z"
}

Retry логика

При ошибке доставки (не-2xx ответ) — автоматические ретраи:

ПопыткаЗадержка
1Немедленно
21 секунда
32 секунды
44 секунды

Максимум 4 попытки. После этого webhook помечается как failed.

Рекомендации

Быстрый ответ

Отвечайте 200 OK как можно быстрее. Обрабатывайте событие асинхронно:

app.post('/webhooks/lumo', async (req, res) => {
  // Сразу отвечаем
  res.status(200).send('OK');
  
  // Обрабатываем в фоне
  setImmediate(() => {
    processWebhook(req.body);
  });
});

Идемпотентность

Используйте X-Lumo-Delivery-Id для дедупликации:

const processedDeliveries = new Set();

function handleWebhook(deliveryId, payload) {
  if (processedDeliveries.has(deliveryId)) {
    return; // Уже обработано
  }
  
  processedDeliveries.add(deliveryId);
  // Обработка...
}

Логирование

Логируйте все входящие webhooks для отладки:

console.log({
  deliveryId: req.headers['x-lumo-delivery-id'],
  event: req.body.event,
  timestamp: new Date().toISOString()
});

Тестирование

Используйте Mock-сервер для тестирования интеграции без реальных транзакций:

https://lumo.redocly.app/_mock/apis