Documentation API Transfert International d'Argent (Money Remit)

Spécifications d'intégration, cycle séquentiel en 4 étapes et guide de test en environnement PAP pour les transferts d'argent transfrontaliers vers portefeuilles mobiles (Mobile Wallets).

Présentation

L'API Money Remit B-MO permet aux partenaires d'exécuter des transferts de fonds transfrontaliers vers des portefeuilles mobiles (Mobile Wallets) en Afrique (ex: Togo, Ghana, Côte d'Ivoire, etc.).

L'intégration d'un transfert d'argent s'articule obligatoirement en 4 étapes séquentielles :

  1. Prérequis corridor (GET /thirdparty/money-remit/requirements) : Découverte dynamique des contraintes KYC, des montants min/max et des choix autorisés selon le pays destinataire.
  2. Validation formelle (POST /thirdparty/money-remit/requirements/check) : Vérification de la conformité du formulaire et des énumérations par le compilateur avant tout appel financier.
  3. Exécution de l'opération (POST /thirdparty/money-remit/operation) : Ordre de virement vers le wallet mobile récepteur et interrogation en direct du switch télécom.
  4. Vérification du statut (GET /thirdparty/operation) : Suivi de l'état final de la transaction via votre référence externe unique.

URL de Base (selon l'environnement sélectionné) :

  • TEST (Défaut) : https://svc.test.bestcash.me/external
  • PAP : https://svc.pap.bestcash.me/external
  • LIVE (Production) : https://svc.bmo.bestcash.me/external

Vous pouvez basculer d'un environnement à un autre à tout moment depuis le menu déroulant en haut des consoles d'essai <ApiPlayground /> ci-dessous.

En-têtes obligatoires :

  • X-Auth-ApiKey : Votre identifiant partenaire API
  • X-Auth-ApiSecret : Votre clé secrète API
  • Content-Type : application/json
  • Accept : application/json

Condition indispensable pour les étapes 3 et 4

[!CAUTION]

Interrogation du switch télécom en temps réel & Compte Mobile Money actif

Lors de l'appel à l'étape 3 (/operation), le serveur Bestcash interroge le réseau télécom distant en temps réel. Si le numéro de téléphone renseigné n'est pas un compte Mobile Money existant et actif sur le réseau de destination (ex: T-Money ou Moov au Togo, MTN Mobile Money ou Vodafone Cash au Ghana), l'appel est rejeté immédiatement avec l'erreur : 400 Bad Request : BENEFICIARY ACCOUNT NOT FOUND

Recommandation stricte pour vos tests :

  • À l'étape 3 (/operation), remplacez le numéro de test par un vrai numéro Mobile Money actif de l'opérateur du pays cible.
  • Le numéro doit être transmis au format international sans espaces ni signe + (ex: 22890000000 pour le Togo, 233243109307 pour le Ghana).
  • Sans portefeuille actif, le switch télécom rejettera systématiquement la transaction.

Règles strictes de validation du formulaire

[!WARNING]

1. Aucun champ superflu ("Extra Fields")

N'envoyez aucun champ non réclamé par l'endpoint des prérequis (par exemple recipientCurrency). La présence d'un champ non supporté entraîne un rejet immédiat avec l'erreur 400 VALIDATION FAILED (extra fields).

[!IMPORTANT]

2. Respect scrupuleux de la casse des énumérations

Les valeurs textuelles des listes de choix (choices) doivent respecter la casse exacte renvoyée à l'étape 1 :

  • Salary (et non SALARY ni salary)
  • Family Maintenance (et non family maintenance ni FAMILY MAINTENANCE)
  • Sister (et non SISTER)
  • CI pour la carte d'identité

1. Récupérer les prérequis par pays (GET /thirdparty/money-remit/requirements)

Chaque pays de destination applique ses propres contraintes réglementaires (KYC), ses plafonds financiers et ses listes de choix autorisées. Cet endpoint permet d'interroger dynamiquement la configuration du corridor.

  • Méthode : GET
  • URL : /external/thirdparty/money-remit/requirements
  • Paramètres de requête (Query params) :
    • countryCode (obligatoire) : Code pays ISO 3166-1 alpha-2 du pays récepteur (ex: TG pour le Togo, GH pour le Ghana, CI pour la Côte d'Ivoire).

Tester la récupération des prérequis corridor

Obtenez dynamiquement les champs obligatoires et les choix KYC autorisés pour un pays de destination.

Authentification (En-têtes B-MO)
Paramètres d'URL / Query Parameters (1)

Exemple de requête cURL

curl -X GET "https://svc.pap.bestcash.me/external/thirdparty/money-remit/requirements?countryCode=GH" \
  -H "X-Auth-ApiKey: +2290196666262" \
  -H "X-Auth-ApiSecret: y7MwWuWeQORtpA==" \
  -H "Accept: application/json"

Exemple de réponse HTTP 200

{
  "isProviderMandatory": false,
  "minAmount": 100,
  "maxAmount": 10000,
  "mandatoryFields": [
    { "code": "recipientSurname", "type": "string" },
    { "code": "recipientName", "type": "string" },
    { "code": "recipientMsisdn", "type": "numeric" },
    {
      "code": "remittancePurpose",
      "type": "choice",
      "choices": [
        "Family Maintenance",
        "Salary",
        "Savings",
        "Business Travel",
        "Education Support"
      ]
    },
    {
      "code": "sourceOfFunds",
      "type": "choice",
      "choices": [
        "Salary",
        "Savings",
        "Business Income",
        "Loan",
        "Others"
      ]
    },
    {
      "code": "relationshipSender",
      "type": "choice",
      "choices": [
        "Sister",
        "Brother",
        "Father",
        "Mother",
        "Friend"
      ]
    }
  ],
  "providers": [
    { "name": "MTN", "code": "", "minAmount": 100, "maxAmount": 10000 }
  ]
}

2. Valider les données du transfert (POST /thirdparty/money-remit/requirements/check)

Permet de soumettre l'intégralité des champs KYC et financiers pour validation par le compilateur avant toute exécution financière. Cela garantit qu'aucun champ obligatoire ne manque et que les formats de données sont conformes.

  • Méthode : POST
  • URL : /external/thirdparty/money-remit/requirements/check
  • En-têtes requis :
    • Content-Type: application/json
    • Accept: application/json
    • X-Auth-ApiKey: +2290196666262
    • X-Auth-ApiSecret: y7MwWuWeQORtpA==

Tester la validation des données KYC

Vérifiez la conformité de vos données avant exécution.

Authentification (En-têtes B-MO)
Paramètres d'URL / Query Parameters (0)

Aucun paramètre d'URL configuré.

Corps de la Requête (JSON Body)

Exemple de requête cURL (Corridor Ghana - GH)

curl -X POST "https://svc.pap.bestcash.me/external/thirdparty/money-remit/requirements/check" \
  -H "X-Auth-ApiKey: +2290196666262" \
  -H "X-Auth-ApiSecret: y7MwWuWeQORtpA==" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "amount": 100,
    "recipientSurname": "Amor",
    "recipientName": "Prince",
    "recipientMsisdn": "233243109307",
    "recipientAddressLine1": "centre-ville",
    "recipientIdType": "CI",
    "recipientNationality": "GH",
    "recipientBirthDate": "2000-04-09",
    "recipientIdNumber": "123698547",
    "recipientIdExpiryDate": "2029-04-09",
    "senderPhone": "+2299225098",
    "senderFirstName": "Antoine",
    "senderLastName": "Atrokpo",
    "senderCountry": "BJ",
    "senderNationality": "BJ",
    "senderDateOfBirth": "2000-12-12",
    "senderIdType": "CI",
    "senderIdNumber": "123589647",
    "senderIdExpiryDate": "2029-04-09",
    "senderAddress": "Dantokpa",
    "senderCity": "Cotonou",
    "remittancePurpose": "Family Maintenance",
    "sourceOfFunds": "Salary",
    "relationshipSender": "Sister"
  }'

Exemple de réponse HTTP 200 (Succès)

{
  "code": 200,
  "message": "VALIDATION SUCCESS"
}

Exemple de réponse HTTP 400 (Échec de validation)

{
  "code": 400,
  "message": "Validation Failed",
  "errors": {
    "sourceOfFunds": [
      "This value is not valid."
    ],
    "remittancePurpose": [
      "This value should not be blank."
    ]
  }
}

3. Exécuter l'opération financière (POST /thirdparty/money-remit/operation)

Initie le virement vers le wallet mobile récepteur et déclenche le contrôle auprès du switch de l'opérateur distant.

  • Méthode : POST
  • URL : /external/thirdparty/money-remit/operation
  • Champ spécifique partenaire obligatoire :
    • externalReference (obligatoire) : Votre identifiant unique de transaction (ex: "REMIT-GH-AMOR-001" ou "REMIT-TG-SUCCESS-001").

Tester l'exécution du transfert d'argent

Initiez le virement Mobile Money avec une référence unique.

Authentification (En-têtes B-MO)
Paramètres d'URL / Query Parameters (0)

Aucun paramètre d'URL configuré.

Corps de la Requête (JSON Body)

Exemple de requête cURL

curl -X POST "https://svc.pap.bestcash.me/external/thirdparty/money-remit/operation" \
  -H "X-Auth-ApiKey: +2290196666262" \
  -H "X-Auth-ApiSecret: y7MwWuWeQORtpA==" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "amount": 100,
    "externalReference": "REMIT-GH-AMOR-001",
    "recipientSurname": "Amor",
    "recipientName": "Prince",
    "recipientMsisdn": "233243109307",
    "recipientAddressLine1": "centre-ville",
    "recipientIdType": "CI",
    "recipientNationality": "GH",
    "recipientBirthDate": "2000-04-09",
    "recipientIdNumber": "123698547",
    "recipientIdExpiryDate": "2029-04-09",
    "senderPhone": "+2299225098",
    "senderFirstName": "Antoine",
    "senderLastName": "Atrokpo",
    "senderCountry": "BJ",
    "senderNationality": "BJ",
    "senderDateOfBirth": "2000-12-12",
    "senderIdType": "CI",
    "senderIdNumber": "123589647",
    "senderIdExpiryDate": "2029-04-09",
    "senderAddress": "Dantokpa",
    "senderCity": "Cotonou",
    "remittancePurpose": "Family Maintenance",
    "sourceOfFunds": "Salary",
    "relationshipSender": "Sister"
  }'

Réponses possibles

Succès nominal (HTTP 201 CREATED - Statut CONFIRMED)

{
  "prefixedAmount": "1 133 F CFA",
  "prefixedOperationCost": "0 F CFA",
  "prefixedTotalOperationCost": "1 133 F CFA",
  "operationCode": "04182325042934",
  "status": "CONFIRMED",
  "operationCost": 0.0,
  "amount": 1133.0,
  "operationType": "MONEY_REMITTANCE-MOBILE_WALLET",
  "reference": "TPMW20260908164229511",
  "creationDate": "2026-09-08T16:42:29+00:00",
  "recipientReceivedPrefixedAmount": "10 GHS",
  "recipientMsisdn": "233243109307"
}

Exécution sandbox simulée / test non déboursé (HTTP 201 - Statut FAILED)

{
  "prefixedAmount": "5 883 F CFA",
  "prefixedOperationCost": "0 F CFA",
  "operationCode": "",
  "status": "FAILED",
  "operationCost": 0.0,
  "amount": 5883.0,
  "operationType": "MONEY_REMITTANCE-MOBILE_WALLET",
  "reference": "TPMW20260908164229511",
  "creationDate": "2026-09-08T16:42:29+00:00"
}

[!NOTE] Interprétation du code HTTP 201 : Une réponse HTTP 201 signifie que la requête a été acceptée et traitée techniquement par le système. Cependant, l'opération n'est considérée comme un succès financier que si la propriété "status" vaut "CONFIRMED" ou "ONGOING". Un statut "FAILED" indique un échec au niveau de l'opérateur distant ou de la ligne bénéficiaire, même en présence d'un code HTTP 201.


4. Vérifier le statut de l'opération (GET /thirdparty/operation)

Permet d'interroger à tout moment l'état d'un transfert précédemment initié en utilisant votre référence unique partenaire (externalReference).

  • Méthode : GET
  • URL : /external/thirdparty/operation
  • Paramètres de requête (Query params) :
    • externalReference (obligatoire) : La référence unique transmise à l'étape 3 (ex: REMIT-GH-AMOR-001).

Tester la vérification de statut de transfert

Consultez l'état final d'un transfert avec votre externalReference.

Authentification (En-têtes B-MO)
Paramètres d'URL / Query Parameters (1)

Exemple de requête cURL

curl -X GET "https://svc.pap.bestcash.me/external/thirdparty/operation?externalReference=REMIT-GH-AMOR-001" \
  -H "X-Auth-ApiKey: +2290196666262" \
  -H "X-Auth-ApiSecret: y7MwWuWeQORtpA==" \
  -H "Accept: application/json"

Exemple de réponse HTTP 200

{
  "status": "CONFIRMED",
  "operationCost": 0.0,
  "amount": 1133.0,
  "operationType": "MONEY_REMITTANCE-MOBILE_WALLET",
  "reference": "TPMW20260908164229511",
  "creationDate": "2026-09-08T16:42:29+00:00",
  "externalReference": "REMIT-GH-AMOR-001"
}

Dictionnaire des paramètres de transfert

ParamètreTypePrésenceDescription & Format
amountnumberObligatoireMontant du transfert à envoyer.
externalReferencestringObligatoire (étape 3)Référence unique générée par le partenaire pour identifier l'opération.
recipientMsisdnstringObligatoireNuméro Mobile Money récepteur en format international sans + (ex: 233243109307).
recipientNamestringObligatoireNom de famille du bénéficiaire.
recipientSurnamestringObligatoirePrénom du bénéficiaire.
recipientNationalitystringObligatoireCode pays ISO 3166-1 alpha-2 de la nationalité du récepteur (ex: GH, TG).
recipientBirthDatestringObligatoireDate de naissance du récepteur au format YYYY-MM-DD (ex: 2000-04-09).
recipientIdTypestringObligatoireType de pièce d'identité du récepteur (CI pour carte d'identité, PASSPORT, etc.).
recipientIdNumberstringObligatoireNuméro de la pièce d'identité du récepteur.
recipientIdExpiryDatestringObligatoireDate d'expiration de la pièce au format YYYY-MM-DD (ex: 2029-04-09).
recipientAddressLine1stringObligatoireAdresse physique ou quartier de résidence du récepteur.
senderPhonestringObligatoireNuméro de téléphone de l'émetteur au format international (ex: +2299225098).
senderFirstNamestringObligatoirePrénom de l'émetteur.
senderLastNamestringObligatoireNom de famille de l'émetteur.
senderCountrystringObligatoireCode pays ISO 3166-1 alpha-2 de résidence de l'émetteur (ex: BJ).
senderNationalitystringObligatoireCode pays ISO 3166-1 alpha-2 de la nationalité de l'émetteur (ex: BJ).
senderDateOfBirthstringObligatoireDate de naissance de l'émetteur au format YYYY-MM-DD (ex: 2000-12-12).
senderIdTypestringObligatoireType de pièce d'identité de l'émetteur (CI, PASSPORT, etc.).
senderIdNumberstringObligatoireNuméro de pièce d'identité de l'émetteur.
senderIdExpiryDatestringObligatoireDate d'expiration de la pièce au format YYYY-MM-DD (ex: 2029-04-09).
senderAddressstringObligatoireAdresse physique de l'émetteur (ex: Dantokpa).
senderCitystringObligatoireVille de l'émetteur (ex: Cotonou).
remittancePurposestringObligatoireMotif du transfert parmi les choix autorisés (ex: Family Maintenance, Salary, Savings).
sourceOfFundsstringObligatoireProvenance des fonds parmi les choix autorisés (ex: Salary, Savings, Business Income).
relationshipSenderstringObligatoireRelation avec le bénéficiaire parmi les choix autorisés (ex: Sister, Brother, Father, Friend).

