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

Выпуск карты

Endpoint

POST /cards/request

Заголовок Idempotency-Key обязателен, без него — 400 IDEMPOTENCY_KEY_REQUIRED. Нужно право cards.create.

Тело запроса необязательно. Единственное поле — externalId, ваш идентификатор карты (см. Привязка к своему id).

Пример запроса

curl -X POST 'https://b2b.lumowallet.io/cards/request' \
  -H 'X-API-Key: YOUR_API_KEY' \
  -H 'Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000'

С привязкой к своему идентификатору:

curl -X POST 'https://b2b.lumowallet.io/cards/request' \
  -H 'X-API-Key: YOUR_API_KEY' \
  -H 'Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000' \
  -H 'Content-Type: application/json' \
  -d '{"externalId": "user-42-card-1"}'

Варианты ответа

Карта выдана сразу

{
  "status": "assigned",
  "card": {
    "id": "8c7f1823-0d43-4618-86ee-fa0c77643cb2",
    "externalId": "user-42-card-1",
    "status": "assigned",
    "maskedPan": "4466********1234",
    "expiry": "03/29",
    "assignedAt": "2026-04-23T12:00:00.000Z",
    "createdAt": "2026-04-23T12:00:00.000Z",
    "upayState": null,
    "upayStateName": null
  }
}

Ответ — 201. Состояние у эквайера (upayState, upayStateName) в этом ответе не заполняется — запрашивайте его через GET /cards/{id}.

Карта поставлена в очередь

{
  "status": "pending",
  "request": {
    "id": "2077f4ef-a03d-4001-82e3-1965e44036e8",
    "externalId": "user-42-card-1",
    "status": "pending",
    "cardId": null,
    "createdAt": "2026-04-23T12:00:00.000Z"
  }
}

Когда карта выпустится, вы получите webhook card.assigned с requestId заявки, а у заявки появится cardId и статус fulfilled. Если в очереди несколько ваших заявок, выданная карта закрывает самую раннюю из них. Статус заявки можно и опрашивать:

curl 'https://b2b.lumowallet.io/cards/requests/2077f4ef-a03d-4001-82e3-1965e44036e8' \
  -H 'X-API-Key: YOUR_API_KEY'

Ответ — объект заявки в том же формате, что request выше (право cards.read).

Вебхук card.assigned приходит и на мгновенную выдачу — с requestId: null: карта к этому моменту у вас уже есть из ответа на запрос. В тестовом режиме вебхук не отправляется.

Повтор запроса

Idempotency-Key защищает от двойного выпуска: повтор с тем же ключом не создаёт вторую карту и не списывает комиссию ещё раз. Но вернуть результат первого запроса повтор может не всегда:

  • первый запрос сразу выдал карту и externalId не передавался — вернётся та же карта;
  • передавали externalId — повтор отклоняется 409 CARD_EXTERNAL_ID_TAKEN, а в details приходит cardId выданной карты или requestId заявки;
  • первая заявка ушла в очередь, первый запрос ещё выполняется или на балансе не хватает средств на временный резерв — повтор завершится ошибкой.

Поэтому передавайте externalId и ищите результат через details ошибки, GET /cards?externalId=… или вебхук card.assigned. Для каждой новой карты используйте новый ключ.

Исключение — ответ 502: эквайер не ответил, но карту мог выдать. Такая карта придёт вебхуком card.assigned без requestId и без externalId.

Привязка к своему id

externalId — необязательное поле в теле запроса: ваш идентификатор карты (id пользователя, номер заказа, что угодно до 128 печатаемых ASCII-символов без пробелов). Дальше он ездит вместе с картой:

  • возвращается в POST /cards/request, GET /cards, GET /cards/{id} и GET /cards/requests/{requestId};
  • приходит в webhook card.assigned — так отложенный выпуск связывается с вашей сущностью без хранения маппинга на нашей стороне;
  • по нему можно искать карту: GET /cards?externalId=user-42-card-1.

Если заявка ушла в очередь, externalId хранится на ней и переезжает на карту в момент выдачи.

