# API tokens

Create the personal access tokens your scripts and integrations use, narrow them to what they need, and roll or revoke them in time.

A personal access token lets your own scripts and integrations call `/api/v2` as you. It is shown once, it always expires, and it never grants more than you may do yourself.

Building an app that other people install? Let it [sign them in with OAuth](https://developers.plnnrly.com/en/docs/api/v2/guides/oauth-apps/) instead of asking them for a token.

## Create a token

1. In plnnrly, open **API access** in the user menu (top right, under your name). The page that opens is called **API tokens**.
2. Choose **Create token**.
3. Fill in the form. The fields are explained below.
4. Copy the token from the **Your new API token** dialog. It is shown once: after you close the dialog, nobody can see it again. If you lose it, [roll](#roll-a-token) the token or revoke it and create another.

The **How to connect** block at the top of the page shows your **Base URL**, ready to copy, and how to send the token: in the header `Authorization: Bearer <token>`.

| Field         | What to fill in                                                                                                                                                                                   |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Name**      | Required. Name it after the integration, not after yourself: it is what you will read in the token list a year from now.                                                                          |
| **Scopes**    | **Read**, **Write** or **Delete**. **Write** includes **Read**, and **Delete** includes both, so ticking one ticks and locks the ones it includes. Only the scopes your role can use are offered. |
| **Resources** | Optional. Leave it on **All resources**, or pick the resources this integration touches. Only the resources your role can use are listed.                                                         |
| **Expires**   | Required. It defaults to 90 days from today and can be at most 12 months away.                                                                                                                    |

The token list shows each token's **Name**, **Scopes**, **Created**, **Expires** and **Last used** date. **Last used** is the quickest way to find tokens that nothing uses any more.

## Scopes and resources

**Scopes** and **Resources** together make the abilities the token carries. Ticking **Read** and **Write** with the resources **Projects** and **Budgets** creates four:

```text
api:read:projects   api:read:budgets
api:write:projects  api:write:budgets
```

On **All resources**, the token carries the unnarrowed abilities instead, such as `api:read` and `api:write`, which cover every resource. **Delete** is stored as `destroy`, so its abilities read `api:destroy:projects` or `api:destroy`.

**Resources** shows the permission group names you also see on the **Roles** page, not the prefixes in the abilities. This is what each one covers:

| Resources option       | Prefix                   | Covers                                                                                                                                              |
| ---------------------- | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| Projects               | `projects`               | `/projects`, `/project-links`                                                                                                                       |
| Budgets                | `budgets`                | `/budgets`                                                                                                                                          |
| Budget groups          | `budget_groups`          | `/budget-groups`                                                                                                                                    |
| Work types             | `work_types`             | `/work-types`                                                                                                                                       |
| Workflows              | `workflows`              | `/workflows`, `/workflow-statuses`, `/workflow-transitions`                                                                                         |
| Customers              | `customers`              | `/customers`, `/contacts`, `/contact-roles`                                                                                                         |
| Customer categories    | `customer_categories`    | `/customer-categories`                                                                                                                              |
| Sales invoices         | `sales_invoices`         | `/sales-invoices`, `/sales-invoice-rows`                                                                                                            |
| Invoices               | `invoices`               | `/invoices`, the legacy per-project invoices from before sales invoices                                                                             |
| Customer subscriptions | `customer_subscriptions` | `/customer-subscriptions`, `/subscription-items`                                                                                                    |
| Subscription types     | `subscription_types`     | `/subscription-types`, `/subscription-type-items`                                                                                                   |
| Subscription products  | `subscription_products`  | `/subscription-products`                                                                                                                            |
| Company branches       | `company_branches`       | `/company-branches`                                                                                                                                 |
| Users                  | `users`                  | `/users`                                                                                                                                            |
| Project workspace      | `project_management`     | `/work-items` and everything under it, `/subtasks`, `/work-item-links`, `/labels`, `/sprints`, `/todos`, and the comments and uploads of work items |
| Kanban boards          | `kanban`                 | `/tasks`, `/projects/{project}/tasks`                                                                                                               |
| Time entries           | `times`                  | `/worklogs`                                                                                                                                         |
| Worklog overview       | `hours`                  | `/timers`                                                                                                                                           |
| Project drive          | `project_drive`          | Drive items owned by a project                                                                                                                      |
| Customer drive         | `customer_drive`         | Drive items owned by a customer                                                                                                                     |
| Organisation drive     | `organization_drive`     | Drive items owned by the organisation                                                                                                               |
| User drive             | `user_drive`             | Drive items owned by a user                                                                                                                         |
| Absences               | `absences`               | `/absences`                                                                                                                                         |
| Public holidays        | `holidays`               | `/holidays`                                                                                                                                         |
| Free days              | `free_days`              | `/free-days`                                                                                                                                        |
| Daily check-ins        | `checkins`               | `/checkins`                                                                                                                                         |
| Furlough requests      | `furlough`               | `/furlough-balance-mutations`                                                                                                                       |
| Agenda                 | `events`                 | `/events`                                                                                                                                           |

The four drive options cover `/drive-items`, `/drive-folders`, `/drive-documents` and `/notes`, plus the comments, files and uploads of drive items, each for the items with that owner.

> **Warning:**
> **Time entries** and **Worklog overview** are often mixed up. Logged hours, `/worklogs`, are **Time entries** (`times`). Running timers, `/timers`, are **Worklog overview** (`hours`). A token narrowed to **Worklog overview** cannot log time: `POST /worklogs` answers `403` insufficient-token-scope.

Two rules limit what a token can carry:

- **The form only offers what your role reaches.** **Scopes** lists the classes you can use on at least one resource, and **Resources** lists the resources you can use with at least one class, which is why two colleagues can see different options. A combination your role cannot use, such as **Write** on a resource you may only read, can still be created, but it never lets the token do more than your role allows.
- **There is no wildcard.** No token ever carries "everything", and an unknown resource is dropped rather than stored.

Narrow each token to what its integration does. A nightly export needs **Read** on two resources. Giving it **Delete** on everything because that was one click less turns a leaked token from an incident into a disaster.

[Scopes and permissions](https://developers.plnnrly.com/en/docs/api/v2/guides/scopes/) lists every ability and the operations it covers.

### Narrowing to your own time or check-ins

The worklogs, timers and check-ins you file yourself need no permission. Reading them back does, even your own: `hours::read` for worklogs and timers, `checkins::read` for check-ins. **Resources** lists **Worklog overview** and **Daily check-ins** only with those permissions, and **Time entries** with `hours::read` or an extra time permission such as `times::write_overtime`.

Without those, you cannot narrow a token to your own time or check-ins. Create a **Write** token on **All resources** instead. It still reaches only what your role allows.

## Expiry

Every token expires. There is no option for a token that never expires.

- **Expires** defaults to 90 days from today and can be at most 12 months away.
- An expired token answers `401` [unauthenticated](https://developers.plnnrly.com/en/docs/api/v2/guides/errors/#unauthenticated), the same as a revoked one.
- The token list highlights an **Expires** date that has passed.

Plan for the date before it arrives: [roll](#roll-a-token) the token, or create its replacement, deploy it and revoke the old one.

## Roll a token

**Roll** replaces a token's secret and gives it a new expiry date.

1. In the token list, choose **Roll** on the token.
2. Pick the new **Expires** date. It starts at the old date while that is still in the future.
3. Copy the new secret. It is shown once.

What happens:

- The token keeps its name and its abilities.
- The old secret stops working at once, so your clients get `401` until you give them the new one.
- Rolling also renews a token that has already expired.
- Rolling works when you already hold ten tokens. The one exception is rolling an expired token while you hold ten other live ones.

Which to use:

- **Roll** when a short gap is acceptable.
- For no gap at all: create a new token, deploy it, then revoke the old one.

## Revoke a token

**Revoke** deletes a token at once. Every client that uses it gets `401` [unauthenticated](https://developers.plnnrly.com/en/docs/api/v2/guides/errors/#unauthenticated) from its next request. There is no grace period.

Revoking is not the only way to narrow access. Permissions are read again on every request, so taking a permission away from a role narrows every token its users hold, at once. If a token can do more than it should, a role change may be the better fix.

## The ten-token cap

You can hold at most ten live API tokens. Expired tokens and connected apps do not count. At the cap, submitting **Create token** shows "You already have ten active API tokens. Revoke one before you create another."

The cap exists because of the [rate limits](https://developers.plnnrly.com/en/docs/api/v2/guides/rate-limits/). Each token has an allowance of its own, but all tokens in the organisation also share one organisation allowance, so more tokens never add room beyond that ceiling.

## Who may create tokens

Creating, rolling and revoking tokens needs the **Manage API tokens** permission. The same permission decides whether you may connect an app to the REST API with [OAuth](https://developers.plnnrly.com/en/docs/api/v2/guides/oauth-apps/). Connecting an AI assistant over MCP does not need it.

- In a new organisation the **Admin** role holds it from the start. If nobody sees **API access**, someone who manages roles grants it as below.
- To give it to a role, open **HRM › User Management › Roles**, edit the role, and tick **Manage API tokens** under **API tokens** on the **Settings** tab.
- Taking it away stops the user's OAuth apps at once: their calls answer `403` [insufficient-permission](https://developers.plnnrly.com/en/docs/api/v2/guides/errors/#insufficient-permission). The user's personal tokens keep working until they expire, but the user can no longer see, roll or revoke them. To clean them up, give the permission back first.

The organisation's switch comes first. While the REST API is switched off, **API access** is hidden and every token answers `404`. See [when the API is switched off](https://developers.plnnrly.com/en/docs/api/v2/guides/authentication/#when-the-api-is-switched-off).

## Connected apps

Apps that signed you in with [OAuth](https://developers.plnnrly.com/en/docs/api/v2/guides/oauth-apps/) are listed under **Connected apps** on the same page, with the host they send you back to. The section appears once at least one app is connected.

- You approve an app once. From then on it renews its own access, so there is nothing to copy and no expiry date to plan for.
- **Revoke** disconnects an app from the API at once, and it has to ask you to sign in again. If the same sign-in also connected it to MCP, that ends too.
- A connected app does not count towards the ten-token cap.

## MCP access is separate

AI assistants use the [MCP server](https://developers.plnnrly.com/en/docs/mcp/), not these tokens. They connect by signing you in, and you manage them in the **AI** panel (the sparkles icon in the top bar), where **Disconnect** ends a connection. See [disconnect an app](https://developers.plnnrly.com/en/docs/mcp/#disconnect-an-app).

An API token cannot open an MCP session, and an AI assistant's connection cannot call `/api/v2` unless it also asked for `api:` scopes. If you want both an assistant and an integration, connect the assistant by signing in and create an API token for the integration.

## Related

- [Authentication](https://developers.plnnrly.com/en/docs/api/v2/guides/authentication/): how a token is sent and what it acts as.
- [Scopes and permissions](https://developers.plnnrly.com/en/docs/api/v2/guides/scopes/): every ability and permission, and what each covers.
- [Rate limits](https://developers.plnnrly.com/en/docs/api/v2/guides/rate-limits/): the per-token and per-organisation allowances.
