---
title: "Keys, kinds and scopes"
description: "The two key kinds, scopes, rotation, and why a key never outranks its creator."
canonical: "https://writavo.com/docs/authentication"
last-updated: "2026-09-25"
---

# Keys, kinds and scopes

Every request carries a key. The key decides which Site you reach and what you may do there.

## Sending a key

Send it on every request. Only a hash of each key is stored, so a lost key cannot be recovered, only rotated.

## The two kinds

**What a publishable key cannot do** (returns 403)

```bash

curl https://api.writavo.com/v1/usage \
  -H "Authorization: Bearer wv_pub_EXAMPLE000000000000000000000000000"

```

`GET /usage` returns the organisation's credit balance and plan, so a browser-safe key is refused whatever scopes it carries.

## What a publishable key may reach

Only five scopes may sit on a publishable key: articles:read, authors:read, entries:read, meta:read and taxonomy:read. Every other scope, including media:read, pipeline:read and comments:read, needs a secret key. It may call only these operations:

## Scopes

What a key may do; every operation names the scope it needs. A scope is the outer bound: the
creator's live permissions, the plan and, for pipeline runs, credits and the spend cap still apply.

- **Publishable keys:** `:read` scopes only, never `media:read`, `pipeline:read`, `webhooks:read`
  or any settings, delivery, SEO, outreach, team, billing, insights or logs scope. `meta:read`
  is allowed but `GET /usage` is not. See `x-publishable` on each operation.
- **AI agent keys:** any scope except `keys:read`, `keys:write`, `webhooks:read` and
  `webhooks:write`.
- **Comments:** `comments:read` and `comments:write` need the comments.moderate permission.
  Approved comments are read with `articles:read`; readers' comments are posted with
  `engagement:write`.
- **Sensitive:** `plan:write` and `prompts:write` change what the AI writes; `pipeline:config`,
  `seo:write`, `delivery:write` and `billing:write` can spend money; `team:write` and
  `roles:write` change who can do what.

## A key never outranks its creator

> A secret key can do **what its creator can do right now, limited to its scopes**. This is checked on every request, not fixed at creation.

If the creator is demoted, loses a permission or leaves the organisation, their keys narrow or stop on the next request, and an integration may start returning `403 INSUFFICIENT_SCOPE`.

- Create keys for long lived integrations under an account that will not be reorganised.
- When someone leaves, recreate their keys under a current member.
- `GET /keys` shows the scopes actually granted. A missing scope means the creator did not have it.

**List the keys on this Site** (returns 200)

```bash

curl https://api.writavo.com/v1/keys \
  -H "Authorization: Bearer wv_sk_EXAMPLE0000000000000000000000000000"

```

Metadata only. A secret is shown once at creation and is never retrievable, because only a hash is stored.

## Expiry, rotation and revocation

- **Expiry is optional.** Set `expires_at` at creation; after that the key fails with `API_KEY_EXPIRED`.
- **Rotation issues a new secret**, shown once. Update your integration, then let the old one go.
- **Revocation is immediate** on the next request, and answers `API_KEY_REVOKED`.
- **`key_prefix` is the only part you can display.** Use it to tell keys apart in your logs and UI.

All of these are on the [keys resource](/docs/api/api-keys) and in the dashboard.

## Signing in from a terminal

The Writavo CLI and MCP server need no pasted key. They show a link and a short code, and you approve in the dashboard.

- **The key is made on your machine.** Only its SHA-256 is sent, so the secret never leaves your machine.
- **You choose the Site and see the scopes.** The key never gets more than you hold yourself.
- **It is a normal key**, listed under Settings > API keys and Settings > AI agents, and can be rotated or revoked. It expires after 90 days; the client can extend it while in use (`POST /auth/key/extend`), up to 365 days from creation.
- **Only approve what you started.** A code you did not ask for would give someone else access to your Site. Deny it.

Building your own client? Use `POST /auth/device` and `POST /auth/device/token` (see the [device sign-in reference](/docs/api/device-sign-in)). They are the only endpoints that take no key.

Assistants that support remote MCP can use `https://mcp.writavo.com/mcp`, which signs you in with OAuth 2.1 in the browser. OAuth works on that host only; this API accepts API keys only. See [the MCP server](/docs/mcp).

## When authentication fails

`INVALID_API_KEY`, `API_KEY_REVOKED` or `API_KEY_EXPIRED`: no key, or an unusable one. It never
distinguishes "no such key" from "wrong key".

`INSUFFICIENT_SCOPE`. The key lacks this operation's scope, or its creator's permissions no
longer cover it. Another Site's object is always 404, never this. A 403 may also be:

- `AGENT_ACCESS_DISABLED` - AI agent access is turned off.
- `APPROVAL_DENIED` - a person denied this action.
- `FORBIDDEN` (organisation, team, settings) - a change no scope allows, such as an AI agent
  changing the access of the person it acts for, anything about ownership, or a setting
  only a person may change. The message says what to do instead.
