# Scopes

Every endpoint declares a required scope. The bearer token must hold that
scope or the request fails with **`403 insufficient_scope`** and a
`WWW-Authenticate: Bearer error="insufficient_scope" scope="<scope>"` header.

Scopes are granted when:

- the user **approves the OAuth consent screen** for a third-party client, or
- the admin **selects scopes when minting a PAT**.

## Active scopes

| Scope | What it grants |
|---|---|
| `user:read` | Read the authenticated user's profile (`/v1/me`). |
| `event_types:read` | List and read event types. |
| `event_types:create` | Create event types. (Reserved — no public write endpoints yet.) |
| `event_types:update` | Modify event types. (Reserved.) |
| `event_types:delete` | Delete event types. (Reserved.) |
| `slots:read` | Check slot availability. |
| `bookings:read` | List and read bookings. |
| `bookings:create` | Create bookings. |
| `bookings:cancel` | Cancel bookings. |
| `bookings:reschedule` | Reschedule bookings. |
| `bookings:update` | Patch booking metadata, responses, and attendee name. |
| `webhooks:read` | List and read webhook subscriptions, and their recent deliveries (`/v1/webhooks`). |
| `webhooks:write` | Create, edit, delete, rotate the secret of, and test webhooks. |
| `availability:read` | Read schedules. (Reserved.) |
| `availability:write` | Modify schedules. (Reserved.) |

"Reserved" scopes are recognised by the auth server but no `/v1/*` endpoint
consumes them yet — they exist so apps can request the right surface ahead of
the endpoints landing.

## Alias scopes

Some commonly-bundled scopes are exposed as **aliases**. When a token is
granted with an alias, the alias is **expanded at grant time** into its
constituent granular scopes — runtime checks always read the expanded set.

| Alias | Expands to |
|---|---|
| `event_types:write` | `event_types:create`, `event_types:update`, `event_types:delete` |
| `bookings:write` | `bookings:create`, `bookings:cancel`, `bookings:reschedule`, `bookings:update` |

Practical consequence: a token granted `bookings:write` carries four granular
scopes — that's the set you'll see in `meta.request_id` audit logs, in the
`/v1/_ping` response, and in the `scope` claim of an issued OAuth token.

## Reserved scopes (not yet active)

These appear in discovery but no endpoint currently consumes them:

```
routing_forms:read    routing_forms:create   routing_forms:update
routing_forms:delete  routing_forms:write    teams:read
teams:write           calendars:read         calendars:write
analytics:read        mcp:scheduling:read    mcp:scheduling:write
```

## Required scope per endpoint

| Method · Path | Scope |
|---|---|
| `GET /v1/_ping` | *none* (auth only) |
| `GET /v1/me` | `user:read` |
| `GET /v1/event-types` | `event_types:read` |
| `GET /v1/event-types/:idOrSlug` | `event_types:read` |
| `GET /v1/slots` | `slots:read` |
| `GET /v1/slots/check` | `slots:read` |
| `GET /v1/bookings` | `bookings:read` |
| `GET /v1/bookings/:uid` | `bookings:read` |
| `POST /v1/bookings` | `bookings:create` |
| `POST /v1/bookings/:uid/cancel` | `bookings:cancel` |
| `POST /v1/bookings/:uid/reschedule` | `bookings:reschedule` |
| `PATCH /v1/bookings/:uid` | `bookings:update` |
| `GET /v1/webhooks` | `webhooks:read` |
| `GET /v1/webhooks/:id` | `webhooks:read` |
| `GET /v1/webhooks/:id/deliveries` | `webhooks:read` |
| `POST /v1/webhooks` | `webhooks:write` |
| `PATCH /v1/webhooks/:id` | `webhooks:write` |
| `DELETE /v1/webhooks/:id` | `webhooks:write` |
| `POST /v1/webhooks/:id/rotate-secret` | `webhooks:write` |
| `POST /v1/webhooks/:id/test` | `webhooks:write` |

## Requesting scopes

**OAuth:** include them on `/v1/oauth/authorize` as a space-separated `scope`
parameter. The set must be a subset of the client's registered `allowed_scopes`
— otherwise `400 invalid_scope`. The user can narrow further from the consent
screen; granted scopes are the user's choice intersected with the request.

**PAT:** select scopes in the **New API key** dialog in
[Admin Center → API](/360/api). Expanding the scope set on an existing key
requires re-confirming your account password — narrowing does not.

## Insufficient scope

```json
{
  "error": {
    "code": "insufficient_scope",
    "message": "This action requires the 'bookings:create' scope",
    "details": { "required_scope": "bookings:create" },
    "request_id": "req_…"
  }
}
```

The remedy is always: mint or re-authorize a token that holds the required
scope. Scopes cannot be elevated mid-session.
