# 3DS OTP

Когда карта используется для покупки, эквайер присылает SMS с OTP-кодом.
У нас нет SIM — мы получаем коды напрямую из почтового ящика эквайера и
выдаём через API.

## Endpoint

```
GET /cards/:id/otp/latest
```

## Пример

```bash
curl 'https://b2b.lumowallet.io/cards/8c7f1823-.../otp/latest' \
  -H 'X-API-Key: YOUR_API_KEY'
```

## Ответ

```json
{
  "id": "a1b2c3d4-...",
  "cardId": "8c7f1823-...",
  "code": "582130",
  "maskedCard": "4466 ** ** 1234",
  "subject": "3DS Verification",
  "receivedAt": "2026-04-23T12:00:10Z",
  "expiresAt": "2026-04-23T12:02:10Z",
  "consumedAt": null
}
```

Если свежего OTP нет — возвращается `null`.

## Как получать коды в real-time

### Вариант 1 — поллинг

Опрашивайте эндпоинт каждые 5–15 секунд после инициации 3DS-проверки.
OTP живёт `2 минуты` (поле `expiresAt`). Наш поллер почты сканирует
ящик каждые 15 секунд.

### Вариант 2 — webhook (рекомендуется)

Подпишитесь на событие `card.otp_received`:

```json
{
  "event": "card.otp_received",
  "data": {
    "cardId": "8c7f1823-...",
    "code": "582130",
    "receivedAt": "2026-04-23T12:00:10Z",
    "expiresAt": "2026-04-23T12:02:10Z"
  }
}
```

Webhooks доставляются сразу после того, как наш поллер увидел письмо.

## Тестовый режим

`cardsTestMode = true` всегда возвращает фиксированный код `843903` со
сроком 2 минуты от текущего момента — удобно для автотестов.