---
title: "Authentication and keys"
description: "The Flume Partner API authenticates with two headers. A partner key identifies your platform, and a user access token identifies the user you call for."
url: https://docs.tryflume.ai/concepts/authentication
updated: 2026-11-11
---

# Authentication and keys

> The Flume Partner API authenticates with two headers. A partner key identifies your platform, and a user access token identifies the user you call for.

Every call carries your **partner key** in `X-Flume-Partner-Key`. Calls made for a user also carry that user's **access token** in `X-Flume-User-Token`. Neither is a bearer token.

## What are the two credentials?

| Credential | Header | Identifies | Lifetime |
|---|---|---|---|
| Partner key | `X-Flume-Partner-Key` | Your platform | Until you revoke or rotate it |
| User access token | `X-Flume-User-Token` | One user of yours | No expiry. It is replaced each time the user verifies, in your screens or in the iframe |

```sh
curl "https://sandbox-api.tryflume.ai/partner/v1/filters" \
  -H "X-Flume-Partner-Key: $FLUME_PARTNER_KEY"
```

## Which calls need which header?

| Calls | Partner key | User access token |
|---|---|---|
| `POST /start-iframe-session` | Required | Optional. Always send it when you hold one |
| `POST /users/trigger-verification`, `POST /users/confirm-verification` | Required | Not needed. If you send one, it must be valid |
| `POST /users/exchange-connect-code`, `DELETE /users/{external_ref}/token` | Required | Not used |
| `GET /filters` | Required | Not needed. If you send one, it must be valid |
| `GET /keys`, `POST /keys`, `DELETE /keys/{key_id}` | Required | Not used |
| `POST /detect-category`, `POST /search`, `GET /searches/{search_session_uuid}` | Required | Required |
| `GET /products/{sku_uuid}`, `POST /request-instant-quote`, `GET /quotes/{quote_uuid}` | Required | Required |
| `POST /save-item`, `POST /save-item/{save_uuid}/result` | Required | Required |
| `POST /sales-requests`, `POST /deep-links` | Required | Required |

## What does a partner key look like?

- Shape: `sk_<environment>_<your slug>_<random text>`.
- A sandbox key starts with `sk_dev_`. A live key starts with `sk_prod_`.
- A key works in one environment only. A sandbox key on the live API is refused like an unknown key.
- The **prefix** (up to the first 4 random characters) is safe to log. The rest is secret.
- Flume stores only a hash of the key. Flume cannot show a lost key again. Rotate instead.

## How do you get a key?

- Flume issues your first key. See [Get a sandbox key](https://docs.tryflume.ai/get-a-key.md).
- There is no sign-up form and no dashboard today.
- After that you list, rotate and revoke keys yourself with the [keys endpoints](https://docs.tryflume.ai/guides/rotate-keys.md).

## What does a user access token look like?

- Shape: `ut_<environment>_<your slug>_<random text>`.
- You get it once, from `POST /users/confirm-verification` or `POST /users/exchange-connect-code`.
- It has no expiry date.
- A user has one working token at a time. It stops working when:
  - you call `DELETE /users/{external_ref}/token`,
  - the user verifies again on your screens (the response holds the new token),
  - the user verifies in the iframe (the new token comes from the connect code exchange),
  - the user's email changes.

See [Users and verification](https://docs.tryflume.ai/concepts/users.md).

## What happens when a credential is wrong?

| Situation | Status | Code |
|---|---|---|
| Key missing, unknown, revoked, expired or from the other environment | 401 | [`PARTNER_KEY_INVALID`](https://docs.tryflume.ai/api/errors.md#partner_key_invalid) |
| User token header not sent on a call that needs it | 403 | [`USER_NOT_CONNECTED`](https://docs.tryflume.ai/api/errors.md#user_not_connected) |
| User token unknown, revoked, replaced or another partner's | 401 | [`USER_TOKEN_INVALID`](https://docs.tryflume.ai/api/errors.md#user_token_invalid) |
| The user's Flume account is closed | 403 | [`USER_ACCOUNT_CLOSED`](https://docs.tryflume.ai/api/errors.md#user_account_closed) |
| You sent the key in an `Authorization` header | 401 | [`EMBED_TOKEN_INVALID`](https://docs.tryflume.ai/api/errors.md#embed_token_invalid) |

The API gives one answer for every bad key. It does not say which part was wrong.

> **Not a bearer token:** The partner key goes in `X-Flume-Partner-Key`, never in `Authorization`. A call with `Authorization: Bearer ...` and no `X-Flume-Partner-Key` returns `401` `EMBED_TOKEN_INVALID`.

## Can you call the API from a browser?

No. The API is server to server.

- Browser calls from your origin are blocked by CORS.
- A key or a user access token in a browser is a leaked credential.
- The Flume iframe holds its own short-lived credential. You never see or handle it.

## How should you store credentials?

- Keep the partner key in a secret manager. Never in source control or a client bundle.
- Store each user access token encrypted, against that user, on your server.
- Log the key prefix and `X-Request-Id`. Never log a full key or token.
- [Rotate](https://docs.tryflume.ai/guides/rotate-keys.md) a key at once if you think it leaked.
