Reference donnees anti-fraude
Tables et colonnes
wallet_transactions
| Colonne |
Type |
Notes |
id |
uuid |
PK |
customerId |
uuid |
FK vers customers |
createdAt |
timestamp |
Date de creation |
kind |
enum |
Type de transaction (voir section Kinds) |
status |
enum |
waiting, confirmed, declined, canceled |
value |
integer |
Montant en centimes. Negatif pour les debits (retraits, achats) |
paymentMethodId |
uuid nullable |
Lien vers payment_methods. Renseigne a 100% sur withdrawal, JAMAIS sur topup_card/topup_checkout |
context |
jsonb nullable |
Contexte specifique au kind. Discriminated union par type |
referenceId |
uuid nullable |
Lien vers une WT parente (ex: withdrawal_fee -> withdrawal) |
balance |
integer |
Solde apres la transaction |
index |
bigint |
Ordre de creation (pour le ranking des debits) |
customers
| Colonne |
Type |
Notes |
id |
uuid |
PK, sert aussi de accountId Lemonway |
createdAt |
timestamp |
Date de creation du compte |
email |
text |
Email du customer |
withdrawableBalances |
jsonb |
{ current, pendingCredit, pendingDebit } en centimes |
deletedAt |
timestamp nullable |
Non null = compte supprime |
transactionRights |
enum |
Droits de transaction |
payment_methods
| Colonne |
Type |
Notes |
id |
uuid |
PK |
customerId |
uuid |
FK vers customers |
kind |
enum |
iban_withdraw ou virtual_iban_deposit |
createdAt |
timestamp |
Date d'ajout |
bic |
text nullable |
Code BIC de la banque |
iban |
text nullable |
IBAN |
deletedAt |
timestamp nullable |
Non null = supprime |
lemonwayBankAccountStatus |
integer nullable |
Statut chez LW |
primary_purchase
| Colonne |
Type |
Notes |
status_view |
text |
Statut de l'achat. confirmed = investissement reel |
propertyId_view |
uuid |
Propriete achetee |
json |
jsonb |
Contient investorId, brickCount, etc. |
createdAt_view |
timestamp |
Date d'achat |
Pour compter les investissements d'un customer :
SELECT COUNT(*)::int
FROM primary_purchase
WHERE (json->>'investorId')::uuid = $1
AND "status_view" = 'confirmed'
Kinds de wallet_transactions
Topups carte (money-in CB)
| Kind |
Description |
Utiliser pour l'analyse fraude |
topup_card |
Paiement carte directe via Lemonway |
OUI |
topup_checkout |
Paiement carte / Apple Pay via Checkout.com |
OUI |
topup_wire |
Virement bancaire |
NON (pas une carte) |
topup |
Legacy generique |
NON (ancien format) |
Pour les analyses fraude, toujours utiliser kind IN ('topup_card', 'topup_checkout').
Retraits (money-out)
| Kind |
Description |
Utiliser pour l'analyse fraude |
withdrawal |
Retrait standard |
OUI |
withdrawal_legacy |
Ancien format de retrait |
NON (ignore) |
withdrawal_fee |
Commission de retrait |
NON (pas un retrait) |
Pour les analyses fraude, toujours utiliser kind = 'withdrawal'.
Autres kinds utiles
| Kind |
Description |
primary_purchase |
Achat de bricks (debit) |
revenue_royalty |
Revenu locatif |
revenue_obligation_coupon |
Coupon obligataire |
Statuts
| Statut |
Signification |
waiting |
En attente d'execution |
confirmed |
Execute avec succes |
declined |
Refuse |
canceled |
Annule |
Regles de filtrage par statut
| Contexte |
Filtre a appliquer |
Raison |
| Topups carte pour analyse fraude |
Aucun filtre sur le statut |
Un topup declined reste une tentative suspecte (test de carte volee) |
| Retraits |
status = 'confirmed' |
Seuls les retraits effectivement sortis comptent |
| Investissements |
status_view = 'confirmed' sur primary_purchase |
Seuls les achats finalises |
Pieges connus
paymentMethodId
- Renseigne a 100% sur les
withdrawal : lien exact vers l'IBAN utilise pour le retrait
- JAMAIS renseigne sur les
topup_card / topup_checkout (0 sur 848K+ transactions)
- Impossible de distinguer les cartes depuis cette colonne. Pour le multi-cartes, il faut utiliser le
card.id retourne par l'API Lemonway GET /moneyins
Colonnes legacy
customers.lemonwayBalance : alias legacy de availableWithdrawableBalance_view. Ne PAS utiliser pour le solde reel
withdrawal_legacy : ancien kind de retrait. Ne pas inclure dans les analyses recentes
topup (sans suffixe) : kind legacy. Ne PAS confondre avec topup_card
Montants
- Tous les montants sont en centimes (integer)
value est negatif pour les debits (retraits : ex -50000 = 500 EUR retires)
- Pour les montants en euros dans les tableaux : diviser par 100
Context jsonb
- Nullable sur les withdrawals
- Pour les withdrawals, le context contient exactement deux champs :
{
"type": "withdrawal",
"withdrawRequestId": "..."
}
Le context de la wallet_transaction ne porte aucune information anti-fraude. La decision anti-fraude est synchrone (block/allow) et stockee sur l'entite WithdrawRequest (champs outcome = allowed | blocked et fraudCheck = { version, description, config, metrics, decision: { blocked, fraudChecks } }).
Pour analyser les decisions anti-fraude, requeter withdraw_requests (champs outcome / fraud_check), pas wallet_transactions.context.
BICs de reference
Neobanques exotiques (signal fort de fraude)
| BIC |
Banque |
Pays |
Nb fraudeurs (sur 53) |
| DBLKFR22XXX |
Deblock |
France |
10 |
| BZENLT22XXX |
Zen.com |
Lituanie |
9 |
| INTFBGSFXXX |
iCard |
Bulgarie |
2 |
| CFTEMTM1XXX |
(fintech) |
Malte |
2 |
| EVIULT2VXXX |
kevin. |
Lituanie |
2 |
| SUMUIE22XXX |
SumUp |
Irlande |
2 |
| SUPULT22XXX |
(fintech) |
Lituanie |
2 |
Banques mainstream (attention faux positifs)
| BIC |
Banque |
Nb fraudeurs |
| REVOFRP2XXX |
Revolut |
10 |
| BFBKFRP1XXX |
BforBank/BRED |
9 |
| TRWIBEB1XXX |
Wise |
4 |
| BOUSFRPPXXX |
Boursorama |
4 |
Signal : IBANs hors-FR
Un client francais avec un IBAN non-FR (prefixes LT, BG, MT, IE, BE) est un signal d'alerte. A combiner avec d'autres signaux, pas en standalone.
Regles de blocage runtime (FraudCheckV2)
Les regles ci-dessous sont evaluees a chaque tentative de retrait investisseur via WithdrawFraudService.buildAndCheckWithdrawRequest.
Inputs (WithdrawContext)
| Champ |
Source SQL |
accountAgeDays |
(NOW()::date - customers.createdAt::date)::int |
confirmedInvestmentCount |
Count de wallet_transactions avec kind = 'primary_purchase', status = 'confirmed', et (context->>'refundableUntil')::timestamptz < NOW() |
cardTopupCount |
Count de wallet_transactions avec kind IN ('topup_card', 'topup_checkout') — aucun filtre sur status |
bic |
payment_methods.bic du moyen de paiement selectionne (trimme avant evaluation) |
Regle A — Pattern fraude (AND composite)
| Condition |
Seuil V2 |
Seuil V1 (historique) |
| Compte recent |
accountAgeDays < 60 |
idem |
| Pas d'investissement confirme non remboursable |
confirmedInvestmentCount = 0 |
idem |
| Topups carte |
cardTopupCount >= 1 |
>= 3 |
Regle B — BIC blackliste (OR independant)
Le BIC (trimme) est teste en prefixe (pas egalite stricte) contre la liste : DBLKFR22, BZENLT22, INTFBGSF, CFTEMTM1, EVIULT2V, SUMUIE22, SUPULT22.
Decision
blocked = matchesFraudPattern || isBlacklistedBic
Bypasses
- Admin (
executedBy === 'admin') : jamais bloque
- Whitelist (
investor_withdraw_whitelist row exists) : jamais bloque
Le fraudCheck complet (version, config snapshot, metriques, decision avec flags individuels) est persiste dans investor_withdraw_requests quel que soit l'outcome.
Difference V1 vs V2
Seul changement : minCardTopupCount passe de 3 (V1) a 1 (V2). V1 reste dans le code pour la validation des records historiques (discriminated union sur version), mais seul V2 est evalue a runtime.