PayDunya gère ~38 % des paiements en ligne en Afrique francophone fin 2025. C'est l'agrégateur de référence quand vous voulez un seul provider pour Wave + Orange Money + carte. Mais le SDK Node officiel est obsolète depuis 2023, la doc REST est éclatée, et 80 % des intégrations production qu'on audite ont des bugs IPN.
TL;DR
- SDK Node officiel obsolète → utiliser
paydunya-sdkcommunautaire ou REST direct.- 3 modes :
direct-pay(wallet seul),checkout(page hosted),onsite(avancé, KYC strict).- Webhook IPN signé HMAC, idempotence obligatoire.
- Reversement T+1 ouvré sur compte bancaire ou IBAN UEMOA.
Architecture cible
`
[Site] → init invoice → [PayDunya API]
↓
[Page hosted PayDunya]
↓
[Client paie : Wave / OM / carte]
↓
↓
redirect IPN webhook
↓ ↓
[Page retour] [POST /api/webhooks/paydunya]
↓
[Vérifier signature]
↓
[Mettre commande en "paid"]
`
Étape 1 — créer un compte développeur
paydunya.com→ S'inscrire → "Espace développeurs"- Mode TEST par défaut (clés
test-...) - Pour passer en LIVE : KYC complet (CNI, RCCM, NINEA, RIB) → validation 5-10 jours ouvrés
Clés à récupérer :
MASTER_KEY(identifiant compte)PRIVATE_KEY(signature)PUBLIC_KEY(frontend si onsite mode)TOKEN(auth API)
Étape 2 — invoice (mode checkout)
`ts
// lib/paydunya.ts
const PD_BASE = 'https://app.paydunya.com/api/v1';
interface CreateInvoiceInput {
orderId: string;
totalXof: number;
items: { name: string; qty: number; unitPriceXof: number }[];
customerEmail?: string;
customerName?: string;
customerPhone?: string;
}
export async function createInvoice(input: CreateInvoiceInput) {
const res = await fetch(${PD_BASE}/checkout-invoice/create, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'PAYDUNYA-MASTER-KEY': process.env.PD_MASTER_KEY!,
'PAYDUNYA-PRIVATE-KEY': process.env.PD_PRIVATE_KEY!,
'PAYDUNYA-TOKEN': process.env.PD_TOKEN!,
},
body: JSON.stringify({
invoice: {
total_amount: input.totalXof,
description: Commande ${input.orderId},
items: Object.fromEntries(
input.items.map((it, i) => [item_${i}, {
name: it.name,
quantity: it.qty,
unit_price: String(it.unitPriceXof),
total_price: String(it.unitPriceXof * it.qty),
}])
),
},
store: {
name: 'Kolonell Boutique',
},
custom_data: {
order_id: input.orderId,
},
actions: {
callback_url: 'https://kolonell.com/api/webhooks/paydunya',
return_url: https://kolonell.com/checkout/return?order=${input.orderId},
cancel_url: https://kolonell.com/checkout/cancel?order=${input.orderId},
},
}),
});
const data = await res.json();
if (data.response_code !== '00') {
throw new Error(PayDunya error: ${data.response_text});
}
return {
token: data.token,
redirectUrl: data.response_text, // URL hosted PayDunya
};
}
`
Étape 3 — webhook IPN
`ts
// app/api/webhooks/paydunya/route.ts
import crypto from 'crypto';
Besoin d'un site web professionnel ?
Kolonell crée des sites web qui attirent des clients, optimisés pour le marché sénégalais. Devis gratuit en 2 minutes.
import { NextRequest, NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';
export async function POST(req: NextRequest) {
const formData = await req.formData();
const data = Object.fromEntries(formData.entries()) as Record
// 1. Vérifier signature (hash_data) — PayDunya signe avec MASTER + PRIVATE keys
const expectedHash = crypto
.createHash('sha512')
.update(process.env.PD_MASTER_KEY! + data.invoice_token)
.digest('hex');
if (data.hash !== expectedHash) {
return NextResponse.json({ error: 'invalid_signature' }, { status: 401 });
}
// 2. Idempotence par invoice_token
const existing = await prisma.paymentEvent.findUnique({
where: { externalId: data.invoice_token },
});
if (existing) return NextResponse.json({ ok: true, deduped: true });
// 3. Vérifier le statut côté PayDunya (ne pas faire confiance au body seul)
const verifyRes = await fetch(
https://app.paydunya.com/api/v1/checkout-invoice/confirm/${data.invoice_token},
{
headers: {
'PAYDUNYA-MASTER-KEY': process.env.PD_MASTER_KEY!,
'PAYDUNYA-PRIVATE-KEY': process.env.PD_PRIVATE_KEY!,
'PAYDUNYA-TOKEN': process.env.PD_TOKEN!,
},
}
);
const verified = await verifyRes.json();
if (verified.status === 'completed') {
await prisma.$transaction([
prisma.paymentEvent.create({
data: {
externalId: data.invoice_token,
provider: 'paydunya',
type: 'invoice_completed',
payload: verified,
},
}),
prisma.order.update({
where: { id: verified.custom_data.order_id },
data: { status: 'paid', paidAt: new Date() },
}),
]);
}
return NextResponse.json({ ok: true });
}
`
Étape 4 — gestion des refunds
Pas d'API refund publique PayDunya en mai 2026. Procédure :
- Demande via dashboard PayDunya partenaire
- Validation manuelle équipe PayDunya (24-72h)
- Reversement effectué selon délai original
Pour automatiser partiellement : créer une table refund_requests avec statut, l'agent PayDunya valide, callback IPN reçu pour confirmation.
Étape 5 — modes alternatifs
Direct Pay (wallet uniquement)
Utile si vous voulez offrir UNIQUEMENT Wave ou OM, sans page checkout PayDunya :
`ts
const res = await fetch('https://app.paydunya.com/api/v1/direct-pay/credit-account', {
method: 'POST',
headers: { /* ... clés ... */ },
body: JSON.stringify({
account_alias: '+221771234567', // Wave alias = numéro
amount: '5000',
}),
});
`
Onsite mode
Avancé : capture du paiement DANS votre interface (sans redirection). Nécessite KYC niveau 2 + audit PCI DSS si carte. Pour 95 % des cas, mode checkout suffit.
Pièges fréquents
- Mode test vs live : oublier de switcher les clés en prod. Toujours détecter via
process.env.NODE_ENV. unit_priceen string : PayDunya impose la valeur en string, pas number."5000"pas5000.custom_data: nécessaire pour passer votreorder_idqui revient dans l'IPN.- Vérification hash IPN : 70 % des intégrations ne vérifient pas → endpoint exposé.
- Reversement manuel : passer en mode "Reversement automatique" dans dashboard PayDunya, sinon argent reste sur compte virtuel.
Frais et reversement
| Méthode | Frais | Reversement |
|---|---|---|
| Wave Sénégal | 1.2-2.0 % négocié | T+1 ouvré IBAN UEMOA |
| Wave Côte d'Ivoire | 2.0 % | T+1 ouvré IBAN UEMOA |
| Orange Money | 1.8-2.3 % | T+1 ouvré IBAN UEMOA |
| Carte Visa/Mastercard | 3.5 % + 100 FCFA | T+3 ouvré IBAN UEMOA |
| Free Money | 2.5 % | T+1 ouvré |
Négociation possible dès 2-3M FCFA volume mensuel — en discuter avec votre Account Manager PayDunya.
Cas réel — boutique cosmétique Dakar (12 mois)
| Métrique | Valeur |
|---|---|
| Volume mensuel | 14M FCFA |
| Frais PayDunya moyens | 1.7 % |
| Coût frais 12 mois | 2,86M FCFA |
| Taux échec paiement | 4,2 % (vs 11 % avec autre agrégateur) |
| Délai reversement bancaire | T+1 ouvré (jamais raté) |
FAQ
Q : SDK Node ou REST direct ?
R : REST direct — le SDK communautaire n'est pas maintenu. Plus de contrôle et moins de bugs.
Q : Peut-on tester sans KYC ?
R : Oui, mode TEST avec clés sandbox. Les paiements ne sont pas réels mais simulés. KYC obligatoire seulement pour passer en LIVE.
Q : Combien de devises supportées ?
R : XOF, XAF (CEMAC), GHS, NGN. EUR/USD via partenariat Stripe.
Conclusion
PayDunya reste la meilleure passerelle pour un e-commerce focused UEMOA en 2026. L'intégration end-to-end propre prend 3-5 jours-développeur. Le ROI est immédiat : un agrégateur fiable vaut nettement les frais 1.5-2 % vs gérer 4 connecteurs séparés.
Mohamed Bah
Fondateur, Kolonell
Passionné par le digital et l'entrepreneuriat en Afrique, Mohamed accompagne les entreprises sénégalaises dans leur transformation digitale depuis 2020. Fondateur de Kolonell, il croit que chaque PME mérite une présence en ligne professionnelle et accessible.
