Idempotence
L'API Facturino supporte l'idempotence sur toutes les requêtes POST. En cas d'erreur réseau, de timeout ou de retry automatique,
rejouer la même requête avec la même clé garantit qu'une seule opération est effectivement réalisée — la deuxième tentative retourne le résultat de la première.
Quand utiliser l'idempotence
- Toujours sur les opérations de création non-rejouables :
POST /v1/invoices,POST /v1/customers,POST /v1/quotes… - Toujours sur les actions à effet de bord :
POST /v1/invoices/:id/send,POST /v1/invoices/:id/payments,POST /v1/invoices/:id/finalize. - Optionnel sur
PATCHetDELETE— ces verbes sont nativement idempotents au niveau HTTP, mais l'idempotency-key reste utile pour tracer une intention métier précise. - Inutile sur les
GET— ils sont déjà idempotents.
Header Idempotency-Key
Ajoutez un header Idempotency-Key contenant une chaîne unique pour l'opération métier :
$ curl -X POST https://facturino.com/api/v1/invoices \
-H "Authorization: Bearer fac_test_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-7842-create-invoice" \
-d '{...}' Génération de la clé
Une bonne clé d'idempotence est :
- Stable — la même opération métier doit produire la même clé (ne pas générer aléatoirement à chaque retry).
- Unique — deux opérations métier différentes doivent produire des clés différentes.
- Lisible — préférez un préfixe sémantique pour faciliter le debug :
invoice-create-{orderId}plutôt qu'un simple UUID. - Courte — maximum 255 caractères, format libre (lettres, chiffres, tirets, underscores).
Exemples par SDK
Node.js — les SDKs officiels exposent le paramètre idempotencyKey sur chaque méthode :
import { randomUUID } from 'crypto'
// Génération d'une clé stable et persistée côté client
const idempotencyKey = `invoice-create-${orderId}`
const invoice = await facturino.invoices.create(
{ customerId: 'cus_...', lines: [...] },
{ idempotencyKey },
)
// Un retry avec la MÊME clé retourne l'invoice déjà créée (HTTP 200) Python :
import uuid
key = f"invoice-create-{order_id}"
invoice = client.invoices.create(
customerId="cus_...",
lines=[...],
idempotency_key=key,
) Go :
key := fmt.Sprintf("invoice-create-%s", orderID)
// La clé d'idempotence est un champ du struct de paramètres
invoice, err := client.Invoices.Create(&facturino.InvoiceParams{
Customer: "cus_...",
Items: []*facturino.ItemParams{ /* ... */ },
IdempotencyKey: key,
}) Cycle de vie d'une clé
| Événement | Comportement |
|---|---|
| Première requête | Le serveur exécute l'opération et stocke {key, body_hash, response} |
| Retry avec même clé + même payload | Le serveur retourne la réponse mise en cache (succès ou l'erreur métier persistée) — l'opération n'est jamais rejouée |
| Retry avec même clé + payload différent | Erreur 409 Conflict avec code = "conflict" |
Échec de validation (4xx avant toute exécution : schéma, champ en lecture seule) | La clé est libérée — un retry corrigé avec la même clé peut s'exécuter |
Erreur métier pendant l'exécution (4xx) | La réponse d'erreur est persistée : un retry avec la même clé renvoie la même erreur, sans jamais ré-exécuter d'effet de bord |
Échec serveur (5xx) | La réservation reste en attente (self-heal) — un retry après la fenêtre retentera réellement l'opération |
| Expiration | Les clés sont conservées 24 heures à compter de la première utilisation, puis supprimées automatiquement |
Portée de la clé
Les clés d'idempotence sont scopées à votre entreprise et à l'environnement (livemode). Vous pouvez donc réutiliser la même chaîne
dans deux environnements différents (test et production), ou entre deux entreprises distinctes.
En revanche, à l'intérieur d'un même environnement, une clé est globale tous endpoints confondus — ne réutilisez pas
order-7842 à la fois pour une création de facture et une création de client.
Erreurs courantes
Si vous réutilisez une clé avec un payload différent, l'API refuse la requête :
HTTP/1.1 409 Conflict
{
"error": {
"type": "conflict_error",
"code": "conflict",
"message": "Idempotency key already used with a different request body.",
"hint": "Generate a new idempotency key for new operations.",
"request_id": "req_..."
}
}
Pour résoudre :
- Générez une nouvelle clé pour la nouvelle opération.
- Ou attendez 24 h (expiration automatique) si vous voulez réutiliser la même chaîne sémantique.
Bonnes pratiques
- Persistez la clé en base de données avant le premier appel API. Si votre processus crashe avant la réponse, vous saurez quelle clé réutiliser au prochain démarrage.
- Liez la clé à un objet métier (numéro de commande, ID de session) plutôt qu'à un UUID aléatoire.
- Logguez la clé avec chaque requête pour faciliter le rapprochement en cas d'incident.
- Ne déduisez rien de l'absence de la clé en cache — l'expiration 24 h peut intervenir avant un retry tardif.
Étapes suivantes
- Gestion des erreurs — codes 409 conflict et stratégies de retry
- Limitation de débit — retry après 429
- Webhooks — idempotence côté consommateur