07 merchant scenarios
Сценарии для мерчантов и агентов: инвойсы, NFC, пополнения.
Мерчант и агент — отдельные accountType. Каждый endpoint защищён guard requireAccountType(session, [...]). Все финансовые операции создаются через POST /intents Payment Manager с HMAC-подписью.
| Метод | Кто вызывает | Тип операции |
|---|---|---|
createInvoice |
merchant | INVOICE_PAYMENT |
cancelInvoice |
merchant | — (отмена) |
chargeByNfc |
merchant | NFC_CHARGE |
createTopup |
agent | TOPUP |
requestSettlement |
merchant | WITHDRAWAL |
Создание QR-инвойса¶
Мерчант выставляет счёт; покупатель сканирует QR и платит из своего кошелька.
sequenceDiagram
participant MerchApp as Merchant App
participant AC as Auth Center
participant PM as Payment Manager
MerchApp->>AC: createInvoice(amount, currency, idempotencyKey, note?, ttlSeconds?)
AC->>AC: requireAccountType([merchant])
AC->>AC: resolve merchantWallet из v_user_tb_accounts
AC->>PM: POST /intents (HMAC, operationType=INVOICE_PAYMENT, toTbAccountId=merchant)
PM-->>AC: IntentDto { intentId, status: CREATED, qrSignature, expiresAt }
AC->>AC: encodeInvoiceQr(intentId, merchantTbAccountId, amount, expiresAt, signature)
AC-->>MerchApp: InvoiceQrPayload { qrPayload, intentId, expiresAt, merchantDisplayName }
MerchApp->>MerchApp: отображает QR покупателю
Детали:
merchantDisplayName—businessNameиз профиля, fallbackfirstName, fallback email.- QR содержит HMAC-подпись PM; Auth Center верифицирует её при
previewInvoiceна стороне покупателя. ttlSecondsзадаёт время жизни QR; PM вернётINVOICE_EXPIREDпосле истечения.- Мерчант может отменить невыкупленный инвойс через
cancelInvoice(intentId).
Приём NFC-платежа¶
Покупатель прикладывает NFC-карту к устройству мерчанта; деньги списываются автоматически.
sequenceDiagram
participant ConsCard as NFC Chip (покупатель)
participant MerchApp as Merchant App
participant AC as Auth Center
participant PM as Payment Manager
participant TB as TigerBeetle
MerchApp->>ConsCard: READ_CNT + NDEF read
ConsCard-->>MerchApp: token (base64url) + counter
MerchApp->>AC: chargeByNfc(token, counter, amount, currency, idempotencyKey, lat?, lon?)
AC->>AC: requireAccountType([merchant])
AC->>AC: resolveAndConsume → верифицирует token, атомарно продвигает счётчик
AC->>AC: assertNfcEnabled(customerUserId)
AC->>AC: checkTagLimits(tag, amount) — perTapLimit, dailyLimit
AC->>PM: POST /intents (HMAC auth-center-merchant, NFC_CHARGE)
PM->>TB: consumer wallet → merchant wallet
TB-->>PM: SETTLED
PM-->>AC: IntentDto { status: COMPLETED }
AC-->>MerchApp: NfcChargeResult
chargeByNfcподписывается привилегированным HMAC-ключомauth-center-merchant— отдельная параserviceId / secretот стандартногоauth-center. Это позволяет PM применять особые правила авторизации для pull-charge операций.
Проверки до PM (порядок важен):
- Токен найден в реестре → статус
active→ TTL не истёк. - Счётчик строго вырос (
counter > lastCounter) — защита от replay/клона. - NFC включён глобально и для владельца метки.
perTapLimitиdailyLimitне превышены.
Пополнение клиента (Topup)¶
Агент принимает наличные и зачисляет деньги на кошелёк клиента.
sequenceDiagram
participant AgentApp as Agent App
participant AC as Auth Center
participant PM as Payment Manager
participant TB as TigerBeetle
AgentApp->>AC: createTopup(consumerPhone, amount, currency, idempotencyKey, comment?)
AC->>AC: requireAccountType([agent])
AC->>AC: hashPhone(consumerPhone) → lookup UserProfile
AC->>AC: проверить accountType == consumer
AC->>PM: POST /intents (HMAC, operationType=TOPUP, recipientUserId=consumer)
PM->>TB: agent liquidity pool → consumer wallet
TB-->>PM: SETTLED
PM-->>AC: IntentDto { status: COMPLETED }
AC-->>AgentApp: IntentDto
Детали:
- Только
agent-аккаунты вправе вызыватьcreateTopup;consumerиmerchantполучают 403. - Телефон клиента хешируется через PII-сервис перед поиском — в запрос PM номер не попадает.
- Операция синхронная: PM возвращает
COMPLETEDсразу после записи в TigerBeetle.
Settlement [PLAN]¶
Функциональность не реализована. Endpoint
requestSettlementприсутствует в коде (operationType=WITHDRAWAL), но PM-сага вывода средств находится в разработке.
Предполагаемый сценарий: мерчант запрашивает вывод накопленного баланса через агента-партнёра. Агент физически передаёт наличные, PM списывает средства с кошелька мерчанта на кошелёк агента. Подтверждение агентом — отдельный шаг (двухфазный трансфер в TigerBeetle).