# Authentication

> Create an Emelia API key in Settings, API & Webhooks, and send it in the Authorization header of every request.

Source: https://docs.emelia.io/docs/authentication

Every request to the Emelia API carries your API key in the `Authorization` header. There is no OAuth flow and no token to refresh.

## Create a key

[Get your API key](https://v3.emelia.io/settings/api)

1. Open the Emelia app and go to **Settings, API & Webhooks** ([v3.emelia.io/settings/api](https://v3.emelia.io/settings/api)).
2. Click **Create new key**.
3. Copy the key and store it as a secret, for example in an `EMELIA_API_KEY` environment variable.

A key is exactly 48 letters and digits. You can create several keys, and disable or delete one at any time from the same page.

> **A key opens the whole account.** There are no scopes: a key can read and change your campaigns, lists and contacts, spend your credits and act on every part of your account. Protect it like a password, and give one key to each integration.

## Send the key

Put the key, as is, in the `Authorization` header:

[`GET /advanced/campaigns`](https://docs.emelia.io/docs/campaigns/list-campaigns.md)

**curl**

```bash
curl https://api.emelia.io/advanced/campaigns \
  -H "Authorization: $EMELIA_API_KEY"
```

**JavaScript**

```js
const emelia = (path, init = {}) =>
  fetch(`https://api.emelia.io${path}`, {
    ...init,
    headers: {
      Authorization: process.env.EMELIA_API_KEY,
      'Content-Type': 'application/json',
      ...init.headers,
    },
  });

const res = await emelia('/advanced/campaigns');
console.log(await res.json());
```

**Python**

```python
import os
import requests

session = requests.Session()
session.headers["Authorization"] = os.environ["EMELIA_API_KEY"]

res = session.get("https://api.emelia.io/advanced/campaigns")
print(res.json())
```

A `Bearer ` prefix is accepted too (`Authorization: Bearer <key>`), which helps with HTTP clients that add it on their own.

The same key works for the whole host, including the lists and contacts routes under `https://api.emelia.io/lists`, and for the [MCP server](https://docs.emelia.io/docs/ai/mcp.md).

## When the key is refused

The API answers `401`:

```json
{ "error": "Authentication required" }
```

The lists and contacts routes (`/lists/...`) add a code: `{ "error": "Authentication required", "code": "AUTH_REQUIRED" }`.

Check, in this order:

1. **The variable is empty** in the process that sends the request. `echo ${#EMELIA_API_KEY}` prints its length (48), without showing the key.
2. **The key has extra characters**: a space, a line break, quotes. A value that is not exactly 48 characters long is never read as an API key.
3. **The key was disabled or deleted** in Settings, API & Webhooks. A disabled key gets the same `401` as an unknown one.
4. **It is another product's key**, or an Emelia Inbox API key (`mk_...`): it gets a plain `401` here.

## Keep it safe

* Always send the key in the `Authorization` header. Never put it in a URL, a query string or front end code.
* Call Emelia from your server, never from a browser or a mobile app.
* One key per integration (Make, n8n, your back end, an AI agent): if one leaks, you disable it without breaking the others.
* If a key leaked, delete it in Settings, API & Webhooks, then create a new one and update your integrations.
