kado
Le cadeau, digitalisé.
Documentation Produit — Version 1.1 · Sénégal & UEMOA · Mai 2026
PWA Mobile-First Chèques Cadeaux Digitaux Wave + Orange Money Offline-ready QR Code NFC-free
Bénéficiaire
Reçoit & utilise ses bons
Entreprise RH
Émet & distribue les bons
Commerçant
Encaisse & reçoit le versement
Admin kado
Supervise la plateforme
Qu'est-ce que kado ?

kado est une plateforme PWA de chèques cadeaux digitaux conçue pour le Sénégal et l'UEMOA. Elle permet aux entreprises d'émettre des bons dématérialisés à leurs employés, qui les utilisent chez des commerçants partenaires via un simple QR code — sans application à télécharger, sans carte bancaire, sans espèces.

Positionnement : kado opère sous convention de distribution EME (Établissement de Monnaie Électronique). Les fonds sont hébergés dans un compte de provision ségrégué chez le partenaire EME (Wari ou Joni-Joni). kado n'est pas émetteur de monnaie électronique.
Cas d'usage principaux
Tickets repas
L'entreprise émet des bons MEAL_TICKET utilisables chez les restaurants partenaires. L'employé paie son déjeuner avec son QR code.
Primes & cadeaux
Bons GIFT_VOUCHER pour récompenser un employé — fête de fin d'année, prime exceptionnelle, anniversaire d'entreprise.
Transport
Bons TRANSPORT pour le remboursement des frais de déplacement domicile-travail. Utilisables chez les taxis et Dakar Dem Dikk.
Bonus fidélité
Bons BONUS offerts par les commerçants à leurs clients réguliers via le programme de fidélité intégré.
Modèle économique
Source de revenusMécanismeTauxExemple
Commission transaction Prélevée sur chaque validation QR 2% du montant Bon 10 000 FCFA → 200 FCFA commission kado
Abonnement SaaS Abonnement mensuel par entreprise 30 000 FCFA / mois (Standard)
60 000 FCFA / mois (Premium)
5 entreprises × 30 000 = 150 000 FCFA/mois
Soldes expirés Bons non utilisés à expiration (J+180) 100% du solde restant Résiduel, non planifié
Parcours global
Entreprise
Approvisionne & émet les bons
SMS
Lien d'activation envoyé
Bénéficiaire
Active & consulte ses bons
Bénéficiaire
Scanne le QR du commerçant
Validation
Débit immédiat du bon
Reversement
Wave/OM en J+1
Stack technique
ComposantTechnologieHébergementRôle
API BackendNestJS 10 · TypeScript · Prisma 5RailwayLogique métier, auth, paiements
Frontend WebNext.js 15 · React 19 · PWAVercelToutes les interfaces utilisateur
Base de donnéesPostgreSQL 16RailwayDonnées persistantes, ledger
Cache / QueuesRedis 7 · BullRailwayOTP, sessions, jobs asynchrones
SMSNexah (principal) · Twilio (fallback)CloudOTP, notifications bons
PaiementsWave Mobile Money · Orange MoneyCloudApprovisionnement + reversements
MonitoringSentryCloudAlertes erreurs production
Espace Bénéficiaire — kado.sn/app
Application mobile-first : L'interface bénéficiaire est une PWA optimisée pour les téléphones Android bas de gamme (Tecno Y4, ~35 000 FCFA). Aucune installation requise — le lien SMS suffit. Fonctionne en mode hors-ligne pour l'affichage des QR codes.
Connexion OTP

Le bénéficiaire se connecte via son numéro de téléphone sénégalais (+221). Un code à 6 chiffres est envoyé par SMS, valable 5 minutes. Après 3 échecs consécutifs, le compte est bloqué 30 minutes.

Saisie numéro
kado
Entrez votre numéro
+221 77 ••• ••••
Recevoir le code →
Saisie OTP
Code envoyé au
+221 77 ••• ••••
4
2
_
Expire dans 4:32
Portefeuille (Wallet)

La page principale affiche le solde total disponible en FCFA et la liste des bons actifs avec leur statut. 4 onglets permettent d'accéder aux offres flash, commerçants proches et programme fidélité.

