Sur un réseau peu fiable, une requête POST peut échouer après avoir été exécutée côté serveur : la mission est créée, mais vous ne recevez jamais la réponse. Si vous réessayez naïvement, vous créez un doublon. L’idempotence résout ce problème. En attachant un en-tête Idempotency-Key à vos requêtes mutantes, vous garantissez que l’opération ne produit son effet qu’une seule fois, quel que soit le nombre de fois où vous la rejouez.
L’idempotence est le filet de sécurité de la création de mission. Combinée à la réconciliation par webhook, elle rend votre intégration robuste face aux pannes transitoires.

En bref

En-tête

Idempotency-Key: <votre-clé> — une chaîne libre que vous générez (un UUID v4 est idéal).

Portée

Les POST mutants : surtout la création de mission, mais aussi refacturations, options, annulation, dates.

Durée de vie

Une clé est mémorisée 24 h. Au-delà, la même clé est traitée comme neuve.

Rejeu

Une réémission identique renvoie la réponse en cache avec l’en-tête Idempotent-Replayed: true.

Comment l’utiliser

1

Générez une clé unique par opération métier

Une clé d’idempotence représente une intention : « créer cette mission-ci ». Générez une nouvelle clé pour chaque opération distincte — un UUID v4 fait parfaitement l’affaire.
IDEM=$(uuidgen)   # ex. 1f3c2b7a-9d4e-4a1b-8c2f-0e6d5a4b3c2d
2

Attachez-la à la requête mutante

Ajoutez l’en-tête Idempotency-Key à votre POST (en plus de X-Api-Key).
Idempotency-Key: 1f3c2b7a-9d4e-4a1b-8c2f-0e6d5a4b3c2d
3

Rejouez la même clé en cas d'incertitude

Si la requête échoue par timeout ou erreur réseau, réémettez-la à l’identique (même clé, même corps). Le serveur exécute l’opération au plus une fois et vous renvoie le résultat — qu’il vienne de la première exécution ou du cache.

Exemple : créer une mission de façon sûre

L’en-tête Idempotency-Key est posé une fois ; les deux mêmes appels ne créent qu’une seule mission.
BASE="https://api.myexpressdriver.com/v1"
IDEM=$(uuidgen)

curl -s -X POST "$BASE/transports" \
  -H "X-Api-Key: $MED_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $IDEM" \
  -d '{
    "vehicle":  { "type": "VP", "registration": "AB-123-CD", "brand": "Renault", "model": "Clio" },
    "pickup":   { "address": "10 Rue de Rivoli, 75004 Paris", "date": "2026-07-01", "start_time": "08:00", "end_time": "12:00" },
    "delivery": { "address": "1 Place Bellecour, 69002 Lyon",  "date": "2026-07-01", "start_time": "14:00", "end_time": "18:00" },
    "billing":  { "company_name": "Garage Demo SARL", "email": "compta@garage-demo.fr", "address": "5 Avenue des Champs, 75008 Paris" }
  }'
La réponse 201 est identique à chaque rejeu :
{
  "id": "-O9xAbCdEf",
  "transport_id": "M-54321",
  "status": "scheduled",
  "price": { "amount_ht": 180.5, "currency": "EUR" }
}

Sémantique détaillée

Le tableau ci-dessous décrit comment le serveur traite une clé selon le scénario.
ScénarioComportement
Première requêteExécutée normalement. La réponse (code + corps) est mise en cache, indexée sur la clé.
Même clé + même corpsLa réponse en cache est rejouée à l’identique, avec l’en-tête Idempotent-Replayed: true. Aucun nouvel effet de bord.
Même clé + corps différent409 Conflict — la clé a déjà servi pour une autre requête (voir plus bas).
Requête concurrente, même clé409 Conflict tant que la première requête est encore en cours de traitement.
Réponse serveur 5xxNon mise en cache : le verrou est libéré pour qu’un retry puisse réussir.

Le rejeu : Idempotent-Replayed

Quand le serveur renvoie une réponse en cache, il ajoute l’en-tête de réponse :
Idempotent-Replayed: true
Cet en-tête vous permet de distinguer une exécution réelle d’un rejeu, par exemple pour la journalisation. Le corps et le code HTTP, eux, sont strictement identiques à la première réponse.
Vérifiez Idempotent-Replayed après chaque retry : sa présence confirme que votre réémission n’a pas créé de doublon.

Conflit de clé : 409

Réutiliser une même clé avec un corps de requête différent est une erreur de votre côté : la clé identifie une opération précise, elle ne peut pas en désigner deux. Le serveur répond alors 409 Conflict au format RFC 9457 (application/problem+json) :
{
  "type": "about:blank",
  "title": "Conflict",
  "status": 409,
  "detail": "Idempotency-Key reused with a different request body."
}
N’arrondissez pas, ne reformatez pas et ne ré-ordonnez pas le corps entre deux réémissions d’une même clé : la moindre différence est considérée comme un corps divergent et déclenche un 409. Pour une nouvelle opération, générez une nouvelle clé.

Les erreurs serveur ne sont pas cachées

Une réponse 5xx (par exemple 502 Bad Gateway d’un service amont) n’est pas mémorisée. Le verrou associé à la clé est relâché, ce qui rend le retry sûr : vous pouvez réémettre la même requête avec la même clé sans risque de doublon ni de 409 parasite.
Logique de retry recommandée
POST /transports  (Idempotency-Key: <clé>)
  ├─ 201 / 200  → succès, conservez le résultat
  ├─ 409        → corps divergent : NE PAS retenter avec la même clé
  ├─ 422        → corps invalide : corrigez, nouvelle clé
  ├─ 429        → back-off + respect de Retry-After, même clé
  └─ 5xx        → retry avec la MÊME clé (back-off exponentiel)

Quand l’utiliser

L’idempotence protège les opérations qui créent ou modifient un état et dont un doublon aurait des conséquences. Posez systématiquement une Idempotency-Key sur :
Le cas d’usage prioritaire. Un doublon créerait deux missions facturables. C’est ici que l’idempotence apporte le plus de valeur.
Évite d’appliquer deux fois le même changement de prix lors d’un retry.
Empêche d’ajouter la même option (et de recalculer le prix) en double.
Garantit qu’un retry n’enclenche pas une seconde annulation.
Évite de réémettre une notification de changement d’horaires au client.
Empêche l’ajout en double des mêmes pièces jointes à la mission.
Les requêtes GET sont déjà idempotentes par nature : elles ne modifient aucun état et n’ont pas besoin d’en-tête Idempotency-Key.

Bonnes pratiques

  • Une clé par intention métier. Générez la clé avant le premier envoi et conservez-la pour tous les retries de cette même opération. Ne réutilisez jamais une clé pour une opération différente.
  • Persistez la clé côté client (file d’attente, base) jusqu’à obtenir une réponse définitive, afin de pouvoir rejouer après un crash de votre processus.
  • Branchez votre logique sur le code HTTP (status), pas sur le texte de detail qui peut évoluer.
  • TTL 24 h : une clé expirée n’offre plus de protection. Une opération reprise au-delà de 24 h sera traitée comme nouvelle — utilisez une clé fraîche.

Étapes suivantes

Démarrage rapide

Créez votre première mission de bout en bout, avec idempotence.

Format des erreurs

Comprenez les réponses 409, 422 et 5xx (RFC 9457).

Webhooks

Réconciliez les événements manqués et déduplisez côté consommateur.