Skip to content
StableAudienceDevSécuritéQAAudit banqueComplianceOwner@product-teamDernière revue2026-05-21

Flow — Paiement marchand par carte physique

Le consumer paie un marchand en tapant les 6 derniers chiffres du card_number imprimé sur la carte physique du marchand (8 caractères au total, préfixés par MERCHANT_CARD_PREFIX).

Sequence diagram

Trust boundaries traversées

ÉtapeCrossingContrôle
3App consumer → OrchestratorJWT + guards
5Préfixage card_numberVariable d’environnement MERCHANT_CARD_PREFIX (default 63)
6Lookup carteUNIQUE PARTIAL sur card active par POS
12Risk preflightscope risk:evaluate
18Ledger écrituremetadata.posId persisté

Spécificités carte marchand

  • 6 chiffres saisis par l’utilisateur (UX optimisée pour comptoir et feature phones).
  • Préfixe MERCHANT_CARD_PREFIX (env, default 63) ajouté côté serveur pour reconstruire le card_number 8 caractères complet (cf. ADR-0005).
  • Carte = POS : cards.pos_id est UNIQUE PARTIAL → identification précise du point de vente qui encaisse.
  • Brute-force protection : à rate-limiter côté API (cf. known-gaps).
  • Legacy : merchants.merchant_code 6 chiffres est déprécié mais encore lu en ILIKE pour rétro-compatibilité.

Pré-conditions

  • Merchant KYB validé, au moins un POS actif.
  • Carte physique active, liée à un POS (UNIQUE PARTIAL).
  • Consumer KYC validé, solde suffisant.

Post-conditions

EntityÉtat
Wallet consumer- (montant + frais)
Wallet merchant+ montant
Wallet commissions Nex+ frais
intentsstatus completed, metadata.posId = POS de la carte
Audit trailtrace card_number (suffixe seulement masqué dans les logs publics)

Acceptance criteria (Gherkin)

gherkin
Scenario: Paiement carte marchand valide
  Given une carte active 63123456 liée au POS-X du merchant M
  And un consumer avec 50 000 XAF de solde
  When le consumer tape "123456" + montant 8 000 XAF
  Then le serveur préfixe en "63123456" et résout POS-X
  And le risk preflight renvoie "approved"
  When le consumer confirme avec son PIN
  Then le wallet M reçoit 8 000 XAF
  And l'intent persiste metadata.posId = POS-X

Scenario: Carte désactivée
  Given une carte avec statut "inactive"
  When un consumer tente un paiement avec son suffixe
  Then le lookup échoue
  And l'intent n'est pas créé

Scenario: Brute-force sur les 6 chiffres
  Given un attaquant qui teste plusieurs combinaisons à la suite
  When le seuil de rate limit est dépassé
  Then les tentatives suivantes sont rejetées
  And un événement de sécurité est journalisé

Liens

Nex — Plateforme fintech CEMAC