IPPayIberionPay

Développeurs

Documentation API IberionPay

Encaissez par MTN MoMo et Orange Money depuis votre site, votre application ou votre logiciel de gestion. Une clé secrète, un appel HTTP, un callback signé : le reversement part automatiquement sur votre numéro Mobile Money du même réseau que votre client.

1. Démarrage rapide

  1. Créez un compte, puis complétez votre dossier marchand (KYC). L'API est réservée aux marchands vérifiés.
  2. Dans Services → API et callbacks, enregistrez vos deux numéros de reversement (MTN MoMo et Orange Money).
  3. Générez une clé : vous obtenez une clé publique pk_live_… et une clé secrète sk_live_… affichée une seule fois.
  4. Renseignez votre URL de callback HTTPS et conservez le secret de signature.
  5. Appelez l'endpoint d'encaissement, puis traitez le callback.

URL de base : https://iberionpay.com/api/public/v1 — toutes les réponses sont en JSON, tous les montants sont des entiers en francs CFA (XAF), sans décimale.

2. Frais et montants

FluxTauxQuand
Pay-in (collecte client)3 %Au débit du client
Payout (reversement marchand)1,5 %Au reversement sur votre numéro
Total prélevé4,5 %Déduit du montant collecté

Exemple sur 10 000 FCFA : pay-in 300 FCFA + payout 150 FCFA = 450 FCFA de frais, soit 9 550 FCFA reversés (net dans la réponse API).

Montant minimum 10 FCFA, maximum 500 000 FCFA par transaction. Les frais sont déduits du montant encaissé : si vous voulez recevoir un net précis, majorez le montant demandé au client.

3. Authentification

Chaque requête serveur porte votre clé secrète dans l'en-tête Authorization. Ne l'exposez jamais dans du code front-end, une application mobile ou un dépôt public.

http
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

La clé publique pk_live_… sert uniquement à identifier votre compte (rapprochement, support). Vous pouvez détenir jusqu'à 5 clés actives et révoquer une clé à tout moment — la révocation est immédiate.

4. Créer un encaissement

POST https://iberionpay.com/api/public/v1/charges — déclenche la demande de paiement Mobile Money. Votre client reçoit une invite USSD/appli à valider avec son code secret.

ChampTypeDescription
amountentier, requisMontant en XAF à collecter (ex. 5000).
customerPhonetexte, requisNuméro du payeur, 9 chiffres (6XXXXXXXX).
customerOperatortexte, requisMTN_MOMO_CMR ou ORANGE_CMR — choisi par le client.
customerNametexte, optionnelNom du payeur, 80 caractères max.
metadataobjet, optionnelVos références (orderId, invoiceId…) renvoyées dans les callbacks.

L'en-tête Idempotency-Key est votre référence de commande et doit être strictement unique pour chaque paiement, à vie. Si la même clé est renvoyée une seconde fois, la demande est refusée avec 409 idempotency_key_reused (la réponse indique la référence déjà utilisée) : aucun ancien encaissement n'est renvoyé et aucun paiement n'est validé par erreur. N'utilisez jamais un compteur susceptible de se réinitialiser ; préférez un identifiant unique (UUID ou identifiant de commande jamais réattribué).

bash
curl -X POST https://iberionpay.com/api/public/v1/charges \
  -H "Authorization: Bearer sk_live_..." \
  -H "Idempotency-Key: CMD-1024" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 10000,
    "customerPhone": "6XXXXXXXX",
    "customerOperator": "MTN_MOMO_CMR",
    "customerName": "Jean Mbarga",
    "metadata": { "orderId": "1024" }
  }'

Réponse 201 :

json
{
  "data": {
    "id": "6f0d6e2c-6a1e-4f3f-9d0b-2c9a1f7b1234",
    "reference": "IBP-7K3M9Q",
    "status": "collecting",
    "amount": 10000,
    "fee": 450,
    "net": 9550
  }
}

amount est débité au client, fee correspond aux 4,5 % (3 % pay-in + 1,5 % payout) et net est le montant reversé sur votre numéro du même opérateur, automatiquement, dès que la collecte est confirmée.

5. Suivre un encaissement

GET https://iberionpay.com/api/public/v1/charges/{id ou référence} — état à jour d'une transaction. GET https://iberionpay.com/api/public/v1/charges renvoie vos 50 derniers encaissements.

bash
curl https://iberionpay.com/api/public/v1/charges/IBP-7K3M9Q \
  -H "Authorization: Bearer sk_live_..."
statusSignification
initiatedEncaissement créé, demande en préparation.
collectingEn attente de validation par le client.
collectedPaiement client confirmé, reversement en préparation.
paying_outReversement en cours vers votre numéro.
completedTerminé : le net est arrivé sur votre numéro.
failedRefusé, annulé ou expiré : aucun débit conservé.
refund_requiredCollecté mais reversement bloqué : notre équipe intervient.

Ne livrez la commande que sur completed (ou collected si vous acceptez le risque de reversement). N'interrogez pas cet endpoint en boucle serrée : privilégiez le callback, avec une vérification toutes les 10 secondes maximum en secours.

6. Consulter le solde

GET https://iberionpay.com/api/public/v1/balance — cumul de vos encaissements.

json
{
  "data": {
    "currency": "XAF",
    "settled": 1250000,   // net déjà reversé
    "pending": 35000,     // encaissements en cours
    "fees": 56250,        // frais prélevés
    "count": 143          // nombre de transactions terminées
  }
}

7. Callbacks signés

Nous appelons votre URL HTTPS en POST à chaque changement d'état, avec ces en-têtes :

http
x-iberionpay-timestamp: 1735689600
x-iberionpay-signature: sha256=<hmac>
x-iberionpay-delivery: <identifiant de livraison>

