Skip to content
Sandbox

Reading the response

In what order to read a Merchant API response, why a 200 does not mean a merchant was found, and what Noryo actually does with each of your fields.

View as Markdown

A 200 does not mean a merchant was found. It means the request was settled. What the engine answered is in enrichment.status.

Reading order

  1. The HTTP status. 200: a settled result. Any other status: a Problem Details object, to handle according to its code. See Errors.
  2. enrichment.status. resolved or refresh_recalculated: complete identity. partial: incomplete or uncertain identity. not_found: nobody.
  3. enrichment.reason, for partial and not_found: why.
  4. merchant, if the status allows: name, category, logo_url, location.
  5. merchant.confidence, as a ranking signal, not as a probability.
  6. usage and the Noryo-Idempotency-Replayed header, if you track your consumption.
resolved              identity complete, above the policy threshold
partial               something is missing, or confidence below threshold
not_found             the engine answered, and its answer is "nobody"
refresh_recalculated  a refresh produced a new complete result

not_found is a normal, complete answer, not an error and not a failure. The failure case is 503 engine_error, and it is billed to nobody.

confidence is a score, not a probability

"confidence": 0.94
JSON

Do not read this as "94 % chance of being correct." Noryo has measured that the ordering of this score is not monotonic at the top of the range: a 0.99 is less reliable than a 0.90. See Confidence.

location is an object, or null

"location": { "city": "PARIS", "postal_code": "75018" }
"location": { "city": "MULHOUSE" }
"location": null
JSON

The key is always present. Absent and unknown look too alike for you to have to tell them apart. See Location.

What Noryo does with your input

descriptor, amount, currency, occurred_at, country and mcc all enter the economic identity: two calls differing only by amount are two distinct enrichments, billed separately.

Only descriptor currently drives resolution. In particular, country does not filter the answer. That is measured, not accidental: on our calibration set, a strict "declared country must equal merchant country" filter removed 95 resolved results to correct 15 genuinely wrong ones, and on cross-border homonyms, where the gain should have been greatest, it removed 36 to correct 1. It is recorded in the calibration dataset and will be re-measured as non-French coverage grows.

The raw descriptor is not retained. Retention is 0 days: no column of the module can store it, and it never appears in a log.

currency and country must be upper case

eur is rejected with 400, and so is fr. This is deliberate: the canonical form compares these fields verbatim, so EUR and eur would be two distinct economic identities and two invoices for what you meant as one call. The validator refuses the ambiguity rather than normalising behind your back. See Validation.

What to do with each result

ResultSensible use
resolved, refresh_recalculatedDisplay the identity; store it on your side
partialDisplay with caution, or have it reviewed; see Partial data
not_foundDisplay the raw descriptor; see not_found
503 engine_errorRetry with the same Idempotency-Key; see Retries

In this section

  • not_found: a result, not an error.
  • Confidence: what the score measures, and what it does not.
  • Partial data: partial, omitted fields and unknown location.

Published on 2026-10-08 21:04 UTC (version 1).

Was this page helpful?