Idempotence
Rejouer une création sans risque grâce à l'en-tête Idempotency-Key.
Un délai dépassé côté réseau ne vous dit rien sur ce que le serveur a fait. Rejouer un
POST /transfers à l'aveugle peut payer deux fois un bénéficiaire. Une clé d'idempotence lève
l'ambiguïté : le second appel renvoie la réponse du premier au lieu de refaire le travail.
Deux pages, deux questions
Cette page décrit la mécanique : l'en-tête, son format, où il fonctionne, combien de temps il dure. Pour choisir vos clés, structurer vos nouvelles tentatives et dédupliquer les webhooks dans votre propre code, consultez Bonnes pratiques → Idempotence.
L'en-tête
Envoyez Idempotency-Key sur la requête. Sans préfixe X-.
Authorization: sk.kZ3qP8mWvL2xR7tB5nY4hC6dF9jS1aG0eU3i...
Idempotency-Key: 8f14e45f-ceea-467a-9bd1-2c2bd7a1e0a4
Content-Type: application/jsonIdempotency-Keystringfacultatif[A-Za-z0-9._:-]+. Un UUID v4 est le choix habituel. Tout caractère hors de cet alphabet renvoie un 422 sur idempotency_key.Les clés sont rattachées au triplet (clé, équipe, environnement). La même chaîne utilisée en sandbox et en live correspond à deux clés indépendantes, et aucune autre équipe ne peut entrer en collision avec les vôtres.
Où ça fonctionne
| Endpoint | Protection |
|---|---|
POST /payments | Index unique en base de données, permanent |
POST /transfers | Index unique en base de données, permanent |
POST /refunds | Réponse mise en cache, 24 heures |
POST /customers | Réponse mise en cache, 24 heures |
POST /beneficiaries | Réponse mise en cache, 24 heures |
POST /invoices | Réponse mise en cache, 24 heures |
POST /links | Réponse mise en cache, 24 heures |
POST /webhooks | Réponse mise en cache, 24 heures |
Les deux protections se comportent de la même façon vues de l'extérieur, et diffèrent par la durée pendant laquelle elles se souviennent.
Les paiements et les transferts stockent la clé sur la ligne elle-même, sous une contrainte d'unicité. La protection n'expire jamais : rejouer cette clé dans un an renvoie toujours le paiement d'origine au lieu d'en créer un second. C'est aussi cette contrainte qui maintient la garantie en cas de concurrence : deux requêtes simultanées avec la même clé aboutissent à une seule ligne et à deux réponses identiques.
Tout le reste met la première réponse en cache pendant 24 heures. Passé ce délai, la clé est oubliée et le même appel crée une nouvelle ressource. C'est le bon compromis pour un client ou un lien de paiement, où un doublon est une gêne plutôt qu'une perte.
Rejouer une requête
Générez la clé une seule fois, au moment de l'intention métier, et réutilisez-la pour chaque tentative réseau de cette même intention.
curl https://api.wajub.com/transfers \
-H "Authorization: $WAJUB_API_KEY" \
-H "Idempotency-Key: payout-invoice-4172" \
-H "Content-Type: application/json" \
-d '{
"amount": 100000,
"currency": "XAF",
"beneficiary": {
"phone": "237670000000",
"channel": "cm.mtn",
"name": "Amina Nkeng"
}
}'Envoyez-la une seconde fois et vous recevez la première réponse, à l'octet près, avec le même id
de transfert. Rien n'a été créé, aucun argent n'a bougé.
Le SDK PHP invente une clé si vous ne le faites pas
Chaque appel qui n'est ni un GET ni un DELETE envoie un Idempotency-Key, que vous l'ayez
demandé ou non, de la forme wajub-{uuid}. Cela couvre les nouvelles tentatives réseau du SDK
lui-même, qui réutilisent les mêmes en-têtes. Cela ne couvre pas vos nouvelles tentatives :
rappeler create() génère une nouvelle clé et crée une seconde ressource. Passez un
RequestOptions(idempotencyKey: ...) explicite dès que l'appel peut être relancé par votre
propre code, un worker de file d'attente ou un utilisateur qui clique deux fois.
Réutiliser une clé avec un corps différent
Rejouer n'est sûr que s'il s'agit de la même requête. Si vous réutilisez une clé avec un payload différent, Wajub refuse au lieu de renvoyer en silence une ressource que vous n'avez pas demandée :
Sur POST /payments, la comparaison utilise un hash stocké sur le paiement : elle tient donc
pendant toute la vie de l'enregistrement. Sur POST /transfers, le hash est mis en cache pendant
24 heures : passé ce délai, la clé renvoie toujours le transfert d'origine, elle cesse simplement
de vérifier que les corps correspondent. Les transferts comparent amount, currency,
beneficiary, description et reason.
Un en-tête mal formé arrive sous la forme du même 422 avec un autre message,
The Idempotency-Key header format is invalid.
Concurrence
Deux requêtes qui partagent une clé sont traitées l'une après l'autre : la seconde attend jusqu'à dix secondes que la première se termine, puis lit son résultat. Vous n'avez jamais deux créations en cours pour une même clé, ni une ressource écrite à moitié.
Une clé par intention métier, pas par tentative
Dérivez la clé de quelque chose de déjà unique dans votre propre domaine : un ID de commande, un
numéro de facture, une ligne de paie. payout-invoice-4172 survit à un redémarrage du processus,
à un redéploiement et à une nouvelle tentative de la file d'attente. Un UUID généré dans la
boucle de nouvelles tentatives ne survit à aucun des trois.
Repérer une requête rejouée
Dans Konsole → API Logs, une réponse servie par la
protection d'idempotence porte un badge replayed, ce qui vous permet de distinguer un appel en
double d'une ressource en double.
X-Idempotency-Key n'est pas cet en-tête
X-Idempotency-Key existe dans la plateforme, utilisé quand un prestataire de paiement nous
envoie un webhook. Il n'a rien à voir avec l'API destinée aux marchands, et l'envoyer n'a aucun
effet.