Mes bons
Solde disponible
47 500 FCFA
Bons
Offres
Magasins
Fidélité
2 bons actifs
Ticket repas
Expire le 15/09/2026
Actif
25 000
FCFA
Bon cadeau
Utilisé: 7 500 FCFA
Partiel
22 500
FCFA
Scanner un QR commerçant
Mon QR code
Ticket repas · MEAL_TICKET
25 000 FCFA
Ticket repas — Solde disponible
Expire le 15/09/2026 · dans 151 jours
kado.sn · code: 3f7a9c2e…
Offres flash
Offres flash du jour
Pizza La Mama
-20%
Restauration · Plateau
Jusqu'à 20h00
Shell Select VDN
-15%
Transport · Ouakam
Jusqu'à 22h00
Fonctionnalités détaillées
FonctionnalitéDescriptionRoute
Authentification OTPConnexion par SMS, code 6 chiffres, TTL 5 min/app/login
PortefeuilleSolde total, liste bons actifs/expirés/utilisés, animation count-up/app/wallet
QR Code plein écranAffichage QR avec timer expiration, Screen Wake Lock (écran allumé), mode offline/app/wallet/[id]
Historique transactionsToutes les validations d'un bon avec date/commerçant/montant/app/wallet/[id]/history
Paiement directPayer un commerçant par montant libre sur un bon sélectionné/app/pay
Scanner QR commerçantScanner le QR d'un commerçant pour initier un paiement/app/scan
Offres flashPromotions limitées dans le temps par les commerçants prochesOnglet Wallet
Commerçants prochesCarte des partenaires kado avec géolocalisationOnglet Wallet
Programme fidélitéPoints accumulés par commerçant, solde et historiqueOnglet Wallet
Activation invitationPremier accès via lien SMS envoyé par l'entreprise/join/[token]
Espace Entreprise RH — kado.sn/dashboard
Interface desktop-first conçue pour les gestionnaires RH. Permet d'émettre des bons en masse (import CSV), de suivre la consommation en temps réel, de gérer les collaborateurs et de consulter les rapports RSE/impact social.
Provisionnement & émission
kado.sn/dashboard
Sonatel SA · Plan Premium
Seynabou DIOP · RH
Provision disponible
2 450 000
FCFA · rechargé le 01/04
Bons émis ce mois
128
pour 89 bénéficiaires
Consommé
1 840 000
FCFA · 75% du budget
Derniers bons émis
BénéficiaireMontantType
+221 77 ••• 41225 000 FREPAS
+221 76 ••• 89050 000 FCADEAU
+221 78 ••• 12315 000 FTRANSP.
Émettre un bon
Téléphone bénéficiaire
+221 77 ••• ••••
Montant (FCFA)
25 000
Type
Ticket repas
Émettre →
Fonctionnalités détaillées
FonctionnalitéDescriptionDétail
Connexion sécuriséeJWT + PIN ou OTP SMS selon le rôleRôles COMPANY_ADMIN / COMPANY_VIEWER
Tableau de bordKPIs en temps réel : provision, bons émis, consomméMise à jour automatique
Émission unitaireUn bon à la fois pour un bénéficiaireNotification SMS automatique au bénéficiaire
Import CSVJusqu'à 500 collaborateurs en une opérationRapport d'erreurs ligne par ligne
Émission programméePlanifier l'émission à une date future (scheduledAt)Cron job d'émission automatique
Gestion collaborateursListe des invitations envoyées et leur statutPENDING / ACCEPTED / EXPIRED
Annulation de bonAnnuler un bon non encore utilisé → remboursement provisionÉcriture ledger CANCEL
Suivi consommationQuel commerçant, quel bénéficiaire, quel montantDonnées anonymisées (RGPD)
Rapport RSE / ImpactCommerçants locaux soutenus, bénéficiaires uniques, montant totalOnglet Impact social
Gestion trésorerieHistorique des approvisionnements, solde disponibleWave + OM + virement + chèque
Format CSV d'import
# Colonnes obligatoires : phone, amount (FCFA), type # Colonnes optionnelles : note, scheduledAt (ISO 8601) phone,amount,type,note,scheduledAt +221771234567,25000,MEAL_TICKET,Ticket repas avril, +221762345678,50000,GIFT_VOUCHER,Prime Q1 2026,2026-05-01T08:00:00Z +221783456789,15000,TRANSPORT,, +221774567890,30000,BONUS,Félicitations anniversaire,
Les montants sont en FCFA entiers dans le CSV. La conversion en centimes est faite automatiquement par l'API. Maximum 500 lignes par import. Un rapport d'erreurs est retourné pour chaque ligne invalide.
Terminal Commerçant POS — kado.sn/pos
Flux initié par le bénéficiaire : Le commerçant saisit le montant et génère un QR de paiement sur son terminal. Le bénéficiaire scanne ce QR depuis son app kado (/app/scan) — caméra active immédiatement, sans menu intermédiaire.
Parcours de validation complet
1. Commerçant saisit le montant
Montant à encaisser
8 500
FCFA
1
2
3
4
5
6
7
8
9
0
Générer QR · 8 500 FCFA →
2. POS affiche le QR
À scanner par le client
8 500 FCFA
Montant 8 500 FCFA
Expire dans 2:14
Annuler
3. Bénéficiaire scanne le QR
kado · Payer
Pointez vers le QR
du commerçant
Auchan VDN · 8 500 FCFA
4. Confirmation POS
Paiement validé !
8 500 FCFA
Client+221 77 ••• 412
Type bonTicket repas
Solde restant16 500 FCFA
Réf.REDEEM-3f7a…
Votre versement (net 98%) 8 330 FCFA
Versement Wave · demain
Dashboard commerçant

