Créer un enrichissement
POST /merchant/v1/enrichments en détail : le corps, les identifiants, la réponse, ce qui est facturé, et chaque issue possible, du rejeu au 409 en passant par le 503.
POST /merchant/v1/enrichments rend une identité marchande pour un libellé bancaire brut. Il exige le scope enrich:write.
Le corps
| Champ | Obligatoire | Rôle |
|---|---|---|
descriptor | oui | Le libellé brut, 512 caractères au plus. Le seul champ qui oriente aujourd'hui la résolution. Non conservé. |
amount | non | Montant de la transaction. Entre dans l'identité économique. |
currency | non | ISO 4217 en majuscules. Entre dans l'identité économique. |
occurred_at | non | Date et heure en UTC, suffixe Z. Entre dans l'identité économique. |
country | non | ISO 3166-1 alpha-2 en majuscules. Entre dans l'identité économique ; ne filtre pas la réponse. |
mcc | non | Code de catégorie marchande, quatre chiffres en chaîne. Entre dans l'identité économique. |
external_transaction_id | non* | Votre identifiant de la transaction. Porte la déduplication économique. |
* Au moins l'un des deux est requis : l'en-tête Idempotency-Key ou le champ external_transaction_id. En production, envoyez les deux. Voir Les deux identifiants.
Les formats exacts sont dans Formats, les refus dans Validation.
Exemple
curl -sS -X POST "https://api.noryo.app/merchant/v1/enrichments" \
-H "Authorization: Bearer $NORYO_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6c1a2f0e-1b7d-4c55-8f3a-0d9e2b4c7a61" \
-d '{
"descriptor": "CB MCDONALDS PARIS 4519",
"amount": 12.40,
"currency": "EUR",
"occurred_at": "2026-09-06T11:42:00Z",
"country": "FR",
"mcc": "5814",
"external_transaction_id": "tx_8f21c0"
}'ShellLa réponse
Un 200 porte quatre objets :
{
"enrichment_id": "enr_ffe80956-cc3e-4e1f-b4b6-724ad231fbb7",
"merchant": {
"name": "McDonald's",
"category": "alimentation.restaurant",
"location": { "city": "PARIS", "postal_code": "75018" },
"logo_url": "https://www.mcdonalds.fr/apple-touch-icon.png",
"confidence": 0.96
},
"enrichment": { "status": "resolved", "reason": null, "environment": "sandbox", "source": "noryo", "customized": false },
"usage": { "billable": false, "units": 1, "deduplicated": false, "deduplicated_by": null }
}JSONAvec les en-têtes Noryo-Request-Id, Noryo-Idempotency-Replayed, Noryo-RateLimit-Limit et Noryo-RateLimit-Remaining. Chaque champ est décrit dans Enrichment et Merchant.
Un 200 ne veut pas dire qu'un marchand a été trouvé. Lisez enrichment.status : resolved, partial ou not_found. Voir Statuts.
Ce qui est facturé
| Statut | Production | Sandbox |
|---|---|---|
resolved | billable: true, units: 1 | billable: false, units: 1 (décompté de la dotation) |
partial | non facturé, units: 0 | units: 0 |
not_found | non facturé, units: 0 | units: 0 |
Ce qui se passe si…
| Situation | Réponse |
|---|---|
Vous renvoyez la même requête avec la même Idempotency-Key dans les 24 heures | 200, le corps mémorisé, Noryo-Idempotency-Replayed: true ; rien n'est facturé |
Vous renvoyez la même transaction (même external_transaction_id, même entrée), quelle que soit la date | 200, le résultat courant, deduplicated: true, billable: false, units: 0 |
Même Idempotency-Key, autre requête | 409 idempotency_key_reuse |
Même external_transaction_id, autre entrée économique | 409 transaction_id_conflict |
Ni Idempotency-Key ni external_transaction_id | 400 identifier_required |
La même transaction, dont le résultat courant a dépassé ses 90 jours de rétention (jamais pour un not_found) | 410 result_content_expired : le contenu a été purgé. Voir Rétention et 410. |
| La dotation Sandbox est épuisée et le résultat aurait coûté une unité | 402 sandbox_quota_exhausted |
| Le moteur de résolution ne répond pas | 503 engine_error : rien n'est facturé ni mémorisé ; reprenez avec la même Idempotency-Key |
| Une requête identique est en cours avec la même clé | La vôtre attend sa fin et rend le rejeu, ou 503 busy avec Retry-After |
| Votre seau de débit est vide | 429 rate_limited avec Retry-After ; rien n'est calculé ni facturé |
En TypeScript
import { randomUUID } from "node:crypto";
const BASE_URL = "https://api.noryo.app"; // à placer en configuration
export async function createEnrichment(tx: {
id: string; descriptor: string; amount?: number; currency?: string; occurredAt?: string;
}) {
const res = await fetch(`${BASE_URL}/merchant/v1/enrichments`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.NORYO_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": randomUUID(), // à générer une fois par opération et à garder pour les reprises
},
body: JSON.stringify({
descriptor: tx.descriptor,
external_transaction_id: tx.id,
// Omettez un champ absent : null est refusé.
...(tx.amount !== undefined ? { amount: tx.amount } : {}),
...(tx.currency ? { currency: tx.currency.toUpperCase() } : {}),
...(tx.occurredAt ? { occurred_at: tx.occurredAt } : {}),
}),
});
const body = await res.json();
if (!res.ok) throw Object.assign(new Error(body.code), { problem: body });
return body; // lisez body.enrichment.status avant body.merchant
}TypeScriptPour les reprises, voir Reprises.
Publié le 2026-10-08 21:04 UTC (version 1).