La signature est un HMAC-SHA256 de la chaîne timestamp + "." + corps brut avec votre secret whsec_…. Vérifiez-la avant de traiter le contenu, en comparaison à temps constant, et rejetez un timestamp de plus de 5 minutes.

javascript
import crypto from "crypto";

app.post("/iberionpay/callback", express.raw({ type: "*/*" }), (req, res) => {
  const timestamp = req.header("x-iberionpay-timestamp") || "";
  const received = (req.header("x-iberionpay-signature") || "").replace("sha256=", "");
  const raw = req.body.toString("utf8");

  const expected = crypto
    .createHmac("sha256", process.env.IBERIONPAY_WEBHOOK_SECRET)
    .update(timestamp + "." + raw)
    .digest("hex");

  const a = Buffer.from(received);
  const b = Buffer.from(expected);
  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
    return res.status(401).send("invalid signature");
  }
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) {
    return res.status(401).send("stale timestamp");
  }

  const { event, data } = JSON.parse(raw);
  if (event === "charge.completed") {
    // marquez la commande data.metadata.orderId comme payée (idempotent)
  }
  res.sendStatus(200);   // répondez 2xx sous 10 s
});

Corps reçu :

json
{
  "event": "charge.completed",
  "createdAt": "2026-08-25T18:20:31.000Z",
  "data": {
    "id": "6f0d6e2c-6a1e-4f3f-9d0b-2c9a1f7b1234",
    "reference": "IBP-7K3M9Q",
    "status": "completed",
    "amount": 10000,
    "fee": 450,
    "net": 9550,
    "currency": "XAF",
    "customerPhone": "2376XXXXXXXX",
    "customerOperator": "MTN_MOMO_CMR",
    "customerName": "Jean Mbarga",
    "source": "api",
    "metadata": { "orderId": "1024" },
    "createdAt": "2026-08-25T18:19:58.000Z"
  }
}

Événements : charge.pending, charge.completed, charge.failed, charge.refund_required. Sans réponse 2xx sous 10 secondes, nous relançons à 30 s, 2 min, 10 min, 1 h puis 6 h. Traitez chaque événement de manière idempotente (une même référence peut arriver deux fois) et rejouez une livraison manuellement depuis le tableau de bord si besoin.

8. Codes d'erreur

HTTPerrorQue faire
400invalid_bodyChamp manquant ou type incorrect.
400invalid_customer_phoneNuméro non valide (9 chiffres, commence par 6).
400no_payout_number_for_operatorEnregistrez votre numéro pour cet opérateur dans API et callbacks.
401unauthorizedClé secrète absente, erronée ou révoquée.
403merchant_not_approvedVotre KYC marchand n'est pas encore approuvé.
402operator_rejectedRefus opérateur (solde, code, numéro) : aucun débit.
409idempotency_key_reusedCette référence a déjà servi à un encaissement : chaque paiement exige une clé unique.
500charge_not_createdErreur temporaire : réessayez avec une nouvelle clé unique.

Format d'erreur : { "error": "unauthorized" }. Tous vos appels (méthode, statut, durée) sont consultables dans l'onglet « Appels API récents ».

9. Exemples d'intégration

Node.js / Next.js

javascript
const res = await fetch("https://iberionpay.com/api/public/v1/charges", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.IBERIONPAY_SECRET_KEY}`,
    "Idempotency-Key": order.id,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    amount: order.total,
    customerPhone: order.phone,
    customerOperator: order.operator,   // "MTN_MOMO_CMR" | "ORANGE_CMR"
    metadata: { orderId: order.id },
  }),
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(error);
// data.reference : affichez-la au client, attendez le callback

PHP / Laravel

php
$response = Http::withToken(env('IBERIONPAY_SECRET_KEY'))
    ->withHeaders(['Idempotency-Key' => $order->id])
    ->post('https://iberionpay.com/api/public/v1/charges', [
        'amount' => $order->total,
        'customerPhone' => $order->phone,
        'customerOperator' => $order->operator,
        'metadata' => ['orderId' => $order->id],
    ]);

if ($response->failed()) {
    report($response->json('error'));
}
$charge = $response->json('data');

Python

python
import os, requests

r = requests.post(
    "https://iberionpay.com/api/public/v1/charges",
    headers={
        "Authorization": f"Bearer {os.environ['IBERIONPAY_SECRET_KEY']}",
        "Idempotency-Key": str(order_id),
    },
    json={
        "amount": total,
        "customerPhone": phone,
        "customerOperator": operator,
        "metadata": {"orderId": str(order_id)},
    },
    timeout=30,
)
r.raise_for_status()
charge = r.json()["data"]

Vérification de signature en PHP

php
$timestamp = $request->header('x-iberionpay-timestamp');
$received = str_replace('sha256=', '', $request->header('x-iberionpay-signature'));
$expected = hash_hmac('sha256', $timestamp . '.' . $request->getContent(), env('IBERIONPAY_WEBHOOK_SECRET'));

if (!hash_equals($expected, $received)) {
    abort(401);
}

10. Passage en production

  • Stockez sk_live_… et whsec_… en variables d'environnement.
  • Utilisez une clé par plateforme (site, application, caisse) pour révoquer sans tout interrompre.
  • Envoyez toujours une Idempotency-Key stable par commande.
  • Ne validez la livraison que sur charge.completed.
  • Journalisez reference et id : ce sont nos clés de support.
  • Rappel des frais : 3 % au pay-in et 1,5 % au payout, prélevés sur le montant collecté.

Prêt à intégrer ?

Générez vos clés et votre secret de callback depuis votre espace marchand.

Ouvrir API et callbacks