# Enrichir une transaction

> Envoyer une transaction brute à POST /transactions/v1/enrichments et lire ce que la réponse affirme, ignore ou refuse.

Une transaction brute entre, un enrichissement structuré sort. `POST /transactions/v1/enrichments` prend un objet `TransactionInput`, authentifié par votre clé `nry_txn_sbx_*` (voir [Authentification](https://developer.noryo.app/fr-FR/transaction-intelligence/authentication)), et rend un objet `Enrichment` : contrepartie, type de transaction, relations, séries. Cette page décrit le corps attendu, l'en-tête `Idempotency-Key`, la différence entre 201 et 200, et les deux blocs à lire en premier : `signals` et `resolution.policy`.

## L'opération

**`POST /transactions/v1/enrichments`** — Enrichir une transaction.

#### Paramètres

| Nom | Dans | Requis | Type | Description |
| --- | --- | --- | --- | --- |
| `Idempotency-Key` | header | — | string | Facultatif. Avec la même clef et la même requête : rejeu (200), la réponse d'origine est rendue telle quelle, version de moteur comprise. Avec la même clef et une requête différente : 409. « REQUÊTE DIFFÉRENTE » se juge sur l'empreinte économique (`fingerprint`), et sur elle seule : deux corps qui ne diffèrent que par `external_transaction_id`, `account_hint` ou `counterparty_hint` ont la même empreinte et sont la même requête pour l'idempotence — le premier envoi est rejoué tel quel. Ne réutilisez pas une clef pour deux transactions que vous distinguez par ces seuls champs. Aucune version de moteur n'entre dans cette identité : un déploiement entre deux tentatives ne transforme pas un rejeu en opération neuve. La valeur brute n'est jamais rangée ni journalisée. La clef est retenue au moins 24 heures : elle expire 24 heures après le premier envoi et n'est effacée que par la purge quotidienne qui suit cette expiration. Entre 24 et 48 heures après le premier envoi, la même clef ouvre donc une opération neuve (201) — jamais avant 24 heures. De 1 à 255 octets d'ASCII visible (0x21 à 0x7E) ; une valeur vide ou hors alphabet est refusée 400. Motif : `^[\x21-\x7E]{1,255}$`. |

#### Corps de la requête

`application/json` · requis · Schéma `TransactionInput`

| Champ | Type | Requis | Description |
| --- | --- | --- | --- |
| `descriptor` | string · length 1–512 | oui | — |
| `direction` | string | oui | Valeurs : `incoming`, `outgoing`. |
| `occurred_at` | string · date-time | — | RFC 3339 avec décalage. Jamais réduit à une date : minuit n'est pas le même jour partout. |
| `amount` | Money | — | — |
| `amount.value` | string | oui | Décimal en chaîne. Un flottant perdrait des centimes en silence. Le nombre de décimales admis dépend de la devise : `5.905 EUR` est refusé, `100.50 ISK` aussi (ISK et JPY n'en ont aucune, KWD en a trois). Motif : `^-?(0\|[1-9][0-9]{0,15})(\.[0-9]{1,4})?$`. |
| `amount.currency` | string | oui | Une devise hors de cette liste est refusée 422 `unknown_currency`. Valeurs : `CAD`, `CHF`, `DKK`, `EUR`, `GBP`, `ISK`, `JPY`, `KWD`, `NOK`, `PLN`, `SEK`, `USD`. |
| `payment` | object | — | — |
| `payment.rail` | string · length ≤ 128 | — | — |
| `payment.mcc` | string | — | Motif : `^[0-9]{4}$`. |
| `payment.card_present` | boolean | — | — |
| `payment.network_merchant_id` | string · length ≤ 128 | — | — |
| `payment.raw_type` | string · length ≤ 128 | — | — |
| `location_hint` | object | — | — |
| `location_hint.country` | string | — | Motif : `^[A-Z]{2}$`. |
| `location_hint.city` | string · length ≤ 128 | — | — |
| `location_hint.postal_code` | string · length ≤ 128 | — | — |
| `counterparty_hint` | object | — | L'IBAN est réduit dès l'entrée à son pays et son code banque. Le numéro de compte n'entre pas dans le système, donc ne peut pas en sortir. |
| `counterparty_hint.iban` | string | — | Motif : `^[A-Z]{2}[0-9]{2}[A-Z0-9]{10,30}$`. |
| `counterparty_hint.bic` | string | — | Motif : `^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$`. |
| `account_hint` | object | — | Le compte sur lequel la transaction est passée — à distinguer de `counterparty_hint`, qui désigne l'autre bout. Sans lui, une paire de virement ne peut pas être identifiée : le seul signal qui la désigne est « mon compte est ta contrepartie, et ta contrepartie est mon compte ». L'IBAN est réduit dès l'entrée, comme celui de la contrepartie : le numéro de compte n'entre pas dans le système. `external_account_id` : votre propre identifiant du compte, pour les cartes, portefeuilles et rails sans IBAN. Il sert à une chose : relier la transaction à une couverture déclarée sur le même compte. Il n'entre pas dans l'empreinte. Mesuré : il était accepté, puis jeté — la série n'avait aucune source, et `lifecycle.state` restait `unknown`. |
| `account_hint.iban` | string | — | Motif : `^[A-Z]{2}[0-9]{2}[A-Z0-9]{10,30}$`. |
| `account_hint.external_account_id` | string · length 1–128 | — | — |
| `external_transaction_id` | string · length 1–128 | — | Votre propre identifiant de transaction. Il n'entre pas dans l'empreinte : il dit comment vous nommez la transaction, pas ce qu'elle est. Il sert à empêcher deux envois d'une même transaction de se rapprocher l'un de l'autre. |

Exemple — Un achat carte, avec le compte pour relier une couverture

```json
{
  "descriptor": "CARTE 09/09 MONOPRIX PARIS 15",
  "direction": "outgoing",
  "occurred_at": "2026-09-09T07:31:00+02:00",
  "amount": {
    "value": "49.90",
    "currency": "EUR"
  },
  "payment": {
    "rail": "card",
    "mcc": "5411",
    "card_present": true
  },
  "location_hint": {
    "country": "FR"
  },
  "account_hint": {
    "iban": "FR7630006000011234567890189"
  },
  "external_transaction_id": "tx-2026-09-09-0042"
}
```

Exemple — Un prélèvement SEPA récurrent

```json
{
  "descriptor": "PRLV SEPA NETFLIX INTERNATIONAL",
  "direction": "outgoing",
  "occurred_at": "2026-09-05T03:10:00+02:00",
  "amount": {
    "value": "13.49",
    "currency": "EUR"
  },
  "payment": {
    "rail": "sepa_direct_debit"
  },
  "account_hint": {
    "iban": "FR7630006000011234567890189"
  }
}
```

Exemple — Une carte prépayée : le compte se nomme par votre identifiant

```json
{
  "descriptor": "APPLE.COM/BILL",
  "direction": "outgoing",
  "amount": {
    "value": "2.99",
    "currency": "EUR"
  },
  "account_hint": {
    "external_account_id": "carte-4970"
  }
}
```

#### Réponses

| Statut | Description |
| --- | --- |
| `200` | Déjà enrichie : requête rejouée, rien n'a été créé. `Location` est posé ici aussi : le client apprend où vit la ressource qu'il n'a pas créée. |
| `201` | Enrichissement créé. |
| `400` | Corps illisible, ou Idempotency-Key hors alphabet. |
| `401` | Credential absente, mal formée, d'une autre famille, inconnue, révoquée, ou dont le préfixe déclaré ne correspond pas au préfixe enregistré. Un seul code pour tous ces cas : les distinguer serait un oracle. |
| `403` | Workspace ou organisation inactif. |
| `409` | Cette Idempotency-Key a déjà servi pour une requête différente — c'est-à-dire d'empreinte économique (`fingerprint`) différente. Même clef + même empreinte = rejeu (200), jamais 409. |
| `413` | Corps trop volumineux. |
| `415` | Le corps doit être du application/json. |
| `422` | Schéma fermé : champ inconnu, ou contrainte violée. `errors[].code` nomme la règle, et la liste est celle du runtime, par construction : `body_not_object`, `unknown_field`, `required_non_empty_string`, `too_long`, `contains_control_character`, `must_be_incoming_or_outgoing`, `must_be_rfc3339_with_offset`, `must_be_object`, `must_be_string`, `must_be_boolean`, `must_be_four_digits`, `must_be_iso_3166_1_alpha_2_uppercase`, `malformed_iban`, `malformed_bic`, `must_be_non_empty_string`, `amount_not_object`, `amount_value_not_string`, `amount_value_malformed`, `amount_currency_not_string`, `amount_currency_malformed`, `amount_currency_unknown`, `amount_precision_exceeds_currency`. `must_be_rfc3339_with_offset` couvre la forme et le calendrier : `2026-02-30T00:00:00Z`, `+16:00` ou `23:59:60` sont refusés. `must_be_object` refuse aussi un tableau, pour les quatre familles. `contains_control_character` : un caractère de contrôle (C0, DEL, C1) dans un texte, tabulation, saut de ligne et retour chariot exceptés. `amount_currency_unknown` est rendu sous le type `unknown_currency`, les autres sous `invalid_input`. |
| `429` | `rate_limited` : la limite opérationnelle de débit est atteinte, pour cette clef ou pour le workspace (le `detail` le dit). Rien n'a été calculé, rien n'a été rangé, aucun événement n'a été émis. Rejouez après `Retry-After`. Voir `x-noryo-rate-limit`. |
| `500` | Erreur interne. |

#### Erreurs nommées par le contrat

- [`invalid_api_key`](https://developer.noryo.app/fr-FR/transaction-intelligence/errors/invalid_api_key)
- [`account_inactive`](https://developer.noryo.app/fr-FR/transaction-intelligence/errors/account_inactive)
- [`idempotency_conflict`](https://developer.noryo.app/fr-FR/transaction-intelligence/errors/idempotency_conflict)
- [`request_entity_too_large`](https://developer.noryo.app/fr-FR/transaction-intelligence/errors/request_entity_too_large)
- [`unsupported_media_type`](https://developer.noryo.app/fr-FR/transaction-intelligence/errors/unsupported_media_type)
- [`invalid_input`](https://developer.noryo.app/fr-FR/transaction-intelligence/errors/invalid_input)
- [`unknown_currency`](https://developer.noryo.app/fr-FR/transaction-intelligence/errors/unknown_currency)
- [`rate_limited`](https://developer.noryo.app/fr-FR/transaction-intelligence/errors/rate_limited)
- [`internal_error`](https://developer.noryo.app/fr-FR/transaction-intelligence/errors/internal_error)

#### Limites de débit

Cette opération consomme la limite de débit `debit_ti_v1`.

`debit_ti_v1` — operational_burst_protection · token_bucket

- par clé : 120 requêtes / minute (capacité 120, recharge 2/s)
- par workspace : 600 requêtes / minute (capacité 600, recharge 10/s)

« 120 requetes / minute » est traduit en seau a jetons : capacite 120 (la rafale toleree) rechargee a 2 jetons / seconde (le regime durable). Une clef au repos peut envoyer 120 requetes d'un coup, puis 2 par seconde ; sur la premiere minute apres un repos, jusqu'a 240 passent. Le workspace, lui, borne la somme de toutes ses clefs a 600 / minute (capacite 600, 10 / s) : cent clefs ne font pas cent fois la limite.

Ce n'est pas : `sandbox_lifetime_quota`, `production_usage_quota`, `billing_entitlement`, `commercial_promise`.

→ [POST /transactions/v1/enrichments](https://developer.noryo.app/fr-FR/transaction-intelligence/reference/create-enrichment.md)

Le corps est du `application/json`, sinon 415. Toute erreur porte `request_id` dans son corps, à citer au support ; une fois la credential acceptée, chaque réponse porte aussi les en-têtes `noryo-request-id`, `noryo-ratelimit-limit` et `noryo-ratelimit-remaining` (voir [Limites de débit](https://developer.noryo.app/fr-FR/transaction-intelligence/rate-limits)).

## Le corps : `TransactionInput`

**Schéma `TransactionInput`**

Schéma fermé : un champ inconnu est refusé (422), jamais ignoré.

| Champ | Type | Requis | Description |
| --- | --- | --- | --- |
| `descriptor` | string · length 1–512 | oui | — |
| `direction` | string | oui | Valeurs : `incoming`, `outgoing`. |
| `occurred_at` | string · date-time | — | RFC 3339 avec décalage. Jamais réduit à une date : minuit n'est pas le même jour partout. |
| `amount` | Money | — | — |
| `amount.value` | string | oui | Décimal en chaîne. Un flottant perdrait des centimes en silence. Le nombre de décimales admis dépend de la devise : `5.905 EUR` est refusé, `100.50 ISK` aussi (ISK et JPY n'en ont aucune, KWD en a trois). Motif : `^-?(0\|[1-9][0-9]{0,15})(\.[0-9]{1,4})?$`. |
| `amount.currency` | string | oui | Une devise hors de cette liste est refusée 422 `unknown_currency`. Valeurs : `CAD`, `CHF`, `DKK`, `EUR`, `GBP`, `ISK`, `JPY`, `KWD`, `NOK`, `PLN`, `SEK`, `USD`. |
| `payment` | object | — | — |
| `payment.rail` | string · length ≤ 128 | — | — |
| `payment.mcc` | string | — | Motif : `^[0-9]{4}$`. |
| `payment.card_present` | boolean | — | — |
| `payment.network_merchant_id` | string · length ≤ 128 | — | — |
| `payment.raw_type` | string · length ≤ 128 | — | — |
| `location_hint` | object | — | — |
| `location_hint.country` | string | — | Motif : `^[A-Z]{2}$`. |
| `location_hint.city` | string · length ≤ 128 | — | — |
| `location_hint.postal_code` | string · length ≤ 128 | — | — |
| `counterparty_hint` | object | — | L'IBAN est réduit dès l'entrée à son pays et son code banque. Le numéro de compte n'entre pas dans le système, donc ne peut pas en sortir. |
| `counterparty_hint.iban` | string | — | Motif : `^[A-Z]{2}[0-9]{2}[A-Z0-9]{10,30}$`. |
| `counterparty_hint.bic` | string | — | Motif : `^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$`. |
| `account_hint` | object | — | Le compte sur lequel la transaction est passée — à distinguer de `counterparty_hint`, qui désigne l'autre bout. Sans lui, une paire de virement ne peut pas être identifiée : le seul signal qui la désigne est « mon compte est ta contrepartie, et ta contrepartie est mon compte ». L'IBAN est réduit dès l'entrée, comme celui de la contrepartie : le numéro de compte n'entre pas dans le système. `external_account_id` : votre propre identifiant du compte, pour les cartes, portefeuilles et rails sans IBAN. Il sert à une chose : relier la transaction à une couverture déclarée sur le même compte. Il n'entre pas dans l'empreinte. Mesuré : il était accepté, puis jeté — la série n'avait aucune source, et `lifecycle.state` restait `unknown`. |
| `account_hint.iban` | string | — | Motif : `^[A-Z]{2}[0-9]{2}[A-Z0-9]{10,30}$`. |
| `account_hint.external_account_id` | string · length 1–128 | — | — |
| `external_transaction_id` | string · length 1–128 | — | Votre propre identifiant de transaction. Il n'entre pas dans l'empreinte : il dit comment vous nommez la transaction, pas ce qu'elle est. Il sert à empêcher deux envois d'une même transaction de se rapprocher l'un de l'autre. |

Seuls `descriptor` et `direction` sont requis ; un champ facultatif n'est utile que s'il est lu (voir `signals.used` plus bas).

| Champ | Requis | Ce qu'il porte |
|---|---|---|
| `descriptor` | oui | Le libellé tel qu'il figure sur le relevé, de 1 à 512 caractères. |
| `direction` | oui | `incoming` ou `outgoing`. |
| `occurred_at` | non | L'instant de la transaction, RFC 3339 avec décalage. |
| `amount` | non | Un objet `Money` : `value` en chaîne, `currency` parmi les devises acceptées. |
| `payment` | non | `rail`, `mcc` (quatre chiffres), `card_present`, `network_merchant_id`, `raw_type`. |
| `location_hint` | non | `country` (ISO 3166-1 alpha-2, en majuscules), `city`, `postal_code`. |
| `counterparty_hint` | non | `iban`, `bic` de l'autre bout. |
| `account_hint` | non | `iban` ou `external_account_id` du compte sur lequel la transaction est passée. |
| `external_transaction_id` | non | Votre propre identifiant de transaction, de 1 à 128 caractères. |

### Un schéma fermé

Un champ inconnu n'est jamais ignoré : il est refusé par un 422 `invalid_input` dont `errors[]` porte `field` et `code`, ici `unknown_field`. La règle vaut aussi à l'intérieur de `payment`, `location_hint`, `counterparty_hint` et `account_hint`, et un tableau à la place de l'un de ces objets est refusé `must_be_object`.

### `occurred_at` : un instant, pas une date

La valeur est un horodatage RFC 3339 avec décalage, par exemple `2026-09-09T07:31:00+02:00`. Une date seule est refusée : minuit n'est pas le même jour partout, et la cadence des séries se lit au calendrier. Le code `must_be_rfc3339_with_offset` couvre la forme et le calendrier : `2026-02-30T00:00:00Z`, un décalage `+16:00` ou une seconde `23:59:60` sont refusés.

### `amount` : un décimal en chaîne

**Schéma `Money`**

| Champ | Type | Requis | Description |
| --- | --- | --- | --- |
| `value` | string | oui | Décimal en chaîne. Un flottant perdrait des centimes en silence. Le nombre de décimales admis dépend de la devise : `5.905 EUR` est refusé, `100.50 ISK` aussi (ISK et JPY n'en ont aucune, KWD en a trois). Motif : `^-?(0\|[1-9][0-9]{0,15})(\.[0-9]{1,4})?$`. |
| `currency` | string | oui | Une devise hors de cette liste est refusée 422 `unknown_currency`. Valeurs : `CAD`, `CHF`, `DKK`, `EUR`, `GBP`, `ISK`, `JPY`, `KWD`, `NOK`, `PLN`, `SEK`, `USD`. |

`amount.value` est une chaîne (`"49.90"`), jamais un nombre JSON : un flottant perdrait des centimes en silence. Le nombre de décimales admis dépend de la devise : `5.905` en EUR est refusé (`amount_precision_exceeds_currency`), `100.50` en ISK aussi, car ISK et JPY n'en ont aucune et KWD en a trois. `currency` doit appartenir à l'enum de `Money.currency` ; toute autre devise rend un 422 de type `unknown_currency`.

### `account_hint` et `counterparty_hint`

L'IBAN, du compte comme de la contrepartie, est réduit dès l'entrée à son pays et son code banque : le numéro de compte n'entre pas dans le système. Sans `account_hint`, une paire de virement ne peut pas être identifiée. Pour une carte ou un portefeuille sans IBAN, `external_account_id` porte votre propre identifiant ; il sert à relier la transaction à une [couverture d'observation](https://developer.noryo.app/fr-FR/transaction-intelligence/observation-coverage) déclarée sur le même compte et n'entre pas dans l'empreinte.

`external_transaction_id` n'entre pas non plus dans l'empreinte : il dit comment vous nommez la transaction, pas ce qu'elle est, et il empêche deux envois d'une même transaction d'être rapprochés l'un de l'autre.

## `Idempotency-Key`

L'en-tête est facultatif. Sa valeur va de 1 à 255 octets d'ASCII visible (`0x21` à `0x7E`) ; une valeur vide ou hors alphabet rend un 400 `invalid_idempotency_key`.

| Situation | Réponse |
|---|---|
| Clé jamais vue | 201, l'enrichissement est créé. |
| Même clé, même empreinte (`fingerprint`) | 200 : rejeu, la réponse d'origine rendue telle quelle, version de moteur comprise. |
| Même clé, empreinte différente | 409 `idempotency_conflict`. |

« Requête différente » se juge sur l'empreinte économique, et sur elle seule. Deux corps qui ne diffèrent que par `external_transaction_id`, `account_hint` ou `counterparty_hint` ont la même empreinte : le premier envoi est rejoué. Ne réutilisez donc pas une clé pour deux transactions que vous ne distinguez que par ces champs. Une clé est retenue au moins 24 heures ; au-delà, elle peut ouvrir une opération neuve.

> **Note** Un 409 ou un 400 sur la clé arrive après une credential valide : il consomme un jeton de débit, comme un 422.

## 201 ou 200

Un 201 signifie qu'un enrichissement a été créé ; un 200, qu'une requête déjà traitée a été rejouée, sans rien créer. Les deux portent un en-tête `Location` vers la ressource, relisible pendant 30 jours par `GET /transactions/v1/enrichments/{enrichment_id}` (voir [Relire un enrichissement](https://developer.noryo.app/fr-FR/transaction-intelligence/read-an-enrichment)). Le corps est un `Enrichment` : `enrichment_id`, `created_at`, `contract_version`, `canonical_version`, `fingerprint`, `signals`, `resolution`, puis `relationships` et `series` (listes vides quand aucune relation ni série n'a été conclue) et `relationships_policy`, dont `unresolved` dit pourquoi un détecteur n'a pas conclu.

## `signals.used` et `signals.ignored`

`signals.used` liste les signaux reçus qui ont été transmis au moteur : au résolveur d'identité, ou à la base pour les séries, les relations et la couverture d'observation. `signals.ignored` liste ceux que personne n'a lus. Seuls les champs présents dans votre requête figurent dans l'une ou l'autre liste. Aujourd'hui, `payment.mcc`, `payment.card_present`, `payment.network_merchant_id`, `location_hint.city`, `location_hint.postal_code` et `counterparty_hint.bic` sont acceptés puis ignorés.

Ce bloc n'est pas une commodité : sans lui, vous pourriez envoyer un MCC pendant des mois, recevoir 201, et croire qu'il pèse sur la réponse. Vérifiez dans vos tests d'intégration qu'aucun champ dont vous dépendez n'apparaît dans `ignored`. `signals.conflicting` recopie `resolution.signal_conflicts`, pour que le bloc soit complet.

## Le sens de `policy.outcome`

`resolution.policy` dit ce que la réponse affirme, et c'est le champ à utiliser pour décider. Il porte `outcome`, `archetype`, `missing` et `policy_version`.

| `outcome` | Signification |
|---|---|
| `resolved` | Toutes les dimensions exigées par l'archétype sont là. |
| `partial` | La nature est connue, mais une dimension exigée manque, ou des signaux se contredisent et le moteur refuse de conclure. |
| `unresolved` | La nature même de la transaction est inconnue. |

Ce que « résolu » veut dire dépend de la nature de la transaction. Un virement à une personne est `resolved` sans qu'aucune identité ne soit créée ; un retrait d'espèces est `resolved` sans marchand ; un achat carte, lui, exige sa contrepartie, et son absence rend `partial` avec `missing: ["counterparty_entity"]`. Un `counterparty` à `null` est un résultat, pas une panne, et `counterparty_note` dit pourquoi. Les nombres de `resolution.confidence` sont des constantes déclarées, ni probabilités ni seuils : voir [Sémantique des scores](https://developer.noryo.app/fr-FR/transaction-intelligence/score-semantics).

## Exemples

Avec `curl` :

```bash
curl -X POST https://api.noryo.app/transactions/v1/enrichments \
  -H "Authorization: Bearer $NORYO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: tx-2026-09-09-0042" \
  -d '{
    "descriptor": "CARTE 09/09 MONOPRIX PARIS 15",
    "direction": "outgoing",
    "occurred_at": "2026-09-09T07:31:00+02:00",
    "amount": { "value": "49.90", "currency": "EUR" },
    "payment": { "rail": "card", "mcc": "5411", "card_present": true },
    "location_hint": { "country": "FR" },
    "account_hint": { "iban": "FR7630006000011234567890189" },
    "external_transaction_id": "tx-2026-09-09-0042"
  }'
```

Avec `fetch` :

```ts
const response = await fetch("https://api.noryo.app/transactions/v1/enrichments", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.NORYO_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": "tx-2026-09-09-0042",
  },
  body: JSON.stringify({
    descriptor: "CARTE 09/09 MONOPRIX PARIS 15",
    direction: "outgoing",
    occurred_at: "2026-09-09T07:31:00+02:00",
    amount: { value: "49.90", currency: "EUR" },
    payment: { rail: "card", mcc: "5411", card_present: true },
    location_hint: { country: "FR" },
    account_hint: { iban: "FR7630006000011234567890189" },
    external_transaction_id: "tx-2026-09-09-0042",
  }),
});

const enrichment = await response.json();
console.log(response.status, enrichment.signals, enrichment.resolution.policy);
```

Sur cette requête, la réponse liste `payment.mcc` et `payment.card_present` dans `signals.ignored`.

## Réponses d'erreur

Toute erreur rendue par l'API est un objet `Problem` avec `type`, `title`, `status` et `request_id`, `detail` quand l'API en donne un et, sur un 422, `errors[]`. Un 401 signale une credential absente, mal formée, d'une autre famille, inconnue ou révoquée ; un 403 un workspace inactif ; un 413 un corps trop volumineux ; un 415 un corps qui n'est pas du `application/json` ; un 429 une limite de débit atteinte, à rejouer après `Retry-After`. Les cas 400, 409 et 422 sont décrits plus haut. Le catalogue complet est sur [Erreurs](https://developer.noryo.app/fr-FR/transaction-intelligence/errors) et sur `/transaction-intelligence/errors/<code>`.

---

Page canonique : https://developer.noryo.app/fr-FR/transaction-intelligence/enrich-a-transaction
