Vue d'ensemble
En attente
FR
EN
🚀
Bienvenue sur NDSGPay — votre compte est en attente d'activation
Votre compte sera activé par l'équipe NDSG après vérification de votre dossier. L'API et les vrais paiements seront disponibles dès l'activation. En attendant, préparez votre intégration avec l'onglet Documentation.
✓
Compte créé
2
Vérification du dossier (KYC) en cours
3
Intégration API
4
Go-live
Volume total
0 XAF
— Depuis le début
Transactions
0
— En attente
Taux de succès
—
Données insuffisantes
Solde disponible
0 XAF
— Collecté - Frais - Payouts
Volume par jour — 7 derniers jours
Collecte
Payout
Aucune donnée pour l'instant — les graphiques se mettront à jour automatiquement
Dernières transactions
Aucune transaction
Vos transactions apparaîtront ici dès que vous aurez intégré l'API NDSGPay.
Toutes les transactions
Aucune transaction pour l'instant
Intégrez l'API NDSGPay pour commencer à collecter des paiements mobile money.
Relevé
Aucune ligne pour l'instant
Ton relevé apparaîtra ici dès qu'une transaction sera complétée.
Demandez le virement de votre solde disponible vers votre compte bancaire.
Historique des virements
Aucune demande de virement
Cliquez sur "Demander un virement" pour transférer votre solde vers votre compte bancaire.
Collecte (total)
0 XAF
Frais : 3% / tx
Payout (total)
0 XAF
Frais : 2% / tx
Taux de succès
—
Insuffisant
Frais générés
0 XAF
Depuis le début
Répartition par opérateur
Données insuffisantes
Les analytics se rempliront automatiquement dès vos premières transactions.
Clés API
Clé publique Chargement...
Clé secrète sk_live_••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
Clé publique — identifie votre compte
Clé secrète — pour les appels API serveur
Webhook
URL callback Non configurée — allez dans Paramètres pour la définir
NDSGPay enverra un POST sur cette URL à chaque transaction confirmée ou échouée. Configurez-la dans Paramètres.
Correspondants disponibles
Pays Opérateur Code correspondent Devise
🇬🇦 GabonAirtel MoneyAIRTEL_GABXAF
🇨🇲 CamerounMTN MoMoMTN_MOMO_CMRXAF
🇨🇲 CamerounOrange MoneyORANGE_CMRXAF
🇨🇬 CongoAirtel MoneyAIRTEL_COGXAF
🇨🇬 CongoMTN MoMoMTN_MOMO_COGXAF
🇧🇯 BéninMTN MoMoMTN_MOMO_BENXOF
🇧🇯 BéninMoov MoneyMOOV_BENXOF
🇨🇮 Côte d'IvoireMTN MoMoMTN_MOMO_CIVXOF
🇨🇮 Côte d'IvoireOrange MoneyORANGE_CIVXOF
🇸🇳 SénégalOrange MoneyORANGE_SENXOF
🇸🇳 SénégalFree MoneyFREE_SENXOF
🇨🇩 RDCAirtel MoneyAIRTEL_CODCDF
🇨🇩 RDCOrange MoneyORANGE_CODCDF
🇨🇩 RDCVodacomVODACOM_MPESA_CODCDF
🇰🇪 KenyaM-PesaMPESA_KENKES
🇷🇼 RwandaAirtel MoneyAIRTEL_RWARWF
🇷🇼 RwandaMTN MoMoMTN_MOMO_RWARWF
🇺🇬 OugandaAirtel MoneyAIRTEL_OAPI_UGAUGX
🇺🇬 OugandaMTN MoMoMTN_MOMO_UGAUGX
🇿🇲 ZambieAirtel MoneyAIRTEL_OAPI_ZMBZMW
🇿🇲 ZambieMTN MoMoMTN_MOMO_ZMBZMW
🇿🇲 ZambieZamtelZAMTEL_ZMBZMW
🇸🇱 Sierra LeoneOrange MoneyORANGE_SLESLE
Solde disponible
—
Collecté – Frais – Payouts
Soldes par opérateur
Chargement...
Initier un retrait
Opérateur
Numéro mobile
Préfixe pays sans 0 (ex: 24174XXXXXX)
Montant (XAF)
Min : 100 XAF Tout retirer
Description (max 22 car.)
Historique des retraits
Aucun retrait
Initiez votre premier retrait depuis le formulaire.
Base URL
# Production NDSGPay
https://ndsgpay-backend.vercel.app/api

