> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mnemom.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# API Keys

> Personal vs. organization keys, capability scopes, and how to rotate them safely.

Mnemom has **two API key surfaces** — personal keys and organization keys — sharing one capability-based scope vocabulary. This guide covers when to use each surface, how scopes work, and how to rotate them safely.

If you came here from the [Org Admin guide](/guides/org-admin), this is the deep dive on key management.

## The two surfaces, side by side

|                         | Personal key                           | Organization key                       |
| ----------------------- | -------------------------------------- | -------------------------------------- |
| **Endpoint**            | `POST /v1/api-keys`                    | `POST /v1/orgs/{org_id}/api-keys`      |
| **Who can create**      | Any authenticated user                 | Owner or admin of the org              |
| **Billed to**           | The user's billing account             | The org's billing account              |
| **Acts as**             | The user's identity                    | The user's identity, scoped to the org |
| **Visible in**          | Settings → Personal → API keys         | Settings → Organization → API keys     |
| **Survives departure?** | No — when the user leaves, key revokes | Yes — admin must explicitly revoke     |
| **Revoke**              | The user (or admin via support)        | Owner, admin, or original creator      |

Both surfaces produce keys with the `mnm_` prefix; they're identical at the wire level. The difference is **billing attribution** and **lifecycle ownership**.

## Scope vocabulary

Mnemom keys use a **capability-based** scope vocabulary. Each scope names what the key is *allowed to do*. The default is least-privilege; admin scopes are opt-in and gated by your role at mint time and re-checked on every request.

| Scope            | Grants                                                                                                                                                                      | Mintable by                        |
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- |
| `gateway`        | Send traffic through the Mnemom gateway worker (proxy LLM requests, capture traces).                                                                                        | Any authenticated user             |
| `api:read`       | `GET` endpoints scoped to the bearer's identity (your agents, traces, cards, policies).                                                                                     | Any authenticated user             |
| `api:write`      | `POST` / `PUT` / `PATCH` / `DELETE` endpoints scoped to the bearer's identity (mutate your agents, cards, policies).                                                        | Any authenticated user             |
| `admin:org`      | `/v1/orgs/{org_id}/...` admin operations on orgs you own or admin (members, settings, billing, org-level keys). Re-checked per request against your current org membership. | Owner or admin of at least one org |
| `admin:platform` | Mnemom-staff platform operations across tenants. Re-checked per request against your current staff role.                                                                    | Mnemom-staff users only            |

**Default for new keys:** `["gateway", "api:read", "api:write"]`. Admin scopes are not added unless you explicitly request them.

### Scope semantics — what to know

* **Capabilities are independent.** `admin:platform` does NOT imply `api:read`. A key with only `admin:platform` cannot call `/v1/agents`. If your automation needs to call non-admin endpoints alongside admin ones, request both.
* **Mint-time ceiling is enforced server-side.** Requesting a scope you're not eligible for returns HTTP 403 at creation time. Examples:
  ```
  POST /v1/api-keys
  { "name": "doomed", "scopes": ["admin:platform"] }
  ← 403 admin:platform scope requires Mnemom-staff role on your account
  ```
* **Request-time role is re-checked** for admin scopes. If a staff member is demoted after minting an `admin:platform` key, that key's admin power stops working immediately on the next request — without rotation. The key still authenticates for non-admin endpoints if those scopes are also present.
* **Demotion is silent.** Mnemom does not auto-revoke admin-scoped keys when a user's role changes. Use `DELETE /v1/api-keys/{key_id}` (or rotate) when offboarding admin-role users.

### Picking scopes for common patterns

* **Local development on your laptop:** `gateway`, `api:read`, `api:write` (the default).
* **CI runner that publishes traces but doesn't mutate state:** `gateway`, `api:read`.
* **Read-only analytics ingest into Snowflake/BQ:** `api:read`.
* **Service account that manages org members from a script:** `admin:org` (plus `api:read` if it needs to read non-admin endpoints).
* **Mnemom-internal automation (deploy gates, on-call tooling):** `admin:platform` (plus `api:read`/`api:write` if it touches non-admin endpoints too).

## When to use which surface

**Personal key, every time** — *unless* one of the things below applies.

* **Local development.** A developer on the team using Mnemom from their laptop. Personal key.
* **Per-engineer CI accounts.** Each engineer has their own CI runner credentialed against their personal account. Personal key.
* **Single-purpose script you're running yourself.** Personal key.

**Organization key when:**

* **Shared CI/CD infrastructure** that runs as the *org*, not as a specific engineer. Survives engineer turnover.
* **Service-account-style automation** — a cron job, a webhook receiver, a third-party integration that needs to outlive any individual member's tenure.
* **Audit / compliance posture** that needs requests attributed to the org rather than to a person. The [audit log](/api-reference/endpoint/get-orgs-org-id-audit-log) tags org-level keys distinctly from user-level keys.

If a member leaves the org, their **personal keys remain valid** (they're still the user's keys, billed to the user) but they obviously won't have access to the org's data anymore. **Org keys created by that member remain valid** until an admin explicitly revokes them — this is the lifecycle gap that motivates org-key rotation as part of a member-offboarding checklist.

## Creating a key

### Personal

```bash theme={null}
curl -X POST https://api.mnemom.ai/v1/api-keys \
  -H "Authorization: Bearer $MNEMOM_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "local dev",
    "scopes": ["gateway", "api:read", "api:write"]
  }'
```

### Organization

