Formats
JSON, encoding, maximum size, the exact format of each request field, the canonical form used to compare two transactions, and the format of returned identifiers.
Transport
| Item | Rule |
|---|---|
| Protocol | HTTPS, to the configured base URL |
Body of POST routes | A JSON object, UTF-8 encoded, sent with Content-Type: application/json |
| Body size | 16 KiB at most (16,384 bytes), counted in bytes, not characters. Beyond: 413 request_entity_too_large |
| Response bodies | JSON. Errors are application/problem+json |
GET route | No body |
The 16 KiB limit comfortably covers one transaction; it exists because the API processes one transaction per request, not a file.
Request fields
| Field | Type | Exact format | Example |
|---|---|---|---|
descriptor | string | Required, not empty (not whitespace only), 512 characters at most | "CB MCDONALDS PARIS 4519" |
amount | number | A finite JSON number; a string is refused | 12.40 |
currency | string | ISO 4217, three upper-case letters | "EUR" |
occurred_at | string | ISO 8601 date and time in UTC with the Z suffix, optional fraction of a second (1 to 9 digits) | "2026-09-06T11:42:00Z" |
country | string | ISO 3166-1 alpha-2, two upper-case letters | "FR" |
mcc | string | Four digits, as a string | "5814" |
external_transaction_id | string | 1 to 255 characters; create only | "tx_8f21c0" |
Only descriptor is required. An optional field you do not have must be omitted: the value null is refused for each of them. See Validation.
Why upper case
eur is rejected with 400, and so is fr. This is deliberate: the canonical form compares currency, country and mcc 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.
The canonical form
To decide whether two requests carry the same transaction (idempotency and deduplication), Noryo compares a canonical form of the six economic fields:
| Field | Processing before comparison |
|---|---|
descriptor | Unicode NFC normalisation, lower case, runs of whitespace collapsed to one space, leading and trailing whitespace removed |
amount | Decimal representation to 15 significant digits |
occurred_at | Converted to UTC and truncated to the second |
currency, country, mcc | None: compared verbatim |
| Absent field | Stays absent: an omitted field and a present field make two different inputs |
As a result, "CB McDonalds Paris" and "cb mcdonalds paris" are the same input; so are 2026-09-06T11:42:00.250Z and 2026-09-06T11:42:00Z; so are 12.4 and 12.40. On the other hand, a request carrying amount and a request without it are two transactions.
This form is only used for comparison. The raw descriptor itself is not retained.
Identifiers returned by the API
| Identifier | Shape | Notes |
|---|---|---|
enrichment_id | enr_ followed by a version 4 UUID, lower case | Random: it reveals neither an order nor a volume. A malformed identifier returns 404. |
request_id / Noryo-Request-Id | req_ followed by a version 7 UUID | Time-ordered, useful for sorting your logs. |
| API key | nry_mer_sbx_<key_id>.<secret> or nry_mer_live_<key_id>.<secret> | See API keys. |
Treat these identifiers as opaque: store and compare them as they are, without extracting meaning from them.
Returned values
| Field | Shape |
|---|---|
merchant.confidence | A number between 0 and 1 |
merchant.category | A text code, for example alimentation.restaurant |
merchant.logo_url | A URI |
merchant.location | An object { "city", "postal_code" } or null. See Location. |
Retry-After | A whole number of seconds |
Published on 2026-10-08 21:04 UTC (version 1).