Deze referentie is alleen in het Engels. Naar het Nederlandse REST API-overzicht

Diese Referenz gibt es nur auf Englisch. Zur deutschen REST-API-Übersicht

Cette référence existe uniquement en anglais. Aller à la présentation de l'API REST en français

Esta referencia solo está en inglés. Ir a la introducción de la API REST en español

Authentication

Authentication

Every request carries a bearer token, sent to your organisation's own address and acting as one user. Here is how it works and how it fails.

View as Markdown

Every request carries a bearer token in the Authorization header, and nothing else proves who it is for. There is no key pair, no session cookie and no request signing.

Terminal
curl "https://<your-url>/api/v2/projects" \
  -H "Authorization: Bearer <token>"

<your-url> is the address you sign in to plnnrly on, such as acme.plnnrly.com, or your organisation's own domain.

There are two kinds of token:

TokenForHow you get one
Personal access tokenScripts, servers and integrations you run yourself.You create it in plnnrly. See API tokens.
OAuth access tokenApps that other people install and that act for whoever signs in.The app signs the person in. See Sign in with OAuth.

Both carry the same read and write abilities. Three differences: an OAuth token never carries the destroy class, it cannot upload file contents (see Files: upload and download), and its user's Manage API tokens permission is checked on every request. Everything else on this page applies to both.

The host is part of the credential

The API is served only on your organisation's own address: https://<your-url>/api/v2.

  • There is no shared API host, and no organisation id in the path or in a header. The host is what selects your organisation.
  • A token works only on the organisation it was created in. On another organisation's host it answers 401.
  • If your organisation has its own domain, only that exact domain serves the API. Any other host, including the www or bare variant of that domain, answers 404 with "No API is served on this host."
  • The API never redirects, so following redirects gains a client nothing. Use the address shown under How to connect on the API tokens page.

Responses carry a Vary header that includes Authorization, so a cache between you and plnnrly cannot serve one caller's rows to another.

A token acts as a user

A token belongs to one user: the person who created it, or the person who signed in to the app. Every request runs as that user, so:

  1. The token sees what the user sees, and no more. Project membership, row visibility and the rules on each record apply exactly as they do in plnnrly.
  2. A role change takes effect at once. Permissions are read again on every request. Taking a permission away from a role narrows every token its users hold, without touching the tokens.
  3. Everything runs as that user. POST /worklogs logs time for the token's owner, and filters that accept me, such as filter[user_id]=me, resolve to them. GET/me returns that user to any API token and needs no permission, so a client can show who it is connected as.

Choose whose token an integration uses with care. It can do exactly what that person can, and it changes when their roles change.

Sign in with OAuth

An app that other people install should not ask them to paste a token. Instead it signs them in with OAuth 2.0 (the authorization code flow with PKCE) and receives an access token that it renews itself. The app needs no secret and no approval from plnnrly in advance: it registers itself on the organisation's host. Sign in with OAuth walks through every step and ends with a complete, runnable example.

OAuth tokens cannot delete

OAuth never offers a destroy-class scope: neither api:destroy nor any api:destroy:{prefix}. Every DELETE on /api/v2 needs that class, so an app signed in with OAuth cannot delete anything through the REST API, not even a soft delete. Deleting needs a personal access token with Delete.

AI assistants are the exception. Over MCP, an assistant can delete through its api_write tool when the organisation allows destructive actions and the user confirms the delete. That does not apply when the same sign-in also asked for api: scopes. See Permissions and safety.

The order of checks

Every request passes these checks in this order. The first one that fails decides the answer.

  1. The REST API is switched off for the organisation: 404 endpoint-not-found.
  2. The bearer token is missing or not valid: 401 unauthenticated.
  3. OAuth tokens only: the user lacks Manage API tokens: 403 insufficient-permission.
  4. The token's scope does not cover the operation: 403 insufficient-token-scope, with required_ability listing what would have worked.
  5. The operation belongs to a feature your organisation does not have, such as billing: 404 endpoint-not-found.
  6. Writes only, the body: an unknown or invalid field answers 422 validation-failed. A field that needs a permission of its own answers 403 insufficient-permission naming that field.
  7. The role lacks the operation's permission: 403 insufficient-permission, with required_permission. On a route with a record in it, this is 404 resource-not-found instead when the role cannot read that kind of record at all, so the answer does not reveal whether the record exists.
  8. The record is not visible to the user: 404 resource-not-found.
  9. The record's own rules refuse the user: 403 forbidden-by-policy, or 404 under the same rule as step 7.
  10. The record's state does not allow the change: 409 state-conflict.

Steps 4 and 7 are separate fixes. A scope failure needs a different token; a permission failure needs a role change. Every operation page states the scope and the permission it needs, and Scopes and permissions explains both.

Other answers can come before or in between: 404 on a host that serves no API, 503 tenant-unavailable while the organisation is being set up, suspended or archived, 429 once you exceed a rate limit, 400 for an unknown query parameter or a missing Idempotency-Key, and 404 resource-not-found right after step 4 when the record id does not exist at all. Errors and retries lists them all.

When authentication itself fails

Every authentication failure answers 401 unauthenticated, whatever the cause:

  • no Authorization header, or a malformed one
  • a token that is unknown or revoked
  • a token that has expired
  • a token from another organisation

Every 401 carries the header WWW-Authenticate: Bearer realm="plnnrly-api".

An expired token answers unauthenticated too. The error catalogue also lists token-expired, but it is not sent today, so treat the two alike.

A personal access token expires within 12 months, so plan for it. Watch the Expires column on the API tokens page, and roll or replace a token before that date. An OAuth app renews its own access token with its refresh token.

When the API is switched off

An administrator can switch the REST API off for the whole organisation, under Settings › Administration › MCP & API. See For administrators for who may do that. While it is off:

  • Every /api/v2 request answers 404 endpoint-not-found with the detail "The REST API is not enabled for this organisation.", whatever the token.
  • The OAuth endpoints answer 404, so apps cannot sign anyone in.
  • API access disappears from the user menu.
  • MCP is switched off too. Switching the API back on does not switch MCP back on.
  • Tokens are kept. They work again once the API is back on, until they expire.

MCP access is a different family

AI assistants connect to the MCP server through the same sign-in, with the mcp:use scope. Older personal MCP tokens keep working there.

  • A token that holds only mcp:use cannot call /api/v2: it answers 403 insufficient-token-scope.
  • A token without mcp:use cannot open an MCP session.
  • An app that asks for mcp:use and api: scopes in one sign-in is held to those api: scopes over MCP as well, and its user's Manage API tokens permission is checked on every call. Because OAuth offers no destroy class, such an app cannot delete over MCP either.

The consent screen lists every scope an app asks for, so the user sees what they approve.

Browsers and CORS

/api/v2 accepts browser requests only from this documentation site, for the Try it panel on operation pages. A single-page app on any other origin cannot call the API from the browser, and neither can it call the OAuth token endpoint. Call the API from your own server instead, and keep the token there.