Aller au contenu

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.requireMfaToken avec action gift-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 simple
  • type: 'gift-card' — top-up + achat d'une carte cadeau (requiert mfaVerificationToken + giftCard)
  • type: 'bricks-reservation' — paiement d'une réservation d'achat primaire (requiert bricksReservationId)

Response

{
  "url": "https://webkit.lemonway.fr/..."
}

URL Lemonway vers laquelle rediriger l'investisseur (page de saisie carte hébergée par Lemonway).

Effets de bord

  • Si type === 'bricks-reservation' : appelle primaryPurchaseService.setCardInForBricksReservation pour rattacher la walletTransaction carte 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_CARDS actif
  • Onboarding investisseur complété
  • Droits transactionnels : 'all' ou 'cashin_fundraise'
  • Si type: 'gift-card' : MFA pré-validé (action gift-card-purchase) + cohérence amountToMoneyIn + 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'

{ "status": "confirmed" }
ou
{ "status": "pending" }

Si confirmed : un évènement Customer.io topup_card est envoyé.

Response — type: 'gift-card'

{ "status": "confirmed", "giftCard": { "...": "carte cadeau créée" } }
ou
{ "status": "pending" }

Si confirmed : la carte cadeau est créée via GiftCardService.createGiftCardPurchaseWt.

Response — type: 'bricks-reservation'

{ "status": "confirmed" }
ou
{ "status": "pending" }

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é par ParseUUIDPipe)

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 (successok, cancelledcancel, 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é par ParseUUIDPipe)

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 successCONFIRMED - 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