API keys & API access

Create and revoke API keys, how authentication works, the scope allow-list, rate limiting and what the API exposes.

Overview#

API keys give you programmatic access to metricsKit's `/api/v1` endpoints outside the console. A key is created in the console; the plaintext is returned only once at creation and can never be viewed again.

  • List: `GET /api/v1/api-keys` (scope `admin:api-keys`)
  • Create: `POST /api/v1/api-keys`
  • Revoke: `DELETE /api/v1/api-keys/:id`
Note: Creating a key requires a console login session (Clerk session) and cannot be done with another API key. Revocation is scoped by user only, so a key holding `admin:api-keys` can in theory revoke another key of the same user.

Create and revoke#

The create body is `{ name, scopes?, expires_at?, rate_limit? }`, where `name` is required.

  • `scopes` is validated again on the backend and only accepts the 8 allow-listed scopes (next section).
  • The plaintext key is returned only in the create response; the database stores only its SHA-256 hash.
  • The generated plaintext is `mk_live_` + 32 hex characters; the validation regex also accepts `mk_(live|test)_[a-f0-9]{32}`.
  • `expires_at` is optional (no value means it never expires); `rate_limit` defaults to 600 (but the current rate-limit path does not read this field).
  • Revocation is a soft delete: `status` is set to `revoked` and the record is kept.
Tip: The console shows the plaintext once at creation with a copy button; you cannot retrieve it later, so save it immediately.

Authentication#

Requests authenticate with the `Authorization` header, accepting either an API key or a Clerk session JWT; a signed-in browser can also use the Clerk session cookie `__client`.

Authorization: Bearer mk_live_<32 hex>

The API-key path first runs a regex check, then looks up `api_keys` by SHA-256, requires `status='active'` and an unexpired key, then reads `scopes`, `rate_limit` and the user plan; `last_used_at` is written at most once every 5 minutes.

Note: Scope checks apply only to API-key identities; console user sessions have implicit full permission.

Scope allow-list#

Only these 8 scopes can be selected at creation:

ScopePurpose
read:overviewMost read endpoints: sites, overview, reports, sharing, and more
read:realtimeCan be created, but no route currently uses it
read:keywordsKeyword endpoints: /reports/keywords-tracker, /sites/:siteId/reports/keywords
read:notesRead timeline notes
read:aiAI Q&A
write:notesWrite timeline notes
admin:api-keysManage API keys themselves
admin:billingStart a billing checkout
Note: Two caveats. First, many write operations (creating a site, updating a site, disconnecting, share links, public-page config, AFF patterns, ecommerce brand terms, URL inspection and more) are also registered as `read:overview`, with no separate `write:*` scope. Second, `read:realtime` can be created but no route in the source uses it — realtime endpoints actually require `read:overview`.

Rate limiting#

Rate limits are designed in three tiers per plan, but the current auth pipeline enforces a flat 600 requests/minute for both API and user:

PlanDesigned (planPolicy)Enforced
free60/min600/min
pro600/min600/min
business3000/min600/min
Note: Counting is per-isolate in memory, bucketed by API key id or user id — not a global strict limit. `enforceRateLimit` fails open on internal errors, and the `rate_limit` field set at creation is not used by the rate-limit path.
  • MCP server: /mcp
  • Plans & feature gating: /plans
  • Data sources overview: /data-sources