Référence des événements
Chaque événement, le moment où il part, et la charge utile qu'il transporte.
Enveloppe commune
Toute livraison a la même forme : un POST dont le corps JSON contient exactement deux clés, event et data. Il n'y a ni identifiant d'événement, ni date d'émission, ni mode (live / sandbox) dans le corps : l'identifiant et l'horodatage sont dans les en-têtes.
| En-tête | Contenu |
|---|---|
X-NguePay-Signature | HMAC-SHA256 hexadécimal (minuscules) de "{timestamp}.{corps brut}", avec le secret de la destination. |
X-NguePay-Timestamp | Horodatage Unix (secondes) de cette tentative : il change à chaque relance, la signature aussi. |
X-NguePay-Event | Nom de l'événement, identique à event dans le corps. |
X-NguePay-Delivery | uuid de la livraison, stable d'une relance à l'autre, rejeu manuel compris. C'est l'uuid de GET /webhooks/{uuid}. Chaque destination a le sien : un même événement livré à deux destinations porte deux identifiants différents. |
Content-Type | application/json. Barres obliques et caractères accentués ne sont pas échappés dans le corps. |
POST https://votre-site.ci/webhooks/nguepay
X-NguePay-Signature: 4f2a9c…
X-NguePay-Timestamp: 1789412345
X-NguePay-Event: payment.succeeded
X-NguePay-Delivery: 7d1f8e20-4c33-4a9b-b0e1-92c7a5d3f604
Content-Type: application/json
{
"event": "payment.succeeded",
"data": { … }
}Catalogue
| Événement | Déclenché quand | Action attendue |
|---|---|---|
payment.succeeded | L'opérateur confirme l'encaissement. | Marquer la commande payée, livrer. |
payment.failed | Refus opérateur : solde, code erroné, rejet. | Libérer le stock, proposer un autre moyen. |
payment.canceled | L'opérateur signale l'annulation du paiement (ex. Orange), ou NguePay corrige le statut. Une annulation que vous faites par POST /transactions/{uuid}/cancel n'envoie pas de webhook : la réponse de l'appel suffit. | Libérer le stock. |
refund.succeeded | Un remboursement a été exécuté. | Mettre à jour la comptabilité, notifier le client. |
payout.succeeded | Un virement sortant est arrivé chez le bénéficiaire — envoi automatique, ou envoi par l'équipe NguePay (Orange Money). | Marquer le versement comme effectué. |
payout.failed | Le virement n'a pas abouti : refusé lors de la validation NguePay (failure_reason: "rejected_by_review"), échec de l'envoi par l'équipe NguePay (manual_execution_failed), refus de l'opérateur, ou fonds de l'opérateur restés insuffisants pendant 24 h (operator_float_insufficient). La provision vous est rendue. | Corriger les coordonnées, relancer sous une nouvelle référence. |
payout.canceled | Vous avez annulé le virement avant son envoi (y compris pendant la validation NguePay). | Rien — informatif. |
webhook.test | Vous déclenchez un test depuis le dashboard. | Répondre 200. Ne rien traiter en métier. |
expired, ou failed avec failure_reason: "expired"), pour un remboursement échoué, ni pour un refus récupérable sur la page de paiement — relisez par API. Exception : une session Stripe expirée produit payment.failed.payment.canceled s'écrit avec un seul « l » sur le canal serveur. Le SDK JavaScript expose historiquement payment.cancelled côté navigateur : deux canaux, deux orthographes, et aucune des deux ne bougera sans préavis.
Charges utiles
payment.succeeded · payment.failed · payment.canceled
{
"event": "payment.succeeded",
"data": {
"transaction_id": "9f1c0c2e-2b4a-4f0d-9a1b-6d2f7c3e4a55",
"status": "succeeded",
"amount": 1500000,
"currency": "XOF",
"reference": "cmd_10452",
"provider": "orange",
"paid_at": "2026-09-17T22:03:41+00:00"
}
}| Champ | Type | Description |
|---|---|---|
transaction_id | uuid | L'uuid de la transaction (GET /payments/{uuid}). |
status | chaîne | succeeded, failed ou canceled — le même que dans event. |
amount | entier | Montant en centimes : divisez par 100 pour obtenir des XOF. Il n'y a pas de amount_xof dans ce webhook. |
currency | chaîne | XOF. |
reference | chaîne | Votre référence de commande — c'est par elle que vous retrouvez la commande. |
provider | chaîne | null | Opérateur : orange pour Orange Money (absent pour Stripe, voir ci-dessous). wave, mtn et pawapay sont temporairement indisponibles. |
paid_at | date | null | Date d'encaissement (+00:00) ; null pour un échec ou une annulation. |
Ni failure_reason, ni metadata, ni refunded_amount_xof : relisez la transaction par API si vous en avez besoin.
payment.succeeded et payment.failed ne portent que transaction_id, status et reference — pas de amount, currency, provider ni paid_at. Ne rendez pas ces champs obligatoires dans votre traitement.refund.succeeded
{
"event": "refund.succeeded",
"data": {
"transaction_id": "9f1c0c2e-2b4a-4f0d-9a1b-6d2f7c3e4a55",
"refund_id": "b17e3a44-9c21-4f77-8a0e-1d5c2b9f3e10",
"amount": 500000
}
}| Champ | Type | Description |
|---|---|---|
transaction_id | uuid | Transaction remboursée. |
refund_id | uuid | L'uuid du remboursement (GET /refunds/{uuid}). |
amount | entier | Montant de ce remboursement, en centimes (pas le cumul). |
status, reference | chaîne | Seulement pour un remboursement fait depuis la console Stripe : status est alors celui de la transaction (succeeded), pas du remboursement, et reference votre référence de commande. |
Chaque remboursement partiel produit son propre refund.succeeded, avec son propre refund_id.
payout.succeeded · payout.failed · payout.canceled
{
"event": "payout.succeeded",
"data": {
"payout_id": "5c8e1a70-2b31-4f0c-9d22-77ab3e1f9c44",
"reference": "vir_vendeur_10452",
"status": "succeeded",
"review": null,
"amount": 500000,
"amount_xof": 5000,
"currency": "XOF",
"provider": "orange",
"beneficiary": "orange — ************00",
"failure_reason": null,
"awaiting_operator_funds": false,
"processed_at": "2026-09-18T10:15:42+00:00"
}
}| Champ | Type | Description |
|---|---|---|
payout_id | uuid | L'uuid du virement (GET /payouts/{uuid}). |
reference | chaîne | Votre référence de virement. |
status | chaîne | succeeded, failed ou canceled. |
review | chaîne | null | Étape de validation NguePay (awaiting_approval, awaiting_execution), comme dans l'objet Virement ; renseignée seulement pour un virement encore pending, donc null dans ces trois événements. |
amount / amount_xof | entier | Centimes / XOF entiers. |
currency | chaîne | XOF. |
provider | chaîne | null | Connecteur qui a exécuté le virement (orange). |
beneficiary | chaîne | Opérateur et numéro masqué, ex. orange — ************00. |
failure_reason | chaîne | null | Motif d'échec : rejected_by_review, manual_execution_failed, operator_float_insufficient ou motif de l'opérateur. |
awaiting_operator_funds | booléen | true tant que le virement attend l'approvisionnement du compte NguePay chez l'opérateur. |
processed_at | date | null | Date de conclusion (+00:00). |
beneficiary est masqué : un webhook part vers une URL que NguePay ne contrôle pas, le numéro complet n'a rien à y faire. Retrouvez le bénéficiaire par reference. Pas de metadata ni de description dans ce webhook. Détail complet sur Virements sortants.
webhook.test
{
"event": "webhook.test",
"data": {
"message": "Ceci est une livraison de test NguePay.",
"endpoint": "3c2a1b08-77de-4c31-9a12-0b8e5f6d4a91",
"sent_at": "2026-09-17T22:10:00+00:00"
}
}message est un texte fixe, endpoint l'uuid de la destination testée — seule destinataire de ce test —, sent_at l'heure de la demande de test.
S'abonner à un sous-ensemble
Une destination sans liste d'événements les reçoit tous, y compris ceux que NguePay ajoutera plus tard. Une destination avec une liste ne reçoit que ce qu'elle a demandé — et ne verra jamais les nouveaux événements sans que vous les ajoutiez.
Ordre d'arrivée
Les événements ne sont pas garantis dans l'ordre : un rejeu après backoff peut arriver après un événement plus récent. Fiez-vous au status transporté et, en cas de doute, relisez la transaction par API plutôt que de reconstruire une chronologie.