Réconciliation

Retrouver l'issue d'un paiement quand la notification n'est pas arrivée.

az54 rejoue la notification sortante, journalise chaque tentative, et vous laisse relire l'état à la demande. Tout ce qui suit est accessible avec une clé d'API seule — aucun jeton de session n'est nécessaire.

Le rejeu automatique

Une notification qui n'aboutit pas est rejouée jusqu'à 6 fois :

TentativeÉmise àÉcart avec la précédente
1immédiatement—
2T+30 s30 s
3T+2 min 30 s2 min
4T+12 min 30 s10 min
5T+1 h 12 min 30 s1 h
6T+7 h 12 min 30 s6 h

Chaque tentative a son propre timeout de 30 secondes et ne suit aucune redirection : un 301 ou un 302 sur votre URL est un échec. La chaîne s'arrête au premier 2xx.

Trois causes d'échec ne sont pas rejouées, parce qu'aucune tentative de plus ne les résoudrait ; le catalogue plus bas les marque comme telles. L'absence de secret de signature, elle, est rejouée : c'est la fenêtre transitoire d'une rotation menée à l'envers (révoquer avant de créer), et la tentative suivante trouvera le nouveau secret.

Une notification non terminale peut aussi être abandonnée en cours de chaîne : si la transaction est devenue terminale entre-temps, livrer un pending six heures plus tard vous ferait régresser. Les transitions étant monotones, seule la notification terminale compte.

Lire l'état à la demande

Deux lectures, selon l'identifiant que vous avez en main.

Par identifiant az54 — GET /v1/transactions/by-id/{transactionId} (référence). C'est le champ id renvoyé par POST /v1/pay-in et POST /v1/pay-out, et le champ transactionId du corps du webhook. La réponse porte la transaction complète — fee, netAmount, cause d'échec, failedAt — et le journal des notifications (section suivante).

Par votre identifiant — GET /v1/transactions?orderId=votre-order-id (référence). Correspondance exacte, qui vous évite de conserver l'identifiant az54. La réponse est une page de liste : elle ne porte pas le journal. Les autres filtres — status, type, failureCategory, dateFrom/dateTo, page, limit — sont dans la référence ; ce sont eux qui servent à balayer un lot en une requête.

Les deux lectures sont scopées à votre organisation. Un id appartenant à une autre organisation répond 404 NOT_FOUND, exactement comme un id inexistant.

Elles consomment le quota général, 1000 requêtes par 15 minutes, compté par seau dérivé de votre clé (Erreurs et limites). De quoi relire sans compter, pas de quoi interroger chaque commande en boucle : une requête filtrée qui ramène un lot vaut mieux que N appels unitaires.

Le journal des tentatives

GET /v1/transactions/by-id/{transactionId} renvoie un tableau notifications[], une entrée par tentative d'émission, de la plus ancienne à la plus récente.

{
  "attemptNo": 2,
  "url": "https://exemple.test/webhooks/az54",
  "httpStatus": 500,
  "errorKind": "HTTP_ERROR",
  "errorDetail": "Request failed with status code 500",
  "durationMs": 214,
  "createdAt": "2026-09-02T18:04:31.882Z"
}

errorKind vaut null sur un envoi réussi, et sinon l'une de ces six valeurs :

errorKindCe qui s'est passéRejoué
HTTP_ERRORVotre serveur a répondu hors 2xx. httpStatus porte son code.oui
NETWORK_ERRORRien n'est arrivé : timeout, DNS injoignable, connexion refusée.oui
SKIPPED_NO_SECRETAucun secret de signature actif sur l'organisation. Rien n'a été posté.oui
SKIPPED_NO_URLNi webhookUrl sur la transaction, ni repli d'organisation. url est null.non
BLOCKED_UNSAFE_URLL'URL résout vers une IP non publique, ou son schéma n'est pas https.non
MISSING_CURRENCYAnomalie côté az54 : la devise de la transaction n'a pas pu être résolue.non

