Lemonway — Webhooks¶
Webhooks serveur-à-serveur appelés par Lemonway pour notifier les changements de statut KYC/KYB, statut de documents, blocage temporaire, chargeback et changement de statut de compte/profil (onboarding V2). Source : hook.controller.ts.
Tous les endpoints sont sous le préfixe /customers/lemonway/webhook. Pas de JwtAuthGuard ni UserRoleGuard — la protection repose sur ApiAuthService.assertApiKeyInQueryParams(queryParams, 'lemonway') : la clé doit être passée en query param apiKey et est comparée en temps constant (crypto.timingSafeEqual) à getEnvConfig().lemonway.apiKeyInternalWebhook. Si la clé n'est pas configurée côté API, l'auth est désactivée (cas dev/test) — la valeur d'env est obligatoire en production. Voir api-auth.service.ts.
POST /webhook/customer-status-changed¶
Notification de changement de statut KYC/KYB (onboarding V1) sur un compte Lemonway investisseur ou SPV. Source : hook.controller.ts#L57.
Query params¶
apiKey— requis silemonway.apiKeyInternalWebhookest configuré
Request body¶
LemonwayWebhookDtoRaw (voir parseLemonwayWebhookDto) — contient notamment ExtId (UUID investisseur ou external id SPV) et IntId (id Lemonway). Tous les champs numériques arrivent en string et sont convertis.
Effets¶
- Si
ExtIdest un UUID valide → cherche l'investisseur. - Cherche toujours le SPV par
lemonwayExternalId(lookup inconditionnel, indépendant du résultat investisseur). - Si ni l'un ni l'autre : log +
200(no-op). - Si investisseur trouvé :
CustomerLemonwayService.syncCustomerStatusOnboardingV1(customer.id). - Si SPV trouvé :
specialPurposeVehiculeService.syncSpvLemonwayKYBStatusOnboardingV1(spv.id). Les deux blocs sont indépendants et peuvent s'exécuter dans le même appel.
Response¶
200 (pas de body).
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
UnauthorizedException |
401 | apiKey query param manquante ou invalide |
lemonway-webhook-payload-missing-ids |
500 | ExtId ou IntId absent du payload |
POST /webhook/document-status-changed¶
Notification de changement de statut sur un document KYC (pièce d'identité, IBAN). Source : hook.controller.ts#L104.
Query params¶
apiKey— requis si configuré
Request body¶
Validé via lemonwayHookDocumentStatusPayload :
IntId,DocId(numbers from string)ExtId(string)DocType— type Lemonway (id pièce, IBAN, etc.)NotifDate(ISO date)NotifCategory—9(document status change)Status— entier 0-8
Effets¶
- Cherche l'investisseur (par
ExtIdUUID) ; si SPV → ignore (non géré). - Si pas d'investisseur : log et ignore (
200). - Re-fetch des documents Lemonway (
lemonwayApi.getAccountDocuments) pour vérifier la cohérence — defense-in-depth car l'endpoint est public et n'importe qui pourrait poster. - Si le statut Lemonway diffère de celui du payload : log + ignore.
- Si pièce d'identité (
isLwDocumentIdentityType) :DocumentStatusHookUpdateService.patchInvestorIdentityDocument. - Si IBAN (
isLwDocumentIbanType) :PaymentMethodsService.syncLemonwayBankAccountStatusesFor(customer.id). - Sinon : log d'erreur (type non géré).
Response¶
200 (pas de body).
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
UnauthorizedException |
401 | API key manquante / invalide |
BadRequestException (vide) |
400 | Payload invalide (validation idtt) |
BadRequestException (vide) |
400 | Le DocId reçu n'existe pas chez Lemonway |
customer-not-found |
404 | Investisseur de la pièce d'identité introuvable |
InternalServerError |
500 | Erreur Lemonway lors du re-fetch |
POST /webhook/customer-temporarily-blocked¶
Notification de blocage temporaire d'un compte (NotifCategory 13). Source : hook.controller.ts#L217.
Query params¶
apiKey— requis si configuré
Request body¶
Validé via customerBlockedHookValidator :
IntId,ExtId,NotifDate,Status(statut compte Lemonway)NotifCategorydoit être13Blocked—0|1mappé en booléen
Effets¶
- Si investisseur trouvé :
CustomerLemonwayService.syncAccountIsBlocked(customer.id). - Si SPV trouvé :
specialPurposeVehiculeService.syncAccountIsBlockedAtLemonway(spv.id). - Sinon : no-op silencieux.
Response¶
200.
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
UnauthorizedException |
401 | API key manquante / invalide |
BadRequestException |
400 | Validation customerBlockedHookValidator échouée |
POST /webhook/charge-back¶
Notification de chargeback sur une transaction money-out. Crée une alerte Slack puis freeze l'investisseur (best-effort, l'erreur du freeze ne casse pas le hook). Source : hook.controller.ts#L252.
Query params¶
apiKey— requis si configuré
Request body¶
Validé via object({ ExtId: string, Comment: string, IdTransaction: numberFromString }).
Effets¶
lemonwayApi.getMoneyOut({ transactionId })pour récupérer le détail.- Alerte Slack envoyée (
chargeBackAlertSlack) avant le contrôle d'erreur du fetch — pour ne pas la perdre si la suite échoue. - Si transaction non trouvée chez Lemonway : log +
200(no-op). CustomerFreezeService.freezeCustomer({ customerId, reason, source: 'webhook-chargeback', sendInternalNotification: true })— erreur silencée.
Response¶
200.
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
UnauthorizedException |
401 | API key manquante / invalide |
BadRequestException |
400 | Validation payload échouée |
BadRequestException (vide) |
400 | Erreur lors du fetch chargeback chez Lemonway |
POST /webhook/account-status-changed¶
Notification de changement de statut de compte Lemonway (onboarding V2). Source : hook.controller.ts#L308.
Query params¶
apiKey— requis si configuré
Request body¶
Le payload complet est passé tel quel à LemonwayAccountService.onboardingStatusChangedHook.
Effets¶
LemonwayAccountService.onboardingStatusChangedHook({ lwAccountId, hookPayload: data }).
Response¶
200.
Erreurs¶
| Code | Statut | Cause |
|---|---|---|
UnauthorizedException |
401 | API key manquante / invalide |
BadRequestException |
400 | AccountID absent / invalide |
POST /webhook/profile-status-changed¶
Notification de changement de statut de profil Lemonway (onboarding V2). Mêmes signature et comportement que account-status-changed — appelle aussi LemonwayAccountService.onboardingStatusChangedHook. Source : hook.controller.ts#L332.
Query params / Request body / Response / Erreurs¶
Identiques à POST /webhook/account-status-changed.
Liens¶
- Service auth API key :
api-auth.service.ts - Service Lemonway customer (V1) :
customers-lemonway.service.ts - Service Lemonway account (V2) :
lemonway-account.service.ts - Service mise à jour documents :
document-status-hook-update.service.ts - Service freeze customer :
customer-freeze.service.ts - DTO Lemonway :
lemonway.dto.ts