Websites11 min read

PayDunya SDK complete: site + IPN + settlement integration (2026)

Mohamed Bah·Fondateur, Kolonell
May 10, 2026
Share:
PayDunya SDK complete: site + IPN + settlement integration (2026)

PayDunya SDK complete: site + IPN + settlement integration (2026)

Websites

PayDunya handles ~38% of online payments in Francophone Africa as of late 2025. It's the reference aggregator when you want a single provider for Wave + Orange Money + card. But the official Node SDK has been stale since 2023, REST docs are scattered, and 80% of production integrations we audit have IPN bugs.

TL;DR

- Official Node SDK stale → use community paydunya-sdk or direct REST.

- 3 modes: direct-pay (wallet only), checkout (hosted page), onsite (advanced, strict KYC).

- HMAC-signed IPN webhook, idempotency mandatory.

- Settlement T+1 business day to UEMOA bank account or IBAN.

Target architecture

`

[Site] → init invoice → [PayDunya API]

[PayDunya hosted page]

[Customer pays: Wave / OM / card]

redirect IPN webhook

↓ ↓

[Return page] [POST /api/webhooks/paydunya]

[Verify signature]

[Mark order "paid"]

`

Step 1 — create developer account

  • paydunya.com → Sign up → "Developers"
  • TEST mode by default (test-... keys)
  • Switch to LIVE: full KYC (ID, RCCM, NINEA, IBAN) → 5-10 business day validation

Keys to retrieve:

  • MASTER_KEY (account ID)
  • PRIVATE_KEY (signature)
  • PUBLIC_KEY (frontend if onsite mode)
  • TOKEN (API auth)

Step 2 — invoice (checkout mode)

`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: Order ${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 };

}

`

Step 3 — IPN webhook

`ts

Need a professional website?

Kolonell builds websites that attract clients, optimized for the Sénégalese market. Free quote in 2 minutes.

import crypto from 'crypto';

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;

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 });

}

const existing = await prisma.paymentEvent.findUnique({ where: { externalId: data.invoice_token } });

if (existing) return NextResponse.json({ ok: true, deduped: true });

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 });

}

`

Step 4 — refunds

No public PayDunya refund API in May 2026. Procedure:

  • Request via PayDunya partner dashboard
  • Manual PayDunya team validation (24-72h)
  • Settlement per original timing

Partial automation: create refund_requests table with status, PayDunya agent validates, IPN callback received as confirmation.

Step 5 — alternative modes

Direct Pay (wallet only)

For ONLY Wave or OM, no PayDunya checkout page:

`ts

const res = await fetch('https://app.paydunya.com/api/v1/direct-pay/credit-account', {

method: 'POST',

headers: { /* ... keys ... */ },

body: JSON.stringify({ account_alias: '+221771234567', amount: '5000' }),

});

`

Onsite mode

Advanced: payment capture INSIDE your UI (no redirect). Requires Tier-2 KYC + PCI DSS audit if card. For 95% of cases, checkout mode is enough.

Common pitfalls

  • Test vs live: forgetting to switch keys in prod. Always detect via process.env.NODE_ENV.
  • unit_price as string: PayDunya requires string, not number. "5000" not 5000.
  • custom_data: needed to pass your order_id back in IPN.
  • IPN hash verification: 70% of integrations skip it → endpoint exposed.
  • Manual settlement: switch to "Auto settlement" in PayDunya dashboard, otherwise money stays in virtual account.

Fees and settlement

MethodFeesSettlement
Wave Senegal1.2-2.0% negotiatedT+1 UEMOA IBAN
Wave Ivory Coast2.0%T+1 UEMOA IBAN
Orange Money1.8-2.3%T+1 UEMOA IBAN
Visa/Mastercard3.5% + 100 XOFT+3 UEMOA IBAN
Free Money2.5%T+1

Negotiation possible from 2-3M XOF monthly volume — discuss with your PayDunya AM.

Real case — Dakar cosmetics shop (12 months)

MetricValue
Monthly volume14M XOF
Average PayDunya fees1.7%
12-month fee cost2.86M XOF
Payment failure rate4.2% (vs 11% other aggregator)
Bank settlement delayT+1 (never missed)

FAQ

Q: Node SDK or direct REST?

A: Direct REST — community SDK isn't maintained. More control, fewer bugs.

Q: Can I test without KYC?

A: Yes, TEST mode with sandbox keys. Payments are simulated. KYC required only to switch to LIVE.

Q: How many currencies?

A: XOF, XAF (CEMAC), GHS, NGN. EUR/USD via Stripe partnership.

Conclusion

PayDunya remains the best gateway for UEMOA-focused e-commerce in 2026. Clean end-to-end integration takes 3-5 dev-days. Immediate ROI: a reliable aggregator easily justifies 1.5-2% fees vs managing 4 separate connectors.

Tags:#PayDunya#API#SDK#Payments#Tutorial#UEMOA
Share:

Mohamed Bah

Fondateur, Kolonell

Passionate about digital and entrepreneurship in Africa, Mohamed has been helping Sénégalese businesses with their digital transformation since 2020. Founder of Kolonell, he believes every SME deserves a professional and accessible online présence.