Orange Money est l’opérateur Mobile Money le plus mature en Afrique de l’Ouest, présent dans tous les pays francophones de la zone CEDEAO/UEMOA et au-delà. Au Sénégal et en Côte d’Ivoire spécifiquement, il reste un acteur incontournable malgré la montée de Wave : nombreux utilisateurs n’utilisent pas Wave, et certains segments B2B passent toujours majoritairement par Orange Money. L’API marchand officielle, exposée via la plateforme Orange Developer, permet d’accepter des paiements directement. Voici le tutoriel complet d’intégration en 2026, valable Sénégal et Côte d’Ivoire.
Ce tutoriel s’inscrit dans notre série Mobile Money. Pour le panorama global, voir notre guide complet API Mobile Money 2026.
L’écosystème Orange Developer
Orange expose plusieurs APIs via developer.orange.com :
- Orange Money Web Payment — checkout via redirection web, le plus simple à intégrer, équivalent à Wave Checkout
- Orange Money B2B Payment — paiement de factures B2B avec validation manuelle
- Orange Money Cash-In / Cash-Out — pour les agrégateurs ou agents
- SMS API — utile pour notifications de paiement
- USSD API — paiement par code USSD pour clients sans smartphone
Pour la majorité des projets e-commerce et SaaS, Orange Money Web Payment est l’API recommandée. C’est ce que couvre ce tutoriel.
Prérequis
- Compte Orange Developer (gratuit, inscription en ligne)
- Application créée dans le portail avec accès Sandbox
- Pour la production : compte marchand Orange Money B2B (KYC + contrat agence Orange Money locale)
- Node.js 20+ ou Bun
- Domaine HTTPS pour notification (callback)
- Niveau attendu : intermédiaire
- Temps : 1 journée pour MVP, 1 semaine pour intégration complète et passage en prod
Étape 1 — Inscription Orange Developer
- Inscription sur
developer.orange.com - Vérification email
- Création d’une application : choisissez « Orange Money Web Payment Senegal » (ou Côte d’Ivoire selon pays cible)
- Récupérez le
Client IDetClient Secret - Notez la
Merchant Keysandbox fournie automatiquement
Étape 2 — Authentification OAuth2
L’API Orange Money utilise OAuth2 client credentials. Vous échangez Client ID + Secret contre un access token, valable ~1h, à mettre en cache.
// src/orange-auth.ts
let cachedToken: { value: string; expiresAt: number } | null = null;
export async function getOrangeAccessToken(): Promise<string> {
// Cache encore valide ?
if (cachedToken && cachedToken.expiresAt > Date.now() + 60_000) {
return cachedToken.value;
}
const credentials = Buffer.from(
`${process.env.ORANGE_CLIENT_ID}:${process.env.ORANGE_CLIENT_SECRET}`,
).toString("base64");
const res = await fetch("https://api.orange.com/oauth/v3/token", {
method: "POST",
headers: {
"Authorization": `Basic ${credentials}`,
"Content-Type": "application/x-www-form-urlencoded",
},
body: "grant_type=client_credentials",
});
if (!res.ok) throw new Error(`Auth Orange échouée: ${res.status}`);
const data = await res.json();
cachedToken = {
value: data.access_token,
expiresAt: Date.now() + data.expires_in * 1000,
};
return cachedToken.value;
}
Étape 3 — Initier un paiement Web
// src/orange-payment.ts
import { getOrangeAccessToken } from "./orange-auth";
const OM_BASE = process.env.ORANGE_API_BASE
?? "https://api.orange.com/orange-money-webpay/dev/v1";
export async function createOrangePayment(params: {
amount: number;
orderId: string;
customerId: string;
returnUrl: string;
cancelUrl: string;
notifUrl: string;
}) {
const token = await getOrangeAccessToken();
const res = await fetch(`${OM_BASE}/webpayment`, {
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json",
"Accept": "application/json",
},
body: JSON.stringify({
merchant_key: process.env.ORANGE_MERCHANT_KEY,
currency: "XOF",
order_id: params.orderId,
amount: params.amount,
return_url: params.returnUrl,
cancel_url: params.cancelUrl,
notif_url: params.notifUrl,
lang: "fr",
reference: params.customerId,
}),
});
if (!res.ok) {
const err = await res.text();
throw new Error(`Orange Money création échouée: ${res.status} ${err}`);
}
// Réponse type :
// { status, message, pay_token, payment_url, notif_token }
return res.json();
}
L’utilisateur est ensuite redirigé vers payment_url qui ouvre la page Orange Money pour valider avec son code PIN.
Étape 4 — Notification (callback)
Orange Money envoie une notification HTTP POST à votre notif_url à la fin de la transaction (succès ou échec). Contrairement à Wave, Orange n’utilise pas de signature HMAC standard — l’authentification se fait via un notif_token que vous recevez à la création et qui doit matcher.
app.post("/webhooks/orange-money", async (c) => {
const body = await c.req.json();
// Récupérer la commande et vérifier le notif_token
const order = await db.select().from(orders)
.where(eq(orders.id, body.order_id))
.limit(1);
if (!order.length) return c.text("Order not found", 404);
if (order[0].orangeNotifToken !== body.notif_token) {
console.warn("Notif token mismatch", body.order_id);
return c.text("Invalid notif_token", 401);
}
// Idempotence : statut déjà final ?
if (order[0].status === "paid" || order[0].status === "failed") {
return c.text("Already processed", 200);
}
// Mettre à jour le statut
if (body.status === "SUCCESS") {
await db.update(orders).set({
status: "paid",
orangeTransactionId: body.txnid,
paidAt: new Date(),
}).where(eq(orders.id, body.order_id));
await sendReceiptEmail(body.order_id);
} else if (body.status === "FAILED" || body.status === "CANCELLED") {
await db.update(orders).set({ status: "failed" })
.where(eq(orders.id, body.order_id));
}
return c.text("OK", 200);
});
Étape 5 — Vérification proactive (status)
Comme avec Wave, doublez le webhook par un polling proactif pour les commandes pending de plus de 15 minutes :
export async function checkOrangePaymentStatus(payToken: string) {
const token = await getOrangeAccessToken();
const res = await fetch(`${OM_BASE}/transactionstatus`, {
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
order_id: orderId,
amount: amount,
pay_token: payToken,
}),
});
return res.json();
// { status: "SUCCESS" | "FAILED" | "PENDING" | "INITIATED", txnid?, message }
}
Étape 6 — Spécificités Sénégal vs Côte d’Ivoire
- URL endpoints : différents selon le pays. Sénégal utilise
orange-money-webpay/dev/v1en sandbox etorange-money-webpay/sn/v1en prod ; Côte d’Ivoire utilise/ci/v1 - Devise : XOF dans les deux cas (UEMOA)
- Numéros de téléphone : préfixe +221 (Sénégal) ou +225 (CI)
- Frais et plafonds : varient selon le contrat marchand local
- Support : agences Orange Money B2B locales différentes — au Sénégal Orange Sonatel, en Côte d’Ivoire Orange CI
Étape 7 — Passage en production
- Validation de votre intégration en sandbox avec tests complets (succès, échec, timeout, double soumission)
- Demande de bascule prod via le dashboard Orange Developer + dossier KYC complet auprès de l’agence Orange Money locale
- Réception des credentials production et de la
Merchant Keyproduction - Mise à jour des variables d’environnement, changement du
OM_BASEURL - Tests progressifs avec petits montants (1000 FCFA) avant ouverture publique
Délai total : 2-4 semaines selon la réactivité de l’agence Orange Money locale. Démarrez tôt.
Étape 8 — Bonnes pratiques production
- Rotation des clefs : régénérer Client Secret tous les 6 mois
- Cache du token : ne pas refetch à chaque appel — économie de latence et conformité aux rate limits
- Retry avec backoff exponentiel : Orange API a parfois des 5xx transitoires
- Monitoring du taux de succès : alerte si taux d’échec > 10 % sur une heure
- Logs sans secrets : ne pas logger les tokens, ni les
pay_tokencomplets
Comparaison Wave vs Orange Money
| Critère | Wave | Orange Money |
|---|---|---|
| UX intégration | Plus moderne, RESTful | OAuth2 + endpoints structurés |
| Documentation | Excellente | Correcte mais parfois datée |
| Webhooks signés | HMAC SHA-256 natif | notif_token |
| Sandbox | Immédiate | Immédiate via Orange Developer |
| Délai prod | 1-2 semaines | 2-4 semaines |
| Frais | ~1 % | ~2-3 % |
| Pénétration utilisateurs | Très forte Sénégal/CI | Universelle Afrique francophone |
Recommandation : intégrer les deux pour maximiser la conversion. Wave domine en zone urbaine/jeunes, Orange Money est dominant pour B2B et population non-Wave.
Adaptation Afrique de l’Ouest
Pour un marchand au Sénégal qui vise la conversion maximum, l’intégration Wave + Orange Money couvre ~95 % des utilisateurs Mobile Money. Pour un marchand en Côte d’Ivoire, ajoutez MTN MoMo qui est important sur ce marché.
Erreurs fréquentes
| Erreur | Cause | Solution |
|---|---|---|
| 403 sur token | Application pas encore validée | Vérifier statut sur dashboard Orange Developer |
| « Invalid merchant_key » | Mauvaise clef sandbox vs prod | Distinguer ENV correctement |
| Notification jamais reçue | URL non HTTPS ou inaccessible | Tester avec ngrok ou Cloudflare Tunnel |
| Token expiré en plein appel | Pas de cache | Implémenter le cache avec marge 60s |
| Double traitement | Idempotence manquante | Vérifier statut avant update |
| Délai bascule prod long | KYC incomplet | Commencer KYC dès le début du projet |