Aller au contenu
Sandbox

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.

Voir en Markdown

POST /merchant/v1/enrichments rend une identité marchande pour un libellé bancaire brut. Il exige le scope enrich:write.

Le corps

ChampObligatoireRôle
descriptorouiLe libellé brut, 512 caractères au plus. Le seul champ qui oriente aujourd'hui la résolution. Non conservé.
amountnonMontant de la transaction. Entre dans l'identité économique.
currencynonISO 4217 en majuscules. Entre dans l'identité économique.
occurred_atnonDate et heure en UTC, suffixe Z. Entre dans l'identité économique.
countrynonISO 3166-1 alpha-2 en majuscules. Entre dans l'identité économique ; ne filtre pas la réponse.
mccnonCode de catégorie marchande, quatre chiffres en chaîne. Entre dans l'identité économique.
external_transaction_idnon*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"
  }'
Shell

La 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 }
}
JSON

Avec 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é

StatutProductionSandbox
resolvedbillable: true, units: 1billable: false, units: 1 (décompté de la dotation)
partialnon facturé, units: 0units: 0
not_foundnon facturé, units: 0units: 0

Ce qui se passe si…

SituationRéponse
Vous renvoyez la même requête avec la même Idempotency-Key dans les 24 heures200, 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 date200, le résultat courant, deduplicated: true, billable: false, units: 0
Même Idempotency-Key, autre requête409 idempotency_key_reuse
Même external_transaction_id, autre entrée économique409 transaction_id_conflict
Ni Idempotency-Key ni external_transaction_id400 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 pas503 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 vide429 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
}
TypeScript

Pour les reprises, voir Reprises.

Publié le 2026-10-08 21:04 UTC (version 1).

Cette page vous a-t-elle aidé ?