# Authentification : utilisez votre clé secrète NDSGPay (sk_live_)
# NE PAS utiliser un token PawaPay — NDSGPay gère PawaPay pour vous
# Les requêtes POST doivent envoyer l'en-tête Content-Type: application/json
# Limites par clé API : 60 créations de paiement/min, 120 consultations/min (HTTP 429 au-delà)
# Opérateurs : contactez support@ndsgservices.com pour la liste activée sur votre compte
Endpoints
POST /api/pay/deposits Initier une collecte
const res = await fetch("https://ndsgpay-backend.vercel.app/api/pay/deposits", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${votre_sk_live_xxx}`,
    "Content-Type": "application/json"
  },
  // Pas de depositId à envoyer : NDSGPay génère l'identifiant et vous le renvoie.
  body: JSON.stringify({
    amount: "5000",               // en XAF
    currency: "XAF",
    correspondent: "AIRTEL_GAB",  // code opérateur : AIRTEL_GAB, MTN_MOMO_CMR, MTN_MOMO_BEN...
    msisdn: "24177000000",        // numéro du client, format international sans + ni espaces
    description: "Commande 1042"  // facultatif, vu par votre client : accents et symboles sont retirés, 22 caractères max
  })
});
const data = await res.json();

// Réponse 200
// {
//   "success": true,
//   "depositId": "b3f0c8e2-...",  // généré par NDSGPay : conservez-le pour suivre la transaction
//   "status": "INITIATED",
//   "message": "Paiement initié. Le client va recevoir une demande de confirmation sur son téléphone."
// }
//
// Erreurs
// 400  { "success": false, "error": "Champs requis manquants : msisdn" }          (liste les champs manquants)
// 400  { "success": false, "error": "Corps de requête vide ou illisible. Envoyez du JSON avec l'en-tête Content-Type: application/json." }
// 400  { "success": false, "error": "Montant invalide : indiquez un nombre positif, sans espace ni séparateur (ex : 5000)." }
// 400  { "success": false, "error": "Correspondant invalide : ..." }   ou refus de l'opérateur
// 401  clé API manquante ou invalide          403  compte non activé
// 429  trop de requêtes                       500  erreur à l'initiation (voir le champ "details")
POST /api/pay/payouts Envoyer des fonds
const res = await fetch("https://ndsgpay-backend.vercel.app/api/pay/payouts", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${votre_sk_live_xxx}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    amount: "10000",
    currency: "XAF",
    correspondent: "AIRTEL_GAB",
    msisdn: "24166000000",                // numéro du bénéficiaire, format international sans + ni espaces
    description: "Remboursement client"   // facultatif, vu par votre client : accents et symboles retirés, 22 car. max
  })
});
const data = await res.json();

// Réponse 200
// { "success": true, "payoutId": "...", "status": "INITIATED", "message": "Virement initié. ..." }
//
// Le payout est prélevé sur votre solde NDSGPay (collectes encaissées, moins les frais).
// Le montant PLUS les frais NDSGPay doivent tenir dans ce solde, sinon :
// 400  { "success": false, "error": "Solde insuffisant. Maximum : 9708 XAF (frais NDSGPay inclus)" }
// 400  { "success": false, "error": "..." }   si l'opérateur refuse (ex : montant au-dessus de sa limite)
GET /api/deposits/:depositId Statut d'une collecte
const res = await fetch(`https://ndsgpay-backend.vercel.app/api/deposits/${depositId}`, {
  headers: { "Authorization": `Bearer ${votre_sk_live_xxx}` }
});
const data = await res.json();

