# `insufficient_scope`: Missing permission

> HTTP 403. The credential reaches the newsletter but does not hold the permission this operation, filter or expansion needs.

Permissions are granted **per newsletter**, in six families: `content`, `audience`, `sending`, `insights`, `settings` and `webhooks`, each at `none`, `read` or `write` (`write` includes `read`). Separately, a credential may hold `account: read`, which covers the operations about the person who owns it (`GET /me` and the collections beside it) and is never implied by anything granted on a newsletter.

This error names what was needed, spelt the way the key form spells it (for example `audience: read`), and what the credential actually holds on the newsletter the request was for. `allowed_values` carries the needed permission. When the refusal is about one parameter value rather than the whole operation, `param` names the parameter and `allowed_values` lists what this credential may send instead, or is left out when it may send nothing there.

Two things decide what a credential holds: what was ticked when it was created, and what its owner can do on the newsletter right now. A person can only grant what they can do themselves, so the same key can lose a permission when its owner's role changes. The same key may also be allowed on one newsletter and refused on the next.

## Why it happens, and how to fix it

### 1. The credential lacks the permission family

The operation needs a family at a level this credential does not hold on this newsletter: reading subscribers needs `audience: read`, creating or editing an article needs `content: write`, sending or scheduling needs `sending: write`, insights need `insights: read`, and so on. The message says which one, and what the credential holds there (for example "On that newsletter this credential holds: content: read, insights: read.").

**Fix:** A key's permissions are fixed when it is minted. Mint a new key on [Settings, API keys](https://usecommune.com/settings/api-keys) with the family named in `allowed_values` ticked for this newsletter, switch your integration to it, then revoke the old key. For an OAuth app, send the creator through authorisation again asking for the scope (for example `audience:read`), and read the scopes actually granted from the token response.

### 2. The owner's role caps what the key can hold

The key was minted with the family, but its owner cannot do that on this newsletter, either because their role never allowed it (an editor can hold at most `settings: read`) or because their role was narrowed after the key was made. The cap is applied on every request, so the message shows what the key holds after it.

**Fix:** Have a newsletter owner or admin mint the key instead, or change the person's role on the newsletter's team page. A new key is not needed if the role is widened; the next request picks it up.

### 3. The operation needs account access

`GET /me` and the account collections (`GET /memberships`, `GET /subscriptions`, `GET /saved-articles`, `GET /liked-articles`) are about the credential's owner rather than a newsletter, and need `account: read`. Nothing granted on any newsletter adds up to it. The message reads "This credential does not hold it anywhere it reaches."

**Fix:** Mint a key with account access turned on, on [Settings, API keys](https://usecommune.com/settings/api-keys), or authorise your OAuth app with the `account:read` scope.

### 4. A read-only credential asked for unpublished content

A credential that holds only `read` on a newsletter sees it as a reader does. On `GET /newsletters/{newsletter}/articles` it may filter `status` by `sent` only, and may not filter by `tag`; on `GET /newsletters/{newsletter}/threads` it may filter `visibility` by `public` only. Anything else would be a view of what is not published, so it is refused rather than answered with an empty page. `param` names the filter.

**Fix:** Drop the filter, or use a value from `allowed_values` (absent for `tag`, which a read-only credential may not filter by at all). To see drafts, scheduled articles, tag-scoped articles or private threads, use a credential holding `write` in one of the newsletter's families.

### 5. An expansion needs a family the operation does not

Some `expand` paths inline rows from another family. `?expand=subscriber` on `GET /newsletters/{newsletter}/insights` inlines subscribers with their email addresses, so it needs `audience: read` on top of the `insights: read` the operation needs. `param` is `expand`, and `allowed_values` lists the paths this credential may expand, or is left out when it may expand none.

**Fix:** Remove the path from `expand` and read the reference it returns instead, or use a credential that also holds the family the message names.

## Retrying

No: the credential has to gain the permission first (a new key, a re-authorisation or a wider role), or the request has to drop the filter or expansion that needs it.

## Example response

```json
{
  "error": {
    "code": "insufficient_scope",
    "message": "This operation needs `audience: read`. On that newsletter this credential holds: content: read, insights: read. Permissions are granted per newsletter, and a credential's holder can only grant what they can do themselves, so check both the credential and your standing on the newsletter.",
    "allowed_values": [
      "audience: read"
    ],
    "request_id": "req_01j9c8h1q7m3n4p5r6s7t8u9v0",
    "docs_url": "https://usecommune.dev/errors/insufficient_scope"
  }
}
```

Often confused with: [`forbidden`](https://usecommune.dev/errors/forbidden.md), [`not_found`](https://usecommune.dev/errors/not_found.md), [`payment_required`](https://usecommune.dev/errors/payment_required.md).
