# Authentication

> Send your API key as a Bearer token or in x-api-key. Keys belong to an organization and can carry budgets and model limits.


Every request needs an API key. Send it in one of two headers:

| Header | Format |
|---|---|
| `Authorization` | `Bearer nh_live_...` |
| `x-api-key` | `nh_live_...` (what the Anthropic SDKs send) |

```bash test
curl https://api.notholy.com/v1/models -H "x-api-key: $NOTHOLY_API_KEY"
```

## Keys

Keys are created in the console under **API keys**. Each key belongs to an organization and a workspace. The secret is shown once and stored only as a hash.

A key can have:

- A total budget and a daily budget in USD. A request that would pass the budget gets `402`.
- A list of allowed models. Other models get `403 key_not_allowed`.
- An expiry date.
- A requests-per-minute limit below the organization limit.

Revoking a key takes effect on the next request.

## Keys in code

Read the key from the environment. Do not commit it. If a key leaks, revoke it in the console and create a new one.

> [!WARNING]
> Never ship a key in client-side code. Call the API from your server or your terminal and keep keys in environment variables or a secret store.

```python test
import os
from openai import OpenAI

client = OpenAI(base_url="https://api.notholy.com/v1", api_key=os.environ["NOTHOLY_API_KEY"])

print([m.id for m in client.models.list()])
```

## Errors

| Status | Code | Meaning |
|---|---|---|
| 401 | `invalid_api_key` | Missing, wrong, revoked or expired key |
| 403 | `key_not_allowed` | The key cannot use this model |
| 403 | `account_suspended` | The organization is suspended. Contact support |
| 403 | `consent_required` | The key's creator refused or withdrew consent to processing in the United States and China. They can accept it in the console |

## Next

- [Models](/en/getting-started/models)
- [Organizations and roles](/en/account/organizations)
