Documentation

Documentation de l'API NguePay : intégrer en sandbox, puis en live

Une seule API pour Orange Money et la carte bancaire, puis Wave et MTN MoMo dès leur ouverture. Vous développez sur l'environnement sandbox, puis vous passez en live en changeant l'adresse de l'API et vos clés. Votre code reste le même.

Afficher les exemples pour :

Environnements

Chaque compte NguePay dispose de deux environnements totalement séparés : comptes, clés, transactions et webhooks ne sont jamais partagés entre eux.

Sandbox Live
UsageDéveloppement et testsPaiements réels de vos clients
Dashboarddashboard.sandbox.nguepay.comdashboard.live.nguepay.com
URL de l'APIhttps://api.sandbox.nguepay.com/api/v1https://api.live.nguepay.com/api/v1
Clé secrètesk_sandbox_…sk_live_…
Clé publiquepk_sandbox_…pk_live_…
Argent réelNonOui
AccèsDès l'inscriptionAprès validation de votre dossier KYC

Une clé sandbox ne fonctionne que sur l'API sandbox, et une clé live que sur l'API live. Si vous mélangez les deux, l'API répond 401 avec le code NGP001.

Clés API

Créez vos clés depuis la rubrique Clés API du dashboard de l'environnement voulu. Chaque jeu contient deux clés :

  • Clé secrète (sk_…) : pour les appels depuis votre serveur. Elle ne doit jamais apparaître dans une page web, une application mobile ou un dépôt de code.
  • Clé publique (pk_…) : pour le navigateur (SDK JS). Elle ne permet que de créer une session de paiement, et seulement depuis les domaines que vous avez déclarés.

La clé secrète n'est affichée qu'une fois, à sa création. Rangez-la dans une variable d'environnement de votre serveur. Toutes les requêtes passent la clé dans l'en-tête Authorization :

sandbox
Authorization: Bearer sk_sandbox_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Pour vérifier votre clé, appelez GET /ping :

sandbox
curl https://api.sandbox.nguepay.com/api/v1/ping \
  -H "Authorization: Bearer sk_sandbox_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Premier paiement

  1. Créez le paiement depuis votre serveur avec POST /payments, en indiquant le montant en XOF, le moyen de paiement et votre référence de commande.
  2. Redirigez votre client vers le checkout_url renvoyé, ou laissez-le valider sur son téléphone selon le moyen choisi.
  3. Attendez le webhook payment.succeeded ou payment.failed avant de valider la commande.
sandbox
curl -X POST https://api.sandbox.nguepay.com/api/v1/payments \
  -H "Authorization: Bearer sk_sandbox_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 5000,
    "provider": "orange",
    "reference": "CMD-20481",
    "description": "Commande CMD-20481",
    "webhook_url": "https://votresite.ci/webhooks/nguepay"
  }'

Réponse (201 à la création, 200 si la même référence a déjà été soumise) :

{
  "success": true,
  "message": "Paiement initié.",
  "data": {
    "uuid": "9d3f1c2a-…",
    "status": "pending",
    "provider_code": "orange",
    "amount_xof": 5000,
    "currency": "XOF",
    "reference": "CMD-20481",
    "checkout_url": "https://pay.…nguepay.com/…",
    "expires_at": "2026-10-14T10:15:00Z"
  }
}

Idempotence. Une même reference ne peut être payée qu'une fois. Si votre serveur renvoie la requête après une coupure réseau, NguePay renvoie la transaction existante au lieu d'en créer une seconde.

Suivre un paiement

Le webhook est la source de vérité. Vous pouvez aussi interroger une transaction à tout moment avec son uuid :

sandbox
curl https://api.sandbox.nguepay.com/api/v1/payments/9d3f1c2a-… \
  -H "Authorization: Bearer sk_sandbox_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
