> For the complete index of the 402pay docs, see [llms.txt](https://402pay.co/docs/llms.txt).

# Authentication

Authenticate with a secret key, scope it per resource, and keep it safe.

Send your secret key as a bearer token in the `Authorization` header. A key belongs to one business, and every request made with it acts as that business. The same key works on both of the API's [base URLs](https://402pay.co/docs/api.md#base-url).

Authenticated request, cURL:

```bash
curl "https://api.402pay.co/api/v1/payments?limit=1" \
  -H "Authorization: Bearer $PAY402_SECRET_KEY"
```

Authenticated request, Node.js:

```js
const response = await fetch("https://api.402pay.co/api/v1/payments?limit=1", {
  headers: {
    Authorization: `Bearer ${process.env.PAY402_SECRET_KEY}`,
  },
});
const { data } = await response.json();
```

Authenticated request, Python:

```python
import os

import requests

response = requests.get(
    "https://api.402pay.co/api/v1/payments?limit=1",
    headers={
        "Authorization": f"Bearer {os.environ['PAY402_SECRET_KEY']}",
    },
)
data = response.json()["data"]
```

## Key types

| Prefix | Kind | Use |
| --- | --- | --- |
| `402s_live_` | Secret | Server-side requests. Every payment it creates is real. |
| `402p_…` | Publishable | Reserved for browser-side use later. Nothing accepts it today: an endpoint that needs a key answers it with 401 `invalid_api_key`, so you can ignore it for now. |

> Keep secret keys on your server and out of source control. Only a hash is stored, so a lost secret can't be shown again: create a new key, then revoke the old one.

In the dashboard: [Create and manage API keys](https://402pay.co/support/api-keys.md).

## Restricted keys

A secret key has full access, or a level per resource: none, read or write. `GET` requests need read and every other method needs write, so a key that only reports on payments can't create one.

| Resource | Covers |
| --- | --- |
| Payments | Payments and metrics. |
| Links | Payment links. |
| Customers | Customer records. |
| Wallet | Balances, addresses and notes. |
| Webhooks | Endpoints, deliveries and test events. |
| Events | The event log. Read only. |
| Checkout settings | Accepted coins, rails and redirects. |

> Money never moves on an API key. Sends from your wallet happen in the dashboard, signed in your browser with your encryption password.

## Errors

| Status | Code | When |
| --- | --- | --- |
| 401 | `unauthenticated` | No key was sent. The response has a `WWW-Authenticate: Bearer` header. |
| 401 | `invalid_api_key` | The key is invalid or revoked, or it's a publishable key. |
| 401 | `invalid_api_key` | The `Authorization` header isn't `Bearer`, a space and the key, such as when the `Bearer` prefix is missing. |
| 403 | `business_forbidden` | The request also sent a `402pay-Business` header naming another business. A key acts only as its own business, so leave the header out. |
| 403 | `permission_denied` | A restricted key doesn't have the access the route needs. |
| 403 | `session_required` | The route is for the dashboard only, such as managing API keys or sending from your wallet. |
