Les deux identifiants
Idempotency-Key protège le transport, external_transaction_id protège la facture. Ce que fait chacun, pourquoi au moins l'un est obligatoire, et pourquoi envoyer les deux.
Noryo Merchant API reconnaît deux identifiants. Ce ne sont pas la même chose, et les confondre est l'erreur la plus coûteuse que cette API permette.
Idempotency-Key | external_transaction_id | |
|---|---|---|
| Où | En-tête de requête | Champ du corps (création uniquement) |
| Ce qu'il protège | Le transport : une reprise réseau | L'identité économique : la même transaction |
| Durée de vie | 24 heures | Pas d'expiration |
| Même valeur, même requête | Rejoue la réponse mémorisée, Noryo-Idempotency-Replayed: true | Rend le résultat courant de la transaction, deduplicated: true, non facturé |
| Même valeur, requête différente | 409 idempotency_key_reuse | 409 transaction_id_conflict |
| Portée | Workspace et environnement | Workspace et environnement |
Au moins l'un des deux est obligatoire
Sur POST /merchant/v1/enrichments, une requête sans Idempotency-Key ni external_transaction_id est refusée :
{
"type": "https://developer.noryo.app/errors/identifier_required",
"title": "Identifier required",
"status": 400,
"code": "identifier_required",
"detail": "provide an Idempotency-Key or an external_transaction_id",
"request_id": "req_…"
}JSONSans l'un des deux, la branche de déduplication serait sautée entièrement, et deux appels identiques deviendraient deux événements facturés que plus rien ne distingue. L'API refuse plutôt que de laisser cela arriver. Sur le rafraîchissement, l'Idempotency-Key est obligatoire dans tous les cas.
Envoyez les deux
La clé protège la reprise, l'identifiant de transaction protège la facture. Ils couvrent des pannes différentes :
- Une reprise après un délai dépassé, quelques secondes plus tard : l'
Idempotency-Keyrend le corps mémorisé, octet pour octet. - Le même relevé réimporté trois semaines plus tard : la clé d'idempotence a expiré depuis longtemps, mais l'
external_transaction_idreconnaît la transaction et rend son résultat sans le facturer à nouveau. - Le rafraîchissement d'un résultat : il n'est possible que si l'appel d'origine portait un
external_transaction_id. Voir Rafraîchir.
external_transaction_id : la déduplication économique
L'external_transaction_id est votre identifiant de la transaction : une chaîne de 1 à 255 caractères, opaque pour Noryo et comparée telle quelle. Le premier appel qui le porte, dans un workspace et un environnement donnés, enregistre la transaction et son entrée économique.
| Appel suivant avec le même identifiant | Réponse |
|---|---|
| Même entrée économique | 200 avec le résultat courant de la transaction : deduplicated: true, deduplicated_by: "external_transaction_id", billable: false, units: 0 |
| Entrée économique différente | 409 transaction_id_conflict |
| Contenu du résultat expiré (plus de 90 jours) | 410 result_content_expired. Voir Rétention et 410. |
Le « résultat courant » est le premier résultat de la transaction, remplacé seulement par un rafraîchissement qui aboutit (refresh_recalculated). Un rafraîchissement partial ou not_found ne le remplace pas.
Deux précisions :
- « Même entrée » se juge sur la forme canonique des six champs économiques, pas sur les octets : une différence de casse ou d'espaces dans le
descriptorn'en est pas une, une différence de montant en est une. Voir Formats. - Une panne du moteur n'enregistre pas la transaction. Un
503 engine_errorne réserve pas l'identifiant : la reprise suivante est traitée comme un premier appel.
Idempotency-Key : la protection du transport
1 à 255 octets d'ASCII visible (0x21 à 0x7E). Noryo n'applique aucune normalisation : pas de rognage, pas de changement de casse, pas de traitement Unicode. KEY-1 et key-1 sont deux clés différentes. Le seul traitement d'espaces est celui que la pile HTTP retire elle-même autour de toute valeur d'en-tête, ce qui échappe à notre contrôle comme au vôtre.
Fenêtre de rejeu : 24 heures. À l'intérieur, la même clé avec la même requête rend la réponse mémorisée, avec Noryo-Idempotency-Replayed: true. Le détail des cas (concurrence, refus, expiration) est dans Idempotence.
Publié le 2026-10-08 21:04 UTC (version 1).