# Authentication

> How to present a Transaction Intelligence API key, where to keep its secret, and what a 401 or a 403 response means.

Every request to the Transaction Intelligence API, apart from the public contract at `GET /openapi.json`, is authenticated with an API key carried in the `Authorization` header. This page covers the key format, how to present it, where to keep its secret and how to read `401` and `403` refusals. Creating a key step by step is covered in the [Quickstart](https://developer.noryo.app/en-GB/transaction-intelligence/quickstart); reading usage per key is covered in [Usage and API keys](https://developer.noryo.app/en-GB/transaction-intelligence/usage-and-api-keys).

## The credential format

A Transaction Intelligence key belongs to the `txn` family. In the sandbox it reads:

```
nry_txn_sbx_<key_id>.<secret>
```

- `nry_txn_sbx_`: the prefix. It states the family (`txn`) and the environment (`sbx`, the sandbox).
- `<key_id>`: the key's public identifier, 10 characters long. It is what Platform shows in the key list and on the Usage page; it is not secret.
- `<secret>`: the secret part, after the dot. It is shown once only.

The contract also describes a `nry_txn_live_` prefix for production. No such key can be created today: production is not open (see [Sandbox limitations](https://developer.noryo.app/en-GB/transaction-intelligence/sandbox-limitations)). It is not obtained through any sequence of actions: it is requested, Noryo reviews it, and an approval issues no key of that form (see [Production access](https://developer.noryo.app/en-GB/transaction-intelligence/production-access)).

The prefix is part of what the server checks: a key presented under a prefix that does not match the one recorded when it was created is refused with `401`, even if the secret is correct.

## Presenting the key

Send the whole key, prefix included, in the `Authorization` header with the `Bearer` scheme. It is the only authentication scheme in the contract.

```bash
curl -X POST https://api.noryo.app/transactions/v1/enrichments \
  -H "Authorization: Bearer $NORYO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "descriptor": "PRLV SEPA NETFLIX INTERNATIONAL",
    "direction": "outgoing",
    "occurred_at": "2026-09-05T03:10:00+02:00",
    "amount": { "value": "13.49", "currency": "EUR" }
  }'
```

```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",
  },
  body: JSON.stringify({
    descriptor: "PRLV SEPA NETFLIX INTERNATIONAL",
    direction: "outgoing",
    occurred_at: "2026-09-05T03:10:00+02:00",
    amount: { value: "13.49", currency: "EUR" },
  }),
});
```

The contract itself, `GET https://api.noryo.app/openapi.json`, is the only resource served without a key: a machine can read it with no workspace context and without consuming any rate-limit token.

## Getting a key on Platform

Keys are created on [Platform](https://platform.noryo.app/keys), on the API keys page. You sign in with your Noryo identity; keys belong to the **workspace** you are a member of, not to you personally.

1. **Enable the Transaction Intelligence sandbox.** A workspace owner or admin enables it once; the action is logged. It is specific to Transaction Intelligence, and it requires a **complete developer profile** for the workspace: identity, professional phone number, organisation, and what you are building. Without it, enabling is refused and no key is issued.
2. **Create a key.** You give it a name and a purpose. Platform then shows the full credential.
3. **Copy the secret straight away.** It is shown at that moment only. Noryo does not keep the secret: only a verifier is stored, enough to recognise the key but not to reconstruct it. A lost secret cannot be recovered; you revoke the key and create another.

The number of **active** keys per workspace is capped. Platform reads the cap from the server; revoked keys do not count towards it.

> **Note** There is no documented rotation procedure. To replace a key: revoke it, then create a new one. If you suspect a secret has leaked, revoke first.

## Where to keep the secret

The secret is a server credential. It lives in an environment variable on your server (`NORYO_API_KEY` in the examples throughout this documentation), read by the process that calls the API.

| Location | Verdict |
|---|---|
| Server environment variable, or a secrets manager | Recommended |
| JavaScript bundle served to a browser | Never |
| Public code repository, or any committed file | Never |
| Mobile application binary | Never |
| Client-side JavaScript, browser extension, web page | Never |

A secret embedded in a client can be read by anyone who holds that client. If your mobile apps or web pages need enrichments, route them through your own server, which alone holds the key.

## Revocation

A key is revoked from Platform, immediately and with no grace period. From the very next request it receives `401`; that request is not counted as usage and does not touch the rate limit. A revoked key keeps its history on the [Usage](https://platform.noryo.app/usage) page: what it did before revocation remains readable.

## Isolated families

Noryo exposes several APIs, each with its own key family. A Merchant API key, prefixed `nry_mer_`, is refused with `401` on Transaction Intelligence, and a `nry_txn_` key is refused on the Merchant API. The isolation is enforced by the verifier itself, not by a mere filter on the prefix: to this server, a key from another family is an unknown credential.

## 401 or 403

The two identity-related refusals read differently.

| Status | Problem `type` | What it means | What to do |
|---|---|---|---|
| `401` | `invalid_api_key` | The credential is not usable: missing, malformed, from another family, unknown, revoked, or presented under a prefix that does not match. | Check the `Authorization` header, then the key's state on Platform. |
| `403` | `account_inactive` | The key is recognised, but the workspace or organisation is not active. | Contact support with the `request_id`. |

The `401` is deliberately a single code: the server does not say whether the key exists, whether it once existed, or whether only the secret is wrong. Telling those cases apart would be an enumeration oracle.

Neither a `401` nor a `403` consumes a rate-limit token, and neither appears in usage on Platform: the credential check comes before the rate limit. Three refusals come even earlier: `400` for an undeclared host, `415` for a body that is not `application/json`, `413` for a body that is too large. Past the credential, a `400` on the JSON or on the `Idempotency-Key`, a `422`, a `404` or a `409` does consume a token, because the key was valid.

A refusal is an RFC 9457 problem, served as `application/problem+json`:

```json
{
  "type": "https://noryo.app/problems/transactions/invalid_api_key",
  "title": "La credential presentee n'est pas utilisable.",
  "status": 401,
  "request_id": "req_01J9…"
}
```

Compare the `type`, never the `title`: the URI is stable, the sentence may be reworded. The full catalogue is in [Errors](https://developer.noryo.app/en-GB/transaction-intelligence/errors) and at [/errors/invalid_api_key](https://developer.noryo.app/en-GB/transaction-intelligence/errors/invalid_api_key).

## The request identifier

Every response rendered after authentication carries the `noryo-request-id` header; every error, even one prior to the credential, carries the same identifier in the `request_id` field of its body. It is the identifier to quote to support.

Two responses come from the hosting layer, before the API, and carry none: a `405` (undeclared verb on a known path, empty body, no `Allow` header) and a `404` on an unknown path. If your call gets either of those without a `noryo-request-id`, check the verb and the path first.

> **Warning** Never paste the key into a support ticket, an application log or a screenshot. The `noryo-request-id` is enough.

## Further reading

- [Quickstart](https://developer.noryo.app/en-GB/transaction-intelligence/quickstart): from your first Platform sign-in to the first enrichment.
- [Usage and API keys](https://developer.noryo.app/en-GB/transaction-intelligence/usage-and-api-keys): what Platform shows per key.
- [Rate limits](https://developer.noryo.app/en-GB/transaction-intelligence/rate-limits): what counts and what does not.
- [Errors](https://developer.noryo.app/en-GB/transaction-intelligence/errors) and [Reference](https://developer.noryo.app/en-GB/transaction-intelligence/reference): the generated catalogue and contract.

---

Canonical page: https://developer.noryo.app/en-GB/transaction-intelligence/authentication
