# Authentication

> API keys belong to the account, can call every endpoint including the ones that spend credits, and are sent as a bearer token. How to create, roll and revoke them, and where they must never go.

Every request carries an API key in the `Authorization` header:

```http
GET /external/v1/credits HTTP/1.1
Host: api.funnelfeedr.com
Authorization: Bearer ff_live_k2Xq9TbW4mNv7RcL1sYd8HpJ3fGa6ZeU0x4QwM
```

The key authenticates the API under `/external/v1` only. It does not log in to the app, and it does not work with the [MCP server](https://funnelfeedr.com/support/mcp-overview), which signs in per person with OAuth.

## Keys belong to the account

An API key is a service credential for your **account**, not for a person. It keeps working when the admin who created it leaves, and it never acts as any user:

- **What it can read.** Funnelfeedr's shared organization and contact data, as your account sees it in the app: your target contact roles decide which contacts `organizations/contacts/match` returns, and what your account has revealed comes back unmasked. It never sees another account's data.
- **What it changes.** Nothing in your account except what a reveal unmasks. There is no endpoint that creates or edits records.
- **What it spends.** Reveals are charged to the account's credits, like a reveal in the app, and unmask the details for everyone in the account.

Every key can call every endpoint, the ones that spend credits included. There is no read-only key and no per-key spending limit: what limits a single request is the `maxCredits` it carries (see [Credits & reveal](https://funnelfeedr.com/developers/credits-and-reveal.md)), and what limits a key is the account's balance. Only admins can create, roll and revoke keys.

## Key format

```text
ff_live_ + 32 random characters + 6-character checksum
```

A key is 46 characters, letters and digits after the prefix, and always starts with `ff_live_`. The last six characters are a checksum of the random part, so a mistyped key is rejected straight away and secret scanners can spot a leaked key without false positives. There is no test mode in v1: every key is a live key against your real data and credits.

The app shows each key by its first characters (for example `ff_live_k2Xq`) so you can tell keys apart. The full key is shown once, when you create it. Funnelfeedr stores only a SHA-256 hash and cannot show it again; if you lose it, roll it.

## Create, roll and revoke

All three are in **Settings → API keys**.

- **Create.** Name the key after the integration that will use it. Copy the key from the confirmation; it is not shown again.
- **Roll.** Issues a new key with the same name, and lets the old key keep working for a period you choose, from immediately up to 7 days. Deploy the new key within that window. When it ends, the old key answers `401 api_key_expired`.
- **Revoke.** Stops the key immediately. It answers `401 api_key_revoked` from then on. Revoke straight away if a key may have leaked, then create a new one.

Each key also has a request log in the app — method, path, status, duration, items and credits — for the last 30 days. It is the place to see what an integration has been doing and what it spent.

## Keep keys secret

A key can do everything the API allows, including spending your account's credits. Treat it like a password.

- **Keep it server-side.** Call the API from a backend, a job, a serverless function or an agent's runtime — never from browser JavaScript, a mobile app or a desktop app you ship. Anything sent to a client can be extracted.
- **Read it from the environment** (`FUNNELFEEDR_API_KEY` by convention) or a secrets manager. Never hard-code it or commit it; keep `.env` files out of git.
- **Never put it in a URL**, a log line, an error report or a prompt you share.
- **One key per integration**, so you can revoke one without breaking the others, and the request log tells you which one did what.

## Authentication errors

| Status | `code` | Meaning |
|---|---|---|
| 401 | `invalid_api_key` | Missing, malformed or unknown key. |
| 401 | `api_key_revoked` | The key was revoked. |
| 401 | `api_key_expired` | The key was rolled and its overlap ended. |
| 403 | `feature_not_enabled` | API access is not enabled for the account. |

None of them are retryable: fix the key, then try again. See [Errors](https://funnelfeedr.com/developers/errors.md) for the response format.
