Перейти к содержимому
Последнее обновление

Webhooks по картам

Lumo отправляет следующие события на ваш webhookUrl в дополнение к событиям ордеров, депозитов и выплат (см. Webhooks).

Формат у всех событий общий:

  • тело — плоский JSON: event, поля события и createdAt — время отправки события. Вложенного объекта data нет;
  • подпись — заголовок X-Lumo-Signature, HMAC-SHA256 от сырого тела с секретом компании;
  • cardId — всегда id карты в нашем API.

События

СобытиеКогда приходит
card.assignedКарта выдана
card.request_cancelledЗаявку на карту отменила наша сторона
card.otp_receivedПришёл 3DS-код
card.transaction.createdНовая операция по карте
card.transaction.settledРанее пришедшая авторизация провелась или отменена
card.status_changedСменилось состояние карты у эквайера
card.closedКарта закрыта, остаток возвращён
card.recharge.succeededПополнение прошло
card.recharge.in_progress_manualПополнение передано на ручной разбор
card.recharge.refundedПосле ручного разбора пополнение отменено, средства возвращены
card.recharge.failedПополнение отклонено при досверке, средства возвращены

card.assigned

Карта выдана. Приходит на любую выдачу: и на отложенную (исходный POST /cards/request вернул status: pending), и на мгновенную. В тестовом режиме событие не отправляется.

  • requestId — заявка, которую закрыла эта карта; null, если карту выдали сразу или без заявки. Эквайер не сообщает, для какой заявки выдана карта, поэтому карта закрывает самую раннюю заявку компании в очереди.
  • externalId — значение из этой заявки или null, если его не передавали.
{
  "event": "card.assigned",
  "cardId": "8c7f1823-...",
  "requestId": "2077f4ef-...",
  "externalId": "user-42-card-1",
  "maskedPan": "4466********1234",
  "expiry": "03/29",
  "assignedAt": "2026-04-23T12:00:00.000Z",
  "createdAt": "2026-04-23T12:00:02.000Z"
}

card.request_cancelled

Заявка на карту отменена, резерв под неё вернулся в доступный баланс.

{
  "event": "card.request_cancelled",
  "requestId": "2077f4ef-a03d-4001-82e3-1965e44036e8",
  "externalId": "user-42-card-1",
  "status": "cancelled",
  "createdAt": "2026-04-23T12:05:00.000Z"
}

Приходит, когда заявку отменили с нашей стороны. На вашу собственную отмену через POST /cards/requests/{id}/cancel события нет: результат вы уже получили в ответе на сам запрос.

card.otp_received

Получен 3DS-код из почты эквайера. См. 3DS OTP.

{
  "event": "card.otp_received",
  "cardId": "8c7f1823-...",
  "code": "582130",
  "maskedCard": "1234",
  "receivedAt": "2026-04-23T12:00:10.000Z",
  "expiresAt": "2026-04-23T12:05:10.000Z",
  "createdAt": "2026-04-23T12:00:11.000Z"
}

maskedCard — окончание номера карты из письма эквайера. Код из письма, пришедшего позже чем через 15 минут, не отправляется; один и тот же код по карте повторно в течение 8 минут — тоже.

card.transaction.created

Новая операция по карте — покупка, возврат, пополнение и т.д.

{
  "event": "card.transaction.created",
  "id": "7f2b12a4-...",
  "cardId": "8c7f1823-...",
  "cardMaskedPan": "4466********1234",
  "upayBillId": "88120394",
  "upayParentId": "77001122",
  "type": 2,
  "typeName": "Consumption",
  "status": 5,
  "statusName": "Unposted",
  "direction": 2,
  "amount": "19.6248",
  "fee": "0",
  "currency": "USD",
  "originalAmount": "910",
  "originalCurrency": "TRY",
  "merchantName": "CHURROS TIME CAFE TURIZM",
  "merchantMcc": "5814",
  "transactionTime": "2026-08-14T10:00:00.000Z",
  "createdAt": "2026-08-14T10:00:20.000Z"
}
  • upayBillId — ID операции у эквайера (в REST-выдаче он называется processorBillId).
  • upayParentId — общий ID авторизации и её проведения (в REST-выдаче он называется processorParentId).
  • direction: 2 — списание с карты, 1 — зачисление. Поля directionName, reason, ditchCode и processorOrderNo в вебхук не входят.
  • Значения typeName и statusName — как в истории транзакций.
  • В отличие от REST-выдачи, вебхуки приходят и на строки пополнений карты (typeName: Recharge/Collateral). Если вы учитываете пополнения по card.recharge.*, такие строки пропускайте.