StatutSignification
pendingPaiement créé, en attente du client.
processingLe client a validé, confirmation de l'opérateur en cours.
succeededPaiement encaissé. Vous pouvez livrer.
failedPaiement refusé, annulé par le client ou expiré. Le motif est dans failure_reason (par exemple expired si le client n'a pas payé avant expires_at).
canceledPaiement annulé avant d'être payé.

Webhooks

Déclarez l'URL de votre serveur dans Paramètres → Webhook du dashboard, ou transmettez webhook_url à la création d'un paiement. Faites-le dans chaque environnement : l'URL et le secret de signature sandbox ne servent pas en live.

NguePay envoie un POST JSON à chaque changement d'état :

ÉvénementQuand
payment.initiatedLe paiement est créé.
payment.succeededLe paiement est encaissé.
payment.failedLe paiement a échoué ou expiré.

Chaque envoi porte les en-têtes X-NguePay-Event, X-NguePay-Delivery, X-NguePay-Timestamp et X-NguePay-Signature. La signature est un HMAC-SHA256 (hexadécimal) de la chaîne {timestamp}.{corps brut}, calculé avec votre secret de webhook. Vérifiez-la avant tout traitement, et refusez les requêtes dont l'horodatage a plus de 5 minutes.

import crypto from "node:crypto";

// Express : app.post("/webhooks/nguepay", express.raw({ type: "application/json" }), handler)
function verifierNguePay(req) {
  const ts = req.get("X-NguePay-Timestamp");
  const sig = req.get("X-NguePay-Signature") || "";
  if (!ts || Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
  const attendu = crypto
    .createHmac("sha256", process.env.NGUEPAY_WEBHOOK_SECRET)
    .update(`${ts}.${req.body}`)
    .digest("hex");
  return sig.length === attendu.length &&
    crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(attendu));
}

Répondez par un code 2xx rapidement. Sans réponse 2xx, NguePay réessaie jusqu'à 3 fois (après 1, 5 puis 30 minutes). Un même événement peut donc arriver plusieurs fois : traitez-le une seule fois, en vous appuyant sur l'uuid de la transaction.

Passer en live

Votre intégration sandbox fonctionne de bout en bout ? Le passage en live se fait sans changer votre code, seulement votre configuration.

  1. Faites valider votre KYC depuis le dashboard sandbox : RCCM, pièce d'identité du représentant légal et compte de reversement.
  2. Connectez-vous au dashboard live sur dashboard.live.nguepay.com et activez vos moyens de paiement.
  3. Générez vos clés live (sk_live_…, pk_live_…) dans Clés API. Déclarez les domaines autorisés pour la clé publique.
  4. Configurez le webhook live : URL de production et nouveau secret de signature.
  5. Changez trois variables sur votre serveur de production, puis faites un premier paiement réel de faible montant.

.env sandbox

NGUEPAY_API_URL=https://api.sandbox.nguepay.com/api/v1
NGUEPAY_SECRET_KEY=sk_sandbox_…
NGUEPAY_WEBHOOK_SECRET=…secret sandbox…

.env live

NGUEPAY_API_URL=https://api.live.nguepay.com/api/v1
NGUEPAY_SECRET_KEY=sk_live_…
NGUEPAY_WEBHOOK_SECRET=…secret live…

Référence : créer un paiement

POST /payments · authentification par clé secrète.

ChampTypeDescription
amount requisentierMontant en XOF, sans décimales, de 100 à 5 000 000.
provider requistexteorange (Orange Money) ou stripe (carte bancaire). wave et mtn seront acceptés à leur ouverture.
reference requistexte (150 max)Votre référence de commande, unique.
phonetexteNuméro mobile money du client, au format international (+225…).
emaile-mailE-mail du client.
descriptiontexte (255 max)Libellé affiché au client.
webhook_urlURLRemplace l'URL de webhook du compte pour ce paiement.
metadataobjetDonnées libres, renvoyées telles quelles.

Dans la réponse, amount_xof donne le montant en XOF. Le champ amount est exprimé en centimes (5000 XOF → 500000).

Codes d'erreur

En cas d'erreur, la réponse contient "success": false, un message et un error_code.

CodeSignification
NGP001Clé API invalide, ou clé utilisée sur le mauvais environnement.
NGP002Montant invalide (hors de 100 à 5 000 000 XOF).
NGP003Moyen de paiement momentanément indisponible.
NGP004Numéro de téléphone invalide.
NGP005Transaction déjà traitée.
NGP006Signature webhook invalide.
NGP007Trop de requêtes, réessayez plus tard.
NGP008Ressource introuvable.
NGP009Transaction refusée pour raison de sécurité.
NGP010Moyen de paiement non activé sur votre compte.
NGP011Plafond mensuel dépassé.
NGP015Clé publique sans domaine déclaré.

Documentation complète

Le détail de chaque sujet, avec des exemples en cURL, PHP, JavaScript et Python :

Une question sur l'intégration ? Écrivez à contact@nguepay.com. Pour une vue d'ensemble, lisez aussi comment accepter les paiements en ligne en Côte d'Ivoire.