```bash theme={null}
curl -X POST https://api.mnemom.ai/v1/orgs/$ORG_ID/api-keys \
  -H "Authorization: Bearer $MNEMOM_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "ci-prod",
    "scopes": ["gateway", "api:read", "api:write"]
  }'
```

In both cases the response carries the **full secret** in the `key` field. You see it once. Mnemom stores only its SHA-256 hash; we cannot recover the secret if you lose it.

```json theme={null}
{
  "key_id": "mk-1a2b3c4d",
  "key": "mnm_8f3e7c2b91a4d6f8...",
  "key_prefix": "mnm_8f3e",
  "name": "ci-prod",
  "scopes": ["gateway", "api:read", "api:write"],
  "created_at": "2026-04-25T12:34:56Z"
}
```

If you omit `scopes` from the request body, the API substitutes the default set (`["gateway", "api:read", "api:write"]`).

## Using a key

```bash theme={null}
curl https://api.mnemom.ai/v1/agents \
  -H "X-Mnemom-Api-Key: mnm_8f3e7c2b91a4d6f8..."
```

The `X-Mnemom-Api-Key` header is the canonical auth path for `mnm_*` keys. (Some legacy SDKs send the key as `Authorization: Bearer mnm_...` — that path is deprecated; migrate to `X-Mnemom-Api-Key`.)

## Legacy keys (`["gateway", "api"]`)

Keys minted before May 2026 carry the legacy two-scope set `["gateway", "api"]`. They continue to work — the auth gate aliases them to `["gateway", "api:read", "api:write"]` at request time, so existing integrations need no changes.

The dashboard renders these keys with a "legacy" badge. To upgrade a legacy key to the canonical vocabulary:

1. Rotate the key (`POST /v1/api-keys/{key_id}/rotate`) — the rotation preserves the legacy scope set on the new key.
2. Revoke the rotated key and create a fresh one (`POST /v1/api-keys`) without specifying `scopes`. The new key inherits the default `["gateway", "api:read", "api:write"]`.

(You don't have to upgrade — legacy keys remain valid indefinitely. But if you want the dashboard to stop annotating them, this is the migration path.)

## Rotation

Two endpoints, identical contract:

* `POST /v1/api-keys/{key_id}/rotate`
* `POST /v1/orgs/{org_id}/api-keys/{key_id}/rotate`

Each **mints a replacement** with the same `name` and `scopes`, then **immediately revokes the old key**. The full new secret returns in the 201 response.

### No grace period — by design

The old key is invalid as soon as the response reaches you. Rotation is for the **suspect or compromised** case where you do not want overlap.

If you need overlap with an in-flight deploy, **don't rotate**. Instead:

1. `POST /v1/api-keys` to create a *second* key.
2. Update your deployment to use the new key.
3. Verify it's working in production.
4. `DELETE /v1/api-keys/{old_key_id}` to retire the original.

### Failure semantics

* **Insert-new fails:** the response is 500; your old key is still valid. Try again.
* **Insert-new succeeds, soft-revoke fails:** the response is 500 with a hint pointing you at `DELETE /v1/api-keys/{old_key_id}` to finish manually. The new key is fully active either way — capture it before retrying.

### Audit trail

Rotations log a distinct `api_key_rotated` event in your billing event history (and the org audit log for org-level rotations). The event records both the old and new `key_id`s so support can trace a rotation chain.

## Org keys after P4f tightening

Org-key creation requires `owner` or `admin` (not `member`). If you're a member who used to create org keys, the path forward is:

1. Use a [personal key](#creating-a-key) instead. They're billed to you, but Mnemom doesn't double-bill — the personal-key checkmeter is a courtesy view, not a separate ledger.
2. Or ask an admin to create the org key for you. Once it exists, you can rotate it (you become the creator post-rotation) but only the admin can have created it initially.

This matches GitHub's PAT-vs-GitHub-App split, Stripe's restricted-keys-are-admin-only convention, and Cloudflare's user-token-vs-service-token model. The reasoning is simple: org-billed keys outlive their creator's tenure and are a real lifecycle hazard if any member can mint them.

## Revocation

```bash theme={null}
curl -X DELETE https://api.mnemom.ai/v1/api-keys/mk-1a2b3c4d \
  -H "Authorization: Bearer $MNEMOM_JWT"
```

Keys soft-delete: `is_active` flips to `false`, `revoked_at` is timestamped, the row stays for audit. You cannot reactivate a revoked key — create a new one.

For org keys, the same shape applies under `/v1/orgs/{org_id}/api-keys/{key_id}`. **Owner, admin, or original creator** can revoke; member can only revoke keys they created themselves.

## Key hygiene checklist

* **Rotate annually**, or whenever a member with access leaves the org. The audit log shows `last_used_at` per key — rotate dormant keys aggressively.
* **Name your keys.** `"name": "ci-prod"` is much more useful than `"Default"` six months later when you're triaging an alert.
* **Use the smallest scope set that works.** Default to `gateway` + `api:read`/`api:write` and only add admin scopes when the integration genuinely needs them. Smaller blast radius if leaked.
* **Prefer `api:read` for analytics integrations.** Read-only keys are safer and the audit trail is cleaner.
* **Never commit secrets.** The `mnm_` prefix is a string git secret-scanners recognize; we recommend GitHub Secret Scanning + push protection to catch accidents.
* **Include a renewal reminder** in your deploy / IaC if the key has a TTL constraint from your security policy. Mnemom keys themselves don't expire by default.
* **Treat admin-scope keys with extra care.** Use them only for the specific automation that needs them; rotate them on any suspected leak; audit which keys carry `admin:org` or `admin:platform` quarterly.
