Documentation développeur
L'API BaobaPay pour encaisser en zones CEMAC (XAF) et UEMOA (XOF) — mobile money, carte et liens de paiement. Le paiement de votre client est routé vers votre compte marchand.
Introduction
L'API est organisée autour de ressources REST, avec des réponses JSON et des codes HTTP standards. Toutes les requêtes passent par HTTPS.
https://api.baobapay.com/api/v1 // production
https://api.sandbox.baobapay.com/api/v1 // sandboxDeux environnements : sandbox (clés sk_sb_…, aucun argent réel) et production (clés sk_live_…, activées à la signature du contrat).
Quickstart
Encaissez un premier paiement mobile money en sandbox, en trois étapes.
1. Créez un pay-in mobile money
curl https://api.sandbox.baobapay.com/api/v1/payins/mobile-money \
-H "Authorization: Bearer sk_sb_9f2a…" \
-H "Idempotency-Key: 8f14e45f" \
-H "Content-Type: application/json" \
-d '{
"reference": "CMD-10412",
"amount": { "currency": "XAF", "value": 24500 },
"operator": "MTN",
"phone": "+237671224188"
}'2. Lisez la réponse
{
"id": "pi_10482",
"status": "PENDING",
"amount": { "currency": "XAF", "value": 24500 }
}3. Recevez la confirmation
Quand le client confirme sur son téléphone, BaobaPay envoie payin.succeeded à votre endpoint de webhook — voir Webhooks plus bas.
{
"type": "payin.succeeded",
"data": { "id": "pi_10482", "status": "SUCCEEDED" }
}Authentification
Chaque requête s'authentifie par une clé secrète passée en en-tête Authorization, au format Bearer. Ne jamais exposer une clé sk_live_ côté client.
Authorization: Bearer sk_sb_9f2a3b7c1d…| Préfixe | Environnement |
|---|---|
| sk_sb_… | Sandbox — actif immédiatement |
| sk_live_… | Production — après signature du contrat |
401 unauthorized. Gérez et régénérez vos clés dans le tableau de bord → Développeurs.Idempotence
Toutes les requêtes POST qui créent des mouvements acceptent un en-tête Idempotency-Key. Rejouer la même clé renvoie la réponse d'origine, sans créer de doublon — indispensable pour les reprises réseau et les retries mobile money.
Idempotency-Key: 8f14e45f-ceea-467d-9c1b-2a…La clé est conservée 24 h. Utilisez un UUID unique par intention de paiement.
Montants & devises
Les montants sont représentés par un objet Money — une devise et une valeur entière. XAF et XOF sont des devises sans sous-unité : la valeur est exprimée en francs entiers (pas de centimes).
{ "currency": "XAF", "value": 24500 } // 24 500 FCFAModèle de fonds
Comprendre où l'argent se trouve à chaque instant est le préalable à toute intégration.
Topologie des wallets
Deux wallets sont créés à l'ouverture d'une plateforme sur les verticales à tiers — marketplace, freelance, crowdfunding, cagnottes, voyage, B2B. En vente directe (e-commerce), seul le wallet principal existe.
| Wallet | Contient | Qui le débite |
|---|---|---|
| WLT-MAIN | Vos commissions | Vous, vers vos comptes de règlement |
| WLT-BENEF | Les fonds appartenant à vos tiers | Vous, vers le compte du tiers uniquement |
| WLT-SM-xxxx | Le solde d'un tiers vérifié | Reversement vers son propre compte |
wallet.created plutôt que d'appeler POST /wallets.Ségrégation
Un retrait depuis WLT-MAIN ne peut aller que vers un compte de règlement de la plateforme. Un reversement depuis un wallet de tiers ne peut aller que vers le compte de ce tiers. L'API refuse toute combinaison croisée — un propriétaire de marketplace ne peut pas vider le wallet de ses vendeurs vers son propre compte.
Cycle d'un retrait
POST /withdrawals → status: PENDING_APPROVAL
↓ (validation interne)
withdrawal.approved → les fonds ne sont pas encore partis
↓ (exécution par l'opérateur)
withdrawal.paid → le solde du wallet est décrémenté ici
ou
withdrawal.failed → le solde reste intact, la demande est rejouablepaid. Un versement validé puis échoué chez l'opérateur laisse les fonds en place.Encaissements espèces
Les déclarations d'espèces sont des données du marchand : aucun wallet n'est crédité, aucun flux n'est réconciliable en banque. Elles sont conservées et exportables, mais n'entrent pas dans le calcul des soldes.
Erreurs
L'API utilise les codes HTTP conventionnels et renvoie un objet d'erreur structuré.
{
"type": "invalid_request",
"code": "insufficient_kyc",
"message": "Le compte marchand doit être vérifié pour encaisser en production."
}| Code | Signification |
|---|---|
| 400 / 422 | Requête invalide ou règle métier non respectée |
| 401 | Clé d'API manquante ou invalide |
| 402 | Paiement refusé (opérateur indisponible, plafond…) |
| 403 | Action non autorisée (flux gelés, KYC) |
| 409 | Conflit — clé d'idempotence rejouée avec un corps différent |
| 429 | Trop de requêtes (rate limit) |
Plugins & modules e-commerce
Encaissez sans écrire de code : modules officiels maintenus par BaobaPay. Chaque module installe le checkout hébergé (momo, carte, lien) et la réconciliation automatique des commandes via webhooks.
Configuration commune : coller la clé API publique + l'URL de webhook générée par le module. Le statut de commande passe automatiquement à « payée » sur payin.succeeded. Sandbox supporté dans chaque module.
Endpoints
Les ressources d'encaissement de l'API agrégateur.
| Méthode | Endpoint | Usage |
|---|---|---|
| POST | /payins/mobile-money | Encaisser par mobile money (Orange, MTN, Express Union…) |
| POST | /payins/card | Encaisser par carte (avec 3-DS/SCA) |
| POST | /payins/recurring | Paiement récurrent (sur enregistrement / mandat) |
| GET | /payins/{payInId} | Récupérer un encaissement — statut, méthode, wallet crédité |
| POST | /payins/recurring/registrations | Créer un mandat de paiement récurrent |
| POST | /preauthorizations | Empreinte / caution carte (capture différée)bientôt |
| POST | /payment-links | Créer un lien de paiement / QR hébergé |
| POST | /refunds | Rembourser un encaissement |
| GET | /transactions | Journal unifié des encaissements (natures PAYIN / REFUND) |
| GET | /reports | États et exports de réconciliation |
| POST | /developers/webhooks | Gérer les endpoints de webhook |
| GET | /developers/api-keys | Lister les clés API — métadonnées seulement, jamais la valeur |
| Titulaires & vérification | ||
| POST | /users | Créer un titulaire (vendeur, bénéficiaire, payeur) |
| GET | /users | Lister les titulaires |
| GET | /users/{userId} | Récupérer un titulaire et son niveau KYC |
| POST | /users/{userId}/kyc/documents | Soumettre une pièce KYC/KYB |
| Wallets | ||
| GET | /wallets | Lister les wallets — principal, bénéficiaires, individuels |
| POST | /wallets | Créer un wallet (automatisation ; la création se fait normalement à la validation KYC) |
| GET | /wallets/{walletId} | Consulter un wallet — solde total, engagé, disponible |
| GET | /wallets/{walletId}/transactions | Mouvements d'un wallet — pagination par curseur |
| Sortie des fonds | ||
| GET | /settlement-accounts | Lister les comptes de règlement du marchand |
| POST | /settlement-accounts | Déclarer un compte de règlement — authentification renforcée exigée |
| PATCH | /settlement-accounts/{settlementAccountId} | Modifier un compte — authentification renforcée exigée |
| POST | /settlement-accounts/{settlementAccountId}/verify | Relancer la vérification du titulaire |
| GET | /withdrawals | Lister les demandes de retrait |
| POST | /withdrawals | Demander un retrait vers un compte de règlement vérifié |
| DELETE | /withdrawals/{withdrawalId} | Annuler une demande encore en attente de validation |
| Espèces, litiges & contexte | ||
| GET | /cash-declarations | Lister les encaissements espèces déclarés |
| POST | /cash-declarations | Déclarer un encaissement espèces — aucun wallet crédité |
| POST | /cash-declarations/{id}/refund | Déclarer un remboursement en espèces |
| GET | /disputes | Lister les litiges |
| GET | /disputes/{disputeId} | Récupérer un litige et ses pièces |
| GET | /operator-enrollments | Lister les enrôlements opérateurs |
| GET | /operator-enrollments/{enrollmentId} | Consulter un enrôlement |
| GET | /me/platforms | Plateformes accessibles à l'utilisateur |
| POST | /session/active-platform | Basculer le contexte de session — authentification renforcée à la première ouverture |
| GET | /platform | Configuration de la plateforme — verticale, fonctionnalités, zone |
Webhooks
BaobaPay notifie votre serveur des événements asynchrones (confirmation d'un paiement, changement KYC, litige…). Chaque livraison est signée et rejouée en cas d'échec (backoff jusqu'à 24 h).
Vérifier la signature
Chaque requête porte un en-tête BaobaPay-Signature — un HMAC-SHA256 du corps brut, calculé avec le secret de votre endpoint. Comparez-le avant de traiter l'événement.
const sig = req.headers['baobapay-signature'];
const expected = crypto
.createHmac('sha256', endpointSecret)
.update(rawBody)
.digest('hex');
if (sig !== expected) return res.status(400).end();
// signature valide → traiter l'événementCatalogue des événements
| Événement | Déclenché quand… |
|---|---|
| EVENT payin.succeeded | un encaissement est confirmé |
| EVENT payin.failed | un encaissement échoue (refus, délai, solde) |
| EVENT refund.done | un remboursement est exécuté |
| EVENT kyc.updated | le statut de vérification d'un client change |
| EVENT kyb.updated | le statut KYB d'une entreprise change |
| EVENT dispute.opened | une contestation / un rejet est ouvert |
| EVENT dispute.closed | une contestation est clôturée (issue connue) |
| EVENT user.blocked | la conformité suspend un titulaire — il ne peut plus encaisser ni être payé |
| EVENT user.unblocked | la suspension d'un titulaire est levée |
| EVENT user.closed | un titulaire est clôturé (données conservées selon la rétention légale) |
| Wallets | |
| EVENT wallet.created | un wallet est créé — automatiquement à la validation KYC d'un titulaire |
| EVENT wallet.balance_updated | le solde d'un wallet change — encaissement, reversement, retrait |
| EVENT wallet.frozen | un wallet est gelé par la conformité |
| Retraits | |
| EVENT withdrawal.approved | une demande de retrait est validée — les fonds ne sont pas encore partis |
| EVENT withdrawal.paid | le retrait est confirmé par l'opérateur — le solde est décrémenté à ce moment |
| EVENT withdrawal.rejected | la demande est refusée avant exécution |
| EVENT withdrawal.failed | l'opérateur n'a pas pu exécuter le versement — numéro invalide, compte clos |
| Comptes de règlement | |
| EVENT settlement_account.verified | un compte de règlement est vérifié — il devient utilisable après le délai de sécurité |
| EVENT settlement_account.rejected | un compte de règlement est refusé — titulaire non conforme au KYB |
| Espèces, opérateurs & conditions | |
| EVENT cash.declared | un encaissement espèces est déclaré — aucun wallet n'est crédité |
| EVENT cash.refund_declared | un remboursement en espèces est déclaré |
| EVENT operator_enrollment.updated | le statut d'un enrôlement opérateur change |
| EVENT terms.published | de nouvelles conditions générales sont publiées |
withdrawal.paid peut précéder withdrawal.approved. Traitez chaque événement comme un fait indépendant, et fiez-vous à l'horodatage du corps plutôt qu'à l'ordre de réception. Les livraisons sont réessayées : votre endpoint doit être idempotent sur event.id.{
"type": "payin.succeeded",
"created": 1752931320,
"data": {
"id": "pi_10482",
"amount": { "currency": "XAF", "value": 24500 },
"operator": "MTN"
}
}Sandbox & tests
La sandbox reproduit l'intégralité de l'API sans argent réel. Déclenchez des succès et des échecs de façon déterministe.
Cartes de test
| Numéro | Résultat |
|---|---|
| 4970 1000 0000 0055 | Paiement réussi (Visa) |
| 4000 0000 0000 0002 | Carte refusée |
| 4000 0000 0000 9995 | Solde insuffisant |
Mobile money de test
+237 6 71 22 41 88→ confirmation réussie+237 6 00 00 00 00→ délai dépassé (non confirmé)