Référence
Référence API
Les 16 endpoints de l'API marchand v1. Tous sont authentifiés par
Authorization: Bearer <secret_key> et relatifs à
https://api.mivaapay.com/api/v1.
| Endpoint | Objet |
|---|---|
POST /payments | Créer un paiement |
GET /payments | Lister les paiements |
GET /payments/{reference} | Récupérer un paiement |
POST /payments/{reference}/refund | Rembourser un paiement |
GET /refunds | Lister les remboursements |
GET /refunds/{reference} | Récupérer un remboursement |
POST /payment-links | Créer un lien de paiement |
GET /payment-links | Lister les liens de paiement |
GET /payment-links/{id} | Récupérer un lien de paiement |
GET /payment-modes | Lister les moyens de paiement |
POST /payment-modes/fees | Simuler les frais |
GET /balance | Solde du portefeuille |
GET /webhooks/endpoint | Consulter l'endpoint webhook |
PUT /webhooks/endpoint | Configurer l'endpoint webhook |
POST /webhooks/test | Envoyer un webhook de test |
GET /webhooks/deliveries | Journal des envois |
Paiements
Créer un paiement
/api/v1/payments
Initie un encaissement. En Mobile Money, le client reçoit une demande de validation sur son
téléphone et le paiement reste pending. En carte, la réponse porte une
payment_url vers laquelle rediriger le client.
Corps de la requête
| Champ | Type | Requis | Description |
|---|---|---|---|
amount | nombre | oui | Montant que vous encaissez, en unité principale. De 1 à 99 999 999. |
currency | chaîne | non | XOF (défaut), XAF, EUR, USD. |
operator | chaîne | oui* | Code opérateur, ex. mtn. *Requis sans payment_mode_id. 32 caractères max. |
payment_mode_id | entier | oui* | Identifiant du catalogue. *Requis sans operator. |
phone_number | chaîne | oui† | 8 à 15 chiffres, indicatif compris, + toléré. †Obligatoire en Mobile Money. |
otp | chaîne | non | Code à usage unique, obligatoire pour les opérateurs à OTP. 16 caractères max. |
description | chaîne | non | Libellé de la commande. 255 caractères max. Défaut : « Paiement API ». |
external_id | chaîne | non | Votre identifiant de commande. Unique par marchand : rend l'appel idempotent. 100 caractères max. |
return_url | URL | non | Page de retour après paiement. Requise par free_sn, utile en carte. |
callback_url | URL | non | Endpoint webhook pour ce paiement. Prioritaire sur l'endpoint du compte. |
metadata | objet | non | Données libres, restituées telles quelles dans les réponses et les webhooks. |
customer | objet | non | Identité du payeur. Obligatoire en carte : firstname, lastname, email. |
customer.firstname | chaîne | non | 100 caractères max. |
customer.lastname | chaîne | non | 100 caractères max. |
customer.email | non | 150 caractères max. Sert de clé de rapprochement de vos clients. | |
customer.address | chaîne | non | 255 caractères max. |
customer.country | chaîne | non | 60 caractères max. Utilisé en carte ; défaut Benin. |
curl -X POST https://api.mivaapay.com/api/v1/payments \
-H "Authorization: Bearer $MIVAAPAY_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{ "amount": 5000, "operator": "mtn", "phone_number": "22997000000", "external_id": "cmd_1042" }'
{
"amount": 5000,
"currency": "XOF",
"operator": "mtn",
"phone_number": "22997000000",
"description": "Commande #1042",
"external_id": "cmd_1042",
"callback_url": "https://boutique.example.com/webhooks/mivaapay",
"customer": { "firstname": "Awa", "lastname": "Diallo", "email": "awa@example.com" },
"metadata": { "panier": "1042" }
}
Réponse — 201 Created
Un objet paiement. payment_url n'est renseignée qu'en carte.
Erreurs
| Code | Cas |
|---|---|
invalid_request | Champ manquant ou invalide ; opérateur inconnu ou inactif ; total débité hors des bornes opérateur (10 à 1 000 000) ; OTP ou identité du porteur manquants. |
payment_failed | L'opérateur a refusé l'initiation. Le paiement est enregistré en failed. |
Renvoyer un external_id déjà utilisé retourne le paiement existant —
avec le statut 201 également — au lieu d'en créer un second.
Lister les paiements
/api/v1/paymentsListe paginée des paiements de votre compte, du plus récent au plus ancien.
Paramètres de requête
| Paramètre | Description |
|---|---|
status | pending, succeeded, failed ou refunded. Une valeur inconnue est traitée comme pending. |
external_id | Filtre sur votre identifiant de commande, en correspondance exacte. |
from | Date de début, comparée à created_at. Format YYYY-MM-DD ou ISO-8601. |
to | Date de fin, comparée à created_at. |
per_page | 1 à 100. Défaut 25. |
page | Numéro de page, à partir de 1. |
curl -G https://api.mivaapay.com/api/v1/payments \
-H "Authorization: Bearer $MIVAAPAY_SECRET_KEY" \
--data-urlencode "status=succeeded" \
--data-urlencode "from=2026-08-01" \
--data-urlencode "per_page=100"
Réponse — 200
Un tableau d'objets paiement dans data, les compteurs dans meta.
to
to=2026-08-31 est interprété comme 2026-08-31 00:00:00 :
les paiements de la journée du 31 sont exclus. Passez la date du lendemain, ou un horodatage
complet, pour inclure toute la journée.
Récupérer un paiement
/api/v1/payments/{reference}
Renvoie un paiement. {reference} accepte la référence MivaaPay ou
votre external_id.
Si le paiement est encore pending, son état est redemandé à l'opérateur avant la
réponse : cet appel est donc plus lent qu'une simple lecture. Prévoyez un timeout d'au moins
30 secondes.
curl https://api.mivaapay.com/api/v1/payments/cmd_1042 \
-H "Authorization: Bearer $MIVAAPAY_SECRET_KEY"
Réponse — 200
Un objet paiement. payment_url y vaut toujours null : elle n'est renvoyée qu'à la création.
Erreurs
not_found si aucun paiement de votre compte ne porte cette référence.
Remboursements
Rembourser un paiement
/api/v1/payments/{reference}/refund
Enregistre une demande de remboursement intégral. Le décaissement est exécuté ensuite par
MivaaPay ; suivez son issue par les webhooks refund.*.
{reference} accepte la référence MivaaPay ou votre external_id.
Corps de la requête
| Champ | Type | Requis | Description |
|---|---|---|---|
reason | chaîne | non | Motif, visible en back-office. 255 caractères max. Défaut : « Remboursement demandé par le marchand ». |
Réponse — 201 Created
Un objet remboursement au statut pending.
amount vaut le total_amount du paiement : votre montant plus la
commission, c'est-à-dire ce que le client avait réellement payé.
Erreurs
| Code | Cas |
|---|---|
not_found | Aucun paiement de votre compte ne porte cette référence. |
conflict | Le paiement n'est pas succeeded, ou un remboursement existe déjà. |
Lister les remboursements
/api/v1/refundsListe paginée de vos remboursements, du plus récent au plus ancien.
Paramètres de requête
| Paramètre | Description |
|---|---|
per_page | 1 à 100. Défaut 25. |
page | Numéro de page, à partir de 1. |
Réponse — 200
Un tableau d'objets remboursement.
Récupérer un remboursement
/api/v1/refunds/{reference}
Renvoie un remboursement. {reference} est ici la référence du
remboursement, pas celle du paiement : c'est la valeur renvoyée par
POST /payments/{reference}/refund.
Si le décaissement est en cours chez l'opérateur, son état est rafraîchi avant la réponse.
Réponse — 200
Erreurs
not_found si aucun remboursement de votre compte ne porte cette référence.
Liens de paiement
Créer un lien de paiement
/api/v1/payment-linksCrée une page de paiement hébergée, à montant et libellé fixés.
Corps de la requête
| Champ | Type | Requis | Description |
|---|---|---|---|
amount | nombre | oui | De 1 à 99 999 999. |
description | chaîne | oui | Affichée au client. 255 caractères max. |
type | chaîne | non | permanent (défaut) ou limité — avec l'accent, en UTF-8. |
max_uses | entier | oui* | *Requis si type vaut limité. Minimum 1. |
starts_at | date | non | Ouverture du lien, ISO-8601. |
expires_at | date | non | Fermeture, postérieure à starts_at. |
Réponse — 201 Created
Un objet lien de paiement, dont le champ url est l'adresse à partager.
Lister les liens de paiement
/api/v1/payment-linksListe paginée de vos liens, du plus récent au plus ancien. Paramètres : per_page (1 à 100, défaut 25) et page.
Récupérer un lien de paiement
/api/v1/payment-links/{id}
Renvoie un lien par son id numérique — celui de la création, pas le fragment
aléatoire de l'URL publique. not_found s'il n'appartient pas à votre compte.
Moyens de paiement
Lister les moyens de paiement
/api/v1/payment-modesCatalogue des moyens de paiement actifs, avec les frais qui vous sont appliqués. Cette réponse n'est pas paginée.
Paramètres de requête
| Paramètre | Description |
|---|---|
country | Code pays ISO-2, ex. CI. Insensible à la casse. |
type | mobile_money, card, bank_transfer ou e_wallet. |
Réponse — 200
Un tableau d'objets moyen de paiement.
Simuler les frais
/api/v1/payment-modes/feesCalcule la commission et le total qui sera débité au client, sans rien créer. À appeler avant d'afficher un prix.
Corps de la requête
| Champ | Type | Requis | Description |
|---|---|---|---|
amount | nombre | oui | Montant que vous encaissez. De 1 à 99 999 999. |
operator | chaîne | oui* | *Requis sans payment_mode_id. |
payment_mode_id | entier | oui* | *Requis sans operator. |
Réponse — 200
{
"payment_mode_id": 1,
"operator": "mtn",
"amount": 5000,
"fee_amount": 90,
"total_amount": 5090,
"fee_percent": 1.8,
"fee_fixed": 0
}
La commission vaut amount × fee_percent / 100 + fee_fixed, arrondie au centième.
total_amount est ce que le client verra sur son téléphone.
Erreurs
invalid_request si le moyen de paiement est introuvable ou inactif.
Portefeuille
Solde du portefeuille
/api/v1/balanceSolde disponible : les encaissements validés, moins les reversements déjà effectués.
Avec une clé sk_test_…, cet endpoint ne renvoie pas
votre solde réel mais la somme de vos encaissements de test : exposer une donnée
financière réelle dans le bac à sable serait une fuite.
Paramètres de requête
| Paramètre | Description |
|---|---|
currency | Devise du portefeuille. Défaut XOF. Insensible à la casse. |
Réponse — 200
{
"currency": "XOF",
"balance": 12845,
"balance_minor": 1284500,
"status": "Actif",
"updated_at": "2026-08-05T09:41:02+00:00"
}
| Champ | Description |
|---|---|
balance | Solde en unité principale — c'est la valeur à afficher, ici 12 845 XOF. |
balance_minor | Le même solde en entier, multiplié par 100. La comptabilité interne travaille en entiers pour éviter les arrondis : le facteur 100 est appliqué à toutes les devises, y compris le XOF qui n'a pourtant pas de subdivision. Utilisez-le si vous voulez éviter les flottants, mais ne l'affichez pas tel quel. |
status | État du portefeuille : Actif, Gelé ou Fermé. Hors de l'état actif, aucun mouvement n'est accepté sur le portefeuille. |
updated_at | Dernier mouvement, en ISO-8601. |
Webhooks
Consulter l'endpoint webhook
/api/v1/webhooks/endpoint
Renvoie l'URL configurée, le secret de signature et la liste des événements émis, pour
l'environnement de la clé employée. livemode rappelle de quel environnement il
s'agit : la configuration de test et celle de production sont
indépendantes.
{
"url": "https://boutique.example.com/webhooks/mivaapay",
"secret": "whsec_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"events": [
"payment.succeeded",
"payment.failed",
"payment.refunded",
"refund.succeeded",
"refund.failed"
],
"livemode": true
}
Sans endpoint configuré, url et secret valent null.
Configurer l'endpoint webhook
/api/v1/webhooks/endpointDéfinit l'URL de notification du compte, ou la supprime.
Corps de la requête
| Champ | Type | Requis | Description |
|---|---|---|---|
url | URL ou null | oui | URL HTTPS de notification, 255 caractères max. null désactive les webhooks. Le champ doit être présent, même à null. |
rotate_secret | booléen | non | true régénère le secret de signature. L'ancien cesse aussitôt d'être valide. |
Réponse — 200
{ "url": …, "secret": …, "livemode": … }. Un secret est créé automatiquement à la
première configuration d'une URL. L'écriture ne porte que sur l'environnement de la clé :
une clé de test ne peut pas modifier la configuration de production.
Envoyer un webhook de test
/api/v1/webhooks/test
Envoie un événement webhook.test sur l'endpoint configuré, signé comme un vrai.
Aucun corps de requête.
{
"sent": true,
"delivery_id": "1f0c9d3a-4f11-9c22-7d5a-1e0b3c68b71e",
"url": "https://boutique.example.com/webhooks/mivaapay"
}
Sans endpoint configuré, la réponse reste un 200 mais porte
"sent": false et le motif dans message.
Journal des envois
/api/v1/webhooks/deliveries
Historique paginé des notifications envoyées, du plus récent au plus ancien, limité à
l'environnement de la clé employée. Paramètres : per_page (1 à 100, défaut 25)
et page.
| Champ | Description |
|---|---|
id | Identifiant de la livraison, identique au champ id du corps envoyé et à l'en-tête X-MivaaPay-Delivery. |
event | Nom de l'événement. |
url | Endpoint appelé. |
status | pending, success ou failed. |
attempts | Nombre de tentatives effectuées, jusqu'à 5. |
response_code | Statut HTTP renvoyé par votre serveur, null s'il était injoignable. |
created_at | Date de mise en file, en ISO-8601. |
delivered_at | Date de livraison réussie, null sinon. |
Objets
Les objets ci-dessous sont ceux que renvoie l'API. Ce sont exactement les mêmes structures que
celles envoyées dans le champ data des webhooks.
Objet paiement
| Champ | Type | Description |
|---|---|---|
reference | UUID | Identifiant MivaaPay du paiement. C'est la clé à conserver. |
identifier | chaîne | Numéro lisible séquentiel, ex. Id2841. Confort d'affichage uniquement. |
external_id | chaîne | Votre identifiant de commande, null si non fourni. |
status | chaîne | pending, succeeded, failed ou refunded. |
amount | nombre | Ce que vous encaissez. |
fee_amount | nombre | Commission MivaaPay, à la charge du client. |
total_amount | nombre | Ce que le client est réellement débité. |
currency | chaîne | Devise du paiement. |
description | chaîne | Libellé de la commande. |
payment_mode | objet | Le moyen de paiement utilisé, null si indisponible. |
customer | objet | { firstname, lastname, email, phone_number }, valeurs à null si non fournies. |
payment_url | URL | Page de paiement hébergée. Renseignée uniquement dans la réponse à la création d'un paiement carte ; null partout ailleurs. |
metadata | objet | Ce que vous aviez envoyé, tel quel. null si absent. |
created_at | date | ISO-8601. |
updated_at | date | ISO-8601. Change au passage de statut. |
Objet remboursement
| Champ | Type | Description |
|---|---|---|
reference | UUID | Identifiant du remboursement. |
payment_reference | UUID | Référence du paiement remboursé. |
amount | nombre | Montant rendu au client : le total_amount du paiement. |
currency | chaîne | Devise du paiement d'origine. |
status | chaîne | pending, succeeded ou failed. |
reason | chaîne | Motif enregistré. |
processed_at | date | Date d'exécution, null tant que le remboursement est en attente. |
created_at | date | Date de la demande, ISO-8601. |
Objet lien de paiement
| Champ | Type | Description |
|---|---|---|
id | entier | Identifiant du lien, à passer à GET /payment-links/{id}. |
url | URL | Adresse publique à partager. |
type | chaîne | permanent ou limité. |
amount | nombre | Montant que vous encaissez. |
description | chaîne | Libellé affiché au client. |
max_uses | entier | Nombre d'utilisations autorisées, null pour un lien permanent. |
uses_count | entier | Utilisations déjà consommées. |
uses_left | entier | Utilisations restantes, null pour un lien permanent. |
starts_at | date | Ouverture, null si non définie. |
expires_at | date | Fermeture, null si non définie. |
created_at | date | ISO-8601. |
Objet moyen de paiement
| Champ | Type | Description |
|---|---|---|
id | entier | Identifiant, utilisable comme payment_mode_id. |
name | chaîne | Nom affichable, ex. « MTN Bénin ». |
type | chaîne | mobile_money, card, bank_transfer, e_wallet ou other. |
operator | chaîne | Code opérateur, utilisable comme operator. |
country | chaîne | Nom du pays, null si inconnu. |
country_code | chaîne | Code ISO-2, null si inconnu. |
fee_percent | nombre | Part proportionnelle de la commission, en pourcentage. |
fee_fixed | nombre | Part fixe de la commission. |
requires_otp | booléen | true si le champ otp est obligatoire à la création du paiement. |
logo | URL | Logo de l'opérateur, null si absent. |