Un parcours de paiement côté serveur avec protection des nouvelles tentatives et des doublons.
1. Prépare les ID et l'accès
Commence avec un magasin activé et des moyens de paiement testés. Dans Réglages → Accès API, crée un identifiant de lecture/écriture limité au projet nécessaire. Garde le token sur ton backend, jamais dans le code navigateur ou un dépôt public.
Copie ID API du projet et ID API du magasin depuis l'encadré du magasin Général → ID API . Ce sont des UUID, pas l'identifiant lisible du projet ni ton numéro de commande. Utilise ton propre nom d'hôte API.
Dans Magasin → IPN, crée un secret de signature avant de fournir un ipn_url. Ton récepteur HTTPS doit être accessible depuis le VPS commerçant.
2. Crée une facture
Remplace les valeurs provisoires et envoie cette requête depuis ton backend. Les montants sont des chaînes décimales, pas des calculs en virgule flottante.
curl --fail-with-body --request POST \
'https://api.example.com/v1/projects/YOUR_PROJECT_ID/stores/YOUR_STORE_ID/invoices' \
--header 'Authorization: Bearer YOUR_MERCHANT_API_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: order-1042-attempt-1' \
--data '{
"amount": "10.00",
"currency": "EUR",
"order_id": "order-1042",
"description": "Example order",
"ipn_url": "https://shop.example.com/payments/wholly-ipn",
"metadata": {
"cart_id": "cart-1042"
}
}'Enregistre data.invoice_id avec ta commande, puis redirige le client vers links.checkout. Utilise une clé d'idempotence unique pour une nouvelle tentative de paiement. En cas d'expiration du délai, réessaie avec le même identifiant d'accès, la même clé et les octets exacts du corps.
Omettre payment_methods utilise les moyens acceptés du magasin. Tu peux les restreindre par facture avec des slugs de blockchain et des symboles ; cela n'active jamais un actif non accepté. Tous les champs de requêtes et exemples de réponse →
3. Choisis les IPN, webhooks ou les deux
IPN suit le cycle de vie de la facture. Définis l'URL IPN par défaut du magasin ou remplace-la avec ipn_url pour une facture. Les webhooks abonnent un endpoint à des événements sélectionnés, par exemple invoice.settled.
Ils utilisent le même format de signature, mais des secrets différents: les IPN utilisent le secret IPN du magasin ; chaque endpoint webhook a son propre secret. Aucun n'utilise le token bearer API pour signer.
Si les deux livrent à ton application, attends-toi à des notifications qui se recoupent. Ne crédite pas une commande deux fois.
4. Vérifie et enregistre la notification
- Lis le corps brut exact de la requête avant l'analyse JSON. Vérifie
Wholly-Signatureavec le secret correspondant et des contrôles d'horodatage/rejeu. Les SDK officiels fournissent des vérificateurs. - Valide l'identité du projet, magasin, facture et événement du corps signé. Les en-têtes de livraison non signés ne sont pas une source d'authentification.
- Stocke l'événement durablement avec une valeur unique de
event_id, puis renvoie rapidement HTTP 2xx. Traite les commandes dans un worker en arrière-plan. - Récupère la facture actuelle depuis ton hôte API configuré, pas un hôte arbitraire fourni dans une requête. Compare le projet, magasin, montant, devise et référence de commande enregistrés.
PHP · Python · JavaScript / TypeScript · Spécification de signature et exemples de récepteurs
5. Traite une seule fois, au règlement
Pour un récepteur basé sur les événements , traite event_type = invoice.settled, puis vérifie le status = settled actuel et ta politique d'exceptions. Traite une seule fois dans une transaction de base de données/une contrainte de commande unique.
Une blockchain à finalisation rapide peut envoyer à la fois payment.received et invoice.settled avec status = settled. Sur une autre blockchain, payment.received peut encore indiquer processing. Aucun de ces parcours n'est une erreur.
Déduplique les événements par event_id, pas seulement par séquence : différents types d'événements peuvent partager une séquence. Les gestionnaires SDK basés sur l'état regroupent plutôt les révisions de factures et vérifient l'état quel que soit le type d'événement. Ne combine pas ce regroupement avec un filtre de type d'événement. Les deux approches exigent toujours une protection contre les doublons au niveau de la commande.
Examine requires_review et les résolutions manuelles avant de traiter. amount_status = paid seul ne prouve pas la confirmation. Les champs d'actif payé au premier niveau résument le règlement ; payment_info contient les réceptions détaillées et les données du devis. Tous les statuts, événements et règles d'exceptions →
6. Teste les nouvelles tentatives et la récupération
Teste un petit paiement, une livraison en double, une facture expirée et un récepteur temporairement indisponible. Rejouer un événement ne doit pas créer un deuxième crédit de commande. Gère les événements désordonnés sans écraser un état plus récent.
Examine Magasin → IPN / Webhooks → Historique → Détails, ou les sections de livraison dans Détails de la facture. Le renvoi réutilise l'événement enregistré, pas un nouveau règlement.
Un crédit de traitement faible suspend les IPN/webhooks pendant que les paiements continuent. Rapproche les commandes en attente via l'API et traite les livraisons conservées après rétablissement. Ne traite jamais une commande à partir d'une redirection navigateur ou d'une capture d'écran du client.