// Réponse 200
// {
//   "success": true,
//   "deposit": {
//     "depositId": "b3f0c8e2-...",
//     "status": "COMPLETED",
//     "amount": 5000,
//     "currency": "XAF",
//     "correspondent": "AIRTEL_GAB",
//     "msisdn": "24177000000",
//     "description": "Commande 1042",
//     "failureCode": null,
//     "failureMessage": null
//     // ... autres champs
//   }
// }
//
// status : INITIATED, SUBMITTED (en cours), puis COMPLETED ou FAILED (définitifs)
// 404  transaction introuvable          403  transaction d'un autre compte
GET /api/payouts/:payoutId Statut d'un payout
const res = await fetch(`https://ndsgpay-backend.vercel.app/api/payouts/${payoutId}`, {
  headers: { "Authorization": `Bearer ${votre_sk_live_xxx}` }
});
const data = await res.json();

// Réponse 200 : { "success": true, "payout": { "payoutId": "...", "status": "COMPLETED", "amount": 10000, ... } }
//
// status : INITIATED, SUBMITTED, ACCEPTED, ENQUEUED (en cours), puis COMPLETED ou FAILED (définitifs)
Webhooks (NDSGPay vers votre serveur)
POST votre URL webhook Notification de statut
// Renseignez votre URL dans Paramètres > URL webhook.
// NDSGPay envoie un POST à chaque statut final (COMPLETED ou FAILED) :
{
  "event": "deposit.updated",         // ou "payout.updated"
  "timestamp": "2026-10-11T10:15:00.000Z",
  "data": {
    "depositId": "b3f0c8e2-...",      // ou "payoutId" : l'identifiant renvoyé à la création
    "status": "COMPLETED"             // ou "FAILED"
    // ... autres champs du message PawaPay : ne vous fiez qu'à l'identifiant et au statut
  }
}

// En-têtes envoyés :
// Content-Type: application/json
// X-NDSGPay-Event: deposit.updated
// X-NDSGPay-Merchant: <votre identifiant marchand>
// X-NDSGPay-Signature: t=1760177700,sha256=<signature>    (secret affiché dans Paramètres)
//
// À savoir
// - Répondez en 2xx en moins de 5 secondes. NDSGPay n'essaie qu'une seule fois : il n'y a pas de nouvel envoi.
// - Ne vous reposez pas uniquement sur les webhooks : pour une transaction encore en cours après quelques
//   minutes, interrogez GET /api/deposits/:id (ou /api/payouts/:id).
// - Une transaction corrigée plus tard par la réconciliation automatique de NDSGPay n'émet pas de webhook.
POST votre URL webhook Vérifier la signature (Node.js)
const crypto = require("crypto");
const express = require("express");
const app = express();

// Vérifie que le webhook vient bien de NDSGPay (secret : Paramètres > Secret de signature webhook)
function verifierSignatureNdsgpay(corpsBrut, entete, secret, toleranceSec = 300) {
  const parts = Object.fromEntries(entete.split(",").map((p) => p.split("=")));
  const t = parts.t;
  const signature = parts.sha256;
  if (!t || !signature) return false;
  if (Math.abs(Date.now() / 1000 - Number(t)) > toleranceSec) return false;   // anti-rejeu
  const attendu = crypto.createHmac("sha256", secret).update(`${t}.${corpsBrut}`).digest("hex");
  const a = Buffer.from(attendu);
  const b = Buffer.from(signature);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

// IMPORTANT : vérifiez sur le corps BRUT (le texte exact reçu), jamais sur un JSON ré-sérialisé
app.post("/webhooks/ndsgpay", express.raw({ type: "application/json" }), (req, res) => {
  const corps = req.body.toString("utf8");
  const entete = req.headers["x-ndsgpay-signature"] || "";
  if (!verifierSignatureNdsgpay(corps, entete, process.env.NDSGPAY_WEBHOOK_SECRET)) {
    return res.sendStatus(400);
  }
  const evenement = JSON.parse(corps);
  // ... mettez à jour votre commande avec evenement.data.depositId (ou payoutId) et evenement.data.status
  res.sendStatus(200);
});
Membres de l'équipe
Chargement…
Caisses POS
Clés API restreintes pour vos caissiers
Chargement...
Informations du compte
NDSGPay enverra un POST sur cette URL à chaque transaction confirmée ou échouée.
Secret de signature webhook
Webhook secret ••••••••••••••••••••••••
Utilisez ce secret pour vérifier l'authenticité des webhooks NDSGPay. Header : X-NDSGPay-Signature
Environnement
Le passage en production nécessite la validation de votre dossier KYC par l'équipe NDSG.
Sécurité