Developer Portal Webhooks

Webhooks

Recevez des notifications en temps réel lorsqu'une transaction change de statut. Chaque notification est signée HMAC-SHA256 pour garantir son authenticité.

Configuration

Configurez votre URL webhook lors de la génération de votre clé API ou via le dashboard marchand. Votre endpoint doit :

  • Répondre en HTTPS
  • Retourner HTTP 200 en moins de 10 secondes
  • Vérifier la signature X-Signature

Types d'événements

ÉvénementDéclencheur
payin.successPaiement entrant confirmé
payin.failedPaiement entrant refusé ou timeout
payin.pendingPaiement entrant en attente de confirmation
payout.successVirement sortant confirmé
payout.failedVirement sortant échoué

Format du payload

json Exemple payin.success
{
  "event": "payin.success",
  "transaction_id": "PAY_XYZABC123456_1719100000",
  "provider": "jeko",
  "provider_ref": "d22c81f3-ee04-4ec5-8bd2-cd8af5dabcfc",
  "status": "success",
  "message": "Payment confirmed.",
  "action_url": null,
  "timestamp": "2024-06-23T12:00:00+00:00"
}

Vérification de la signature

Chaque requête webhook inclut le header X-Signature avec une signature HMAC-SHA256 du payload :

text Header X-Signature
X-Signature: sha256=a1b2c3d4e5f6...
X-Event: payin.success

Vérification en PHP

php Laravel — Vérification HMAC
public function handleWebhook(Request $request): JsonResponse
{
    $secret    = env('ENVOIFACILE_WEBHOOK_SECRET');
    $payload   = $request->getContent();
    $signature = $request->header('X-Signature');

    $expected = 'sha256=' . hash_hmac('sha256', $payload, $secret);

    if (!hash_equals($expected, $signature ?? '')) {
        return response()->json(['error' => 'Invalid signature'], 401);
    }

    $data  = $request->json()->all();
    $event = $data['event'];
    $trxId = $data['transaction_id'];

    match ($event) {
        'payin.success' => $this->onPayinSuccess($trxId, $data),
        'payout.success' => $this->onPayoutSuccess($trxId, $data),
        'payin.failed', 'payout.failed' => $this->onPaymentFailed($trxId, $data),
        default => null,
    };

    return response()->json(['received' => true]);
}

Vérification en Node.js

javascript Express.js — Vérification HMAC
const crypto = require('crypto');

app.post('/webhook/envoifacile', express.raw({ type: 'application/json' }), (req, res) => {
  const secret    = process.env.ENVOIFACILE_WEBHOOK_SECRET;
  const signature = req.headers['x-signature'];
  const payload   = req.body;

  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');

  if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  const data = JSON.parse(payload);
  console.log(`Event: ${data.event} | Trx: ${data.transaction_id}`);

  res.json({ received: true });
});

Utilisez toujours hash_equals ou timingSafeEqual

Ne comparez jamais les signatures avec == ou ===. Ces opérateurs sont vulnérables aux attaques timing. Utilisez hash_equals() (PHP) ou crypto.timingSafeEqual() (Node.js).

Politique de retry

Si votre endpoint ne répond pas HTTP 200 dans les 10 secondes, nous retentons automatiquement :

TentativeDélaiStatut webhook
1ère (immédiate)0spending
2ème+60spending
3ème (finale)+5minabandoned si échec

Idempotence de votre endpoint

Votre endpoint peut recevoir le même événement plusieurs fois (retries). Utilisez le transaction_id comme clé d'idempotence côté réception.