Retour aux guides
Intégration API d'une passerelle de paiement : guide développeur 2026
Intégrer une passerelle de paiement est facile à rater. L'idempotence est sautée, les webhooks sont traités en ligne, les signatures sont ignorées sur un réseau "de confiance", et six mois plus tard un incident de production remonte à un double débit ou un callback perdu.
Ce guide déroule les patterns qui comptent : authentification API, clés d'idempotence, webhooks signés, sémantique de retry, gestion d'erreurs, parité sandbox, et les spécificités crypto. Recommandations concrètes au niveau code, pas des puces marketing.
Stimulez votre activité en acceptant les paiements en crypto-monnaie
Le happy path est 5 % du travail
Une première intégration paraît simple : POST pour créer une charge, redirection du client, webhook reçu, commande marquée payée. Démontrable en un week-end.
L'intégration en production est différente. 95 % du code livré (et 100 % du code qui cause des incidents) gère :
- Requêtes dupliquées (retries réseau, bouton retour, double-clic).
- Livraisons de webhooks dupliquées (sémantique at-least-once).
- Webhooks perdus (pare-feu, timeout, déploiement en cours).
- Échecs partiels (charge réussie mais écriture DB échouée).
- Courses critiques entre réponse API et webhook.
- Remboursements, litiges et transitions d'état tardives.
- Dérive sandbox/production sur un cas limite qui ne survient qu'en prod.
Bâtissez pour ce monde-là dès le premier jour.
Authentification : clés, secrets, OAuth2
Les passerelles authentifient les appels API de trois manières :
- Clés API (secret + publishable). La plus répandue. Clé secrète côté serveur ; publishable côté client pour tokeniser. Jamais de clé secrète dans le navigateur. Rotation trimestrielle et systématique en cas d'exposition.
- OAuth2 (client credentials). Utilisé pour les passerelles plateforme où votre app agit au nom d'un marchand. Access tokens courts + refresh tokens. Plus de pièces, meilleure frontière.
- Requêtes signées HMAC. Chaque requête signée avec un secret. Adapté au serveur-à-serveur à haute exigence ; plus verbeux.
Quelle que soit la méthode : stockez les secrets dans un coffre (AWS Secrets Manager, HashiCorp Vault, GCP Secret Manager), jamais dans le code, jamais dans un .env commité. Portée restreinte (lecture seule, facture uniquement, remboursement uniquement). Rotation trimestrielle. Côté RGPD, documentez les accès dans votre registre de traitements.
Idempotence : le pattern anti-double-débit
Un appel API peut échouer de trois façons : le serveur ne l'a jamais reçu, il l'a traité mais la réponse s'est perdue, il l'a traité et a renvoyé une erreur. Impossible de distinguer côté client. Un retry risque un second débit.
L'idempotence résout ça. Le client génère une clé unique par requête logique (UUID lié à la commande) et l'envoie dans l'en-tête Idempotency-Key. Le serveur mémorise la clé avec la réponse ; un retry avec la même clé renvoie la réponse originale sans ré-exécuter.
POST /v1/charges
Idempotency-Key: 8b7cfa4d-1e6c-4a12-9a3e-...
Content-Type: application/json
{"amount": 9900, "currency": "eur", "source": "tok_..."}
- Générer la clé côté client, une fois par requête logique. Pas par retry.
- Persister la clé avec la commande avant l'appel.
- UUIDv4 ou aléatoire fort. Pas de timestamp. Pas d'auto-incrément.
- Pas éternel : 24 à 72 h de cache typique. Au-delà, nouvelle requête.
- Testez les retries explicitement. Deux envois, une seule charge.
Webhooks : signés, asynchrones, idempotents
Les webhooks sont la contrepartie asynchrone de l'API : la passerelle appelle votre endpoint à chaque événement (paiement confirmé, litige, versement réglé). Mal faits, ils provoquent des échecs silencieux ; bien faits, ils sont la colonne vertébrale de l'état paiement.
- Vérifiez la signature. HMAC-SHA256 sur le corps brut avec secret partagé, comparé à
X-Signature. Rejet si invalide. L'IP source ne suffit jamais. - Retournez 200 vite. Accusé sous 500 ms. Poussez DB, mails, appels tiers vers une file de fond. Un handler lent timeout et amplifie la charge.
- Idempotence sur event ID. Chaque webhook a un ID unique. Enregistrez-le avant de traiter. Doublon, retour 200 sans re-traitement.
- Événements désordonnés. Le webhook "payment succeeded" peut arriver avant la réponse API qui a créé la charge. Machines à état tolérantes à tout ordre.
- Outil de replay. Les opérateurs doivent pouvoir relancer un événement précis depuis le dashboard.
// Express.js pseudo-code
app.post('/webhooks/gateway', express.raw({type: 'application/json'}), (req, res) => {
const sig = req.headers['x-signature'];
const expected = hmac('sha256', SECRET, req.body).toString('hex');
if (!timingSafeEqual(sig, expected)) return res.status(401).end();
const event = JSON.parse(req.body);
if (await seenEvent(event.id)) return res.status(200).end();
await enqueue(event);
return res.status(200).end();
});
Gestion d'erreurs et retries
Catégorisez par retry légitime :
| Catégorie | Exemple | Retry ? |
|---|---|---|
| 4xx client | Carte invalide, paramètre manquant | Non, corriger la requête |
| 402 payment required | Refus émetteur | Non, afficher au client |
| 409 conflict | Collision idempotence | Non, traiter comme doublon |
| 429 rate limit | Trop de requêtes | Oui, backoff expo, respecter Retry-After |
| 5xx serveur | Timeout passerelle, erreur interne | Oui, même clé d'idempotence |
| Timeout réseau | Connexion coupée, DNS | Oui, avec clé d'idempotence |
Backoff exponentiel avec jitter : 1 s, 3 s, 10 s, 30 s, 2 min, 10 min, puis stop + alerte. Jamais de retry synchrone dans le handler, toujours en file.
Sandbox, cartes de test et stratégie
Chaque passerelle majeure fournit un environnement bac à sable avec cartes de test (CB/Visa en France) déclenchant des scénarios :
- 4242 4242 4242 4242 : succès générique.
- 4000 0000 0000 0002 : refus générique.
- 4000 0000 0000 9995 : solde insuffisant.
- 4000 0027 6000 3184 : 3DS2 requis (obligatoire DSP2 en France).
- 4000 0000 0000 0341 : attachement puis refus à la charge.
Discipline de test :
- Chaque chemin en prod a un test sandbox. Aucun "c'est simple" qui échappe.
- Simulez tout événement webhook, y compris ordre inversé et doublons.
- Forçage d'erreurs par design : helper qui rejoue avec code de refus choisi.
- Testez l'idempotence : deux envois, une seule charge assertée.
- Remboursements, remboursements partiels, litiges.
- Test chaos : tuez le worker en cours, vérifiez un reprise propre au redémarrage.
Spécificités API passerelle crypto
Les patterns ci-dessus s'appliquent à l'identique. Les différences sont dans le modèle d'événements, pas la plomberie :
- Cycle de vie facture, pas charge. Créez une facture en euros ; le client choisit l'actif ; la passerelle retourne une adresse ou URI de paiement. Événements :
invoice.created,payment.detected,payment.completed,payment.settled,invoice.expired,invoice.underpaid. - Confirmations comme événements distincts. Les bonnes passerelles émettent un événement à la détection mempool et un autre à la confirmation finale. Traitez-les séparément.
- Pas de tokens carte. Pas de vaulting, pas de 3DS2, pas de tokenisation réseau. Remplacés par des signatures wallet côté client.
- Remboursements = transactions sortantes. Vous initiez une transaction on-chain depuis votre wallet vers l'adresse du client. Prévoyez que l'adresse puisse avoir changé.
- Événements off-ramp.
payout.initiated,payout.paid,payout.failed. Rapprochement 1 versement pour N factures avec les relevés bancaires.
Le code happy-path d'une intégration crypto est plus court que carte : pas de 3DS2, pas de vaulting, pas de chargeback. Les cas limites sont différents, pas plus nombreux.
Check-list pré-lancement
- Secrets dans un coffre, jamais dans le code.
- Clés d'idempotence générées et persistées pour tout POST déplaçant de l'argent.
- Vérification signature webhook en place, testée contre payloads altérés.
- Handlers webhooks renvoient 200 sous 500 ms, traitement async.
- IDs d'événements dédupliqués avant traitement.
- Machines à état tolérantes à l'ordre d'arrivée.
- Backoff exponentiel avec jitter sur toute erreur retryable.
- Dashboards pour webhooks en échec, paiements en échec, versements en échec.
- Alertes sur taux d'erreur soutenu, pas sur échec unitaire.
- Runbooks pour les 5 principaux types d'incident.
- Charge testée à 5x le pic attendu.
- Disaster test : workers tués en cours, reprise propre vérifiée.
- Conformité DORA (depuis 17/01/2025) : notification d'incident TIC.
- Registre RGPD à jour pour les données clients.
API GatewayCrypto
REST, webhooks HMAC, SDKs, sandbox fidèle.
GatewayCrypto offre une API pensée pour les équipes qui tiennent à la qualité : idempotence de série, webhooks signés, événements granulaires, plugins Shopify/Woo/PrestaShop/Magento.
Accéder à la doc et au sandboxStimulez votre activité en acceptant les paiements en crypto-monnaie
Commencer
Questions fréquemment posées
Une requête répétée avec la même clé d'idempotence produit le même résultat sans double débit. Le client envoie un en-tête Idempotency-Key unique par requête logique ; le serveur reconnaît les doublons et renvoie la réponse d'origine.
HMAC-SHA256 sur le corps brut avec le secret partagé, comparé en temps constant à l'en-tête de signature. Rejet si invalide, indépendamment de l'IP source.
HTTP 200 aussi vite que possible, idéalement sous 500 ms. Traitement métier en file d'attente. Un handler inline timeout sous charge et provoque des retries en cascade.
Retries automatiques avec backoff exponentiel : 1 s, 5 s, 30 s, 2 min, 15 min, 1 h, 6 h, 24 h typiquement. Après épuisement, statut échoué et replay manuel dans le dashboard.
Webhooks comme source de vérité. Polling en filet de sécurité : job planifié qui réconcilie les transactions en vol sans statut final. Jamais en signal primaire.
La publishable est safe côté navigateur et tokenise la carte. La secrète vit côté serveur et couvre tout le reste. Ne jamais exposer la secrète ; rotation à toute compromission suspectée.
Utilisez la carte 3DS2 documentée (souvent 4000 0027 6000 3184). La sandbox simule le challenge et renvoie succès frictionless ou challenge requis. DSP2 impose 3DS2 en France sauf exemption.
Mêmes patterns REST + webhooks. Noms d'événements différents (cycle facture au lieu de cycle charge), pas de 3DS2 ni vaulting, remboursements = transactions sortantes on-chain. Discipline identique.
Appel POST /refunds avec l'ID de la charge d'origine. Pour la crypto, incluez l'adresse de retour du client (possiblement différente). Asynchrone ; attendez refund.completed ou refund.failed.
Faire du métier dans le handler webhook au lieu d'enfiler. Ça marche en dev, ça casse sous charge en prod. Retour 200 vite, traitement async ; votre équipe ops vous remerciera.