API de paiement
Intégrez SigmaPay dans votre application en quelques lignes. Une seule API pour accepter Wave, Orange Money, Mixx by Yas et carte bancaire.
Introduction
SigmaPay est une passerelle de paiement multi-opérateurs pour le marché sénégalais. Elle expose une API REST JSON standard, compatible avec tous les langages et frameworks.
https://sigmapay.digitalDémarrage rapide
Prêt en 3 étapes :
Obtenir vos clés API
Créez un compte sur le dashboard et récupérez vos clés TEST et LIVE dans Paramètres → Clés API.
Créer un compte →Initier un paiement
Appelez POST /api/v1/payments depuis votre serveur. Vous recevez une checkoutUrl que vous retournez à votre client.
Recevoir le webhook
Configurez votre URL IPN dans le dashboard. SigmaPay vous notifie dès la confirmation du paiement.
Authentification
Toutes les requêtes authentifiées nécessitent le header Authorization: Bearer <clé_api>.
Authorization: Bearer sigmapay_live_xxxxxxxxxxxxxxxxxx
Content-Type: application/json| Champ | Type | Requis | Description |
|---|---|---|---|
| sigmapay_test_… | string | Non | Clé de test — aucun vrai paiement. À utiliser en développement. |
| sigmapay_live_… | string | Non | Clé de production — vrais paiements. À activer depuis le dashboard. |
Environnements
| Test | Production | |
|---|---|---|
| URL API | https://sigmapay.digital | https://sigmapay.digital |
| Préfixe clé | sigmapay_test_… | sigmapay_live_… |
| Vrais paiements | Jamais — toujours simulés | ⏳ Simulés (voir note) |
| Page de paiement | Bandeau « Mode test », paiement réussi simulé | Paiement réel auprès de l'opérateur |
| Webhook | "mode": "TEST" | "mode": "LIVE" |
| Statistiques et reversements | Exclus | Inclus |
"metadata": { "scenario": "fail" } au corps de la requête de création.Flux de paiement hébergé
SigmaPay fonctionne en mode checkout hébergé : vous créez le paiement depuis votre serveur, redirigez le client vers la page SigmaPay, il paie, et vous recevez un webhook de confirmation.
Créer un paiement
/api/v1/paymentsParamètres
| Champ | Type | Requis | Description |
|---|---|---|---|
| amount | integer | Oui | Montant en XOF, entier — le franc CFA n'a pas de centimes. Ex : 125000 = 125 000 XOF. Minimum : 1. |
| channel | string | Oui | WAVE | ORANGE_MONEY | FREE_MONEY | CARD |
| idempotencyKey | string | Oui | Clé anti-doublons, unique pour votre compte. Renvoyer la même clé renvoie le paiement déjà créé (avec son checkoutUrl), sans double débit ni erreur. |
| customerPhone | string | Non | Téléphone au format international. Ex : +221771234567 |
| customerEmail | string | Non | Email du client pour confirmation automatique |
| description | string | Non | Libellé affiché sur la page de paiement SigmaPay |
| returnUrl | string | Non | URL de redirection après paiement |
| metadata | object | Non | Données libres retournées dans le webhook. Ex : { studentId: "UCK-001" } |
idempotencyKey avec crypto.randomUUID() côté serveur pour éviter les doubles débits en cas de retry réseau.Exemples de code
const res = await fetch('https://sigmapay.digital/api/v1/payments', {
method: 'POST',
headers: {
'Authorization': 'Bearer sigmapay_live_votre_cle',
'Content-Type': 'application/json',
},
body: JSON.stringify({
amount: 125000, // 125 000 XOF
channel: 'WAVE',
idempotencyKey: crypto.randomUUID(),
customerPhone: '+221771234567',
description: 'Frais de scolarité S1 2026',
returnUrl: 'https://votre-site.sn/merci',
metadata: { studentId: 'UCK-2026-1042' },
}),
});
const { checkoutUrl } = await res.json();
// → "https://sigmapay.digital/pay/cpay_8f26b1f3..."
window.location.href = checkoutUrl;Réponse
{
"id": "clxyz1234abcd",
"reference": "TXN-a1b2c3d4-e5f6-...",
"status": "PENDING",
"amount": 125000,
"currency": "XOF",
"channel": "WAVE",
"mode": "LIVE",
"checkoutUrl": "https://sigmapay.digital/pay/cpay_8f26b1f3b9161d76...",
"createdAt": "2026-06-30T10:30:00.000Z"
}Statut d'une transaction
/api/v1/payments/:idconst res = await fetch('https://sigmapay.digital/api/v1/payments/clxyz1234abcd', {
headers: { 'Authorization': 'Bearer sigmapay_live_votre_cle' },
});
const { id, status, amount } = await res.json();
console.log(status); // "SUCCESS"Remboursement
/api/v1/payments/:id/refund| Champ | Type | Requis | Description |
|---|---|---|---|
| amount | integer | Non | Montant à rembourser en XOF. Si absent : remboursement total. |
| reason | string | Non | Motif du remboursement. Affiché dans le dashboard et le webhook. |
// Remboursement total
await fetch('https://sigmapay.digital/api/v1/payments/clxyz1234abcd/refund', {
method: 'POST',
headers: {
'Authorization': 'Bearer sigmapay_live_votre_cle',
'Content-Type': 'application/json',
},
body: JSON.stringify({ reason: 'Cours annulé — remboursement automatique' }),
});
// Remboursement partiel — 50 000 XOF sur 125 000 XOF
await fetch('https://sigmapay.digital/api/v1/payments/clxyz1234abcd/refund', {
method: 'POST',
headers: { 'Authorization': 'Bearer sigmapay_live_votre_cle', 'Content-Type': 'application/json' },
body: JSON.stringify({ amount: 50000, reason: 'Remboursement partiel' }),
});Webhooks (IPN)
SigmaPay envoie un POST HTTP à votre URL webhook à chaque changement de statut. Configurez-la depuis Dashboard → Paramètres → Webhooks.
Payload
Structure à plat, sans enveloppe data. Le champ event vaut toujours transaction.updated — c'est le champ status qui indique le résultat réel.
{
"event": "transaction.updated",
"transactionId": "clxyz1234abcd",
"reference": "TXN-a1b2c3d4-...",
"status": "SUCCESS",
"amount": 125000,
"currency": "XOF",
"channel": "WAVE",
"mode": "LIVE"
}mode vaut TEST pour un paiement créé avec votre clé de test : il est simulé, aucun argent n'a circulé. Vérifiez ce champ avant de livrer une commande, pour qu'un paiement de test ne débloque jamais un vrai produit.
metadata d'origine (studentId, order_id…). Pour retrouver votre commande, stockez l'association entre transactionId (retourné à la création du paiement) et votre propre identifiant, puis faites la correspondance à la réception du webhook — c'est ce que font nos plugins officiels (WooCommerce, Drupal, Moodle).Valeurs possibles du champ status :
SUCCESSPaiement confirméFAILEDPaiement échouéPARTIALLY_REFUNDEDRemboursement partiel — le reste est acquisREFUNDEDRemboursement totalCANCELLEDAnnulé par le clientVérifier la signature
Chaque webhook contient le header X-SigmaPay-Signature — un HMAC-SHA256 du body signé avec votre webhook secret.
const crypto = require('crypto');
app.post('/webhook/sigmapay', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['x-sigmapay-signature'];
const secret = process.env.SIGMAPAY_WEBHOOK_SECRET;
const expected = crypto
.createHmac('sha256', secret)
.update(req.body) // req.body = buffer brut (express.raw obligatoire)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig ?? ''))) {
return res.status(401).json({ error: 'Signature invalide' });
}
const { transactionId, status, amount } = JSON.parse(req.body.toString());
if (status === 'SUCCESS') {
// Retrouver votre commande via transactionId (stocké à la création du paiement)
// puis la marquer payée.
console.log('Paiement reçu :', amount, 'XOF — transaction :', transactionId);
}
res.json({ received: true });
});Sécurité et bonnes pratiques
Ce que SigmaPay garantit, et ce que nous vous demandons de respecter dans votre intégration.
Côté SigmaPay
- Chiffrement en transit : HTTPS obligatoire (TLS 1.2 minimum, HSTS) sur toutes les routes.
- Chiffrement au repos : vos secrets de webhook et les documents de vérification (KYC) sont chiffrés en AES-256-GCM, avec une clé conservée hors de la base de données.
- Clés API et mots de passe stockés uniquement sous forme d'empreinte : même SigmaPay ne peut pas les relire.
- Données personnelles minimisées sur les pages publiques : la page de paiement et la facture n'affichent qu'un numéro masqué (77 ••• •• 67) et un nom abrégé.
Côté marchand
- Suivez vos paiements par webhook, pas par des requêtes GET répétées.
GET /api/v1/payments/:idsert à une vérification ponctuelle et est limité à 60 requêtes par minute. - Ne mettez jamais de donnée sensible dans une URL (clé API, téléphone, email) : les URL restent dans les historiques et les journaux. La clé API va dans l'en-tête
Authorization, les données dans le corps des requêtes POST. - Vérifiez la signature de chaque webhook (
X-SigmaPay-Signature, voir plus haut) avant de livrer quoi que ce soit, et vérifiez son champmode. - Gardez votre clé API côté serveur, jamais dans une application mobile ou du code exécuté dans le navigateur.
- Limites : 100 requêtes par minute et par adresse IP sur l'ensemble de l'API ; au-delà, réponse
429: réessayez avec un délai croissant.
Stock limité : billets, places, dernier article
Si vous vendez un stock limité sur votre propre site, c'est votre site qui connaît ce stock : SigmaPay encaisse les paiements mais ne sait pas combien de billets il vous reste. Sans précaution, deux clients qui achètent le dernier billet au même moment peuvent être débités tous les deux. Voici comment l'éviter :
- Réservez le billet avant de créer le paiement, en une seule opération dans votre base (par exemple
UPDATE … SET stock = stock - 1 WHERE stock > 0). Si aucune ligne n'est modifiée, le billet est épuisé : n'appelez pas SigmaPay. - Créez ensuite le paiement, avec une
idempotencyKeypropre à la commande, et gardez letransactionIdreçu. - Libérez le billet si vous recevez un webhook
FAILEDouCANCELLED, ou si le client n'a pas payé au bout d'un délai que vous fixez (15 minutes, par exemple). - Ne livrez le billet qu'à la réception du webhook
SUCCESS.
maxUses. SigmaPay gère alors lui-même la réservation : deux clients simultanés ne peuvent pas obtenir la même place, et une place abandonnée est remise en vente au bout de 15 minutes.Opérateurs supportés
| Valeur channel | Opérateur | Type | Disponibilité |
|---|---|---|---|
WAVE | Wave | Mobile Money | ⏳ Simulé (voir note ci-dessus) |
ORANGE_MONEY | Orange Money | Mobile Money | ⏳ Simulé (voir note ci-dessus) |
FREE_MONEY | Mixx by Yas | Mobile Money | ⏳ Simulé (voir note ci-dessus) |
CARD | Carte bancaire | Visa / MC | ⏳ Simulé (voir note ci-dessus) |
Codes d'erreur
| HTTP | Code | Cause | Solution |
|---|---|---|---|
| 400 | VALIDATION_ERROR | Body invalide | Vérifier les champs requis et les types |
| 400 | CHANNEL_UNAVAILABLE | Canal choisi pas encore branché à un opérateur réel | Réessayer avec un autre canal, ou contacter support@sigmapay.sn pour connaître les canaux actifs |
| 401 | UNAUTHORIZED | Clé API manquante ou invalide | Vérifier le header Authorization |
| 403 | KYC_REQUIRED | Clé live utilisée avant vérification KYC | Soumettre le KYC depuis le dashboard, ou utiliser une clé test en attendant |
| 404 | NOT_FOUND | Transaction introuvable | Vérifier l'ID ou qu'il vous appartient |
| 422 | UNPROCESSABLE | Montant ≤ 0 ou opérateur invalide | Vérifier les valeurs envoyées |
| 429 | RATE_LIMIT | Trop de requêtes | Implémenter un backoff exponentiel |
| 500 | SERVER_ERROR | Erreur interne SigmaPay | Contacter support@sigmapay.sn avec votre requestId |
Testeur API interactif
Testez l'API directement depuis cette page sans quitter la documentation.
https://sigmapay.digital). Démarrez-le avec npm run start:dev dans le dossier racine.5000 = 5 000 XOF (pas de centimes)
Prêt à intégrer ?
Créez votre compte, récupérez vos clés API et acceptez vos premiers paiements.