> ## Documentation Index
> Fetch the complete documentation index at: https://docs.noxpay.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> How to authenticate with the Noxpay API.

## Base URL

```
https://checkout.noxpay.io
```

## Authentication

All API requests must include your API key in the `api-key` header:

```http theme={null}
api-key: <key>
```

Your API key is available in the Noxpay dashboard under **Settings → API Keys**.

The key identifies your account, and your account scopes every request: reads are filtered to your own transactions and writes are recorded against your account. There is no way to reach another account's data.

<Warning>
  Never expose your API key in client-side code. All requests to the Noxpay API must originate from your backend.
</Warning>

<Note>
  An API key authenticates your account — it does not restrict which operations can be performed. There is no read-only API key: any valid key can create a checkout or accept a conversion. Treat every key as full-access and scope access at your own layer.
</Note>

Every authenticated response carries an `X-API-Version` header with the current build tag.

## Request format

Every `POST` endpoint rejects unknown fields. A typo'd or extra key in the request body returns `400` rather than being silently ignored — so a request that used to work will not start behaving differently after a field is renamed.

Query parameters behave the opposite way: an unrecognised parameter on a `GET` is ignored, and an unparseable value for a known parameter is generally dropped rather than rejected. See the individual endpoint pages for the specifics.

## Status codes

| HTTP Status | Meaning                                                                                                         |
| ----------- | --------------------------------------------------------------------------------------------------------------- |
| `200`       | Success — including resource creation. No endpoint returns `201`                                                |
| `202`       | Only on `POST /v2/rfq/accept`: still being evaluated, **not** an acceptance                                     |
| `400`       | Invalid JSON, unknown field, missing required field, or a value outside the allowed set                         |
| `401`       | Missing or invalid API key                                                                                      |
| `404`       | Single-record routes: not found, **or** belongs to another account — the two are deliberately indistinguishable |
| `405`       | Method not registered for that route                                                                            |
| `409`       | Only on `POST /v2/rfq/accept`: the quote expired and was renewed                                                |
| `410`       | Only on `POST /v2/rfq/accept`: the renewal window closed                                                        |
| `422`       | Only on `POST /v2/rfq/accept`: refused                                                                          |
| `500`       | Internal error                                                                                                  |
| `503`       | Only on `POST /v2/rfq/accept`: the rate provider is unavailable and nothing was decided                         |

## Error responses

**Error body format is not uniform, so branch on the HTTP status rather than on the body.** Three shapes exist:

1. A JSON object, correctly typed — the conversion endpoints:

   ```json theme={null}
   { "error": "from_currency is required" }
   ```

   On a refusal, `POST /v2/rfq/accept` instead returns its full response object, carrying `state` and `reason`.

2. A JSON object sent with `Content-Type: text/plain` — `POST /v2/crossramp_checkout`. The body is still JSON despite the header, so parse the body and ignore the content type.

3. **No body at all** — the single-record and list `GET` routes write only the status line on `401`, `404`, and `500`.

Treat the error body as optional enrichment. A robust client decides what happened from the status code, then reads a body if one is present.
