Aller au contenu
AfriContext

MTN MoMo

MTN MoMo - Collection (Request to Pay)

Demande un paiement MoMo avec X-Reference-Id, puis interroge le statut ou reçoit le callback.

Vérifié sur la doc officielle • Vérifié sur la doc officielle • 08.10.26API v1_0

Même prompt, avec et sans ce contexte

Les passages barrés sont ceux que l'IA a inventés. Basculez pour voir la sortie avec le contexte.

› Demande un paiement MTN MoMo de 100 sur le numéro du client (sandbox).

1await fetch("https://sandbox.momodeveloper.mtn.com/collection/v1/payments", {2  method: "POST",3  headers: { Authorization: "Bearer " + token },4  body: JSON.stringify({ amount: 100, currency: "XOF", phone: msisdn }),5});
404 Resource Not Found3 inventions de l'IAModèle testé : Claude Sonnet, CursorDocumentation source

Authentification

  • Jeton : POST https://sandbox.momodeveloper.mtn.com/collection/token/ avec Authorization: Basic <base64(api_user:api_key)>.
  • Header Ocp-Apim-Subscription-Key: <clé primaire du produit Collection> sur tous les appels.
  • Appels métier : Authorization: Bearer <access_token>.

Endpoints

  • POST /collection/v1_0/requesttopay
    • Headers : X-Reference-Id (UUID v4 généré par vous), X-Target-Environment (sandbox ou l'environnement du pays), X-Callback-Url optionnel.
    • Corps : amount (string), currency, externalId, payer: { partyIdType: "MSISDN", partyId }, payerMessage, payeeNote.
    • Réponse : 202 Accepted sans corps.
  • GET /collection/v1_0/requesttopay/:referenceId renvoie status : PENDING, SUCCESSFUL, FAILED.

Erreurs

  • 409 X-Reference-Id déjà utilisé : générer un nouvel UUID.
  • 400 corps invalide ou partyId mal formaté.
  • 401 jeton expiré.
  • 500 en sandbox avec certains numéros de test : voir les numéros de test documentés.

Webhooks

  • Si X-Callback-Url est fourni, MTN appelle cette URL avec le statut final.
  • Le callback n'est pas signé : toujours confirmer avec GET /requesttopay/:referenceId.

Idempotence et limites

  • X-Reference-Id est la clé d'idempotence : un UUID par demande.
  • Interroger le statut avec un intervalle croissant, pas en boucle serrée.

Pièges courants

Ce que les LLMs inventent le plus souvent pour MTN MoMo.

  • En sandbox, la seule devise acceptée est EUR.
  • La réponse de requesttopay est vide : l'identifiant est celui que vous avez envoyé.
  • amount est une chaîne.
  • Pas de transactionId renvoyé à la création.

Exemple minimal

1export async function requestToPay(token: string, msisdn: string, amount: number): Promise<string> {2  const referenceId = crypto.randomUUID();3  const res = await fetch("https://sandbox.momodeveloper.mtn.com/collection/v1_0/requesttopay", {4    method: "POST",5    headers: {6      Authorization: "Bearer " + token,7      "X-Reference-Id": referenceId,8      "X-Target-Environment": process.env.MOMO_TARGET_ENV ?? "sandbox",9      "Ocp-Apim-Subscription-Key": process.env.MOMO_SUBSCRIPTION_KEY ?? "",10      "Content-Type": "application/json",11    },12    body: JSON.stringify({13      amount: String(amount),14      currency: "EUR",15      externalId: referenceId,16      payer: { partyIdType: "MSISDN", partyId: msisdn },17      payerMessage: "Commande",18      payeeNote: "Commande",19    }),20  });21  if (res.status !== 202) throw new Error("MoMo " + res.status);22  return referenceId;23}

Variables d'environnement

  • MOMO_API_USER
  • MOMO_API_KEY
  • MOMO_SUBSCRIPTION_KEY
  • MOMO_TARGET_ENV