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

Пополнение карты

Пополнение — двухфазное: сначала quote (расчёт стоимости), потом execute. Обе ручки требуют право cards.recharge.

1. Запросить quote

POST /cards/recharge/quote

Параметры

ПараметрТипОписание
cardIduuidID карты из GET /cards
targetAmountnumberСумма, которая должна оказаться на карте (USD)

targetAmount — от 10 до 1 000 000, не больше двух знаков после запятой. Если для компании задан свой минимум (cardMinRechargeUsdt), меньшая сумма отклоняется с сообщением MIN_RECHARGE_AMOUNT: ….

Пример

curl -X POST 'https://b2b.lumowallet.io/cards/recharge/quote' \
  -H 'X-API-Key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{ "cardId": "8c7f1823-...", "targetAmount": 50 }'

Ответ

{
  "cardId": "8c7f1823-...",
  "targetAmount": 50,
  "ourFeeBps": 80,
  "commissionUsdt": 0.4,
  "totalDebitUsdt": 50.4,
  "currency": "USDT"
}
ПолеОписание
targetAmountСколько придёт на карту, USD
ourFeeBpsНаша комиссия за пополнение в bps (80 = 0,8%)
commissionUsdtНаша комиссия: targetAmount × ourFeeBps / 10000
totalDebitUsdtСколько спишется с баланса компании: targetAmount + commissionUsdt
currencyВалюта списания, всегда USDT

Других комиссий нет: на карту приходит ровно targetAmount, с баланса уходит ровно totalDebitUsdt. Суммы не округляются до центов — commissionUsdt может иметь до шести знаков после запятой.

Quote не блокирует средства и действует только в момент запроса.

2. Выполнить пополнение

POST /cards/recharge

Заголовок Idempotency-Key обязателен. Тело — те же cardId и targetAmount. Стоимость пересчитывается заново: отдельно передавать quote не нужно.

Пример

curl -X POST 'https://b2b.lumowallet.io/cards/recharge' \
  -H 'X-API-Key: YOUR_API_KEY' \
  -H 'Idempotency-Key: 9f0dcd94-...' \
  -H 'Content-Type: application/json' \
  -d '{ "cardId": "8c7f1823-...", "targetAmount": 50 }'

Ответ

{
  "id": "7f2b12a4-...",
  "cardId": "8c7f1823-...",
  "targetAmountUsd": 50,
  "userChargeUsdt": 50,
  "commissionUsdt": 0.4,
  "status": "succeeded",
  "failureReason": null,
  "createdAt": "2026-04-23T12:00:00.000Z"
}

Ответ — 201. С баланса списано userChargeUsdt + commissionUsdt — это totalDebitUsdt из quote. Пополнение проводится сразу, поэтому обычно в ответе уже итог: succeeded или in_progress_manual. pending бывает, только если эквайер не ответил, — см. ниже.

Тот же статус приходит webhook'ом card.recharge.* и виден в истории пополнений.

Повтор с тем же ключом

Повтор с тем же Idempotency-Key возвращает то же пополнение в текущем статусе — без второго списания и второго обращения к эквайеру. Генерируйте ключ один раз на пополнение и используйте его при всех повторах.

Ключ действует в рамках компании и не привязан к карте и сумме: повтор с тем же ключом и другими параметрами вернёт первое пополнение. Карта при повторе проверяется заново: если она за это время ушла в закрытие, придёт CARD_RETIRED.

Статусы пополнения

СтатусЗначениеБаланс
pendingЭквайер не ответил, исход выясняетсяСписано
succeededУспех — средства на картеОстаётся списанным
in_progress_manualЭквайер не провёл пополнение или исход не выяснен — разбирается вручнуюОстаётся списанным до решения
refundedПо итогам ручного разбора пополнение отмененоВозврат userChargeUsdt + commissionUsdt
failedОтклонено: эквайер отказал на входе или при досверкеВозврат userChargeUsdt + commissionUsdt

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

Возврат при failed и refunded происходит автоматически и один раз.

Если эквайер не ответил

Если эквайер не ответил вовремя или ответил сбоем, исход неизвестен: карта могла пополниться. Поэтому деньги не возвращаются сразу:

  • POST /cards/recharge отвечает 201 со status: pending, в failureReason — техническая причина;
  • мы автоматически переспрашиваем эквайера с тем же ключом и переводим пополнение в итоговый статус — succeeded, in_progress_manual или failed (с возвратом) — с вебхуком;
  • если за 30 минут исход так и не выяснен, пополнение переходит в in_progress_manual, и его разбирают вручную.

Не создавайте в этом случае новое пополнение — дождитесь вебхука.

Ошибки при execute

HTTPerrorCodeЗначение
400IDEMPOTENCY_KEY_REQUIREDНе передан Idempotency-Key
400VALIDATION_ERRORtargetAmount меньше 10, больше 1 000 000 или с тремя и более знаками после запятой
400CARD_RECHARGE_INVALIDПричина — в начале message: INSUFFICIENT_FUNDS (не хватает доступного баланса на totalDebitUsdt), MIN_RECHARGE_AMOUNT (меньше минимума компании), CARD_RETIRED (карта закрывается или закрыта), CARD_FAILED (карта не выпущена)
403CARDS_NOT_ENABLED / PERMISSION_DENIEDПрограмма карт не подключена или нет права cards.recharge
403CARD_NOT_OWNEDКарта принадлежит другой компании
404CARD_NOT_FOUNDКарта не найдена
422CARD_NOT_ACTIVEКарта ещё не готова к операциям
422UNPROCESSABLEЭквайер отклонил пополнение, например bridge 400: Card is Frozen on upay and cannot be recharged. Списание уже возвращено
502BAD_GATEWAYЭквайер не ответил при расчёте стоимости. Списания не было — запрос можно повторить

Пополнение отклоняется, если карта у эквайера в состоянии Frozen, Locked, Deactivated, Rejected, Cancelled, Replacing или Replaced — см. upayStateName в GET /cards/{id}. Такое пополнение сохраняется в истории со статусом failed, вебхука по нему нет.

История пополнений

По всем картам компании:

curl 'https://b2b.lumowallet.io/cards/recharges?limit=50&before=2026-04-23T00:00:00Z' \
  -H 'X-API-Key: YOUR_API_KEY'

По одной карте:

curl 'https://b2b.lumowallet.io/cards/8c7f1823-.../recharges?limit=50' \
  -H 'X-API-Key: YOUR_API_KEY'

Обе ручки возвращают массив пополнений в том же формате, что ответ execute, новые сначала. limit — 1–200, по умолчанию 50; курсор before — ISO-дата: вернутся пополнения с createdAt < before. Нужно право cards.read.