Le commerçant peut consulter ses transactions du jour, son chiffre d'affaires et l'historique de ses reversements Wave/Orange Money.

kado.sn/pos/dashboard
Aujourd'hui (brut)
47 500
FCFA · 12 transactions
Commission kado (5%)
-950
FCFA prélevés
Votre net (98%)
46 550
FCFA à reverser
Prochain reversement
Demain
via Wave Mobile Money
Transactions du jour
HeureClientMontantNet
09:14+221 77 ••• 4128 500 F8 330 F
09:47+221 76 ••• 89012 000 F11 760 F
11:23+221 78 ••• 12327 000 F26 460 F
Fonctionnalités détaillées
FonctionnalitéDescriptionDétail
Saisie montant (pavé)Clavier numérique dédié, max 1 000 000 FCFAValidation en centimes côté API
QR de paiement commerçantPOS génère un QR que le bénéficiaire scanne avec son app kado (/app/scan)TTL 3 min, polling statut
Scanner QR bénéficiaire (optionnel)Mode alternatif : le commerçant scanne le QR affiché sur l'app du clientZXing library, front/back camera
Confirmation animéeFond vert, vibration, son — retour sensoriel fortnavigator.vibrate([200])
Dashboard revenusCA du jour, net après commission, nb transactionsMise à jour en temps réel
Historique reversementsListe des virements Wave/OM avec référenceRéférence SETTLE-{id}-{date}
Connexion PINCode PIN 4 chiffres pour sécuriser le terminalbcrypt hash en DB
Règles anti-cash : Jamais de bouton "Rendu monnaie". Le montant saisi ne peut pas dépasser le solde du bon. Aucune option de retrait en espèces. Ces règles protègent l'intégrité du système et le statut EME.
Espace Admin — kado.sn/admin
Accès restreint à l'équipe kado. Interface de supervision complète : KPIs temps réel, gestion entreprises/commerçants, pipeline commercial (leads), comptabilité (ledger) et génération de documents officiels.
Dashboard de supervision
kado.sn/admin/dashboard
Bons actifs
1 247
+12% ce mois
Volume (FCFA)
38,4M
+8% vs mois préc.
Commissions
768K
ce mois (2%)
Entreprises actives
23
SaaS + provisions
EntreprisePlanProvisionBons actifsStatut
Sonatel SAPremium12 400 000 F342● Actif
Auchan SénégalStandard5 200 000 F128● Actif
CDE BTPStandard800 000 F45● KYB en cours
Fonctionnalités détaillées
FonctionnalitéDescription
KPIs temps réelVolume total, bons actifs/expirés, commissions du mois, nb entreprises et commerçants
Gestion entreprisesListe, activation KYB, modification plan SaaS, historique provisions
Gestion commerçantsActivation, suspension, catégorie, géolocalisation, historique transactions
Supervision bonsRecherche par code/bénéficiaire, détail cycle de vie, annulation manuelle
Trésorerie kadoRevenus commissions + SaaS, solde, historique 6 mois, graphiques
Ledger comptableJournal INSERT ONLY, toutes les écritures, vérification invariant débit=crédit
Pipeline leadsEntreprises et commerçants prospects, statut NOUVEAU→SIGNÉ, notes de suivi
Génération documentsRapports PDF (CA, reversements, provisions), export CSV
Alertes fraudeDétection patterns suspects : validations exactes, pics volume +300%, répétitions
Flux métier complet
Flux 1 — Approvisionnement entreprise (Wave Checkout)
Entreprise
Saisit montant, clique Wave
Wave Checkout
API crée une session → wave_launch_url
Paiement Wave
Utilisateur paie via lien Wave
Webhook
checkout_status: complete
Ledger
PROVISION créditée
Compte actif
RH peut émettre
Écriture ledger PROVISION :
DEBIT : PROVISION_COMPANY:{id} → +2 500 000 FCFA
CREDIT : (hors ledger — incrémentation provisionBalance sur Company)
Flux 2 — Émission d'un bon
RH
Saisit montant + téléphone
Vérification
Provision suffisante ?
Bon créé
Status: PENDING
EME Queue
Instruction async Bull
ISSUED
SMS + QR activé
Écriture ledger ISSUE :
DEBIT : PROVISION_COMPANY:{cId} → -25 000 FCFA
CREDIT : VOUCHER_LIABILITY:{vId} → +25 000 FCFA
Flux 3 — Validation QR (opération critique)
Bénéficiaire
Scanne le QR du commerçant
HMAC Check
Signature vérifiée
SELECT FOR UPDATE
Verrou DB atomique
Débit
Solde bon réduit
Ledger
3 écritures atomiques
Confirmé
Vibration + son
Écritures ledger REDEEM (transaction atomique) :
DEBIT : VOUCHER_LIABILITY:{vId} → -8 500 FCFA # 100%
CREDIT : MERCHANT_PAYABLE:{mId} → +8 075 FCFA # 95% (net)
CREDIT : REVENUE_COMMISSION → +425 FCFA # 5% (kado)
Anti double-dépense : Le SELECT FOR UPDATE verrouille la ligne du bon pendant toute la transaction. Deux validations simultanées sur le même bon ne peuvent pas toutes les deux réussir.
Flux 4 — Reversement commerçant (T+1)
Cron 23h00
Tous les jours UTC
Calcul soldes
MERCHANT_PAYABLE
Bull Queue
3 tentatives, backoff exp.
Wave / OM
Virement vers le commerçant
Ledger SETTLE
Référence unique
⏳ Statuts d'un bon — Transitions
PENDING
EME confirme
ISSUED
PARTIAL (paiement partiel)
USED (solde = 0)
EXPIRED (cron J+180)
CANCELLED (annulation RH)
API Reference — api.kado.sn/api/v1
Authentification : Toutes les routes sauf /auth/otp/send, /auth/otp/verify et /health nécessitent un header Authorization: Bearer {access_token}.
Auth
POST/auth/otp/send
Envoie un OTP par SMS. Body: {"phone": "+221771234567"}
Public · Rate limit: 3 req/min
POST/auth/otp/verify
Vérifie l'OTP et retourne les tokens JWT. Body: {"phone": "...", "code": "123456"}
Public · Réponse: {accessToken, refreshToken, user}
POST/auth/token/refresh
Renouvelle les tokens. Body: {"refreshToken": "family.token"}
Public
POST/auth/logout
Révoque le refresh token actuel.
JWT requis
Vouchers (Bénéficiaire)
GET/vouchers/me
Retourne tous les bons du bénéficiaire connecté avec soldes et statuts.
BENEFICIARY
GET/vouchers/:id
Détail d'un bon : code QR, valeur, transactions, expiration.
BENEFICIARY (propriétaire uniquement)
POST/vouchers/:id/validate
Valider un QR code. Body: {"merchantId": "...", "amount": 850000} (centimes). Transaction atomique avec SELECT FOR UPDATE.
MERCHANT · Montants en centimes
Companies (RH Entreprise)
GET/companies/me/dashboard
KPIs RH : provision disponible, bons émis/consommés, bénéficiaires.
COMPANY_ADMIN / COMPANY_VIEWER
POST/companies/me/vouchers
Émettre un bon. Body: {"phone": "...", "amountCentimes": 2500000, "type": "MEAL_TICKET", "note": "..."}
COMPANY_ADMIN
POST/companies/me/vouchers/bulk
Import CSV — jusqu'à 500 bons en une seule requête. Multipart/form-data.
COMPANY_ADMIN · Retourne un rapport d'erreurs
Merchants (Commerçant POS)
POST/merchants/me/transaction-request
Créer une demande de paiement QR. Body: {"amountCentimes": 850000}. TTL 3 min.
MERCHANT
GET/merchants/me/transaction-request/:token/status
Polling statut d'une demande de paiement. Retourne PENDING / PAID / EXPIRED.
MERCHANT
GET/merchants/me/dashboard
CA du jour, transactions, reversements.
MERCHANT
Webhooks (Wave & Orange Money)
POST/payments/webhook/wave
Réception des notifications Wave. Vérification HMAC-SHA256 obligatoire. Header: x-wave-signature
Public · HMAC vérifié avec timingSafeEqual
POST/payments/webhook/orange-money
Réception des notifications Orange Money. Même mécanique HMAC.
Public · HMAC vérifié
Health Check
GET/health
État de l'API. Retourne: {"status":"ok","checks":{"database":"ok","redis":"ok"},"timestamp":"..."}
Public · Utilisé par Railway pour les redémarrages
Sécurité & Conformité
Authentification JWT RS256
TokenTTLContenuStockage
Access Token15 minutessub, role, phone, companyIdMémoire JS (jamais localStorage)
Refresh Token30 joursFamille + token aléatoireDB (hashé SHA-256)
Rotation de famille : Si un refresh token déjà révoqué est réutilisé, toute la famille est invalidée → détection de vol de session.
Signatures HMAC-SHA256
UsageMécanismeVérification
QR codes bonsPayload JSON signé avec HMAC_VOUCHER_SECRETtimingSafeEqual (anti timing attack)
Webhooks WaveCorps HTTP signé avec WAVE_WEBHOOK_SECRETtimingSafeEqual
Webhooks Orange MoneyCorps HTTP signé avec OM_WEBHOOK_SECRETtimingSafeEqual
Protections actives
ProtectionImplémentationValeur
Rate limiting globalThrottlerGuard (NestJS)100 req/min par IP
Rate limiting OTP@Throttle sur /auth/otp/send3 req/min par IP
Blocage OTPRedis counter + TTL30 min après 3 échecs
CORS restreintALLOWED_ORIGINS depuis .envkado.sn uniquement
Helmet HTTP headershelmet() NestJSXSS, CSRF, clickjacking
Validation DTOsclass-validator + whitelist:truePropriétés inconnues rejetées
Transactions atomiquesPrisma $transaction + SELECT FOR UPDATEZéro race condition
Mots de passe/PINbcrypt rounds:10Irréversible
Monitoring erreursSentryAlertes temps réel
Ledger immuable — Garanties comptables
Le ledger kado est un journal INSERT ONLY — aucun UPDATE ni DELETE n'est jamais exécuté sur les entrées après leur création. Toute correction passe par une écriture de sens inverse.

Invariant absolu : Pour chaque opération, la somme des débits = la somme des crédits. Vérifié en code par LedgerService.assertBalanced() avant chaque insertion.
Type d'écritureDébitCrédit
PROVISIONWAVE_RECEIVE / OM_RECEIVEPROVISION_COMPANY:{id}
ISSUE (émission bon)PROVISION_COMPANY:{id}VOUCHER_LIABILITY:{id}
REDEEM (validation)VOUCHER_LIABILITY:{id}MERCHANT_PAYABLE:{id} (95%) + REVENUE_COMMISSION (5%)
EXPIREVOUCHER_LIABILITY:{id}EXPIRED_FORFEIT
CANCELVOUCHER_LIABILITY:{id}PROVISION_COMPANY:{id}
SETTLEMERCHANT_PAYABLE:{id}MERCHANT_SETTLED:{id}
SAAS_REVENUECOMPANY_ACCOUNT:{id}REVENUE_SAAS