Codes d'erreurs et Dépannage

Code HTTPMessage d'erreurCause probable & Action de résolution
401 UnauthorizedFull authentication is requiredEn-têtes X-Auth-ApiKey ou X-Auth-ApiSecret manquants, expirés ou erronés.
400 Bad RequestVALIDATION FAILED (extra fields)Un champ non pris en charge (ex: recipientCurrency) a été inclus dans le corps JSON. Retirez tout champ non présent dans la liste des prérequis.
400 Bad RequestThis value is not valid.Valeur d'énumération non reconnue ou casse incorrecte pour remittancePurpose, sourceOfFunds, relationshipSender ou idType.
400 Bad RequestBENEFICIARY ACCOUNT NOT FOUNDLe numéro de téléphone mobile money n'existe pas ou n'est pas actif auprès de l'opérateur télécom distant. Vérifiez le numéro et testez avec un portefeuille réel actif.
400 Bad RequestREVENUE SHARING NOT CONFIGUREDLa grille de partage de commissions pour ce corridor n'est pas encore activée sur votre compte marchand. Contactez le support technique Bestcash pour son activation.
400 Bad RequestTARGET COUNTRY NOT FOUND / COUNTRY NOT FOUNDLe code pays de destination est inconnu du système. Utilisez un code ISO 3166-1 alpha-2 valide (ex: TG, GH, CI).
400 Bad RequestCOUNTRY NOT SUPPORTED / UNSUPPORTED DESTINATIONLes transferts vers ce corridor ne sont pas encore opérationnels ou ouverts à votre compte.
400 Bad RequestINSUFFICIENT BALANCELe solde de votre compte émetteur BMO est insuffisant pour couvrir le montant du transfert et les frais associés.
400 Bad RequestINVALID RECIPIENT MSISDN / INVALID OR MISSING PHONE NUMBERLe numéro du destinataire est manquant ou ne respecte pas le format international (sans +).
400 Bad RequestOPERATION CONFIG NOT FOUNDLa configuration de routage pour ce corridor/opérateur est manquante côté plateforme.
400 Bad RequestSERVICE UNREACHABLEIndisponibilité temporaire du switch télécom ou du partenaire local. Réessayez la requête après quelques instants.
404 Not FoundRESSOURCE_NOT_FOUNDLa référence externe recherchée (externalReference) n'existe pas en base (l'opération a été rejetée avant création).

