> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.lucanto.eu/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.lucanto.eu/_mcp/server.

# Authentication

All API requests authenticate with a Bearer token in the `Authorization`
header:

```
Authorization: Bearer <token>
```

## Token types

| Type                      | Prefix      | Scope                               | Use for                                                           |
| ------------------------- | ----------- | ----------------------------------- | ----------------------------------------------------------------- |
| **Personal access token** | `lct_pat_`  | Every workspace the user belongs to | Personal scripts, Claude Desktop, Cursor, ChatGPT, MCP clients    |
| **Workspace token**       | `lct_live_` | One workspace, bound to the account | E-shop / accounting integrations that act as the workspace itself |

A personal access token spans multiple workspaces, so you always pass the
`workspace_id` in the path. A workspace token is bound to one workspace —
the `workspace_id` in the path must match, or the request returns `403`.

Sandbox tokens use the `lct_test_` prefix and are valid only against
test-mode workspaces. Sandbox mode is on the roadmap.

## Scopes

Tokens carry granular scopes in three tiers, per resource:

* `read:<resource>` — list and get
* `write:<resource>` — read + create + update
* `manage:<resource>` — write + custom actions (issue, mark paid, send, delete)

Resources include `invoices`, `quotes`, `proformas`, `credit_notes`,
`expenses`, `contacts`, `bank_accounts`. A wildcard like `read:*` or
`manage:*` grants the tier across all resources.

Scopes are **capped at creation** by the issuing user's own permissions —
a token can never grant more than the user has. If the user later loses a
role, the token's effective power shrinks with it.

## Errors

A missing or invalid token returns `401`:

```json
{
  "error": "unauthenticated",
  "message": "Authentication required.",
  "request_id": "8f9e4c2b-...",
  "docs_url": "https://docs.lucanto.eu/api/v1/errors/unauthenticated"
}
```

A valid token without the required scope returns `403` (`forbidden`).
See [Errors](/errors).