> For the complete documentation index, see [llms.txt](https://docs.millimetric.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.millimetric.ai/core-concepts/api-keys.md).

# API keys

All API access uses Bearer tokens. We ship four kinds, modelled after Stripe's `pk_/sk_` split so the right ones can safely live in a browser.

| Kind        | Example                    | Where to use it                                       | What it can do                                                                                                                                                                              |
| ----------- | -------------------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pk_live_…` | `pk_live_f6589a94_7xPq…`   | Browsers, public pages, snippets                      | Ingest only. **Origin-allowlisted** — requests must come from an origin in your project's `allowed_origins`. **Rejected at `/mcp`** — MCP never accepts a key that ships in browser source. |
| `sk_live_…` | `sk_live_a1b2c3d4_secret…` | Servers, cron jobs, MCP write access                  | Ingest + read. No origin check.                                                                                                                                                             |
| `rk_live_…` | `rk_live_99887766_secret…` | Server-side dashboards, **MCP clients (recommended)** | Read only — query, stats, sources, MCP read tools. Cannot ingest.                                                                                                                           |
| `ak_live_…` | `ak_live_1c4d8a90_secret…` | **Account-level MCP** — agencies, multi-product teams | Read every project this account owns through one credential. **Business tier only.** Used by `/mcp/account`. Cannot ingest.                                                                 |

## What's in a key

```
{kind}_{env}_{prefix}_{secret}
└──┬──┘ └─┬┘ └──┬───┘ └──┬───┘
 pk/sk/rk live  8-char  url-safe
                lookup  secret
```

* The **prefix** (`pk_live_f6589a94`) is the lookup key. It's safe to display in dashboards and logs.
* The **secret** is shown to you exactly once at mint time. Only `sha256(secret || pepper)` is stored — we cannot recover or re-display it. If you lose it, revoke and mint a new one.

## Origin allowlist for `pk_*` keys

Every project has a list of `allowed_origins`. `pk_*` requests must carry an `Origin:` header that matches one of them, or they're rejected with `403 origin_not_allowed`.

```http
POST /v1/track HTTP/1.1
Authorization: Bearer pk_live_…
Origin: https://yoursite.com   ← must be in the project's allowed_origins
```

If you serve from `https://yoursite.com` and `https://www.yoursite.com`, list both.

`sk_*` and `rk_*` keys ignore `Origin` because they're never meant to be in a browser.

## Minting and revoking

In the dashboard (`apps/web`):

1. Open the project.
2. Click `+ pk` / `+ sk` / `+ rk`, give it a label.
3. The secret appears in a modal **once** — copy it.
4. To revoke, click **Revoke** on the key row. It cannot be undone; existing clients will immediately get `401 invalid_api_key`.

## Scopes vs kinds

| Kind | Scope    | Notes                                                                                                    |
| ---- | -------- | -------------------------------------------------------------------------------------------------------- |
| `pk` | `ingest` | Browser-safe. Only ingest endpoints. **Never accepted by `/mcp`.**                                       |
| `sk` | `ingest` | Same powers as `pk` but no origin check. Required for `/v1/forget`. Accepted by `/mcp`.                  |
| `rk` | `read`   | Read endpoints + MCP read tools. Accepted by `/mcp` (recommended for AI agents).                         |
| `ak` | `read`   | Account-scoped. Accepted **only** by `/mcp/account`. Sees every project the account owns. Business tier. |

If you call a read endpoint with an ingest-scope key (or vice versa) you'll get `403 insufficient_scope`. If you hit `/mcp` with a `pk_` or `ak_` key you'll get `403 key_kind_not_allowed`. If you hit `/mcp/account` with anything other than `ak_`, you'll get `403 account_key_required`.

## When to use an `ak_` key

Use one if you own more than one Millimetric project and you'd otherwise mint and rotate an `rk_` key per project for the same agent. Examples:

* A consultancy / agency running analytics for many clients.
* A multi-product company with one project per app.
* Staging + production isolated as separate projects.

You configure your MCP client once, against `/mcp/account`, and the agent can call `list_projects`, query a single project by `project_id` / `project_slug`, or run cross-project tools like `compare_projects` in one round trip. See [MCP overview](/mcp-for-ai-agents/overview.md).

## Operational notes

* **Rotation**: revoke + re-mint. Re-issuing all keys requires changing the server pepper, which is a deliberate, planned event.
* **Last-used timestamp**: each successful auth updates `last_used_at` on the key. Stale keys are easy to spot.
* **Caching**: the Worker caches verified keys for 5 minutes per instance. Revocation takes effect within that window.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.millimetric.ai/core-concepts/api-keys.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
