API Tokens
Endpoints for managing API tokens for programmatic access.
A token row pairs a type with optional entity scoping. The type must
be a registered token driver; each driver's authorize() decides which
routes the token may call, so an entity-scoped token (e.g. a dataset
token) only works against that entity's surfaces. The default type,
api, is the general-purpose token. Other in-tree types include
report, dataset, query, visual, datasource, assistant,
app_view (App external links), and webhook (App inbound webhooks).
The token string itself is the key field: a JWT signed with the
tenant's token secret, computed at response time and never stored. Any
full read of the row (create response, list, single GET) re-derives it,
so it can be retrieved again later; rotating the tenant token secret
invalidates every key at once.
Reads also carry typeName, the token driver's display name in the
caller's language — the label to show alongside a token rather than the
raw type id. It is computed at response time like key, and is omitted
if the driver behind type can no longer be resolved.
The whole token surface (list, create, read, update, delete) cannot be called through an App's proxied API channel or a server route's fetch(), even if the App whitelists it. Such requests answer 403 Forbidden with API endpoint not allowed for this app. See App Runtime.
GET /api/tokens
List API tokens with optional filtering.
Authentication: Required
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
reportId | string | Filter by Report ID |
datasourceId | string | Filter by Datasource ID |
assistantId | string | Filter by Assistant ID |
visualId | string | Filter by visual ID |
datasetId | string | Filter by Dataset ID |
queryId | string | Filter by query ID |
appId | string | Filter by App ID |
username | string | Filter by username |
{
"_links": {
"self": {
"href": "https://informer.example.com/api/tokens"
}
},
"start": 0,
"count": 1,
"total": 1,
"_embedded": {
"inf:token": [
{
"_links": {
"self": {
"href": "https://informer.example.com/api/tokens/00000000-0000-4000-8000-000000000001"
},
"inf:token-type": {
"href": "https://informer.example.com/api/token-types/api"
}
},
"permissions": {
"edit": true,
"delete": true
},
"id": "00000000-0000-4000-8000-000000000001",
"type": "api",
"readOnly": false,
"notes": "CI integration",
"restrict": null,
"host": null,
"cidr": null,
"data": null,
"requests": 0,
"blocked": 0,
"lastAccessedAt": null,
"expiresAt": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"username": "admin",
"reportId": null,
"queryId": null,
"visualId": null,
"datasourceId": null,
"datasetId": null,
"appId": null,
"assistantId": null,
"oauthClientId": null,
"user": {
"permissions": {
"changeDomain": true,
"changeProfile": true,
"changePassword": false,
"manageMfa": true,
"delete": true,
"edit": true,
"reassign": true,
"superuser": true,
"enable": true,
"changeTheme": true,
"lock": true,
"setGlobalPermissions": true,
"manageLogin": false
},
"displayName": "acme Administrator",
"email": null
},
"assistant": null,
"oauthClient": null,
"typeName": "API",
"key": "eyJhbGciOiJIUzI1NiJ9.example-token-1.signature"
}
]
}
}
POST /api/tokens
Create a new API token. The token is owned by the calling user
(username is set from the session).
Authentication: Required
Permission: tokens:create
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
type | string | No | Token type (default api); must be a registered token driver |
notes | string | No | Token description or notes |
readOnly | boolean | No | Restrict to GETs and read-only-marked routes (default: false) |
restrict | string | No | Network restriction: host or cidr |
host | string | No | Allowed hostname (if restrict: 'host') |
cidr | string | No | CIDR range (if restrict: 'cidr') |
reportId / datasetId / queryId / visualId / datasourceId / assistantId / appId | string | Per type | The entity the token is scoped to; the matching driver validates which FK it requires |
data | object | No | Driver-specific data (e.g. roles for app_view links) |
{
"type": "api",
"notes": "CI integration",
"readOnly": false
}
{
"_links": {
"self": {
"href": "https://informer.example.com/api/tokens/00000000-0000-4000-8000-000000000001"
},
"inf:token-type": {
"href": "https://informer.example.com/api/token-types/api"
}
},
"permissions": {
"edit": true,
"delete": true
},
"id": "00000000-0000-4000-8000-000000000001",
"type": "api",
"readOnly": false,
"notes": "CI integration",
"restrict": null,
"host": null,
"cidr": null,
"data": null,
"requests": 0,
"blocked": 0,
"lastAccessedAt": null,
"expiresAt": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"username": "admin",
"reportId": null,
"queryId": null,
"visualId": null,
"datasourceId": null,
"datasetId": null,
"appId": null,
"assistantId": null,
"oauthClientId": null,
"user": {
"permissions": {
"changeDomain": true,
"changeProfile": true,
"changePassword": false,
"manageMfa": true,
"delete": true,
"edit": true,
"reassign": true,
"superuser": true,
"enable": true,
"changeTheme": true,
"lock": true,
"setGlobalPermissions": true,
"manageLogin": false
},
"displayName": "acme Administrator",
"email": null
},
"assistant": null,
"oauthClient": null,
"typeName": "API",
"key": "eyJhbGciOiJIUzI1NiJ9.example-token-1.signature"
}
Status: 201 Created with a Location header pointing at the new
token.
GET /api/tokens/{id}
Retrieve a specific API token, including its re-derived key.
Authentication: Required (read access: your own tokens, or superuser)
Response: the same shape as a list entry above.
PUT /api/tokens/{id}
Update an API token's metadata. Only notes, data, readOnly,
restrict, host, and cidr are accepted; everything else is
stripped (the type and entity scoping are fixed at creation).
Authentication: Required
{
"notes": "CI integration (rotated owner)"
}
{
"_links": {
"self": {
"href": "https://informer.example.com/api/tokens/00000000-0000-4000-8000-000000000001"
},
"inf:token-type": {
"href": "https://informer.example.com/api/token-types/api"
}
},
"permissions": {
"edit": true,
"delete": true
},
"id": "00000000-0000-4000-8000-000000000001",
"type": "api",
"readOnly": false,
"notes": "CI integration (rotated owner)",
"restrict": null,
"host": null,
"cidr": null,
"data": null,
"requests": 0,
"blocked": 0,
"lastAccessedAt": null,
"expiresAt": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"username": "admin",
"reportId": null,
"queryId": null,
"visualId": null,
"datasourceId": null,
"datasetId": null,
"appId": null,
"assistantId": null,
"oauthClientId": null,
"user": {
"permissions": {
"changeDomain": true,
"changeProfile": true,
"changePassword": false,
"manageMfa": true,
"delete": true,
"edit": true,
"reassign": true,
"superuser": true,
"enable": true,
"changeTheme": true,
"lock": true,
"setGlobalPermissions": true,
"manageLogin": false
},
"displayName": "acme Administrator",
"email": null
},
"assistant": null,
"oauthClient": null,
"typeName": "API",
"key": "eyJhbGciOiJIUzI1NiJ9.example-token-1.signature"
}
DELETE /api/tokens/{id}
Revoke an API token.
Authentication: Required
Deleting a token immediately revokes access. This cannot be undone. Any requests using the token will fail with 401 Unauthorized.
GET /api/token-types
List the registered token types (the same registry the type field
validates against), for the token-creation UI.
Authentication: Required
GET /api/token-types/{id}
Get details for a specific token type.
Authentication: Required
GET /api/token-templates
Get token templates for UI generation.
Authentication: Required
Response:
Array of token template objects with field definitions.