---
title: "Authentication"
description: "Authenticate every request with an API key in the x-api-key header."
---

> Every apinoa docs page as markdown: https://apinoa.com/llms.txt (all in one file: https://apinoa.com/llms-full.txt)

Every request to `gateway.apinoa.com` carries an API key in the `x-api-key` header. There is no other way
to authenticate, and no request is served without one.

## Get a Key

Create a key under **Dashboard > API keys**. The full key is shown **once**, when you create it: copy it
then and store it somewhere safe. If you lose it, create a new one and revoke the old one.

Or get one from your terminal, without opening the dashboard. Run this in your project directory:

```bash
npx apinoa-mcp login
```

It prints a page address, `https://api.apinoa.com/oauth/device`, and an 8-character code such as
`BCDF-GHJK`; in an interactive terminal the page opens by itself. Sign in to apinoa there (or create an
account), type the code and approve. The command then writes `APINOA_API_KEY=<key>` to `.env` in the
current directory (`--out <path>` writes another file). An existing `APINOA_API_KEY` line is replaced
and the rest of the file is kept, and it warns you if `.env` is not git-ignored. It never prints the full
key.

A key made this way starts with `apinoa_mcp_` and expires after 90 days: run `npx apinoa-mcp login` again
then. It is listed under **Dashboard > API keys**, where you can revoke it like any other, and we email you
each time one is created. The CLI keeps up to five keys per account: a sixth sign-in revokes the oldest and
says which. An account's
first key made this way, or by signing in to the [hosted MCP server](/docs/sdks#hosted-nothing-to-install),
comes with **$0.10 of evaluation credit**, once per account; an account that has already had free credit
does not get it.

**Only enter a code you started yourself, in your own terminal, just now.** Anyone who sends you a code to
enter is asking for access to your account.

You can hold several keys at once, which is how you rotate one without downtime: create the new key, move
your traffic to it, then revoke the old one.

## Send It with Every Request

```bash tab="cURL"
curl "https://gateway.apinoa.com/v1/amazon/search?query=wool+socks" \
  -H "x-api-key: $APINOA_API_KEY"
```

```js tab="JavaScript"
const res = await fetch("https://gateway.apinoa.com/v1/amazon/search?query=wool+socks", {
  headers: { "x-api-key": process.env.APINOA_API_KEY },
});
```

```python tab="Python"
import os

import requests

res = requests.get(
    "https://gateway.apinoa.com/v1/amazon/search",
    params={"query": "wool socks"},
    headers={"x-api-key": os.environ["APINOA_API_KEY"]},
)
```

## Keep It on Your Server

A key spends your balance. Call the API from your backend and keep the key in a secret store or an
environment variable: never in a browser, a mobile app or a public repository, where anyone can read it
and bill calls to you.

If a key may have been exposed, revoke it under **Dashboard > API keys**. A revoked key stops working
immediately.

## When Authentication Fails

| Status | Code | Meaning |
|---|---|---|
| 401 | `UNAUTHORIZED` | The `x-api-key` header is missing, or the key is invalid or revoked. |
| 402 | `INSUFFICIENT_BALANCE` | The key is valid, but the balance does not cover the call. |
| 403 | `ACCOUNT_SUSPENDED` | The account is suspended; every key on it is refused. Contact support. |

Each call is charged against your balance at the rate on the [pricing page](/pricing). When the balance
will not cover the next call, the API answers `402`, and retrying does not clear it: top up under
**Dashboard > Balance**.
