Documentation API Collecte CMM (Aggregate Payment)
Spécifications techniques, simulation, initiation et suivi RESTful des opérations de collecte agrégée BMO.
Présentation
L'API Collecte CMM (Aggregate Payment) permet aux partenaires tiers d'effectuer des encaissements et collectes de fonds agrégées vers les solutions BMO.
Le parcours d'intégration s'articule autour de 3 opérations fondamentales :
- Simuler une collecte (
POST /external/aggregate-payment/simulate) : Permet de valider la structure de la requête et d'évaluer l'opération sans générer d'impact financier ni de référence de transaction. - Initier une collecte (
POST /external/aggregate-payment) : Lance l'opération de paiement agrégé, génère une référence unique système et retourne le statut initial (ex:ONGOING). - Suivre le statut d'une collecte (
GET /external/aggregate-payment/{reference}) : Endpoint RESTful permettant d'interroger l'état final ou en cours de la transaction en passant directement la référence dans le chemin URI.
Environnement de Test (Sandbox) & Authentification :
- Base URL TEST (Sandbox - Recommandé) :
https://svc.test.bestcash.me/external(Environnement pré-configuré et validé pour la collecte CMM)- Base URL PAP (Pré-production) :
https://svc.pap.bestcash.me/external- En-têtes d'authentification obligatoires :
X-Auth-ApiKey: Votre clé API partenaire (ex:+2290160606790)X-Auth-ApiSecret: Votre secret API partenaire (ex:l/LshBHhTvhWcA==)Content-Type: application/jsonAccept: application/json
Remarque importante sur l'environnement de test (Sandbox) : Les tests d'initiation et de simulation de la collecte CMM nécessitent un profil client et un wallet récepteur pré-configurés (
BMOPAY, client+2290167895434). Pour éviter l'erreur 401Invalid authentication tokenou 403CUSTOMER NOT FOUND, les consoles d'essai<ApiPlayground />ci-dessous sont configurées par défaut sur l'environnement TEST (Sandbox) (https://svc.test.bestcash.me/external) avec les identifiants dédiés (+2290160606790/l/LshBHhTvhWcA==).
1. Simuler une collecte (POST /external/aggregate-payment/simulate)
Permet de simuler une opération de collecte avant son exécution réelle. Cet appel valide la forme des données transmises (sourceOperationData et targetOperationData) sans débiter les comptes ni créer de transaction persistante (reference: null).
- Méthode :
POST - URL :
/external/aggregate-payment/simulate - Headers requis :
Content-Type: application/jsonAccept: application/jsonX-Auth-ApiKey: +2290160606790X-Auth-ApiSecret: l/LshBHhTvhWcA==
Structure du Body JSON
| Champ | Type | Description |
|---|---|---|
amount | number | Montant total de la collecte (ex: 1000) |
source | string | Source du paiement (ex: "WALLET") |
target | string | Destination du paiement (ex: "BMOPAY") |
sourceOperationData | object | Informations relatives à la source de la collecte |
sourceOperationData.amount | number | Montant prélevé à la source |
sourceOperationData.targetFirstname | string | Prénom du bénéficiaire à la source |
sourceOperationData.targetLastname | string | Nom du bénéficiaire à la source |
sourceOperationData.targetMsisdn | string | Téléphone du bénéficiaire à la source (ex: "+2290196784521") |
sourceOperationData.targetNationality | string | Code pays ISO à 2 lettres (ex: "BJ") |
targetOperationData | object | Informations relatives à la cible de la collecte |
targetOperationData.amount | number | Montant crédité à la cible |
targetOperationData.customer | object | Objet contenant les données du client (phone) |
targetOperationData.reason | string | Motif de l'opération de collecte |
targetOperationData.depositor | string | Nom complet du déposant / initiateur |
targetOperationData.idType | string | Type de pièce d'identité (ex: "CI", "PASSPORT") |
targetOperationData.idNumber | string | Numéro de la pièce d'identité |
Tester la simulation de collecte (Environnement TEST)
Exécutez une simulation d'opération sans génération de référence ni débit.
Aucun paramètre d'URL configuré.
Exemple de réponse HTTP 200 (Simulation)
{
"reference": null,
"amount": 1000.0,
"source": "WALLET",
"target": "BMOPAY",
"status": null
}
2. Initier une collecte (POST /external/aggregate-payment)
Initie le paiement agrégé effectif et enregistre l'opération dans le système BMO.
- Méthode :
POST - URL :
/external/aggregate-payment - Headers requis :
Content-Type: application/jsonAccept: application/jsonX-Auth-ApiKey: +2290160606790X-Auth-ApiSecret: l/LshBHhTvhWcA==
Structure du Body JSON
Le corps de la requête utilise la même structure que l'étape de simulation :
{
"amount": 1000,
"source": "WALLET",
"target": "BMOPAY",
"sourceOperationData": {
"amount": 1000,
"targetFirstname": "Jean",
"targetLastname": "Dupont",
"targetMsisdn": "+2290196784521",
"targetNationality": "BJ"
},
"targetOperationData": {
"amount": 1000,
"customer": {
"phone": "+2290167895434"
},
"reason": "Simulation de test via API",
"depositor": "Koffi Test",
"idType": "CI",
"idNumber": "123456789"
}
}
Tester l'initiation d'une collecte (Environnement TEST)
Soumettez une collecte de fonds agrégée et obtenez la référence unique.
Aucun paramètre d'URL configuré.
Exemple de réponse HTTP 200 (Initiation)
{
"reference": "7487519710968287232",
"amount": 1000.0,
"source": "WALLET",
"target": "BMOPAY",
"status": "ONGOING"
}
Statuts possibles de la réponse d'initiation
INITIATED: Opération créée et en attente de traitement.ONGOING: Traitement de la collecte en cours.COMPLETED: Transaction finalisée et validée avec succès.PARTIALLY_COMPLETE: Traitement partiel de l'opération.INCOMPLETE: Données de traitement incomplètes.FAILED: Échec lors du traitement de la collecte.
IMPORTANT : Conservez l'identifiant numérique retourné dans le champ
reference(ex:"7487519710968287232"). Il est indispensable pour interroger l'état du paiement à l'étape suivante.
3. Suivi du statut de la collecte (GET /external/aggregate-payment/{reference})
Permet de consulter l'état actualisé d'une opération de collecte à l'aide de son identifiant unique.
- Méthode :
GET - URL :
/external/aggregate-payment/{reference} - Format du chemin (URI Path) : Renseigner directement la référence dans l'URL (ex:
/external/aggregate-payment/7487519710968287232). - Headers requis :
Accept: application/jsonX-Auth-ApiKey: +2290160606790X-Auth-ApiSecret: l/LshBHhTvhWcA==
REMARQUE RESTful — Passage de la référence en chemin d'URI : Conformément aux spécifications validées en environnement réel, le suivi de statut de la collecte CMM s'effectue en passant la référence de l'opération directement en variable de chemin (
/aggregate-payment/{reference}) et non en paramètre de requête.
Tester le suivi de statut de collecte (Environnement TEST)
Vérifiez l'état d'une transaction de collecte via sa référence unique dans le chemin URI.
Aucun paramètre d'URL configuré.
Exemple de réponse HTTP 200 (Transaction finalisée)
{
"reference": "7487519710968287232",
"amount": 1000.0,
"source": "WALLET",
"target": "BMOPAY",
"status": "COMPLETED"
}
4. Dépannage & Erreurs courantes (Troubleshooting)
Erreur 401 Unauthorized (Invalid authentication token)
- Cause : Survient lorsque les en-têtes d'authentification
X-Auth-ApiKeyouX-Auth-ApiSecrettransmis ne correspondent pas aux identifiants valides de l'environnement sélectionné. Sur le serveur TEST (Sandbox) (https://svc.test.bestcash.me), l'API de collecte CMM exige spécifiquement la clé partenaire+2290160606790et le secretl/LshBHhTvhWcA==. Si vous aviez conservé une autre clé globale (ex:+2290196666262) dans les champs de votre navigateur, le serveur rejettera la requête avec un code HTTP 401. - Correction : Dans la console d'essai
<ApiPlayground />, veillez à renseigner la clé+2290160606790et le secretl/LshBHhTvhWcA==lorsque vous ciblez l'environnement TEST (Sandbox).
Erreur 403 Forbidden (CUSTOMER NOT FOUND)
- Cause : L'endpoint de simulation (
/simulate) et d'initiation (/aggregate-payment) vérifie la présence du profil client en base de données pour l'environnement ciblé (notamment viatargetOperationData.customer.phoneet les données source). Si le numéro de téléphone transmis (ex:+2290167895434) n'est pas un compte client ou un wallet récepteur actif dans l'environnement sélectionné (PAP vs TEST), le serveur rejette la requête. - Correction : Transmettre un numéro de téléphone client actif et enregistré dans l'environnement de test BestCash (ex:
+2290167895434sur le serveur Sandbox TESThttps://svc.test.bestcash.me/externalavec les clés API+2290160606790).
Erreur 500 Internal Server Error (SERVER ERROR)
- Cause : Survient généralement lorsqu'un champ obligatoire du corps JSON est absent, mal structuré ou typé incorrectement par rapport aux attentes du backend.
- Correction :
- S'assurer que les montants sont transmis sous forme numérique (ex:
"amount": 1000et non sous forme de chaîne de caractères"1000"). - Vérifier la présence et le typage exact des sous-objets
sourceOperationDataettargetOperationData. - Veiller à utiliser les codes pays au format ISO à 2 lettres (ex:
"BJ"pour le Bénin).
- S'assurer que les montants sont transmis sous forme numérique (ex:
Exemple d'intégration complet en Node.js / Axios (Environnement TEST - Sandbox)
Le script suivant illustre le flux complet d'une opération de collecte CMM : simulation facultative, initiation effective avec récupération de la référence, et boucle de contrôle jusqu'à la confirmation du statut final (COMPLETED) via l'URI RESTful ${BASE_URL}/aggregate-payment/${reference} :
import axios from 'axios';
const BASE_URL = 'https://svc.test.bestcash.me/external';
const headers = {
'X-Auth-ApiKey': '+2290160606790',
'X-Auth-ApiSecret': 'l/LshBHhTvhWcA==',
'Content-Type': 'application/json',
'Accept': 'application/json'
};
const payload = {
amount: 1000,
source: 'WALLET',
target: 'BMOPAY',
sourceOperationData: {
amount: 1000,
targetFirstname: 'Jean',
targetLastname: 'Dupont',
targetMsisdn: '+2290196784521',
targetNationality: 'BJ'
},
targetOperationData: {
amount: 1000,
customer: {
phone: '+2290167895434'
},
reason: 'Paiement commande via API',
depositor: 'Koffi Test',
idType: 'CI',
idNumber: '123456789'
}
};
async function executeCmmCollectionWorkflow() {
try {
// 1. Simulation préalable (Optionnel)
console.log('--- 1. Simulation de la collecte CMM ---');
const simRes = await axios.post(`${BASE_URL}/aggregate-payment/simulate`, payload, { headers });
console.log('Résultat de la simulation :', simRes.data);
// 2. Initiation de la collecte
console.log('--- 2. Initiation de la collecte CMM ---');
const initRes = await axios.post(`${BASE_URL}/aggregate-payment`, payload, { headers });
const reference = initRes.data.reference;
console.log(`Collecte initiée avec succès ! Référence : ${reference}, Statut initial : ${initRes.data.status}`);
if (!reference) {
throw new Error("Aucune référence retournée par l'initiation.");
}
// 3. Suivi du statut de la collecte via l'URI RESTful (/aggregate-payment/{reference})
console.log('--- 3. Vérification du statut de l\'opération ---');
// Attente recommandée de quelques secondes si le statut initial est ONGOING
let status = initRes.data.status;
let attempts = 0;
while (status === 'ONGOING' && attempts < 5) {
attempts++;
console.log(`Tentative de vérification ${attempts}...`);
await new Promise(resolve => setTimeout(resolve, 2000)); // Attente de 2s
const statusRes = await axios.get(`${BASE_URL}/aggregate-payment/${reference}`, { headers });
status = statusRes.data.status;
console.log(`Statut de la transaction : ${status}`);
}
console.log(`Traitement terminé. Statut final : ${status}`);
} catch (error) {
if (error.response?.data?.code === 401) {
console.error("Dépannage (401 Invalid authentication token) : Vérifiez que les en-têtes d'authentification contiennent bien X-Auth-ApiKey: +2290160606790 et X-Auth-ApiSecret: l/LshBHhTvhWcA== sur le serveur TEST.");
} else if (error.response?.data?.code === 403) {
console.error("Dépannage (403 CUSTOMER NOT FOUND) : Vérifiez que le numéro de téléphone du client est bien enregistré sur l'environnement ciblé.");
} else if (error.response?.data?.code === 500) {
console.error("Dépannage (500 SERVER ERROR) : Vérifiez que les montants sont de type numérique et que le JSON est correctement structuré.");
} else {
console.error('Erreur durant le workflow de collecte :', error.response?.data || error.message);
}
}
}
executeCmmCollectionWorkflow();