Exemples d'implémentation de bout en bout

const axios = require('axios');

const BASE_URL = 'https://svc.pap.bestcash.me/external';
const HEADERS = {
  'X-Auth-ApiKey': '+2290196666262',
  'X-Auth-ApiSecret': 'y7MwWuWeQORtpA==',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
};

async function executeMoneyRemit() {
  try {
    // 1. Récupérer les prérequis
    console.log('--- 1. Consultation des prérequis (GH) ---');
    const reqRes = await axios.get(`${BASE_URL}/thirdparty/money-remit/requirements?countryCode=GH`, {
      headers: HEADERS
    });
    console.log('Prérequis reçus :', reqRes.data);

    // Données du transfert
    const remitData = {
      amount: 100,
      recipientSurname: "Amor",
      recipientName: "Prince",
      recipientMsisdn: "233243109307", // Portefeuille Mobile Money actif sans le '+'
      recipientAddressLine1: "centre-ville",
      recipientIdType: "CI",
      recipientNationality: "GH",
      recipientBirthDate: "2000-04-09",
      recipientIdNumber: "123698547",
      recipientIdExpiryDate: "2029-04-09",
      senderPhone: "+2299225098",
      senderFirstName: "Antoine",
      senderLastName: "Atrokpo",
      senderCountry: "BJ",
      senderNationality: "BJ",
      senderDateOfBirth: "2000-12-12",
      senderIdType: "CI",
      senderIdNumber: "123589647",
      senderIdExpiryDate: "2029-04-09",
      senderAddress: "Dantokpa",
      senderCity: "Cotonou",
      remittancePurpose: "Family Maintenance",
      sourceOfFunds: "Salary",
      relationshipSender: "Sister"
    };

    // 2. Valider les données du formulaire
    console.log('--- 2. Validation formelle ---');
    const checkRes = await axios.post(`${BASE_URL}/thirdparty/money-remit/requirements/check`, remitData, {
      headers: HEADERS
    });
    console.log('Résultat validation :', checkRes.data);

    // 3. Exécuter l'opération financière
    const externalReference = `REMIT-GH-${Date.now()}`;
    console.log(`--- 3. Exécution de l'opération (${externalReference}) ---`);
    const opRes = await axios.post(`${BASE_URL}/thirdparty/money-remit/operation`, {
      ...remitData,
      externalReference
    }, { headers: HEADERS });

    console.log('Réponse opération :', opRes.data);

    // 4. Suivre le statut
    console.log('--- 4. Vérification du statut ---');
    const statusRes = await axios.get(`${BASE_URL}/thirdparty/operation?externalReference=${externalReference}`, {
      headers: HEADERS
    });
    console.log('Statut final :', statusRes.data);

  } catch (error) {
    console.error('Erreur :', error.response ? error.response.data : error.message);
  }
}

executeMoneyRemit();