Programmes de Fidelite
Creez et gerez des programmes de fidelite personnalises avec points, cashback, paliers et templates de cartes.
Derniere mise a jour : 22 juin 2026
Vue d'ensemble
Les programmes de fidelite YaniPay permettent aux marchands de creer des experiences de retention personnalisees. Chaque programme definit ses propres regles d'attribution de points, paliers de benefices et recompenses.
L'API est divisee en deux parties : l'API Propour les marchands (creation, gestion) et l'API Client pour les particuliers (inscription, consultation).
Types de programmes
Points
Attribution de points proportionnels au montant depense. Les clients echangent leurs points contre des recompenses.
Cashback
Pourcentage du montant credite directement sur la cagnotte du client. Utilisable pour les prochains achats.
Hybride
Combine points et cashback. Attribution de points avec conversion automatique en euros sur la cagnotte.
API Marchand (Pro)
Les endpoints /api/pro/*permettent aux marchands de creer et gerer leurs programmes de fidelite. Un compte professionnel avec le role "MERCHANT" est requis.
| Methode | Endpoint | Description |
|---|---|---|
| POST | /api/pro/programs | Creer un programme |
| GET | /api/pro/programs | Lister ses programmes |
| PATCH | /api/pro/programs/:id | Modifier un programme |
| DELETE | /api/pro/programs/:id | Supprimer un programme |
| POST | /api/pro/programs/:id/card-template | Definir le template de carte |
| GET | /api/pro/stores | Lister les magasins |
| POST | /api/pro/stores | Ajouter un magasin |
Creer un programme
1 // Creer un programme de fidelite complet 2 const response = await fetch('/api/pro/programs', { 3 method: 'POST', 4 headers: { 'Content-Type': 'application/json' }, 5 body: JSON.stringify({ 6 name: 'Club Gourmet', 7 description: 'Programme fidelite pour les amoureux de la gastronomie', 8 type: 'hybrid', // "points" | "cashback" | "hybrid" 9 10 // Configuration points 11 pointsConfig: { 12 pointsPerEuro: 10, // 10 points par euro depense 13 pointValue: 0.01, // 1 point = 0.01 EUR (pour conversion) 14 expirationMonths: 12, // Points expirent apres 12 mois 15 minRedemption: 100, // Min 100 points pour echanger 16 }, 17 18 // Configuration cashback 19 cashbackConfig: { 20 percentage: 2.0, // 2% cashback 21 maxMonthly: 5000, // Max 50 EUR/mois en centimes 22 creditDelay: 48, // Credit apres 48h (anti-fraud) 23 }, 24 25 // Paliers 26 tiers: [ 27 { name: 'Decouverte', minPoints: 0, multiplier: 1.0, color: '#cd7f32' }, 28 { name: 'Gourmet', minPoints: 500, multiplier: 1.5, color: '#c0c0c0' }, 29 { name: 'Chef', minPoints: 2000, multiplier: 2.0, color: '#ffd700' }, 30 { name: 'Etoile', minPoints: 10000, multiplier: 3.0, color: '#e5e4e2' }, 31 ], 32 33 // Regles d'attribution automatique 34 rules: { 35 welcomeBonus: 50, // 50 points a l'inscription 36 birthdayBonus: 200, // 200 points le jour de l'anniversaire 37 referralBonus: 100, // 100 points par parrainage 38 }, 39 40 active: true, 41 }), 42 }); 43 44 const { data: program } = await response.json(); 45 // program.id = "prog_abc123" 46 // program.enrollmentUrl = "https://yanipay.com/loyalty/join/prog_abc123"
Activation immediate
active: true. Les clients peuvent s'inscrire immediatement via le lien d'inscription genere.Templates de cartes
Personnalisez l'apparence de la carte de fidelite affichee dans le wallet mobile des clients. Les templates supportent les couleurs, logos et motifs personnalises.
1 // Definir le template de carte 2 await fetch('/api/pro/programs/prog_abc123/card-template', { 3 method: 'POST', 4 headers: { 'Content-Type': 'application/json' }, 5 body: JSON.stringify({ 6 backgroundColor: '#1a1a2e', 7 backgroundGradient: 'linear-gradient(135deg, #1a1a2e, #16213e)', 8 textColor: '#ffffff', 9 accentColor: '#e94560', 10 logoUrl: '/brands/club-gourmet-logo.png', 11 pattern: 'dots', // "none" | "dots" | "waves" | "grid" 12 showPoints: true, 13 showTier: true, 14 showBarcode: true, // QR code pour scan en magasin 15 }), 16 });
Preview en temps reel
Configuration SavebackNEW
Le savebackest un cashback reverse au client en YANI, en complement des points. Chaque programme possede sa propre configuration de saveback, pilotable via l'API. Voir la vue d'ensemble Saveback pour le concept general.
Configuration via API uniquement
PATCH sur l'endpoint saveback-config). Aucune interface graphique dans le dashboard marchand n'est encore disponible pour ajuster ces parametres.Endpoints
| Methode | Endpoint | Description |
|---|---|---|
| GET | /api/pro/programs/:programId/saveback-config | Lire la config (defauts non persistes si absente) |
| PATCH | /api/pro/programs/:programId/saveback-config | Creer/modifier le taux et les regles de versement |
| GET | /api/pro/saveback-analytics | Analytics agreges des versements (tous programmes) |
Les deux endpoints sont proteges par RBAC ['PROFESSIONNEL', 'ADMIN'] et un rate limit standard (apiRateLimit— 100 req / 15 min). Le modele d'ownership resout programId → store.proIda chaque requete : un marchand ne peut acceder qu'a la config de ses propres programmes (un ADMIN contourne ce controle).
Champs de configuration
| Champ | Type | Description |
|---|---|---|
| currentRate | number | Taux courant (≥ 1 % — plancher SAVEBACK_MIN_RATE) |
| maxRate | number | Plafond du taux pour le programme |
| payoutSchedule | 'IMMEDIATE' | 'DAILY' | 'WEEKLY' | Cadence de versement du saveback |
| minThreshold | number (≥ 0) | Seuil minimal avant declenchement du versement |
| isYaniPayout | boolean | Versement en YANI (true) le cas echeant |
| enabled | boolean | Active ou desactive le saveback du programme |
GET sans config existante
GET retourne des valeurs par defaut sans les persister (avec isDefault: true) : currentRate = 1 %, maxRate = 10 %, payoutSchedule = 'IMMEDIATE', minThreshold = 0, isYaniPayout = true, enabled = true. La config n'est creee en base que lors du premier PATCH.1 import { apiGet } from '@/lib/api/client'; 2 import type { SavebackConfigDTO } from '@platform/api/contracts/saveback'; 3 4 const programId = 'prog_abc123'; 5 6 // Lire la configuration saveback du programme 7 const config = await apiGet<SavebackConfigDTO>( 8 `/api/pro/programs/${programId}/saveback-config` 9 ); 10 11 // config.programId — identifiant du programme 12 // config.minRate — plancher reglementaire (0.01 = 1 %) 13 // config.maxRate — plafond du taux (ex: 0.1 = 10 %) 14 // config.currentRate — taux actuellement applique 15 // config.payoutSchedule — 'IMMEDIATE' | 'DAILY' | 'WEEKLY' 16 // config.minThreshold — seuil minimal de versement 17 // config.isYaniPayout — versement en YANI 18 // config.enabled — saveback actif ?
1 import { apiPatch } from '@/lib/api/client'; 2 import type { 3 SavebackConfigDTO, 4 UpdateSavebackConfigRequest, 5 } from '@platform/api/contracts/saveback'; 6 7 const programId = 'prog_abc123'; 8 9 // Tous les champs sont optionnels — seuls les champs fournis sont mis a jour. 10 // Si la config n'existe pas encore, le PATCH la cree puis applique les valeurs. 11 const body: UpdateSavebackConfigRequest = { 12 currentRate: 0.03, // 3 % de saveback (doit etre >= 1 %) 13 maxRate: 0.1, // plafond 10 % 14 payoutSchedule: 'WEEKLY', // versement hebdomadaire 15 minThreshold: 5, // pas de versement sous ce seuil 16 isYaniPayout: true, 17 enabled: true, 18 }; 19 20 const updated = await apiPatch<SavebackConfigDTO>( 21 `/api/pro/programs/${programId}/saveback-config`, 22 body 23 ); 24 25 // updated.currentRate === 0.03
Erreur 403 — ownership
403 Forbidden (You can only access saveback config for your own programs). Si le programme n'existe pas, la reponse est 404 Not Found. Un taux fourni sous le plancher de 1 % renvoie 400 Bad Request.Analytics saveback
L'endpoint GET /api/pro/saveback-analytics retourne les versements agreges pour tous les programmes du marchand, avec un filtre de periode optionnel (?from= et ?to= au format ISO-8601).
1 import { apiGet } from '@/lib/api/client'; 2 import type { ProSavebackAnalyticsDTO } from '@platform/api/contracts/saveback'; 3 4 // Filtre de periode optionnel 5 const analytics = await apiGet<ProSavebackAnalyticsDTO>( 6 '/api/pro/saveback-analytics?from=2026-01-01&to=2026-06-30' 7 ); 8 9 // analytics.totalEarnedEur — total EUR verse (tous statuts) 10 // analytics.totalEarnedYani — total YANI alloue 11 // analytics.totalPaidYani — somme des versements PAID 12 // analytics.totalPendingYani — somme des versements PENDING 13 // analytics.byStatus — comptes/montants par statut (PENDING/PAID/FAILED) 14 // analytics.byProgram — ventilation par programme 15 // analytics.rangeFrom / rangeTo — bornes du filtre applique
Versement on-chain (payout)
/api/admin/saveback-payout. Il n'est pas pilote par le marchand. Voir la documentation Paiements pour les details du payout.Gestion des magasins
Associez vos points de vente physiques au programme de fidelite pour permettre le scan en magasin et la geolocalisation.
1 // Ajouter un point de vente 2 const response = await fetch('/api/pro/stores', { 3 method: 'POST', 4 headers: { 'Content-Type': 'application/json' }, 5 body: JSON.stringify({ 6 programId: 'prog_abc123', 7 name: 'Club Gourmet - Paris 8e', 8 address: { 9 street: '42 Avenue des Champs-Elysees', 10 city: 'Paris', 11 postalCode: '75008', 12 country: 'FR', 13 }, 14 coordinates: { 15 latitude: 48.8698, 16 longitude: 2.3075, 17 }, 18 openingHours: { 19 monday: { open: '10:00', close: '22:00' }, 20 tuesday: { open: '10:00', close: '22:00' }, 21 // ... 22 }, 23 }), 24 });
API Client
Les routes client permettent aux particuliers de decouvrir, rejoindre et interagir avec les programmes de fidelite.
| Methode | Endpoint | Description |
|---|---|---|
| GET | /api/loyalty/programs | Decouvrir les programmes disponibles |
| POST | /api/v1/mobile/loyalty/enroll/{programId} | S'inscrire a un programme (ID dans l'URL) |
| DELETE | /api/v1/mobile/loyalty/enroll/{programId} | Se desinscrire d'un programme |
| GET | /api/customer/loyalty-cards | Mes cartes de fidelite |
| GET | /api/customer/loyalty-cards/:id | Details d'une carte |
| GET | /api/customer/loyalty-stats | Mes statistiques |
S'inscrire a un programme Mis a jour 2026-04-09
1 // Inscription a un programme de fidelite (ID dans l'URL, pas de body) 2 // Ancien (incorrect) : 3 // const response = await fetch('/api/loyalty/subscribe', { 4 // method: 'POST', 5 // body: JSON.stringify({ programId: 'prog_abc123' }), 6 // }); 7 8 // Nouveau (correct) : 9 const response = await fetch(`/api/v1/mobile/loyalty/enroll/prog_abc123`, { 10 method: 'POST', 11 headers: { 12 Authorization: 'Bearer <token>', 13 'Content-Type': 'application/json', 14 }, 15 // Optionnel : code parrain 16 body: JSON.stringify({ referralCode: 'REF-JOHNDOE' }), 17 }); 18 19 const { success, data } = await response.json(); 20 // { 21 // "success": true, 22 // "data": { 23 // "loyaltyCard": { 24 // "id": "lc_xyz789", 25 // "programId": "prog_abc123", 26 // "programName": "Club Gourmet", 27 // "points": 50, // Welcome bonus 28 // "tier": "Decouverte", 29 // "cashback": 0, 30 // "barcode": "LC-XYZ-789", 31 // "enrolledAt": "2026-04-09T10:30:00Z" 32 // } 33 // } 34 // } 35 36 // Se desinscrire d'un programme : 37 await fetch(`/api/v1/mobile/loyalty/enroll/prog_abc123`, { 38 method: 'DELETE', 39 headers: { Authorization: 'Bearer <token>' }, 40 });
Cartes de fidelite
1 // Response - 200 OK 2 { 3 "success": true, 4 "data": [ 5 { 6 "id": "lc_xyz789", 7 "program": { 8 "id": "prog_abc123", 9 "name": "Club Gourmet", 10 "merchant": "Restaurant Le Parisien", 11 "logoUrl": "/brands/club-gourmet-logo.png" 12 }, 13 "points": 1250, 14 "tier": { 15 "name": "Gourmet", 16 "multiplier": 1.5, 17 "color": "#c0c0c0", 18 "nextTier": { 19 "name": "Chef", 20 "pointsRequired": 2000, 21 "pointsRemaining": 750 22 } 23 }, 24 "cashbackBalance": 1245, // 12.45 EUR en centimes 25 "totalEarned": 4500, 26 "totalRedeemed": 3255, 27 "barcode": "LC-XYZ-789", 28 "enrolledAt": "2024-06-15T14:00:00Z" 29 } 30 ] 31 }
Configuration des paliers
Les paliers (tiers) permettent de recompenser les clients les plus fideles avec des multiplicateurs de points et des avantages exclusifs.
1 import { z } from 'zod'; 2 3 export const tierSchema = z.object({ 4 name: z.string().min(1).max(50), 5 minPoints: z.number().nonnegative(), 6 multiplier: z.number().min(1).max(10), // x1 a x10 7 color: z.string().regex(/^#[0-9A-Fa-f]{6}$/), 8 benefits: z.array(z.string()).optional(), // Avantages textuels 9 }); 10 11 export const programSchema = z.object({ 12 name: z.string().min(3).max(100), 13 description: z.string().max(500).optional(), 14 type: z.enum(['points', 'cashback', 'hybrid']), 15 pointsConfig: z.object({ 16 pointsPerEuro: z.number().positive().max(100), 17 pointValue: z.number().positive().max(1), 18 expirationMonths: z.number().positive().max(60), 19 minRedemption: z.number().nonnegative(), 20 }).optional(), 21 cashbackConfig: z.object({ 22 percentage: z.number().min(0.1).max(20), 23 maxMonthly: z.number().positive(), 24 creditDelay: z.number().nonnegative().max(168), // Max 7 jours en heures 25 }).optional(), 26 tiers: z.array(tierSchema).min(1).max(10), 27 active: z.boolean().default(true), 28 }); 29 30 export type ProgramInput = z.infer<typeof programSchema>; 31 export type TierInput = z.infer<typeof tierSchema>;
Modification des paliers
Prochaines etapes
Ressources associees
Derniere mise a jour : 22 juin 2026 — Section Configuration Saveback (NEW : endpoints GET/PATCH saveback-config, champs reels du body PATCH, ownership 403/404, plancher 1 %, analytics saveback-analytics, renvoi payout admin vers la doc paiements), @platform/api/contracts/saveback