Webhooks
Les webhooks sont des notifications HTTP POST qu'Avirato Payments envoie automatiquement à votre système lorsqu'un événement pertinent se produit : un paiement est finalisé, un remboursement est traité, une capture est confirmée, etc.
Pourquoi ils sont importants
Les webhooks sont le moyen le plus fiable de savoir qu'une opération s'est terminée. Contrairement à la redirection (urlOk/urlKo), qui dépend du retour du client sur votre page :
- Les webhooks arrivent toujours, même si le client ferme le navigateur
- Ils arrivent quelques secondes après que le processeur confirme l'opération
- Ils ne dépendent pas du comportement de l'utilisateur
Recommandation : utilisez les webhooks comme source principale de confirmation des opérations. Utilisez la redirection et le polling en complément.
Comment configurer votre URL de webhooks
Depuis Intégrations > Configuration Webhooks dans le tableau de bord, vous pouvez enregistrer une URL publique par environnement (Live et Test). Chaque URL peut être activée/désactivée séparément. Nous recommandons :
- Une URL HTTPS avec certificat valide.
- Un endpoint dédié à Avirato Payments (par exemple
https://votre-domaine.com/avirato-payments/webhooks). - Vous devez avoir une clé API active pour l'environnement avant de configurer son URL. Sinon, le tableau de bord répond avec 422.
Important : seuls les webhooks générés à partir du moment où l'URL est configurée et active sont envoyés. Les événements antérieurs ne sont pas renvoyés rétroactivement.
Vérification d'authenticité (signature HMAC)
Tous les webhooks live arrivent signés avec HMAC-SHA256 en utilisant le même client_secret qui vous est affiché lors de la création (ou rotation) de la clé API de l'environnement. En-têtes :
| En-tête | Valeur |
|---|---|
X-Avirato-Timestamp | Horodatage Unix (secondes) du moment de l'envoi |
X-Avirato-Signature | t={timestamp},v1={hmac} — où hmac = hash_hmac('sha256', timestamp + "." + body, client_secret) |
Exemple de vérification en PHP :
$timestamp = $_SERVER['HTTP_X_AVIRATO_TIMESTAMP'] ?? '';
$signature = $_SERVER['HTTP_X_AVIRATO_SIGNATURE'] ?? '';
$body = file_get_contents('php://input');
if (!preg_match('/^t=(\d+),v1=([a-f0-9]+)$/', $signature, $m)) {
http_response_code(400);
exit;
}
$expected = hash_hmac('sha256', $timestamp . '.' . $body, $clientSecret);
if (!hash_equals($expected, $m[2])) {
http_response_code(401);
exit;
}En Test, si vous avez créé une clé API test, les webhooks de test sont aussi signés avec son secret. Sinon, ils sont envoyés sans signature pour que vous puissiez explorer le format sans créer de clé API test pour l'instant.
Politique de nouvelles tentatives
En une ligne
Chaque fois qu'Avirato Payments vous envoie un webhook et que votre endpoint ne répond pas avec HTTP 200, il réessaie plus tard. L'attente entre chaque échec et la tentative suivante augmente : elle commence à 10 minutes et se termine à 48 heures. Après un total de 10 tentatives sans succès, Avirato Payments cesse de réessayer automatiquement.
Calendrier complet
Le tableau indique, pour un webhook qui échoue à chaque tentative, le moment exact où votre endpoint reçoit l'appel suivant, compté depuis le moment de l'événement d'origine (autorisation, remboursement, etc.).
| Tentative | Qu'est-ce que c'est | Quand vous le recevez (depuis l'événement) |
|---|---|---|
| 1 | Envoi initial | au moment de l'événement (≈ 0) |
| 2 | 1re nouvelle tentative | 10 min après |
| 3 | 2e nouvelle tentative | 30 min après |
| 4 | 3e nouvelle tentative | 1 h 10 min après |
| 5 | 4e nouvelle tentative | 2 h 40 min après |
| 6 | 5e nouvelle tentative | 5 h 40 min après |
| 7 | 6e nouvelle tentative | 11 h 40 min après |
| 8 | 7e nouvelle tentative | 23 h 40 min après |
| 9 | 8e nouvelle tentative | 1 jour 23 h 40 min après |
| 10 | 9e (et dernière) nouvelle tentative | ≈ 4 jours après (95 h 40 min) |
| — | — | à partir de là, plus de nouvelle tentative |
Au total, 10 tentatives (1 envoi initial + 9 nouvelles tentatives) réparties sur environ 4 jours. L'horloge ne se réinitialise pas à chaque tentative : plus vous répondez correctement tard, plus les tentatives suivantes sont espacées.
Comment savoir à quelle tentative nous en sommes
Dans le tableau de bord, dans Intégrations > Live > Webhooks, chaque ligne de l'historique affiche :
Tentatives: nombre de tentatives consommées jusqu'à présent (1 à 10).Dernière tentative: date et heure du dernier envoi.HTTP: code HTTP renvoyé par votre endpoint lors de cette dernière tentative.État:Livré(success),En attente(nouvelles tentatives encore possibles) ouÉchoué(non applicable en flux live tant qu'il reste des tentatives).
Si l'endpoint continue d'échouer
Si après les 10 tentatives (≈ 4 jours) votre endpoint n'a répondu correctement aucune fois, Avirato Payments cesse de réessayer automatiquement même si vous réparez votre système ensuite. Dans ce cas :
- Réactivez votre endpoint et vérifiez qu'il répond correctement aux webhooks normaux.
- Pour les événements restés en attente, ouvrez Intégrations > Live > Webhooks, identifiez les webhooks à l'état
En attenteet forcez le renvoi manuel via le bouton « Renvoyer ». Chaque renvoi manuel effectue un nouvel appel HTTP vers votre endpoint avec le même payload.
Si vous désactivez ou supprimez temporairement votre URL
- Tant que votre URL est désactivée (ou n'existe pas), Avirato Payments continue de mettre en file d'attente les webhooks des événements qui se produisent.
- Le cron continue de compter les tentatives : si vous réactivez l'URL dans la fenêtre d'environ ≈ 4 jours, les éléments en attente seront livrés automatiquement au prochain tick (tant qu'il reste des tentatives pour ce webhook précis).
- Passée cette fenêtre, les événements sont abandonnés et ne sont pas renvoyés même si vous réactivez l'URL. Vous devrez les demander manuellement depuis le tableau de bord si vous en avez besoin.
Comportement du renvoi manuel
- Si vous renvoyez manuellement un webhook qui était en attente de nouvelles tentatives et que le renvoi réussit, les nouvelles tentatives automatiques s'arrêtent — le webhook est considéré comme livré.
- Vous pouvez renvoyer un webhook déjà livré correctement. Le tableau de bord demandera une confirmation au préalable pour éviter les doublons accidentels, mais le renvoi s'exécute tout de même si vous le confirmez.
Source de vérité de l'état du paiement (Live)
En environnement Live, les notifications du processeur ont le dernier mot sur l'état réel du paiement. Un paiement peut donc changer d'état après que votre système l'ait traité comme finalisé.
Cas typiques où un webhook ultérieur peut inverser un succès antérieur :
- Chargeback : le titulaire conteste le débit auprès de sa banque
- Fraude détectée a posteriori : le processeur identifie une transaction frauduleuse des jours plus tard
- Réversion bancaire : la banque émettrice annule l'opération
- Correction du processeur : une notification antérieure contenait des données incomplètes ou incorrectes
Lorsque nous recevons l'un de ces événements en Live, nous mettons à jour l'état du paiement dans notre système (par exemple, de AUTHORISED à FAILED) et vous envoyons le webhook correspondant. Votre intégration doit :
- Accepter des webhooks asynchrones qui modifient le résultat d'un paiement précédemment réussi
- Traiter les webhooks (pas la réponse immédiate ni la redirection) comme référence pour le rapprochement et l'état final
- Consulter à nouveau l'API (
GET /payment/session/{sessionId}) lorsque vous avez besoin du dernier état connu
Test vs Live : en Test, les webhooks sont générés par notre propre simulateur et reflètent uniquement la simulation que vous avez lancée. Il n'y a pas de chargebacks ni de réversions en Test.
Format général
Tous les webhooks arrivent en POST sur votre URL avec ce format :
En-têtes
| En-tête | Valeur |
|---|---|
Content-Type | application/json |
webcode | Le webcode associé au paiement (ex. : SHOP01) |
Body
{
"event_code": "AUTHORISATION",
"data": {
...champs spécifiques à l'événement...
}
}Réponse attendue
Votre endpoint doit répondre avec HTTP 200. Le corps de la réponse n'est pas évalué — le code d'état suffit.
Si votre endpoint ne répond pas avec HTTP 200, le webhook sera réessayé automatiquement avec un backoff exponentiel.
---
Types d'événement
AUTHORISATION — Paiement finalisé (en ligne ou POS)
Envoyé lorsqu'un paiement (en ligne ou POS) est autorisé avec succès ou échoue.
{
"event_code": "AUTHORISATION",
"data": {
"amount": 15000,
"currency": "EUR",
"paymentReference": "SHOP01-PXT-17195000005678",
"paymentStatus": "AUTHORISED",
"description": "Pedido #12345 - Servicio premium",
"customReference": "ORD-2026-12345",
"paymentSource": "external_api"
}
}| Champ | Toujours présent | Description |
|---|---|---|
amount | Oui | Montant en centimes |
currency | Oui | Code ISO 4217 |
paymentReference | Oui | Référence du paiement |
paymentStatus | Oui | AUTHORISED si succès, FAILED si échec |
description | Oui | Description du paiement |
customReference | Non | Votre référence interne (si fournie à la création de la session/paiement) |
paymentSource | Non | Origine du paiement (ex. : external_api) |
failedReason | Non | Motif de l'échec (uniquement si le paiement a échoué) |
Comment identifier le type de paiement par la référence :
| Préfixe dans la référence | Type | Environnement |
|---|---|---|
-PXT- | Paiement en ligne | Live |
-PXTT- | Paiement en ligne | Test |
-POSX- | Paiement POS | Live |
-POSXT- | Paiement POS | Test |
Exemple de paiement POS réussi :
{
"event_code": "AUTHORISATION",
"data": {
"amount": 8500,
"currency": "EUR",
"paymentReference": "SHOP01-POSX-17195300001234",
"paymentStatus": "AUTHORISED",
"description": "Venta mostrador #205",
"customReference": "VENTA-205-20260628",
"paymentSource": "external_api"
}
}Exemple de paiement échoué (refusé) :
{
"event_code": "AUTHORISATION",
"data": {
"amount": 15000,
"currency": "EUR",
"paymentReference": "SHOP01-PXT-17195000005678",
"paymentStatus": "FAILED",
"description": "Pedido #12345",
"failedReason": "Refused",
"paymentSource": "external_api"
}
}Important : les webhooks sont envoyés pour les paiements réussis et échoués. Vérifiez toujours le champ
paymentStatuspour déterminer le résultat.
---
REFUND — Remboursement traité
Envoyé lorsqu'un remboursement est finalisé (succès ou échec) par le processeur.
{
"event_code": "REFUND",
"data": {
"amount": 5000,
"currency": "EUR",
"paymentReference": "SHOP01-PXT-17195000005678",
"refundReason": "CUSTOMER REQUEST",
"refundReference": "SHOP01-RFX-17195234567890",
"status": "success",
"customReference": "ORD-2026-12345",
"paymentSource": "external_api"
}
}| Champ | Toujours présent | Description |
|---|---|---|
amount | Oui | Montant remboursé en centimes |
currency | Oui | Code ISO 4217 |
paymentReference | Oui | Référence du paiement d'origine |
refundReason | Oui | Motif du remboursement (CUSTOMER REQUEST, FRAUD, RETURN, DUPLICATE, OTHER) |
refundReference | Oui | Référence de cette opération de remboursement |
status | Oui | success ou failed |
customReference | Non | Votre référence interne |
paymentSource | Non | Origine du paiement |
failedReason | Non | Motif de l'échec (uniquement si status: "failed") |
Exemple de remboursement échoué :
{
"event_code": "REFUND",
"data": {
"amount": 5000,
"currency": "EUR",
"paymentReference": "SHOP01-PXT-17195000005678",
"refundReason": "CUSTOMER REQUEST",
"refundReference": "SHOP01-RFX-17195234567890",
"status": "failed",
"failedReason": "Insufficient balance"
}
}---
PREAUTHORISATION — Résultat de capture, annulation ou extension
Envoyé lorsqu'une opération sur une préautorisation est terminée. Le champ action indique le type d'opération.
Capture finalisée
{
"event_code": "PREAUTHORISATION",
"data": {
"paymentReference": "SHOP01-PXT-17195123456789",
"action": "capture",
"result": "success",
"amount": 45000,
"currency": "EUR",
"customReference": "ORD-2026-67890",
"paymentSource": "external_api"
}
}Annulation finalisée
{
"event_code": "PREAUTHORISATION",
"data": {
"paymentReference": "SHOP01-PXT-17195123456789",
"action": "cancellation",
"result": "success",
"customReference": "ORD-2026-67890",
"paymentSource": "external_api"
}
}Extension finalisée
{
"event_code": "PREAUTHORISATION",
"data": {
"paymentReference": "SHOP01-PXT-17195123456789",
"action": "extend",
"result": "success",
"expirationDate": "2026-08-15T00:00:00Z",
"customReference": "ORD-2026-67890",
"paymentSource": "external_api"
}
}| Champ | Toujours présent | Description |
|---|---|---|
paymentReference | Oui | Référence du paiement préautorisé |
action | Oui | capture, cancellation ou extend |
result | Oui | success ou failure |
amount | Uniquement capture | Montant capturé en centimes |
currency | Uniquement capture | Code ISO 4217 |
expirationDate | Uniquement extend réussi | Nouvelle date d'expiration |
customReference | Non | Votre référence interne |
paymentSource | Non | Origine du paiement |
failedReason | Non | Motif de l'échec (uniquement si result: "failure") |
Exemple de capture échouée (montant dépasse l'autorisé) :
{
"event_code": "PREAUTHORISATION",
"data": {
"paymentReference": "SHOP01-PXT-17195123456789",
"action": "capture",
"result": "failure",
"failedReason": "Payment already captured, cannot capture again"
}
}Note sur le flux des modifications : toutes les modifications (remboursement, capture, annulation, extension) sont asynchrones. La réponse immédiate de l'API renvoie l'état
received, indiquant que la requête a été acceptée pour traitement. Le résultat final (successoufailed) arrive ensuite via webhook. L'intégrateur ne doit pas considérer l'opération comme terminée avant de recevoir le webhook de confirmation.
---
CHARGEBACK — Rétrofacturation
Envoyé lorsqu'un titulaire de carte initie une rétrofacturation contre un paiement. Les rétrofacturations sont traitées par l'émetteur de la carte et peuvent prendre des jours ou des semaines à se résoudre.
{
"event_code": "CHARGEBACK",
"data": {
"paymentReference": "SHOP01-PXT-17195123456789",
"chargebackReference": "SHOP01-CHB-17195123456789",
"action": "chargeback",
"result": "success",
"amount": 15000,
"currency": "EUR",
"reason": "Fraudulent transaction",
"chargebackReasonCode": "10.4",
"chargebackSchemeCode": "VISA_10_4",
"defensePeriodEndsAt": "2026-06-15",
"defendable": true,
"disputeStatus": "Undefended",
"paymentSource": "external_api"
}
}| Champ | Toujours présent | Description |
|---|---|---|
paymentReference | Oui | Référence du paiement d'origine |
chargebackReference | Oui | Référence unique de la rétrofacturation |
action | Oui | Toujours chargeback |
result | Oui | success ou failure |
amount | Oui | Montant en centimes |
currency | Oui | Devise ISO 4217 |
reason | Oui | Motif de la rétrofacturation |
chargebackReasonCode | Non | Code motif du schéma de carte |
chargebackSchemeCode | Non | Code du schéma (Visa, Mastercard, etc.) |
defensePeriodEndsAt | Non | Date limite pour contester la rétrofacturation |
defendable | Non | true si vous pouvez contester la rétrofacturation |
disputeStatus | Non | État du litige (Undefended, Defended, etc.) |
failedReason | Non | Motif si result est failure |
paymentSource | Non | Origine du paiement (external_api, etc.) |
---
NOTIFICATION_OF_CHARGEBACK — Avis préalable de rétrofacturation
Avis anticipé qu'une rétrofacturation peut être en cours. Tous les processeurs ne l'envoient pas. Il vous permet de vous préparer avant le traitement formel de la rétrofacturation.
{
"event_code": "NOTIFICATION_OF_CHARGEBACK",
"data": {
"paymentReference": "SHOP01-PXT-17195123456789",
"chargebackReference": "SHOP01-CHB-17195123456789",
"action": "notification_of_chargeback",
"result": "success",
"amount": 15000,
"currency": "EUR",
"reason": "Cardholder disputes transaction",
"chargebackReasonCode": "10.4",
"chargebackSchemeCode": "VISA_10_4",
"defensePeriodEndsAt": "2026-06-15",
"defendable": true,
"disputeStatus": "Undefended",
"autoDefended": false,
"arn": "74027600000012345678901",
"paymentSource": "external_api"
}
}Contient les mêmes champs que CHARGEBACK plus deux champs optionnels supplémentaires :
| Champ | Description |
|---|---|
autoDefended | true si le processeur a contesté automatiquement la rétrofacturation |
arn | Acquirer Reference Number — identifiant de la transaction de l'acquéreur |
---
Webhooks en environnement Test
En environnement Test, les webhooks ne proviennent pas du processeur de paiement réel. Ils sont générés automatiquement par le backend d'Avirato Payments immédiatement après la finalisation de l'opération simulée.
Différences avec Live
| Aspect | Live | Test |
|---|---|---|
| Qui envoie | Le processeur de paiement | Le backend d'Avirato Payments |
| Quand ça arrive | Secondes à minutes après l'opération | 1 à 3 secondes après la réponse HTTP |
| Format | Identique | Identique |
| Champs | Identiques | Identiques |
| Nouvelles tentatives automatiques | Oui (backoff exponentiel, jusqu'à ~4 jours) | Non : le simulateur effectue un seul envoi |
| Renvoi manuel | Oui, depuis le tableau de bord | Oui, depuis le tableau de bord (même bouton) |
| Critère de succès HTTP | HTTP 200 | HTTP 200 |
Ce qu'il faut savoir
- Le format est exactement le même : vous pouvez développer votre logique de traitement des webhooks en Test et elle fonctionnera en Live sans changement
- Ils arrivent pour les paiements réussis ET échoués : en Live comme en Test, vous recevrez des webhooks lorsqu'un paiement est refusé ou qu'une opération échoue
- URLs indépendantes par environnement : les webhooks Test sont envoyés à l'URL configurée pour l'environnement Test, et ceux Live à l'URL Live. Configurez les deux depuis le panneau webhooks du tableau de bord
- Les références utilisent les suffixes Test : les
paymentReferenceetoperationReferencecontiendront les préfixes de test (-PXTT-,-POSXT-,-RFXT-, etc.) - Critère de succès simple : en Live comme en Test, il suffit que votre endpoint réponde HTTP 200 pour que le webhook soit marqué comme livré. Tout autre code d'état est considéré comme un échec et déclenche les nouvelles tentatives (en Live) ou reste en échec dans le tableau de bord (en Test).
- Renvoi manuel disponible en Test et Live : depuis le panneau webhooks du tableau de bord, vous pouvez renvoyer manuellement un webhook précis. En Test comme en Live, le renvoi utilise l'URL actuellement configurée pour cet environnement, pas l'URL utilisée lors de l'envoi d'origine. Si vous renvoyez un webhook déjà livré, le tableau de bord demandera une confirmation explicite pour éviter les doublons accidentels.
Exemple de webhook de test (paiement en ligne réussi)
{
"event_code": "AUTHORISATION",
"data": {
"amount": 15000,
"currency": "EUR",
"paymentReference": "SHOP01-PXTT-17195000005678",
"paymentStatus": "AUTHORISED",
"description": "Pedido test #12345",
"customReference": "TEST-ORD-12345",
"paymentSource": "external_api"
}
}Exemple de webhook de test (POS refusé)
{
"event_code": "AUTHORISATION",
"data": {
"amount": 10077,
"currency": "EUR",
"paymentReference": "SHOP01-POSXT-17195300001234",
"paymentStatus": "FAILED",
"description": "Venta test #100",
"failedReason": "Refused",
"paymentSource": "external_api"
}
}---
Référence rapide
| Opération | event_code | action (le cas échéant) | Comment identifier l'API externe |
|---|---|---|---|
| Paiement en ligne finalisé | AUTHORISATION | — | paymentReference contient -PXT- (Live) ou -PXTT- (Test) |
| Paiement POS finalisé | AUTHORISATION | — | paymentReference contient -POSX- (Live) ou -POSXT- (Test) |
| Remboursement traité | REFUND | — | refundReference contient -RFX- (Live) ou -RFXT- (Test) |
| Capture traitée | PREAUTHORISATION | capture | Opération sur un paiement API externe |
| Annulation traitée | PREAUTHORISATION | cancellation | Opération sur un paiement API externe |
| Extension traitée | PREAUTHORISATION | extend | Opération sur un paiement API externe |
| Rétrofacturation reçue | CHARGEBACK | — | Rétrofacturation initiée par le titulaire de la carte |
| Notification de rétrofacturation | NOTIFICATION_OF_CHARGEBACK | — | Avis préalable d'une possible rétrofacturation |
---
Bonnes pratiques
Idempotence sur votre endpoint
Votre endpoint de webhook peut recevoir la même notification plus d'une fois (nouvelles tentatives ou doublons du processeur). Assurez-vous que traiter le même webhook deux fois ne pose pas de problème : utilisez paymentReference ou refundReference comme clé de déduplication.
Réponse rapide
Répondez au webhook le plus tôt possible (idéalement en moins de 5 secondes). Si vous devez effectuer un traitement lourd, mettez le travail en file d'attente et répondez immédiatement avec HTTP 200.
Ne dépendez pas d'un seul canal
Utilisez les webhooks comme canal principal, mais implémentez aussi :
- Vérification post-redirection : lorsque le client revient sur
urlOk, consultezGET /payment/session/{id}pour confirmer - Polling de sécurité : un processus périodique qui consulte les sessions en état
pendinganciennes pour détecter les paiements finalisés que vous n'auriez pas traités