Webhooks
Recevoir les événements, et pourquoi on les relit.
Pourquoi vous en avez besoin
Un encaissement ne se dénoue pas pendant votre requête. Le client doit valider sur son téléphone, ce qui prend de quelques secondes à plusieurs minutes — ou n'arrive jamais. Le webhook vous prévient quand l'issue est connue, au lieu de vous faire interroger l'API en boucle.
Déclarer une adresse
Depuis la console, section Développeurs. L'adresse doit être en HTTPS et joignable depuis Internet.
Un secret, préfixé whsec_, est généré avec elle et s'affiche
sous l'adresse : c'est lui qui signe les envois vers cette adresse, et lui
seul. Chaque adresse a le sien, donc en révoquer une ne touche pas les
autres. Il n'est pas votre clé API et ne s'utilise jamais à sa place.
Vérifier la signature
Chaque requête porte un en-tête MaticPay-Signature :
MaticPay-Signature: t=1793996400,v1=4f2a...e91c
v1 est le HMAC-SHA256 de t.corps — l'horodatage, un
point, le corps brut — calculé avec votre secret.
<?php
$brut = file_get_contents('php://input');
$entete = $_SERVER['HTTP_MATICPAY_SIGNATURE'] ?? '';
parse_str(str_replace(',', '&', $entete), $parts);
$attendu = hash_hmac('sha256', $parts['t'] . '.' . $brut, VOTRE_SECRET);
// Comparaison a temps constant : un == classique fuit la signature.
if (!hash_equals($attendu, $parts['v1'] ?? '')) {
http_response_code(400);
exit;
}
// Rejeter au-dela de quelques minutes : sinon un envoi capte reste rejouable.
if (abs(time() - (int) $parts['t']) > 300) {
http_response_code(400);
exit;
}
Signez sur le corps brut, avant tout décodage JSON : ré-encoder change les espaces et invalide la signature.
Les événements
payment.created·payment.succeeded·payment.failed·payment.refundedpayout.created·payout.approved·payout.executed·payout.failedinstallment_plan.activated·installment_plan.settled·installment_plan.rescheduled·installment_plan.defaultedpayment_link.created·balance.updated
Répondez vite, traitez après
Renvoyez 200 dès que vous avez enregistré l'événement, et faites
le travail ensuite. Un traitement long dans la requête finit en délai dépassé,
et nous réessayons alors que vous aviez déjà reçu l'information.
Un même événement peut arriver deux fois
C'est normal, et nous ne pouvons pas le garantir autrement : un envoi dont la réponse se perd sera renvoyé. Rendez votre traitement idempotent — retenez l'identifiant de l'événement et ignorez ce que vous avez déjà vu.
Et ne vous fiez pas au corps pour décider : s'il porte un enjeu d'argent,
relisez l'objet avec GET /api/v1/payments/{id}. C'est la règle
que nous appliquons nous-mêmes avec l'opérateur.