Copy as markdown[View .md](https://docs.funnelfizz.com/concepts/api-keys "View the raw markdown for this page")[Open in Claude](https://claude.ai/new?q=Read%20https%3A%2F%2Fdocs.funnelfizz.com%2Fconcepts%2Fapi-keys.md%20and%20help%20me%20with%20this%20FunnelFizz%20topic%3A%20API%20keys "Open this page in Claude with context")[Open in ChatGPT](https://chat.openai.com/?q=Read%20https%3A%2F%2Fdocs.funnelfizz.com%2Fconcepts%2Fapi-keys.md%20and%20help%20me%20with%20this%20FunnelFizz%20topic%3A%20API%20keys "Open this page in ChatGPT with context")

# API keys

Every call into the MCP server or the public REST API is authenticated with a workspace-scoped API key. This page covers the key format, the scope model, the per-workspace cap, rate limits, and how key activity is audited.

## Where to manage keys[​](#where-to-manage-keys "Direct link to Where to manage keys")

**Settings → Developer**. Visible to **ADMIN** members only. Workspaces with `MANAGER` or `VIEW_ONLY` members will see a "request access from a workspace admin" panel.

The page lists every active key with its prefix, scopes, last-used timestamp, and per-month call count. Use **Create key** to mint a new one and **Revoke** to permanently disable it.

## Key format[​](#key-format "Direct link to Key format")

Keys look like `ff_LongRandomString` — about 51 characters total:

* The `ff_` prefix marks it as a FunnelFizz key (useful for secret-scanner regexes).
* The first 12 characters (`ff_XXXXXXXXX`) are the **display prefix** — stored in cleartext so the UI can show you which key is which. It's short enough to be useless on its own.
* The remaining characters are the secret payload.

We **hash the full key with SHA-256** before storing it. We never persist the cleartext anywhere. If you lose it, revoke and mint a new one — we cannot recover it.

The full cleartext is returned exactly once, in the `cleartext` field of the create response. Copy it immediately into your secret manager.

## Scopes[​](#scopes "Direct link to Scopes")

API keys hold one or more of four coarse scopes:

| Scope   | What it grants                                                                                                          |
| ------- | ----------------------------------------------------------------------------------------------------------------------- |
| `setup` | Register tracking sites, email senders/domains, integrations, and custom events.                                        |
| `read`  | List and read every workspace resource: funnels, metrics, profiles (PRO), reports, audit logs, drilldowns.              |
| `write` | Create and edit funnels/splits/extensions, email drafts and campaigns, automations, tracking sites, and integrations.   |
| `admin` | Workspace administration: team management, billing changes, API key management, ownership transfer, workspace deletion. |

Scopes are filtered three ways at request time, and a key only gets a tool if the intersection is non-empty:

* **Plan** — `read` and `write` require **HOBBY+**; `setup` and `admin` work on **FREE**.
* **Role** — `VIEW_ONLY` can only mint `read`; `MANAGER` adds `setup` and `write`; only `ADMIN` can mint `admin`.
* **Granted** — the explicit set you chose when minting the key.

Plan downgrades take effect **immediately** — a key with `write` continues to authenticate but every write tool will respond with a plan-gate error until you re-upgrade. The key itself does not need to be re-minted.

## Per-workspace cap[​](#per-workspace-cap "Direct link to Per-workspace cap")

| Plan  | Active keys |
| ----- | ----------- |
| FREE  | 1           |
| HOBBY | 3           |
| PRO   | 10          |

Revoked keys do not count. Reach the cap and the create endpoint returns `plan_key_cap_exceeded`. The cap exists so you can't mint N keys to bypass the per-key monthly call quota.

## Rate limits[​](#rate-limits "Direct link to Rate limits")

Rate limits apply per key, not per workspace:

| Plan  | Per minute | Per month |
| ----- | ---------- | --------- |
| FREE  | 30         | 5,000     |
| HOBBY | 60         | 50,000    |
| PRO   | 300        | 500,000   |

Mutation tools (`write` + `admin` scopes) additionally count against the per-day / per-month / per-minute MCP mutation caps from your plan — see [`PLAN_LIMITS`](https://github.com/funnelfizz/funnelfizz/blob/main/src/lib/plans.ts) for the exact numbers (`mcpMutationsPerMinute`, `mcpMutationsPerDay`, `mcpMutationsPerMonth`).

The monthly counter resets on the 1st of each UTC month.

## Audit log[​](#audit-log "Direct link to Audit log")

Every key action is recorded:

* **Key lifecycle** (`api_key.create`, `api_key.revoke`) lands in the workspace audit log alongside other admin events.
* **Per-call activity** (every authenticated request, with tool name, status, latency, source IP hash) lands in the per-key activity log. Open any key on the Settings → Developer page and click **Activity** to see the last 200 events.

Both are workspace-scoped and admin-only; team members below the ADMIN role cannot see them.

## Safety tiers for MCP[​](#safety-tiers-for-mcp "Direct link to Safety tiers for MCP")

MCP write tools layer a **safety tier** on top of the scope check:

* **T0** — read-only tools (`list_*`, `get_*`, drilldowns). No confirmation step.
* **T1** — mutations. Require a single-use, 10-minute `target_token` minted via `confirm_target`.
* **T2** — destructive admin actions (workspace delete, ownership transfer). Require an emailed one-time code on top of `target_token`.

The tier is enforced by the tool itself; the API key's scope is necessary but not sufficient. See [safety tiers](https://docs.funnelfizz.com/ai-agents/safety-tiers.md) for the full handshake.

## Revoking a key[​](#revoking-a-key "Direct link to Revoking a key")

**Settings → Developer → \[Key] → Revoke**. Revocation is immediate — in-flight requests fail with `unauthorized` on the next call. Revoked keys can be reused for audit but never re-activated; mint a new one.

If you can't access a working admin session (e.g., your only key was leaked), you can self-revoke from the MCP side with `confirmSelf: true` so you have a way out without locking yourself out.
