# API token scopes: give a token only the access it needs

> Restrict a Linkbreakers API token to the resources it needs, such as links:read or visitors:write. How scopes work, how to create and change a scoped token, and what an insufficient_scope error means.

## Short answer

Every Linkbreakers API token has either **full access** or a list of **scopes**, such as `links:read` or `visitors:write`. A scoped token can only call the endpoints its scopes cover, and anything else is refused with a `403` naming the scope that was missing. Give an AI agent, a reporting script or a single-purpose integration only the scopes it needs, so a leaked token cannot do more than its job.

## Quick summary

- A scope is `resource:read` or `resource:write`, for example `links:read`, `analytics:read` or `webhooks:write`
- A write scope also grants the read scope of the same resource: `links:write` can read links too
- Tokens created without scopes have full access, including any scope added later. Every token that existed before scopes keeps full access
- Every API endpoint requires exactly one scope, declared in the [OpenAPI specification](https://api.linkbreakers.com/internal/openapi/api/v1/api.swagger.json)
- The full list of scopes is public at `GET https://api.linkbreakers.com/v1/api-scopes`
- A token can only create or update tokens with scopes it holds itself
- [Publishable keys](/help/article/secret-key-vs-publishable-key) stay limited to visitor identification and take no scopes

## How scopes work

A scope names a resource and an access level. The resources follow the API: links (with tags, folders and link settings), workflows, QR codes, page themes, media, custom domains, visitors, analytics, webhooks, integrations, workspace, members, API tokens, billing and the Assistant.

When a request arrives, Linkbreakers looks up the one scope that endpoint requires and checks it against the token:

- **Full access** passes every check
- **A scoped token** passes when it holds that scope, or the write scope of the same resource
- **Anything else** is refused with `403` and the code `INSUFFICIENT_SCOPE`

Changes to a token's scopes reach every request within 30 seconds.

Signing in to the dashboard is not affected: your own session always has full access.

## Create a scoped token in the dashboard

1. Go to [**Dashboard → API Tokens**](https://app.linkbreakers.com/workspace/dashboard/api-tokens) and click **Create new token**
2. Name the token after its job, for example "Weekly analytics export"
3. Keep **Secret Key** selected
4. Under **Access**, choose **Restricted**
5. For each resource the token needs, pick **Read** or **Read & write**. Leave the rest on **None**
6. Click **Create token** and copy it. It is shown only once

To change what an existing token can do, open its menu in the token list and choose **Edit access**. You can switch between full access and a restricted set at any time without issuing a new token.

## Create a scoped token with the API

In REST request bodies, scopes use their enum names. Send them in `scopes`; leave `scopes` out for full access.

```bash
curl -X POST https://api.linkbreakers.com/v1/workspace-tokens \
  -H "Authorization: Bearer $LINKBREAKERS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Weekly analytics export",
    "keyType": "WORKSPACE_TOKEN_KEY_TYPE_SECRET",
    "scopes": ["API_SCOPE_ANALYTICS_READ", "API_SCOPE_LINKS_READ"]
  }'
```

The token making this call needs `tokens:write`, and it cannot grant a scope it does not hold. To change scopes later, `PATCH /v1/workspace-tokens/{id}` with new `scopes`, or with `"fullAccess": true` to restore full access.

## Find the scope an endpoint needs

You do not need to guess. The same information is published in three machine-readable places, all generated from one definition in the API:

- **The OpenAPI specification.** Each operation lists its scope under `security` and in `x-required-scope`, and its description ends with "Requires the `links:write` scope." The `oauth2` security scheme lists every scope with a description
- **The scope list.** `GET https://api.linkbreakers.com/v1/api-scopes` returns every scope with its resource, access level and description. It needs no authentication
- **Protected resource metadata.** `https://api.linkbreakers.com/.well-known/oauth-protected-resource` follows RFC 9728 and lists every scope in `scopes_supported`

The SDKs are generated from the OpenAPI specification, so each method's documentation names its scope too.

## Errors

A token without the scope an endpoint needs gets a `403`:

```json
{
  "code": 7,
  "codeType": "INSUFFICIENT_SCOPE",
  "message": "this token is missing the links:write scope this endpoint requires. links:write allows: Create, update and delete links, tags, folders and link settings. Use a token that holds links:write, or one with full access. Learn more: https://linkbreakers.com/help/article/api-token-scopes",
  "details": []
}
```

The response also carries `WWW-Authenticate: Bearer error="insufficient_scope", scope="links:write"`, so a client can tell exactly which scope to ask for.

A request with no token, or a token that is invalid or revoked, gets a `401` with a `WWW-Authenticate` header pointing at the protected resource metadata.

## Scopes for AI agents and MCP

Scopes are the safest way to let an AI agent work in your workspace. Create a token restricted to what the agent's task needs, for example `links:read` and `analytics:read` for an agent that writes reports, and it cannot delete links, change webhooks or create other tokens even if it is told to.

Clients that connect to the [Linkbreakers MCP server](/help/article/how-to-set-up-and-configure-the-linkbreakers-mcp-server) through OAuth can request the same scopes in the `scope` parameter, for example `scope=links:read analytics:read`. The resulting token is limited to those scopes on both the MCP server and the REST API. Requesting `mcp:tools`, or no scope at all, grants full access, which is what existing MCP clients already do.

## Frequently asked questions

### Do my existing tokens still work?

Yes. Every token created before scopes existed has full access and keeps it. Nothing changes until you restrict a token yourself.

### Does `links:write` let a token read links?

Yes. A write scope always includes the read scope of the same resource, so you never need to pick both.

### Why can't my scoped token create another token with more access?

A token can only grant scopes it holds itself. A token with `tokens:write` and `links:read` can create a `links:read` token, but not a full-access one. This stops a restricted token from being used to mint a broader one.

### What happens to a full-access token when new endpoints are added?

It can call them. Full access is not a list of today's scopes: it covers every scope, including ones added later. A restricted token only gains new access when you edit it.

### Can publishable keys have scopes?

No. Publishable keys are designed to sit in client-side code and are limited to visitor identification. Use a restricted secret key for anything else.
