# Authentication

How AI agents authenticate to Everpop. Everpop is built to be operated by
agents, and every way in is documented here.
Base URL: https://everpop.app

## 1. API key (simplest)

- A human creates the key: Dashboard → API (https://everpop.app/dashboard/api). Keys look like `epk_...`.
- Send it on every request: `Authorization: Bearer epk_...`
- The key acts as that user, within their plan limits. Treat it as a secret;
  never embed it in client-side code or share it in logs.
- The REST API and MCP need the **Pro or Scale plan**. Other accounts get
  HTTP 402 with `reason: "subscription"` (no active subscription) or
  `reason: "plan"` (the plan doesn't include API access).

## 2. MCP (Model Context Protocol)

- Endpoint: `https://everpop.app/api/mcp/mcp`
- Two auth modes:
  - **OAuth 2.1 + PKCE (S256)** — discovery at
    [`/.well-known/oauth-authorization-server`](https://everpop.app/.well-known/oauth-authorization-server).
    Public clients only; dynamic client registration is open at the
    `registration_endpoint` listed there. The human approves access in a consent
    popup on everpop.app. Any account can complete consent and list the
    tools; each tool answers an account without Pro or Scale with a 402 result
    (`reason` subscription or plan) instead of acting.
  - **Bearer header** — clients without an OAuth flow send an API key as
    `Authorization: Bearer epk_...`. API keys are never accepted in URL query strings.

## Key lifecycle

- **Scope.** A key is *Full (read + write)*, the default, or *Read-only*. A
  read-only key can call every `GET` endpoint. These calls need a full key:
  `POST /api/v1/clip`, `POST /api/v1/generate`, `POST` and `DELETE /api/v1/videos/upload`,
  `POST /api/v1/videos/complete`, `POST /api/v1/videos/import`, `POST /api/v1/publish`,
  `POST /api/v1/campaigns` and `POST /api/v1/campaigns/{id}/attach`. A read-only
  key there gets HTTP 403 with `code: "scope"`.
- **Expiry.** When creating a key, the user picks 30 days, 90 days (the
  default), 1 year or Never. An expired key cannot be renewed: create a new one.
- **Revocation.** Revoking a key in Dashboard → API stops it at once; it then
  answers like a key that never existed.
- The full key is shown once, when it is created. Everpop stores only a hash of it.

## When the REST API refuses a key

| HTTP | `code` | Meaning | What to do |
|---|---|---|---|
| 401 | `key_missing` | No `Authorization: Bearer epk_...` header. | Send the header. |
| 401 | `key_invalid` | The key is unknown or was revoked. | Ask the user for a current key. |
| 401 | `key_expired` | The key passed its expiry. | The user creates a new key in Dashboard → API. |
| 402 | `subscription` or `plan` | No active subscription, or a plan without API access. | Tell the user; retrying won't change it. |
| 403 | `scope` | A read-only key on a write. | The user creates a key with write access. |
| 403 | `suspended` | The account is suspended. | The user contacts support@everpop.app. |

Every other error code is in [skill.md](https://everpop.app/skill.md) (Error codes).

## What auth does NOT unlock

Publishing is never implicit. `POST /api/v1/publish` requires exact destination
ids, final reviewed metadata and visibility, and explicit confirmation from the
human user — agents included. There is no publish-to-all.

## More

- [llms.txt](https://everpop.app/llms.txt) — canonical facts and API surface.
- [skill.md](https://everpop.app/skill.md) — the full agent guide.
- [openapi.json](https://everpop.app/openapi.json) — machine-readable schema.
