Aller au contenu principal

Callbacks (notifications)

Quand une transaction atteint un statut final, MoyaPay envoie une requête POST à votre serveur.

Où sont-ils envoyés ?​

Aux URL de callback enregistrées sur votre compte par MoyaPay :

  • une URL pour les payins ;
  • une URL pour les payouts.

Pour les créer ou les modifier, contactez votre interlocuteur MoyaPay.

Contenu de la notification​

En-têtes :

En-têteValeur
Content-Typeapplication/json
X-SignatureSignature HMAC-SHA256 du corps, en hexadécimal

Corps :

{
"code": 200,
"status": "SUCCESS",
"message": "Your transaction is SUCCESS",
"transactionID": "COMMANDE-2026-000123",
"amount": "1000",
"date": "2026-10-04T10:15:30.000Z",
"motif": ""
}
ChampDescription
statusStatut final : SUCCESS ou FAILED
transactionIDVotre merchant_transaction_id
amountMontant de la transaction, sous forme de chaîne
dateDate de création de la transaction (ISO 8601)
motifMotif de l'échec quand l'opérateur en fournit un, sinon chaîne vide
code, messageValeurs informatives. Ne basez pas votre logique dessus

Vérifier la signature​

Calculez le HMAC-SHA256 du corps brut de la requête avec votre secret de signature, puis comparez-le à X-Signature. Rejetez la notification si les deux ne correspondent pas.

Utilisez le corps brut

La signature porte sur les octets exacts envoyés par MoyaPay. Si vous analysez le JSON puis le réencodez avant de calculer la signature, l'ordre ou le format des champs peut changer et la vérification échouera. Calculez-la sur le corps tel que reçu.

const crypto = require('crypto');
const express = require('express');

const app = express();

app.post(
'/api/moyapay/notify',
express.raw({ type: 'application/json' }), // corps brut (Buffer)
(req, res) => {
const received = req.get('X-Signature') || '';
const expected = crypto
.createHmac('sha256', process.env.MOYAPAY_CALLBACK_SECRET)
.update(req.body)
.digest('hex');

const valid =
received.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));
if (!valid) return res.sendStatus(401);

const event = JSON.parse(req.body.toString('utf8'));
// Traitement idempotent : event.transactionID, event.status
res.sendStatus(200);
},
);

Répondre à la notification​

  • Répondez avec un statut 2xx pour confirmer la réception.
  • Répondez en moins de 2 secondes : au-delà, MoyaPay abandonne l'appel. Confirmez d'abord, traitez ensuite (file d'attente, tâche asynchrone).

Fiabilité : ce qu'il faut prévoir​

Ne dépendez pas uniquement des callbacks

La notification est envoyée au moment où le statut final est enregistré. Il n'y a pas de planning de relance automatique si votre serveur est indisponible ou répond trop lentement à ce moment-là.

  • Si vous n'avez pas reçu de callback pour une transaction après un délai raisonnable, interrogez son statut.
  • Rendez votre traitement idempotent : une même transaction peut être notifiée plus d'une fois, et un FAILED peut être suivi d'un SUCCESS (voir Statuts).
  • Gardez votre secret de signature côté serveur et ne le publiez jamais (dépôt de code, application mobile, etc.).