Skip to content

Authentication

Every route except /health, /api/v1/openapi.json, /api/v1/docs and /api/v1/token requires a bearer token.

Authorization: Bearer <token>

Tokens are held in the operating system keychain, with a label, a scope and an optional lifetime. This documentation does not describe the shape of a token — treat it as an opaque string, and store it the way you store any other secret.

From the command line:

tcc config create-api-token --scope full

Or over HTTP, from the machine itself:

POST /api/v1/token
{ "name": "my-integration", "scope": "full" }

That route takes no token of its own. It is safe only because the server binds to loopback, so anything that can reach it is already on the machine. The answer carries the token and its scope.

Over HTTP that answer is the only time the token is shown: GET /api/v1/api-tokens lists them masked. The command line can still reveal a stored one to the person at the machine, which is why the keychain is the boundary that matters.

GET and POST on /api/v1/api-tokens list and mint tokens; DELETE /api/v1/api-tokens/{id} revokes one.

A token carries one of three scopes. Scope is enforced centrally, from the HTTP method and the path, before a handler runs.

ScopeMay do
readAny GET outside the management routes
writeThe same, plus writes to your own data
fullEverything, including organisation management and token management

Management means /api/v1/org/members, /api/v1/org/groups, /api/v1/org/alerts and /api/v1/api-tokens. Those need full on every method, reads included. Nothing else needs full — the rest of the organisation routes, activity and analytics among them, are ordinary reads.

Give an integration the narrowest scope that does its job. A reporting script wants read; it will then be refused if it ever tries to delete something.

A missing or invalid token is 401. A valid token whose scope is too narrow is 403, with a body naming the scope you have, the request you made and the scope it would need:

{
"error": "insufficient_scope",
"message": "Token scope 'read' cannot perform DELETE /api/v1/tags/abc. Requires write or full scope.",
"required_scope": "write or full"
}

Revoking a token is immediate: delete it through /api/v1/api-tokens/{id} and the next request carrying it is refused.