Lemonway — Carte¶
Endpoints liés aux paiements par carte bancaire via Lemonway : création d'intentions de paiement (carte one-shot ou carte enregistrée), redirection après paiement et webhook de confirmation. Source : card.controller.ts.
Tous les endpoints sont sous le préfixe /customers/lemonway. Les endpoints de paiement (POST /payment-intent/..., GET /card/saved) requièrent un JWT investisseur valide (JwtAuthGuard) et le rôle CUSTOMER (UserRoleGuard). Les endpoints de webhook (GET|POST /webhook-card/:walletTransactionId) sont publics (pas de guard) — le walletTransactionId (UUID v4) sert d'identifiant non devinable et la vérité finale est récupérée auprès de Lemonway côté serveur.
POST /payment-intent/card¶
Initie un paiement par carte (carte non enregistrée) et retourne l'URL Lemonway sur laquelle rediriger l'investisseur pour saisir sa carte. Source : card.controller.ts#L64.
Pré-conditions¶
- Onboarding investisseur complété (
Customer.assertCompletedInvestorOnboarding) - Droits transactionnels :
'all'ou'cashin_fundraise'(Customer.assertTransactionRights) - Si
type: 'gift-card': MFA pré-validé (MFAPreAuthFlowService.requireMfaTokenavec actiongift-card-purchase) - Si
type: 'gift-card':amountToMoneyIn + lemonwayBalance >= giftCard.amount
Request body¶
Validé via payWithCardRequestBody (depuis @bricks-common/api-communication). Discriminé sur type :
type: 'classic'— top-up de wallet simpletype: 'gift-card'— top-up + achat d'une carte cadeau (requiertmfaVerificationToken+giftCard)type: 'bricks-reservation'— paiement d'une réservation d'achat primaire (requiertbricksReservationId)
Response¶
URL Lemonway vers laquelle rediriger l'investisseur (page de saisie carte hébergée par Lemonway).
Effets de bord¶
- Si
type === 'bricks-reservation': appelleprimaryPurchaseService.setCardInForBricksReservationpour rattacher lawalletTransactioncarte créée à la réservation.
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
payment-intent.gif-card-amount-too-high |
400 | Carte cadeau : montant > amountToMoneyIn + lemonwayBalance |
amount-too-low |
400 | Montant inférieur au minimum Lemonway |
amount-too-high |
400 | Montant supérieur au plafond carte (businessRules.moneyIn.card.maxAmountInCents) |
customer.rights.account-is-being-verified |
400 | Compte Lemonway restreint (en vérification) |
primary-purchase-wrong-status |
400 | Réservation pas dans le bon statut pour rattacher une carte |
primary-purchase-no-reservation |
400 | Purchase sans réservation |
primary-purchase-not-found |
400 | Réservation introuvable |
| MFA errors (variants) | 400 | Cas carte cadeau, jeton MFA invalide / manquant |
GET /card/saved¶
Liste les cartes enregistrées Lemonway de l'investisseur. Retourne [] si le feature flag ENABLE_MONEY_IN_SAVED_CARDS est désactivé. Source : card.controller.ts#L142.
Pré-conditions¶
- Onboarding investisseur complété
- Droits transactionnels :
'all'ou'cashin_fundraise'
Response¶
Tableau de cartes enregistrées (forme dépendante de cardTopupService.getSavedCards). Vide si feature flag off.
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
InternalServerError |
500 | Échec de la récupération côté Lemonway |
POST /payment-intent/saved-card¶
Initie un paiement avec une carte déjà enregistrée (sans redirection Lemonway). Le paiement est confirmé immédiatement ou en attente (3-DS). Source : card.controller.ts#L174.
Pré-conditions¶
- Feature flag
ENABLE_MONEY_IN_SAVED_CARDSactif - Onboarding investisseur complété
- Droits transactionnels :
'all'ou'cashin_fundraise' - Si
type: 'gift-card': MFA pré-validé (actiongift-card-purchase) + cohérenceamountToMoneyIn + lemonwayBalance >= giftCard.amount
Request body¶
Validé via payWithSavedCardRequestBody. Mêmes 3 variantes que POST /payment-intent/card (classic, gift-card, bricks-reservation), plus l'identifiant de carte enregistrée.
Response — type: 'classic'¶
ou
Si confirmed : un évènement Customer.io topup_card est envoyé.
Response — type: 'gift-card'¶
ou
Si confirmed : la carte cadeau est créée via GiftCardService.createGiftCardPurchaseWt.
Response — type: 'bricks-reservation'¶
ou
Rattache la WT carte à la réservation via primaryPurchaseService.setCardInForBricksReservation.
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
BadRequestException (vide) |
400 | Feature flag ENABLE_MONEY_IN_SAVED_CARDS désactivé |
payment-intent.gif-card-amount-too-high |
400 | Carte cadeau : montant trop élevé |
payment-intent.expired-card |
400 | Carte enregistrée expirée |
BadRequestException (vide) |
400 | Erreur Lemonway lors du débit |
balance-too-low |
400 | Carte cadeau : balance insuffisante post-paiement |
primary-purchase-wrong-status |
400 | Réservation pas dans le bon statut |
primary-purchase-no-reservation |
400 | Purchase sans réservation |
primary-purchase-not-found |
400 | Réservation introuvable |
| MFA errors (variants) | 400 | Jeton MFA invalide pour gift-card |
GET /webhook-card/:walletTransactionId¶
Page de retour Lemonway après saisie carte. Public (pas de guard) — Lemonway redirige le navigateur de l'investisseur ici en GET avec des query params. Lit le statut réel de la transaction côté Lemonway puis renvoie un 302 vers le front. Source : card.controller.ts#L311.
Path param¶
walletTransactionId— UUID v4 (validé parParseUUIDPipe)
Query params¶
LemonwayCardPaymentIntentDto :
response_wkToken— token Lemonway (optionnel)response_transactionId— id transaction Lemonway (optionnel)redirectPath— chemin front cible (défaut/wallet)
Response¶
302 vers <frontUrl><redirectPath>?card_payment_state=<ok|fail|cancel>&amount=<totalValue> selon le statut Lemonway (success → ok, cancelled → cancel, sinon fail).
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
InvalidRequest |
400 | Aucun token Lemonway ni walletTransactionId exploitable |
TransactionNotFound |
404 | WalletTransaction introuvable en base |
BadRequestException (vide) |
400 | walletTransaction.lemonwayTransactionId manquant |
Transaction not found at Lemonway |
404 | Transaction absente côté Lemonway |
InternalServerError |
500 | Erreur Lemonway autre que not-found |
POST /webhook-card/:walletTransactionId¶
Webhook serveur-à-serveur appelé par Lemonway pour notifier le résultat du paiement carte. Public (pas de guard) — la sécurité repose sur le walletTransactionId UUID non devinable et sur la consultation directe de l'API Lemonway pour le statut réel. Source : card.controller.ts#L376.
Path param¶
walletTransactionId— UUID v4 (validé parParseUUIDPipe)
Effets¶
Dans une transaction Postgres avec lock pessimiste :
1. Verrouille la WalletTransaction cible (statut requis : WAITING).
2. Lock le customer (CustomerBalanceService.lockCustomer).
3. Récupère le statut réel de la transaction Lemonway (lemonwayApi.getMoneyIn).
4. Met à jour walletTransaction.status :
- Lemonway success → CONFIRMED
- Lemonway cancelled ou autre → DECLINED
5. Si contexte topup_card : enrichit le contexte avec les infos de la carte (mapCardFromLwMoneyIn).
6. Sauvegarde via CustomerBalanceService.saveWalletTransactions.
Hors transaction : déclenche cardTopupService.cardStatusConfirmedOrDeclined (logique métier post-paiement, ex. validation réservation primary-purchase).
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
money-in.card.hook.WALLET_TRANSACTION_NOT_FOUND |
404 | WT inconnue (cas log + ignore) |
BadRequestException (vide) |
400 | lemonwayTransactionId manquant |
money-in.card.hook.WALLET_TRANSACTION_NOT_WAITING |
400 | WT déjà finalisée — webhook ignoré |
Transaction not found at Lemonway |
404 | Lemonway ne retrouve pas la transaction |
InternalServerError |
500 | Autre erreur Lemonway |
Liens¶
- Service top-up carte :
card-payment.service.ts - Service primary purchase (rattachement réservation) :
primary-purchase.service.ts - API Lemonway :
lemonway.api.ts - DTO Lemonway :
lemonway.dto.ts - Service MFA (carte cadeau) :
mfa.pre-auth-flow.service.ts