Уникальность — в рамках вашей компании. Второй выпуск с тем же значением вернёт 409 CARD_EXTERNAL_ID_TAKEN, а в details придёт cardId (или requestId) того, кто уже занял значение:

{
  "statusCode": 409,
  "error": "Conflict",
  "errorCode": "CARD_EXTERNAL_ID_TAKEN",
  "message": "externalId \"user-42-card-1\" уже занят картой 8c7f1823-0d43-4618-86ee-fa0c77643cb2",
  "details": {
    "externalId": "user-42-card-1",
    "cardId": "8c7f1823-0d43-4618-86ee-fa0c77643cb2"
  }
}

У разных компаний значения не пересекаются — свой user-42-card-1 может быть у каждой. Карты, выпущенные без externalId, приходят с null, и задним числом поле не проставляется.

Отмена заявки

Пока карта по заявке не выпущена, заявку можно отменить — например, если она надолго зависла в очереди, а деньги под неё нужны на другое.

POST /cards/requests/{requestId}/cancel

Нужно право cards.create.

curl -X POST 'https://b2b.lumowallet.io/cards/requests/2077f4ef-.../cancel' \
  -H 'X-API-Key: YOUR_API_KEY'
{
  "id": "2077f4ef-a03d-4001-82e3-1965e44036e8",
  "externalId": "user-42-card-1",
  "status": "cancelled",
  "cardId": null,
  "createdAt": "2026-04-23T12:00:00.000Z"
}

Резерв под заявку возвращается в доступный баланс, а externalId снова освобождается — его можно использовать в новой заявке.

Отменить можно только заявку в статусе pending. Если карта уже выпущена, придёт CARD_REQUEST_NOT_CANCELABLE: выданную карту не отменяют, её закрывают через POST /cards/{id}/retire. Если карта по заявке выдаётся прямо сейчас, отмена может завершиться 422 — тогда карта придёт вебхуком card.assigned.

Повторная отмена не ошибка — вернётся та же заявка, и ничего не изменится. Поэтому запрос безопасно повторять, если ответ не дошёл.

Заявку может отменить и наша сторона — например, если карту по ней выдать не удалось. Тогда придёт webhook card.request_cancelled, а резерв так же вернётся на баланс.

Резервирование средств

На момент POST /cards/request:

  1. Проверяется, что availableBalance >= openingFee + minInitialDeposit, иначе — 400 с errorCode: BAD_REQUEST и сообщением INSUFFICIENT_FUNDS: need N USDT, have M.
  2. Сумма openingFee + minInitialDeposit переводится в frozenBalance.
  3. При выдаче карты резерв снимается целиком: openingFee списывается с balance, minInitialDeposit возвращается в доступный баланс.
  4. Если запрос к эквайеру не прошёл — вся сумма размораживается.

Ошибки

HTTPerrorCodeЗначение
400IDEMPOTENCY_KEY_REQUIREDНе передан Idempotency-Key
400BAD_REQUESTСообщение INSUFFICIENT_FUNDS: … — не хватает availableBalance на резерв
400VALIDATION_ERRORexternalId пустой, длиннее 128 символов или с недопустимыми символами
403CARDS_NOT_ENABLEDУ компании не подключена программа карт
409CARD_EXTERNAL_ID_TAKENexternalId уже занят картой или заявкой компании
422UNPROCESSABLEЭквайер отклонил заявку, причина в message
502BAD_GATEWAYЭквайер не ответил, исход неизвестен. Резерв возвращён; если карта всё же выдана, она придёт вебхуком card.assigned. Повторяйте с тем же Idempotency-Key
400CARD_REQUEST_NOT_CANCELABLEЗаявку нельзя отменить: карта уже выпущена
403CARD_NOT_OWNEDGET /cards/requests/{id}: заявка принадлежит другой компании
404CARD_REQUEST_NOT_FOUNDЗаявки с таким id у компании нет

Ограничение

Одна заявка за раз для заданного Idempotency-Key. Чтобы выпустить 10 карт — сделайте 10 вызовов с разными ключами.