errorDetail est un indice de debug, tronqué à 500 caractères et non contractuel. durationMs ne mesure que la requête HTTP : il est null quand aucune n'a été tentée.

Trois propriétés du journal :

  • attemptNo repart à 1 à chaque notification. Une transaction en émet plusieurs (une par changement de statut, plus la mise à disposition d'une authorizationUrl), et chacune a sa propre chaîne de rejeu. Compter les lignes ne donne donc pas le nombre de notifications émises.
  • Une chaîne plus courte que les 6 tentatives est normale : elle s'est arrêtée sur un 2xx, sur une cause non rejouable, ou parce qu'un statut terminal l'a périmée.
  • Le journal est borné aux 50 tentatives les plus récentes, et les lignes sont conservées 30 jours. Archivez ce dont vous avez besoin au-delà.

Renvoyer une notification

POST /v1/transactions/by-id/{transactionId}/resend-callback

Pas de corps (référence). La réponse 200 signifie « renvoi programmé » : l'appel enfile une nouvelle notification, avec sa propre chaîne de 6 tentatives. Ce n'est pas un envoi synchrone — relisez notifications[] pour en connaître l'issue.

Trois contraintes :

  • Réservé aux transactions terminales (completed, failed, cancelled). Sur created, initiated, pending ou processing, la réponse est un 409 CONFLICT : il n'y a rien de définitif à renvoyer, et le rejeu automatique est de toute façon encore en cours.
  • 3 requêtes par minute et par transaction. Le renvoi déclenche une chaîne entière côté az54 : ce n'est pas un bouton sur lequel s'appuyer en boucle.
  • Le corps renvoyé porte l'état courant, pas l'événement historique : le statut terminal de la transaction, avec sa cause d'échec si elle a échoué. nextAction.authorizationUrl y figure si une URL d'autorisation avait été émise, mais elle est alors probablement expirée côté prestataire — et une transaction encore en cours de redirection n'est pas renvoyable, puisqu'elle n'est pas terminale.

La procédure

  1. Répondez 2xx d'abord, traitez ensuite, et gardez votre handler de webhook idempotent.
  2. Sur un 502 ou un timeout, rejouez la même requête avec le même orderId (Idempotence).
  3. Balayez périodiquement, par lot. Une requête sur la période concernée (dateFrom/dateTo, limit=100) ramène tout ce qu'il faut rapprocher chez vous. C'est ce qui remplace l'attente indéfinie d'une notification — et ça coûte une requête, pas une par commande.
  4. Quand une transaction est terminale mais que vous n'avez rien reçu, lisez notifications[] par identifiant az54 : errorKind vous dit si le problème est chez vous (HTTP_ERROR, NETWORK_ERROR), dans votre configuration (SKIPPED_NO_URL, SKIPPED_NO_SECRET, BLOCKED_UNSAFE_URL) ou chez nous (MISSING_CURRENCY).
  5. Corrigez, puis renvoyez. Un renvoi avant correction rejoue les mêmes six échecs.

Ce que la réconciliation ne couvre pas encore

  • Pas de relevé comptable par API. Ni export CSV, ni endpoint de relevé asynchrone : GET /v1/transactions paginé est le seul chemin. L'export CSV du tableau de bord ne fait rien d'autre que parcourir ces pages.
  • Pas de soldes par clé d'API. GET /v1/balances exige un jeton de session.
  • Une authorizationUrl manquée n'est pas récupérable. Elle n'est portée par aucune lecture, et le renvoi étant réservé aux transactions terminales, un pay-in en redirection dont la notification s'est perdue se relance avec un nouvel orderId (Workflows de pay-in).
  • Pas de repli d'URL réglable par clé d'API. Un repli d'organisation existe côté az54 — SKIPPED_NO_URL en tient compte — mais s'y régler est un réglage de compte, pas une surface d'intégration : session seule, non exposé par le tableau de bord aujourd'hui. Détail dans Webhook sortant.

On this page