Intégrez MTPay
Créez des liens de paiement Mobile Money depuis votre serveur, recevez un webhook signé dès que le client paie, livrez automatiquement.
- Base URL
- mt-pay.vercel.app
- Version
- v1
- Format
- JSON
En 3 etapes
Demarrage
- 1
Obtenez votre cle
Depuis le dashboard, demandez un acces API. Un admin valide et vous recevez votre cle
mt_live_…et votre secret webhook. - 2
Creez un lien
Un appel
POST /api/v1/payment-linksrenvoie unepaymentUrla envoyer au client. - 3
Ecoutez le webhook
MTPay appelle votre URL des que le paiement aboutit. Verifiez la signature, puis livrez.
Claude Code, Cursor, Copilot...
Integrer avec une IA
Ouvrez votre projet dans Claude Code, Cursor ou un autre agent de codage, collez l'un de ces prompts tel quel. Chacun porte le contrat exact de l'endpoint concerne, l'agent n'a rien a deviner ni a inventer.
Ajouter un paiement
Je veux integrer MTPay (paiement Mobile Money) dans ce projet.
Documentation : https://mt-pay.vercel.app/docs
Ce que je veux :
1. Un appel serveur POST https://mt-pay.vercel.app/api/v1/payment-links pour creer
un lien de paiement des qu'un client valide sa commande. Header
Authorization: Bearer <MTPAY_API_KEY> (variable d'env, jamais en dur).
Body JSON : { clientName, clientPhone, amount, service, country,
returnUrl }. returnUrl = l'URL de CE projet vers laquelle MTPay
redirige le client une fois le paiement confirme (bouton immediat +
retour automatique apres quelques secondes) — sans elle le client
reste bloque sur la page de recu MTPay sans jamais revenir ici.
2. Rediriger le client vers la paymentUrl renvoyee par l'API
(data.paymentUrl dans la reponse 201).
3. Une route webhook POST qui recoit les confirmations de paiement MTPay
(voir la section Webhook de la doc), verifie la signature HMAC SHA-256
avec MTPAY_WEBHOOK_SECRET avant de faire quoi que ce soit, puis marque
la commande payee quand event === "payment.completed".
4. Gere aussi payment.failed et payment.expired (commande a rouvrir /
ne pas livrer), et payment.refunded (paiement rembourse au client :
annuler la commande).
Adapte les noms de fonctions/fichiers aux conventions deja utilisees dans
ce projet plutot que d'imposer une structure nouvelle.Juste le webhook
Ajoute a ce projet une route qui recoit les webhooks MTPay
(paiements Mobile Money).
Contrat exact (doc complete : https://mt-pay.vercel.app/docs#webhook) :
- MTPay envoie un POST avec le corps BRUT (ne pas re-serialiser avant de
verifier la signature, sinon le HMAC ne correspond plus)
- En-tetes : X-MTPay-Event (payment.completed | payment.failed |
payment.expired | payment.refunded) et X-MTPay-Signature
(format "sha256=<hex>")
- payment.refunded : le paiement a ete rembourse au client par MTPay
(status "REFUNDED") — annuler la commande / retirer l'acces
- Verification : HMAC SHA-256 du corps brut avec MTPAY_WEBHOOK_SECRET,
comparaison en temps constant (pas de === naif sur les secrets)
- Payload JSON : { event, paymentId, amount, currency, status, customer:
{ name, phone }, failure? }
- failure (payment.failed / payment.expired, si l'operateur a donne un
motif) : { code, message }, ex. code "INSUFFICIENT_BALANCE" — a
afficher au client pour qu'il sache quoi corriger
- Toujours repondre 200 rapidement si la signature est valide, meme si
le paymentId est inconnu (MTPay reessaie sinon)
- Repondre 401/403 uniquement si la signature ne correspond pas
Le paymentId correspond a l'id du lien cree via POST /api/v1/payment-links :
utilise-le pour retrouver la commande correspondante dans ce projet.Afficher le solde
Ajoute a ce projet un affichage du solde MTPay disponible
(paiements Mobile Money encaisses).
Appel serveur : GET https://mt-pay.vercel.app/api/v1/balance
Header : Authorization: Bearer <MTPAY_API_KEY>
Reponse (200) :
{
"data": {
"currency": "XOF",
"availableBalance": 125000,
"totalCollected": 340000,
"totalWithdrawn": 200000,
"pendingWithdrawalAmount": 15000,
"counts": { "links": 42, "completed": 31, "pendingWithdrawals": 1 }
}
}
Affiche availableBalance formate dans la devise (currency), avec
totalCollected et counts.completed en sous-texte. Cache le montant
derriere l'authentification existante de ce projet (jamais accessible
sans etre connecte a l'admin/au compte).Variables d'environnement
Donnez a l'agent le nom des variables (MTPAY_API_KEY, MTPAY_WEBHOOK_SECRET) plutot que leur valeur. Collez les vraies valeurs vous-meme dans votre fichier .env, jamais dans le prompt.
Toutes les requetes
Authentification
Chaque appel serveur porte votre cle API dans l'en-tete Authorization. Gardez-la cote serveur : elle ne doit jamais apparaitre dans du code client.
Authorization: Bearer mt_live_xxxxxxxxxx
Content-Type: application/jsonCle exposee ?
Revoquez-la depuis le dashboard et generez-en une nouvelle. Une cle fuitee permet de creer des liens en votre nom.
Endpoint
Creer un lien de paiement
curl -X POST https://mt-pay.vercel.app/api/v1/payment-links \
-H "Authorization: Bearer mt_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"clientName": "Awa Konate",
"clientPhone": "+22997000000",
"amount": 15000,
"service": "Commande boutique",
"country": "BEN"
}'Corps de la requete
clientNamestringrequisNom du client affiche sur la page de paiement.
clientPhonestringrequisNumero Mobile Money au format international.
amountnumberrequisMontant a encaisser, en unite entiere de la devise.
servicestringrequisLibelle de ce qui est vendu.
countrystringoptionnelCode ISO-3 du pays. Par defaut : celui du marchand.
currencystringoptionnelPar defaut : la devise du pays (XOF, XAF, CDF...).
descriptionstringoptionnelDetail libre affiche au client.
returnUrlstringoptionnelURL de votre site vers laquelle rediriger le client apres paiement reussi (bouton immediat + retour automatique apres quelques secondes). Sans elle, le client reste sur la page de recu MTPay.
Reponse 201
{
"data": {
"id": "V1StGXR8Z5",
"clientName": "Awa Konate",
"clientPhone": "+22997000000",
"amount": 15000,
"currency": "XOF",
"service": "Commande boutique",
"description": "",
"status": "PENDING",
"createdAt": "2026-08-11T09:24:00.000Z",
"country": "BEN",
"paymentUrl": "https://mt-pay.vercel.app/pay/V1StGXR8Z5"
}
}Envoyez data.paymentUrl a votre client par WhatsApp, SMS ou e-mail.
Endpoint
Consulter un paiement
curl https://mt-pay.vercel.app/api/v1/payment-links/V1StGXR8Z5 \
-H "Authorization: Bearer mt_live_xxx"Utile pour verifier un statut a la demande. Pour la confirmation temps reel, preferez le webhook.
Endpoint
Lister vos liens
curl "https://mt-pay.vercel.app/api/v1/payment-links?status=COMPLETED&page=1&pageSize=20" \
-H "Authorization: Bearer mt_live_xxx"Renvoie { "data": [ … ] }. Filtrez par status (optionnel : PENDING, COMPLETED, FAILED, EXPIRED). Paginez avec page et pageSize (100 max, 20 par defaut). Le total, la page courante et le nombre de pages sont renvoyes dans les en-tetes de reponse.
X-Total-Count: 134
X-Page: 1
X-Page-Size: 20
X-Total-Pages: 7Endpoint
Consulter votre solde
curl https://mt-pay.vercel.app/api/v1/balance \
-H "Authorization: Bearer mt_live_xxx"{
"data": {
"currency": "XOF",
"availableBalance": 125000,
"totalCollected": 340000,
"totalWithdrawn": 200000,
"pendingWithdrawalAmount": 15000,
"counts": { "links": 42, "completed": 31, "pendingWithdrawals": 1 }
}
}availableBalance suit la meme regle que le dashboard : total encaisse moins retraits deja approuves. Utile pour afficher votre solde sans repasser par le dashboard web.
Endpoint public
Pays et reseaux disponibles
Aucune cle requise : construisez votre selecteur pays/operateur avant meme d'avoir un acces API approuve.
curl https://mt-pay.vercel.app/api/v1/countries{
"data": [
{
"code": "BEN",
"flag": "BJ",
"name": "Bénin",
"currency": "XOF",
"feePercent": 4.9,
"payout": true,
"networks": [
{ "id": "MTN_MOMO_BEN", "label": "MTN MoMo", "brand": "MTN" },
{ "id": "MOOV_BEN", "label": "Moov Money", "brand": "MOOV" }
]
}
]
}Temps reel
Webhook
MTPay appelle votre URL en POST a chaque changement de statut. Repondez 200 rapidement : un autre code declenche une nouvelle tentative.
X-MTPay-Signature: sha256=...
X-MTPay-Event: payment.completed{
"event": "payment.completed",
"paymentId": "V1StGXR8Z5",
"amount": 15000,
"currency": "XOF",
"status": "COMPLETED",
"customer": {
"name": "Awa Konate",
"phone": "+22997000000"
}
}{
"event": "payment.failed",
"paymentId": "V1StGXR8Z5",
"amount": 6000,
"currency": "XAF",
"status": "FAILED",
"customer": {
"name": "Jean Moussavou",
"phone": "+24177000000"
},
"failure": {
"code": "INSUFFICIENT_BALANCE",
"message": "The customer does not have enough funds to complete the payment."
}
}failure accompagne payment.failed et payment.expiredquand l'operateur a donne un motif. Codes frequents : INSUFFICIENT_BALANCE (solde insuffisant, frais inclus), PAYMENT_NOT_APPROVED (PIN non valide), PAYER_NOT_FOUND (numero inconnu de l'operateur), PAYER_LIMIT_REACHED (plafond atteint).
payment.refunded (statut REFUNDED) signale qu'un paiement a été remboursé au client : annulez la commande ou retirez l'accès correspondant.
Verifiez toujours la signature
Recalculez un HMAC SHA-256 du corps brut avec votre secret webhook et comparez-le a X-MTPay-Signature avant de livrer quoi que ce soit.
Reference
Statuts d'un paiement
Lien cree, le client n'a pas encore paye.
Paiement confirme par l'operateur. Livrez la commande.
Paiement refuse ou annule par le client.
Le lien a depasse sa duree de validite.
Reference
Pays et devises
Passez le code ISO-3 dans country. La devise est deduite automatiquement si vous ne la precisez pas.
BENBéninCIVCôte d'IvoireSENSénégalTGOTogoCMRCamerounGABGabonCOGCongoCODRD CongoKENKenyaUGAOugandaZMBZambieSLESierra LeoneETHÉthiopieReference
Erreurs
Toute erreur renvoie le meme format : un code stable sur lequel brancher de la logique (retry, message specifique...), et un message informatif qui peut evoluer sans casser votre integration.
{
"error": {
"code": "NOT_FOUND",
"message": "Lien de paiement introuvable."
}
}INVALID_REQUESTCorps de requete invalide ou champ requis manquant/incorrect.
UNAUTHORIZEDEn-tete Authorization absent ou cle API inconnue.
FORBIDDENCle valide mais acces API non approuve pour ce compte.
NOT_FOUNDL'identifiant n'existe pas ou appartient a un autre marchand.
CONFLICTL'action est refusee dans cet etat (ex. lien deja paye).
RATE_LIMITEDTrop de requetes en peu de temps. Reessayez plus tard.
INTERNAL_ERRORErreur cote MTPay. Reessayez ; contactez le support si persistant.
Une question sur l'integration ?
Demandez votre acces API : vous recevrez votre cle, votre URL webhook et votre secret.