Vérifiez toujours les montants et les bénéficiaires avant l’envoi.
Base URL : https://api.faygaw.org/v1. Gardez votre clé API sur votre serveur.
Créez une session avec une description du produit et votre référence.
Ouvrez le checkout_link retourné ; le client choisit Wave ou Orange Money.
Conservez le checkout_id et interrogez GET /checkouts/{checkout_id} pour confirmer le paiement.
Collections Postman simplifiées.
Les créations Payout et Direct-Link ont chacune une requête Wave et une requête OM. Seules les variables base_url, api_key, expected_environment et payout_phone_number sont utilisées selon la collection. Modifiez les autres exemples directement dans les requêtes. Les clés Idempotency-Key et références sont déjà renseignées ; changez-les pour une nouvelle opération, conservez-les pour un rejeu. Pour une lecture, remplacez l’identifiant d’exemple dans l’URL par celui reçu à la création.
Utilisez Authorization: Bearer <api_key>. Les clés commencent par fg_sbx_ pour SANDBOX ou fg_prod_ pour PROD. La clé complète est authentifiée ; son préfixe ne suffit pas.
Scopes : checkout:write pour créer, checkout:read pour lire et balance:read pour les soldes. Une clé reste côté serveur.
Préparer votre intégration dans le portail
Dans l’espace Partenaire, ouvrez Développeur pour créer une clé API, configurer les IP publiques de vos serveurs et vos endpoints webhook. Choisissez uniquement les permissions nécessaires et conservez les clés et secrets sur votre serveur.
Dans la liste des clés API, utilisez « Modifier les permissions » pour activer ou retirer des permissions sans changer la clé utilisée par votre intégration. La valeur confidentielle n’est pas réaffichée. Décocher toutes les permissions bloque les appels de cette clé sans la révoquer. Pour la création comme pour la modification, ne sélectionnez que les permissions nécessaires.
Les menus Développeur et Finance donnent accès aux outils d’intégration et aux opérations financières.Création d’une clé API : nommer l’intégration et sélectionner ses permissions.
Dans Transactions, la colonne MSISDN présente le compte client au format international sans + (chiffres uniquement). Le détail présente aussi le numéro brut reçu du provider. Pour un partenaire Sénégal, un numéro local OM à neuf chiffres est normalisé avec 221 ; un numéro international Wave garde son indicatif. La recherche exacte accepte le numéro international avec ou sans +, ou le format national lorsque le pays est connu. Les dates UTC sont affichées sur deux lignes et les filtres de période et de recherche sont regroupés.
Autoriser les IP de vos serveurs
Configurez les IP publiques de sortie de vos serveurs dans Partenaire > Développeur > Whitelist IP. IPv4, IPv6, CIDR et plages sont acceptés : une entrée par ligne, 25 lignes par ajout. Sans règle active correspondant à l’IP source, l’API répond HTTP 403 ip-not-allowed. Retirer la dernière règle active bloque les appels API dans cet environnement. Attendez l’activation affichée avant vos tests. Cette liste ne concerne ni les pages de paiement du client, ni votre récepteur webhook.
Ajout des IP autorisées : saisir une adresse ou une plage par ligne.Modification d’une règle IP : changer le libellé, l’adresse ou son activation.Suppression d’une règle IP : recopier l’adresse complète pour confirmer.
Transactions du portail
Consultez vos opérations et leurs détails dans l’espace Partenaire. Utilisez les identifiants retournés par l’API pour les retrouver.
Environnements
La même URL https://api.faygaw.org/v1 dessert SANDBOX et PROD. La clé authentifiée détermine le Partner et l’environnement. Aucun paramètre de requête ne permet de changer d’environnement.
Spécificités SANDBOX
Utilisez une clé fg_sbx_ pour SANDBOX et une clé fg_prod_ pour PROD.
Vérifiez toujours les montants et les bénéficiaires avant l’envoi.
Les limites SANDBOX s’appliquent indépendamment par provider et par partenaire. Par défaut, le minimum Checkout est de 10 XOF et le minimum Payout de 100 XOF. Les minimums et plafonds SANDBOX peuvent être adaptés sur demande du partenaire auprès de Faygaw, après validation. Respectez les limites indiquées dans la réponse d’erreur et contactez Faygaw si une adaptation est nécessaire.
Montants et devises
Les montants sont des chaînes exprimées dans la devise demandée. Pour XOF, utilisez un entier positif ; un suffixe décimal composé uniquement de zéros est accepté et normalisé. Conservez les montants retournés comme chaînes pour préserver leur précision.
Idempotence
Idempotency-Key est optionnelle et recommandée pour Checkout : 1 à 191 caractères imprimables, clé à forte entropie, sans expiration. Réutilisez la même clé et le même corps après une réponse incertaine.
Même demande normalisée : HTTP 201 et même session. Corps différent : HTTP 409. La portée est partenaire, environnement, opération et clé. client_reference est obligatoire mais non unique ; conservez aussi le checkout_id.
Limites de requêtes
HTTP 429 indique qu’une limite de requêtes est atteinte. Respectez Retry-After avant de réessayer avec la même clé d’idempotence et le même corps. Ne remplacez pas une opération dont le résultat reste incertain.
Crée une session Checkout et retourne le lien de paiement à ouvrir pour le client. client_reference est obligatoire ; Idempotency-Key est recommandée. Réutilisez la même clé et le même corps après une réponse incertaine. Une saisie invalide renvoie HTTP 400 avec error.message et, le cas échéant, error.details[].field. Utilisez les limites indiquées dans l’erreur de montant.
Vérifiez toujours les montants et les bénéficiaires avant l’envoi.
Consulte l’état courant du Checkout. Les champs provider, provider_reference, faygaw_partner_fee et net_amount peuvent être null avant la sélection du moyen de paiement. Un retour navigateur ne confirme pas le paiement.
Crée un Checkout Direct-Link avec Wave ou Orange Money au Sénégal, en XOF. Retournez launch_options à votre application : WAVE pour Wave ; ORANGE_MONEY et MAXIT pour Orange Money, même si leurs URL sont identiques. Utilisez checkout:write, une IP autorisée et de préférence une Idempotency-Key stable. Sa portée est distincte de Hosted Checkout. Modifier le provider ou le corps avec la même clé entraîne HTTP 409. Après un timeout, conservez la même clé et le même corps. Une réponse 503 peut contenir un snapshot checkout : conservez son identifiant. Confirmez le paiement avec GET ou checkout.paid signé.
Vérifiez toujours les montants et les bénéficiaires avant l’envoi.
OPEN, PROCESSING et UNKNOWN ne prouvent pas un paiement. SUCCEEDED confirme le paiement. FAILED, EXPIRED et CANCELLED sont des états terminaux sans paiement réussi. Utilisez le statut API et les événements signés. Dans Hosted Checkout, le client sélectionne son moyen de paiement. Les URL de retour servent à la navigation et ne constituent jamais une preuve de paiement.
Le Payout est disponible avec Wave et Orange Money au Sénégal, en XOF. amount correspond au montant à envoyer au bénéficiaire. Idempotency-Key est obligatoire et client_reference doit être unique. Utilisez un numéro international sans +, par exemple 221771234567. Pour Orange Money : provider: ORANGE_MONEY. HTTP 201 CREATED avec status PROCESSING confirme la création ; le résultat final est asynchrone. Consultez GET /payouts/{payout_id} ou écoutez payout.succeeded et payout.failed. Un rejeu idempotent conserve la réponse initiale. UNKNOWN signifie que le résultat final du payout n’est pas encore déterminé. Ne soumettez pas une opération de remplacement. Continuez à récupérer le payout existant jusqu’à obtention d’un statut terminal.
Vérifiez toujours les montants et les bénéficiaires avant l’envoi.
POST/v1/payoutspayout:write
Créer un Payout
AuthentificationBearer API key
IdempotenceObligatoire
Formatapplication/json
Paramètres
Champ
Type
Présence
Description
Exemple
amount
decimal string
requis
Montant bénéficiaire exact.
100
currency
string(3)
requis
Devise du payout.
XOF
provider
enum
requis
Provider du paiement : WAVE ou ORANGE_MONEY.
wave
recipient.phone_number
string
requis
Numéro international sans + (221…). Le préfixe + reste accepté pour compatibilité.
221XXXXXXXXX
client_reference
string 1–255
requis
Référence métier unique pour vos payouts dans l’environnement.
Retourne l’état courant du payout. Après un rejeu de création, utilisez ce GET pour lire sa dernière évolution. UNKNOWN signifie que le résultat final du payout n’est pas encore déterminé. Ne soumettez pas une opération de remplacement. Continuez à récupérer le payout existant jusqu’à obtention d’un statut terminal.
Vérifiez la clé et son environnement ; ne réessayez pas en boucle.
403
ip-not-allowed
The source IP address is not allowed.
Utilisez une IP autorisée ou mettez à jour votre allowlist.
403
forbidden-scope
This API key is not authorized for this operation.
Utilisez une clé disposant du scope requis.
429
rate-limited
Too many requests. Retry later.
Appliquez un backoff ; évitez les boucles agressives.
500
internal-error
An unexpected error occurred.
Conservez request_id ; réessayez prudemment selon l’idempotence.
503
service-unavailable
The service is temporarily unavailable.
Réessayez avec backoff. Pour une mutation, conservez la même clé d’idempotence.
Après validation de la demande et réservation des fonds, Faygaw répond HTTP 201 avec status PROCESSING. Le versement est traité de manière asynchrone. Configurez les webhooks payout.succeeded et payout.failed pour recevoir son résultat définitif ; GET /payouts/{payout_id} donne son état courant. Un rejeu idempotent conserve la réponse initiale et ne déclenche pas un nouvel envoi. UNKNOWN indique un résultat encore indéterminé : conservez la même clé et ne créez pas un versement de remplacement.
Statuts Payout
PROCESSING : traitement en cours. PENDING : résultat en attente. UNKNOWN : résultat indéterminé. SUCCEEDED : payout réussi. FAILED : payout échoué. Seuls SUCCEEDED et FAILED sont terminaux. UNKNOWN signifie que le résultat final du payout n’est pas encore déterminé. Ne soumettez pas une opération de remplacement. Continuez à récupérer le payout existant jusqu’à obtention d’un statut terminal.
Remboursez intégralement un Checkout payé de votre compte. Le montant et les frais FAYGAW d’origine sont restitués au Partner ; aucun nouveau frais Refund n’est ajouté.
POST/v1/refundsrefund:write
Créer un Refund
AuthentificationBearer API key
IdempotenceObligatoire
Formatapplication/json
Paramètres
Champ
Type
Présence
Description
transaction_id
string ≤ 40
requis
Le transaction_id FAYGAW du Checkout payé ; ni son id co_, ni un identifiant provider.
client_reference
string ≤ 255
requis
Votre référence métier unique par compte et environnement pour les Refunds. Distincte de la clé d’idempotence.
reason
string ≤ 255 | null
facultatif
Motif non vide si renseigné ; peut être omis ou null.
Envoyez Authorization: Bearer, Content-Type: application/json et Idempotency-Key (1 à 191 caractères). Aucun paramètre de requête. Le provider, la devise, le montant et le bénéficiaire sont déterminés depuis le paiement initial ; ne les envoyez pas. Un seul remboursement intégral est possible par paiement.
HTTP 201 confirme la création du Refund, pas la réussite financière du remboursement. Enregistrez son id puis consultez son état avec GET ou les webhooks.
Erreurs de cette méthode
Les messages ci-dessous sont ceux renvoyés par l’API, en anglais. Pour invalid-field, le message et details précisent le champ concerné.
HTTP
Code
Message public
Action recommandée
400
idempotency-key-required
The request is invalid.
Ajoutez Idempotency-Key (1 à 191 caractères).
400
invalid-field
Invalid Refund fields.
Vérifiez les champs du JSON ; seuls transaction_id, client_reference et reason sont acceptés.
400
invalid-request
The request is invalid.
Vérifiez le format des valeurs et l’absence de paramètres de requête.
401
authentication-required
Authentication is required.
Ajoutez Authorization: Bearer avec votre clé API.
401
invalid-api-key
The API key is invalid or inactive.
Vérifiez la clé et son état dans le portail.
403
forbidden-scope
This API key is not authorized for this operation.
Vérifiez la permission requise par la méthode.
403
ip-not-allowed
The source IP address is not allowed.
Autorisez l’IP publique sortante de votre serveur.
404
refund-original-not-found
Refund not found.
Utilisez le transaction_id du Checkout payé de votre compte, dans le même environnement.
409
idempotency-conflict
The request conflicts with an existing operation.
Réutilisez exactement la clé et le corps de la demande initiale.
409
refund-already-exists
The request conflicts with an existing operation.
Consultez le Refund existant si vous avez son id ; sinon contactez le support avec request_id.
409
refund-reference-conflict
The request conflicts with an existing operation.
Utilisez une référence unique pour une nouvelle intention de remboursement.
422
refund-insufficient-partner-funds
The payment request was declined.
Vérifiez votre solde disponible.
422
refund-original-not-paid
The payment request was declined.
Vérifiez que le Checkout d’origine est SUCCEEDED.
422
refund-provider-unavailable
The payment request was declined.
Contactez le support ; le provider est celui du paiement initial.
429
rate-limit-exceeded
The request limit has been reached.
Respectez Retry-After lorsqu’il est présent, puis réessayez avec la même clé et le même corps.
503
SERVICE_UNAVAILABLE
The service is temporarily unavailable.
Attendez avant de réessayer ; conservez la clé, le corps et request_id.
Conservez error.code et error.request_id (également renvoyé dans X-Request-Id) pour le diagnostic. Ne déduisez pas le statut financier d’une erreur de transport.
Conservez error.code et error.request_id (également renvoyé dans X-Request-Id) pour le diagnostic. Ne déduisez pas le statut financier d’une erreur de transport.
Demandez une seule nouvelle tentative sur un Refund existant après la fenêtre automatique de 72 heures. Le montant et les frais d’origine sont conservés.
POST/v1/refunds/{refund_id}/retryrefund:write
Relancer un Refund
AuthentificationBearer API key
IdempotenceObligatoire
Formatapplication/json
Paramètres
Utilisez le ref_ existant et conservez sa client_reference. Envoyez Authorization: Bearer, Content-Type: application/json et Idempotency-Key (1–191 caractères). Corps JSON vide {}, aucun paramètre de requête. N’envoyez ni montant, ni provider, ni nouvelle référence.
Les reprises automatiques durent au maximum 72 heures après la demande initiale. Un refus de tentative ne rend pas le paiement définitivement non remboursable. Après cette limite, relancez le même Refund avec POST /v1/refunds/{refund_id}/retry et une nouvelle Idempotency-Key : une seule tentative, sans nouveau cycle automatique de 72 heures. Réutilisez la même clé et le même corps après une réponse perdue. HTTP 202 confirme la prise en charge, pas le remboursement ; consultez GET. Un Refund déjà SUCCEEDED ne déclenche aucun nouvel envoi. Aucun nouveau frais FAYGAW ; restitution des montants confirmée seulement par SUCCEEDED.
Refund introuvable pour ce compte et cet environnement.
409
refund-retry-not-due
La fenêtre automatique de 72 h n’est pas encore terminée.
409
refund-retry-in-progress / idempotency-conflict
Tentative encore en cours ou clé déjà utilisée pour une autre demande.
401 / 403 / 429 / 503
Voir les erreurs communes
Authentification, permission, limite de débit ou indisponibilité.
Une relance déjà en attente est réutilisée ; les requêtes concurrentes ne créent pas plusieurs envois. Après une nouvelle réponse incertaine, consultez GET avant de décider d’une autre relance. Ne bouclez pas automatiquement sur cette route.
Exemple de réponse d’erreur
{
"error": {
"code": "refund-retry-not-due",
"message": "The request conflicts with an existing operation.",
"request_id": "req_refund_retry_example"
}
}
Statuts et suivi d’un Refund
Statut
Description
PROCESSING
Remboursement en cours.
UNKNOWN
Résultat non confirmé. Continuez le suivi ; ne créez pas de remplacement.
SUCCEEDED
Remboursement confirmé.
FAILED
Cycle de tentatives échoué ; relance manuelle possible après 72 h. Une confirmation ultérieure peut établir SUCCEEDED.
Un refus clair libère les réservations de cette tentative, mais les reprises automatiques peuvent continuer dans la fenêtre de 72 heures. Un résultat incertain conserve les réservations jusqu’à confirmation. À expiration, les envois automatiques s’arrêtent. FAILED décrit un cycle échoué et reste relançable manuellement ; UNKNOWN ne prouve pas l’absence de remboursement. Seul SUCCEEDED confirme la restitution du montant et des frais FAYGAW d’origine.
Une indisponibilité ou un délai dépassé pendant la vérification du remboursement ne constitue pas un échec du Refund et ne produit pas refund.failed. Le résultat reste UNKNOWN et les réservations sont conservées tant que la restitution n’est pas confirmée. Les vérifications reprennent automatiquement dans la fenêtre de 72 heures. À son terme, utilisez la relance manuelle du même Refund ; ne créez pas une demande de remplacement. Continuez le suivi par GET et traitez refund.succeeded dès sa confirmation.
Lire les champs de réponse
Champ
Description
id
Identifiant du Refund, à conserver pour GET.
transaction_id / original_transaction_id
Transaction du remboursement / transaction du paiement initial.
Provider initial / référence provider nullable, même en cas de succès.
environment / livemode
Environnement de la clé / indicateur repris du paiement initial.
created_at / updated_at / completed_at
Dates UTC ; completed_at est nullable tant que le traitement n’est pas terminé.
failure_code
Code d’échec nullable ; provider-refund-failed lorsqu’un cycle se termine sur un refus confirmé.
Idempotence et réponse perdue
Après un timeout ou une réponse perdue, renvoyez exactement la même demande avec la même Idempotency-Key. La réponse de création initiale est rejouée : utilisez ensuite GET pour l’état actuel. Changer de clé ne crée pas un second remboursement du même paiement.
Notifications et rapprochement
Les événements refund.created, refund.succeeded et refund.failed suivent les règles de signature et livraison des webhooks. Dédupliquez par event.id et appliquez la sequence la plus élevée : 1 à la création, 2 pour le résultat initial, 3 si une confirmation tardive corrige un échec. Aucun événement refund.unknown n’est émis.
Le status historique du Checkout reste SUCCEEDED. Son champ optionnel payment_status distingue PAID de REFUNDED. Rapprochez votre référence métier avec id, original_transaction_id et les notifications reçues.
Webhooks partenaires signés
Événements disponibles : checkout.paid, payout.succeeded et payout.failed. Il n’existe pas d’événement payout.unknown.
Les requêtes sont des POST HTTPS, sans redirection. Les en-têtes Faygaw-Event-Id et Faygaw-Delivery-Id identifient l’événement et sa livraison vers cet endpoint. Le JSON contient id, type, api_version, sequence, created_at, environment et data.object. Les montants sont des chaînes d’entiers en unités mineures.
Vérifiez Faygaw-Signature: t=timestamp,v1=signature sur les octets bruts du corps, avant toute transformation JSON : HMAC-SHA256 avec le secret complet, sur timestamp + "." + corps_brut. Comparez en temps constant et contrôlez l’âge du timestamp selon une tolérance configurée sur votre serveur. En rotation, deux valeurs v1 sont présentes ; l’une des signatures valides suffit.
Enregistrez durablement la notification valide avant de répondre avec un statut 2xx, par exemple 204. Aucun corps JSON de réponse n’est exigé. Dédupliquez sur event.id : une réponse perdue peut entraîner une nouvelle livraison. Gardez les octets bruts pour vérifier la signature ; ne signez pas un JSON reconstruit.
Un retour navigateur vers success_url n’est jamais une preuve de paiement. Utilisez un webhook authentifié ou GET /checkouts/{checkout_id}. Une erreur de livraison ne modifie jamais le paiement.
Configurer vos webhooks dans le backoffice
Dans Partenaire > Développeur > Webhooks, ajoutez une URL HTTPS publique et choisissez au moins un événement : checkout.paid, payout.succeeded, payout.failed, refund.created, refund.succeeded ou refund.failed. Conservez sur votre serveur le secret affiché à sa création ; il est distinct de la clé API. Pendant le renouvellement, ancien et nouveau secrets peuvent coexister. Terminez la rotation après avoir adapté le récepteur. Si le secret n’a pas été sauvegardé, renouvelez-le.
Un endpoint activé reçoit automatiquement les nouveaux événements auxquels il est abonné, sans activation supplémentaire. Vous pouvez modifier ses abonnements sans le recréer.
Saisir l’URL HTTPS de réception et sélectionner les événements à recevoir.Sauvegarder le secret de signature sur votre serveur, puis confirmer sa conservation. Secret de démonstration sans accès réel.Retrouver l’endpoint créé, son statut et les événements sélectionnés.
Consulter le suivi des webhooks
Lorsque le suivi est disponible dans votre espace Partner, ouvrez Développeur > Webhooks. Les données restent limitées à votre compte et à l’environnement sélectionné. Une indisponibilité PROD ne bascule pas vers SANDBOX.
Onglet
Utilisation
Aperçu
Événements créés, livraisons attendues, accusés HTTP, reprises, latence observée et livraisons en attente. Les taux de livraison et de réussite des tentatives ont des dénominateurs distincts.
Configurer End-points
Gérer les URL HTTPS, les événements souscrits et la rotation des secrets.
Logs Webhooks
Filtrer une période de 31 jours maximum, puis ouvrir un événement, une destination et son historique de tentatives. La recherche utilise un identifiant exact d’événement, livraison, tentative ou transaction. Deux tentatives peuvent être comparées.
Santé
Examiner cinq contrôles de diagnostic et le taux d’erreur de livraison sur les 7 derniers jours pour chaque endpoint. Aucune activité observée ou un échantillon insuffisant ne prouve pas qu’un endpoint est sain.
Un événement peut viser plusieurs destinations : un accusé reçu sur une destination ne signifie pas que toutes ont répondu. HTTP 2xx confirme l’accusé HTTP, pas le traitement métier ni la vérification de signature par votre serveur.
Les en-têtes et corps archivés se chargent à la demande. Signature et données sensibles sont masquées dans les réponses, l’affichage et les copies du portail Partner ; le secret de signature n’y est jamais révélé. Un corps vide, une réponse non reçue, un contenu partiel ou trop volumineux et une archive indisponible sont des situations distinctes. Certains contenus non structurés sont retenus pour protéger les données sensibles.
Le JSON affiché peut être mis en forme et expurgé : il ne remplace jamais les octets bruts reçus par votre serveur pour vérifier HMAC. Les contrôles signalés comme indisponibles ne déclenchent aucun envoi. La consultation et les erreurs de livraison ne modifient pas votre Checkout, Payout ou Refund.
Lorsqu’ils sont disponibles et autorisés sur votre compte, Tester et Renvoyer lancent des demandes ponctuelles. Depuis Santé, Tester ouvre une fenêtre avec la destination et le bouton Lancer le test. Aucun diagnostic ne part avant ce clic. Ce clic demande immédiatement le démarrage du test ; une indisponibilité temporaire peut retarder sa prise en charge. Le test exécute cinq contrôles : joignabilité du serveur, validité et expiration du certificat SSL, rejet d’une signature invalide, acceptation d’une requête correctement signée, et réponse en moins de 15 secondes. Le diagnostic envoie deux requêtes synthétiques webhook.test, sans montant ni opération financière : une avec une signature volontairement invalide, puis une avec une signature valide et fraîche. Votre récepteur doit reconnaître ce type de diagnostic sans exécuter d’action financière. Le récepteur de la boutique de test distingue les événements Checkout, Payout et Refund ; seul checkout.paid déclenche sa confirmation de commande. HTTP 401 ou 403 est attendu pour la signature invalide ; un autre rejet, par exemple HTTP 400 ou 404, ne prouve pas le contrôle de signature et reste à vérifier. Une redirection n’est jamais suivie.
Le modal affiche les étapes réellement enregistrées : En attente, En cours, Réussi, À vérifier, Échec ou Non exécuté, puis le résultat final. Fermer le modal arrête le suivi à l’écran, pas le traitement. Reprendre le suivi ne renvoie aucune requête. Une réponse perdue n’est pas présentée comme un succès et n’est pas rejouée automatiquement.
Le taux d’erreur porte sur les tentatives de livraison réelles terminées au cours des 7 derniers jours, hors diagnostics. Il est vert à 0 %, en avertissement au-dessus de 0 % jusqu’à 20 % inclus, et rouge au-delà de 20 % avec « Taux d’erreur élevé — Vérifiez votre endpoint ». Sans tentative de livraison réelle, le taux affiche « Aucune donnée » et ne contribue pas au score Santé. Les cinq contrôles de diagnostic réussis donnent donc 5/5 en vert. Dès que des tentatives réelles existent, le taux historique devient le sixième critère. Un contrôle de diagnostic absent ou non terminé reste comptabilisé ; sans diagnostic disponible ou pendant son exécution, le score reste neutre.
Renvoyer cible une livraison et sa destination d’origine : mêmes octets et identifiant d’événement, nouvelle signature et nouvel horodatage. Le renvoi peut servir après un accusé déjà reçu. Il ne rejoue aucun paiement, ne modifie aucun solde et ne prolonge pas les reprises automatiques. Confirmez l’événement et la destination ; votre récepteur doit dédupliquer sur l’identifiant de l’événement.
Retirer un type d’événement des abonnements de votre endpoint empêche les futurs envois et les reprises automatiques de ce type. Les livraisons concernées sont arrêtées sans effacer leur historique. Un renvoi manuel de cet événement exige aussi un abonnement actif. Une requête HTTP déjà partie peut encore recevoir sa réponse ; un accusé déjà reçu reste acquis. Réinscrire un événement ne réarme pas les livraisons annulées. Les diagnostics webhook.test restent indépendants des abonnements métier.
Une demande enregistrée n’est pas encore une livraison réussie. Des permissions et limites s’appliquent ; le délai de réessai est indiqué lorsqu’il peut être calculé. Une URL modifiée ou un endpoint inactif bloque l’envoi. Après un résultat incertain, vérifiez vos journaux avant de demander un nouvel envoi. Arrêter le suivi dans le modal n’annule pas la demande ; reprendre son état ne crée pas un nouvel envoi. Les tests ponctuels sont séparés des statistiques de livraison des événements métier.
En SANDBOX, les endpoints actifs des partenaires actifs reçoivent également un diagnostic quotidien avec les mêmes cinq contrôles et les mêmes requêtes synthétiques webhook.test. Les passages sont répartis sur la journée UTC et peuvent être retardés en cas de charge ou d’indisponibilité. Une interruption ne rejoue pas toutes les journées manquées. Le dernier résultat applicable à la configuration courante apparaît dans Santé ; un test ponctuel reste disponible. Ces diagnostics sont exclus des statistiques de livraison métier.
Événements partenaires
checkout.paid confirme un Checkout payé. payout.succeeded confirme un Payout réussi. payout.failed confirme un Payout échoué. Il n’existe pas d’événement payout.unknown. L’échec d’une tentative isolée ne constitue pas un échec final du Checkout.
Livraison et reprises
Une réponse 2xx acquitte la livraison. En cas d’échec ou de réponse perdue, le même événement peut être livré à nouveau avec le même corps, un nouveau timestamp et une nouvelle signature. Les redirections ne sont pas suivies. Les reprises automatiques peuvent se poursuivre pendant 72 heures à compter du premier envoi. Désactiver ou supprimer un endpoint arrête ses reprises en attente. Dédupliquez les événements, enregistrez-les durablement puis acquittez rapidement ; traitez séparément les tâches longues.
Erreurs
Utilisez error.code, le statut HTTP et request_id pour diagnostiquer une réponse. HTTP 401 indique un problème d’authentification, 403 une autorisation insuffisante, 404 une ressource non accessible, 409 un conflit et 429 une limite atteinte. Un échec réseau ou HTTP 503 ne prouve jamais qu’un paiement a échoué.
{
"error": {
"code": "invalid-request",
"message": "The request is invalid.",
"request_id": "example-request-id"
}
}
Metadata
metadata permet d’associer de petites références métier à une ressource. Ces valeurs sont restituées dans les webhooks.
Règle
Valeur
Nombre de clés
Maximum 10
Nom de clé
1–40 caractères
Regex
^[A-Za-z0-9][A-Za-z0-9_.-]{0,39}$
Valeur
String uniquement, max 255 caractères
Ne stockez jamais de secrets, mots de passe, documents ou données sensibles dans metadata.
Bonnes pratiques
Conservez checkout_id, transaction_id, client_reference, refund_id et la clé d’idempotence avec votre commande.
Après une réponse perdue ou un timeout, réessayez avec exactement la même clé et le même payload. Une nouvelle clé ne résout pas une incertitude financière.
La réponse rejouée d’un POST peut être celle de l’admission initiale : consultez le GET pour l’état courant.
Ne considérez jamais PROCESSING ou UNKNOWN comme un remboursement réussi ou définitivement échoué.
Vérifiez l’état serveur ; une redirection navigateur ne prouve pas un paiement ou un remboursement.
Gardez les clés API et secrets de signature côté serveur. Ne journalisez pas les tokens ni le fragment du lien Hosted.
Vérifiez la signature du webhook sur les octets bruts, son timestamp et l’environnement attendu.
Dédupliquez les notifications par event_id. Conservez-les durablement avant de répondre 2xx, puis traitez les tâches longues en arrière-plan.
Tolérer une livraison répétée ou désordonnée ne doit jamais produire un second effet métier. Consultez le GET en cas de notification absente ou incohérente. Pour les notifications Refund, conservez la séquence la plus élevée déjà traitée. Une confirmation tardive peut corriger un échec précédent ; consultez GET pour résoudre une contradiction.
Respectez Retry-After lorsqu’il est fourni après un HTTP 429. Conservez le X-Request-Id pour faciliter une demande au support.