Plum / developers

Personal access tokens

Create long-lived tokens for your own scripts, choose an expiry, and revoke them.

A personal access token lets your own scripts and tools call the Optima API as you. Send it as Authorization: Bearer <token> to the same REST routes Optima's apps use, or to /mcp. A token is tied to your account; it is not for third-party applications. Apps that act for other people use OAuth with a consent screen.

A token looks like optima_pat_ followed by 43 characters. Optima stores only a hash of it and shows it exactly once, when you create it.

Create a token

Create tokens from a signed-in Optima app, using an app session or an Optima app's OAuth token with account:manage. A personal access token cannot create another token.

curl https://api.getoptima.com/tokens \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "X-API-Version: 1" \
  -H "Content-Type: application/json" \
  -d '{"name": "Nightly export", "expires_in_days": 90}'

name is required: 1 to 80 characters after trimming, to help you recognize the token later. expires_in_days is required too. Send a whole number of days from 1 to 3650, or null for a token that never expires. Optima does not choose an expiry for you. Common choices are 30, 90, or 365 days.

The response is 201 Created:

{
  "success": true,
  "data": {
    "personal_access_token": {
      "id": "0b8f7a39-5f0f-4a4e-9a36-6a0f0f4c3e21",
      "name": "Nightly export",
      "last_four": "Qx7a",
      "permissions": ["pipelines:read", "...", "devices:manage"],
      "created_at": "2026-09-29T12:00:00.000000+00:00",
      "last_used_at": null,
      "expires_at": "2026-12-28T12:00:00.000000+00:00"
    },
    "token": "optima_pat_..."
  }
}

Copy token into your secret store now. Optima cannot show it again; if you lose it, revoke it and create another. Never commit a token to source control or put it in a URL.

Warning: tokens that never expire. A token created with "expires_in_days": null has expires_at: null and works until you revoke it, sign out everywhere, or delete your account. Anyone who obtains it can read and change your Optima data indefinitely, including transcripts, contacts, and audio. Prefer an expiry, keep never-expiring tokens in a secret manager, and revoke any token you no longer use.

A token receives every account permission (never a workspace permission), and its permissions list shows what it can do, by current permission names. A permission that depends on an account setting, such as a content layer or developer access, works only while the account has it. It never has more authority than your own account. Creating a token requires a credential that holds every one of those permissions, so a Plum app with a narrower grant, such as Plum for Mac, cannot create one.

An account can hold at most 20 active tokens. A token counts until it is revoked or expires. Creating another returns 409 with error code TOKEN_LIMIT_REACHED:

{
  "success": false,
  "error": { "code": "TOKEN_LIMIT_REACHED", "message": "Active personal access token limit reached" }
}

Revoke a token you no longer use, then try again.

See create a token for the exact schema.

Use a token

curl https://api.getoptima.com/me \
  -H "Authorization: Bearer optima_pat_..." \
  -H "X-API-Version: 1"

A token works on account REST routes and on /mcp, with the permissions in its permissions list. A token is strictly personal: it has every account permission but never workspace:read, workspace:members, or workspace:manage, so workspace routes return 403 FORBIDDEN. Use a signed-in Optima app for workspaces. An MCP client that supports a static bearer token can use it instead of OAuth sign-in. Tokens never work on device, staff, or internal routes.

A token that is unknown, expired, or revoked, or that belongs to a deleted account, returns 401 UNAUTHORIZED with the same error. Optima does not say which. Optima records last_used_at at most once a minute.

What a token cannot do

Even with every permission, a personal access token receives 403 FORBIDDEN from routes that change how you sign in or that manage the account itself:

RoutePurpose
POST /tokens, GET /tokensCreate or list personal access tokens
DELETE /tokens/{id} with another token's IDRevoke a different token
DELETE /meDelete the account
POST /me/restoreRestore a deleted account
POST /me/sign-outSign out, including sign out everywhere
GET /me/connections, DELETE /me/connections/{id}List and disconnect connected apps
POST /auth/logoutEnd an app session

Connected apps and the browser sign-in session are managed from a signed-in Optima app, such as your Optima account settings; a token cannot reach them.

List tokens

GET /tokens lists your unrevoked tokens, newest first, with the usual limit and cursor pagination. It returns the same metadata as creation, never the token itself. Expired tokens stay listed until you revoke them: compare expires_at with the current time, and treat null as never expiring. See list tokens.

Revoke a token

curl -X DELETE https://api.getoptima.com/tokens/TOKEN_ID \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "X-API-Version: 1"

Revocation takes effect immediately and returns 204 No Content. Revoking a token that is already revoked also returns 204; an ID that is not one of your tokens returns 404. Revoked tokens disappear from the list and cannot be restored. See revoke a token.

Revoke a token with itself

A script can revoke the token it is using, for example after finishing a one-off job or when it detects the token may have leaked. Send DELETE /tokens/{id} with the token as the bearer and its own id from the create response:

curl -X DELETE https://api.getoptima.com/tokens/TOKEN_ID \
  -H "Authorization: Bearer optima_pat_..." \
  -H "X-API-Version: 1"

It returns 204 No Content, records personal_access_token.revoked with reason user, and every later request with the token returns 401. A token cannot revoke any other token: another ID returns 403 FORBIDDEN.

Optima also revokes every token when you sign out everywhere or delete your account. Restoring a deleted account does not bring its tokens back.

Events

Token creation and revocation are account events, useful as a record of when access changed:

EventWhen
personal_access_token.createdA token was created.
personal_access_token.revokedA token was revoked.

resource.id is the token's ID. data contains last_four and expires_at (null for a token that never expires); personal_access_token.revoked also has reason: user for DELETE /tokens/{id}, sign_out_everywhere, or account_deleted. Events never contain the token, its hash, or its name. A token reaching its expiry is not an event.

{
  "type": "personal_access_token.revoked",
  "resource": { "type": "personal_access_token", "id": "0b8f7a39-5f0f-4a4e-9a36-6a0f0f4c3e21" },
  "data": {
    "changed_fields": [],
    "last_four": "Qx7a",
    "expires_at": "2026-12-28T12:00:00.000000+00:00",
    "reason": "user"
  }
}

On this page