amount/currency — в валюте карты (USD). originalAmount/originalCurrency — сумма в валюте мерчанта до конвертации: покупка на 910 ₺ придёт именно так. У служебных строк (пополнение, деактивация карты) обе — null.

card.transaction.settled

Ранее пришедшая авторизация провелась (Posted) или была отменена (Cancelled). Эквайер присылает это отдельной строкой с новым upayBillId и тем же upayParentId — в среднем через 29 часов после авторизации. Поля — те же, что у card.transaction.created.

:::warning Не считайте платёж дважды

created и settled — это один платёж, а не два. Связывайте их по upayParentId: приход settled означает, что соответствующая авторизация достигла финального статуса, а не что произошла новая покупка.

:::

card.status_changed

Карта сменила состояние на стороне эквайера — заморожена, заблокирована, деактивирована.

{
  "event": "card.status_changed",
  "cardId": "8c7f1823-...",
  "cardMaskedPan": "4466********1234",
  "upayState": 3,
  "upayStateName": "Frozen",
  "previousState": 1,
  "previousStateName": "Normal",
  "syncedAt": "2026-08-14T10:00:00.000Z",
  "createdAt": "2026-08-14T10:00:03.000Z"
}

Состояния: 1 Normal, 2 Pending Activation, 3 Frozen, 4 Locked, 5 Deactivated, 7 Activating, 8 Locking, 9 Unlocking, 10 Deactivating, 13 Rejected, 14 Cancelled, 15 Replacing, 16 Replaced.

Это состояние не то же самое, что status карты в нашем API: там наш жизненный цикл (assigned → closing → closed), и карта остаётся assigned, будучи замороженной у эквайера. Пополнение карты в состояниях Frozen, Locked, Deactivated, Rejected, Cancelled, Replacing и Replaced отклоняется. Текущее состояние — upayState / upayStateName в GET /cards/{id}.

card.closed

Карта закрыта (см. Закрытие карты). Остаток за вычетом комиссии за закрытие возвращён на баланс компании.

{
  "event": "card.closed",
  "cardId": "8c7f1823-...",
  "maskedPan": "4466********1234",
  "closingBalance": 24.5,
  "feeUsdt": 1,
  "refundUsdt": 23.5,
  "createdAt": "2026-04-24T09:30:00.000Z"
}

card.recharge.*

У всех четырёх событий пополнения одинаковый состав — актуальное состояние пополнения:

{
  "event": "card.recharge.succeeded",
  "rechargeId": "7f2b12a4-...",
  "cardId": "8c7f1823-...",
  "status": "succeeded",
  "targetAmountUsd": 50,
  "userChargeUsdt": 50,
  "commissionUsdt": 0.4,
  "failureReason": null,
  "createdAt": "2026-04-23T12:00:05.000Z"
}
СобытиеЧто значитБаланс
card.recharge.succeededСредства на картеСписание userChargeUsdt + commissionUsdt остаётся
card.recharge.in_progress_manualЭквайер не провёл пополнение или исход не выяснен — разбирается вручную. Причина в failureReasonПока списано. Для ускорения напишите в поддержку с rechargeId
card.recharge.refundedПо итогам ручного разбора пополнение отмененоuserChargeUsdt + commissionUsdt возвращены
card.recharge.failedЭквайер отклонил пополнение при досверке после сбоя, причина в failureReasonuserChargeUsdt + commissionUsdt возвращены

Ручной разбор in_progress_manual обычно заканчивается событием succeeded или refunded. Если итога долго нет, напишите в поддержку.

Если эквайер отклонил пополнение сразу, ответом 422 на POST /cards/recharge, события card.recharge.failed не будет: исход вы уже получили в ответе.

Гарантии доставки

  • Повторы одной доставки приходят с тем же X-Lumo-Delivery-Id — по нему отбрасывайте дубли. cardId для этого не подходит: по одной карте приходит много разных событий.
  • Для идемпотентной обработки по смыслу используйте ключ события: rechargeId + status для пополнений, upayBillId для операций, requestId или cardId для card.assigned.
  • Порядок не гарантируется: card.recharge.succeeded может прийти раньше соответствующего card.transaction.created, если эквайер быстрее подтвердил пополнение, чем обновил историю.
  • События по операциям приходят только на новые строки. Если эквайер поменял что-то в уже отданной операции, отдельного события не будет — актуальное состояние всегда в GET /cards/:id/transactions.
  • После четырёх неудачных попыток доставка прекращается — см. журнал доставок.