Пополнение — двухфазное: сначала quote (расчёт стоимости), потом execute. Обе ручки требуют право cards.recharge.
POST /cards/recharge/quote| Параметр | Тип | Описание |
|---|---|---|
cardId | uuid | ID карты из GET /cards |
targetAmount | number | Сумма, которая должна оказаться на карте (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 не блокирует средства и действует только в момент запроса.
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, и его разбирают вручную.
Не создавайте в этом случае новое пополнение — дождитесь вебхука.
| HTTP | errorCode | Значение |
|---|---|---|
| 400 | IDEMPOTENCY_KEY_REQUIRED | Не передан Idempotency-Key |
| 400 | VALIDATION_ERROR | targetAmount меньше 10, больше 1 000 000 или с тремя и более знаками после запятой |
| 400 | CARD_RECHARGE_INVALID | Причина — в начале message: INSUFFICIENT_FUNDS (не хватает доступного баланса на totalDebitUsdt), MIN_RECHARGE_AMOUNT (меньше минимума компании), CARD_RETIRED (карта закрывается или закрыта), CARD_FAILED (карта не выпущена) |
| 403 | CARDS_NOT_ENABLED / PERMISSION_DENIED | Программа карт не подключена или нет права cards.recharge |
| 403 | CARD_NOT_OWNED | Карта принадлежит другой компании |
| 404 | CARD_NOT_FOUND | Карта не найдена |
| 422 | CARD_NOT_ACTIVE | Карта ещё не готова к операциям |
| 422 | UNPROCESSABLE | Эквайер отклонил пополнение, например bridge 400: Card is Frozen on upay and cannot be recharged. Списание уже возвращено |
| 502 | BAD_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.