Access API
The access API is the administration surface of a TRAX LRS: it manages stores, API clients, MCP access, users and remote connections. Authentication, value/field types, the shared query object and error responses are common to all TRAX APIs.
Every endpoint is served under the authenticating API client:
METHOD /trax/api/gateway/clients/{client}/<endpoint>
The leading clients/{client} segment selects the API client whose HTTP-Basic credentials authorize
the call (see Authentication); <endpoint> is the administration
resource, one of the sections below. Success returns 200 with a JSON body { "data": … }
(data is the resource, or an array for list endpoints); delete/clear endpoints return 204 with an
empty body.
Contents: Stores · Clients · MCP access keys · MCP clients · Users · Connections
Getting access
- Enable the API. This API is gated by the
ACCESS_APIfeature toggle (Settings → App). When off, the machine-token API is unavailable (the console UI is unaffected). - Client permission. The calling client must have the
access/allpermission enabled (Clients → edit → Permissions) — it grants stores, clients (including MCP access keys and MCP clients), users and connections management. Authentication is HTTP Basic — see Authentication. - Base path. Copy your client's
endpoint(…/clients/{client}) from the Clients page (the ⓘ info button) and append the resource paths below.
Stores
Stores partition the LRS data. Model: Store (table trax_stores).
POST /trax/api/gateway/clients/{client}/stores
GET /trax/api/gateway/clients/{client}/stores
PUT /trax/api/gateway/clients/{client}/stores/{store}
GET /trax/api/gateway/clients/{client}/stores/{store}
GET .../stores returns all stores (unfiltered, sorted by name); it takes no filters.
{store} is the store id.
Body (POST / PUT)
| Name | Type | Description |
|---|---|---|
slug |
string (max 36) | URL-safe unique key. Required on create, unique in trax_stores; not accepted on update (immutable). |
name |
string | Human-readable store name. Required. |
supported_versions |
array of enum | Optional. The xAPI versions the store accepts; each item one of 1.0.3, 2.0.0 (min 1 item). Defaults from config when omitted. |
Example response
{
"data": {
"id": 1,
"slug": "default",
"name": "Default",
"status": "active",
"supported_versions": ["1.0.3", "2.0.0"],
"created_at": "2024-06-01T09:00:00.000000Z",
"updated_at": "2024-06-01T09:00:00.000000Z"
}
}
Clients
API clients hold the credentials, guard, permissions and ingestion pipeline used to read/write a store.
Model: Client (table trax_clients).
POST /trax/api/gateway/clients/{client}/clients
GET /trax/api/gateway/clients/{client}/clients
PUT /trax/api/gateway/clients/{client}/clients/{client}
GET /trax/api/gateway/clients/{client}/clients/{client}
DELETE /trax/api/gateway/clients/{client}/clients/{client}
The trailing clients/{client} is the managed client resource (its id); the leading
clients/{client} is the authenticating API client.
Filters (GET .../clients)
The list is a filtered query — pass the query object (filters, sort,
limit, …). filters accepts only:
| Name | Type | Description |
|---|---|---|
search |
string | Free-text search over clients. |
store |
string | Restrict to clients bound to this store id. |
guard |
string | Restrict to this guard (basic-http, cmi5-token or mcp). |
Body (POST / PUT)
| Name | Type | Description |
|---|---|---|
slug |
string (max 36) | URL-safe unique key: letters, digits, - and _ only. Required on create, unique in trax_clients; not accepted on update. |
name |
string | Client name. Required. |
guard |
enum | Authentication guard, one of basic-http, cmi5-token. Required. |
credentials.username |
string | HTTP-Basic username. Required on create; optional on update (omit to keep). |
credentials.password |
string (min 8) | HTTP-Basic password. Required on create; optional on update (omit to keep). |
cors |
string | null | Optional CORS origin(s) configuration. |
permissions |
object | The predefined permission bundles enabled for the client, as a {bundle: true} map (e.g. {"data/all": true, "xapi/all": true}). Required. |
pipeline.validate_statements |
boolean | Validate incoming statements. |
pipeline.check_conflicts |
boolean | Detect statement id conflicts. |
pipeline.record_attachments |
boolean | Store statement attachments. |
pipeline.void_statements |
boolean | Process voiding statements. |
pipeline.update_activities |
boolean | Update the activities catalogue. |
pipeline.update_agents |
boolean | Update the agents catalogue. |
pipeline.update_vocab |
boolean | Update the verb / activity-type vocabulary. |
pipeline.update_activity_ids |
boolean | Update the activity-id index. |
pipeline.update_agent_ids |
boolean | Update the agent-id index. |
pipeline.query_targeting |
boolean | Enable query targeting. |
pipeline.authority.account.name |
string | Authority account name applied to stored statements. Required. |
pipeline.authority.account.homePage |
URL | Authority account homePage. Required, valid URL. |
store |
string | Id of the store this client is bound to. Required. |
The pipeline.* flags accept a "mixed boolean" (true/false, 1/0, "true"/"false"). credentials
is write-only — never returned in responses.
Example response
{
"data": {
"id": 1,
"slug": "app",
"name": "Application",
"guard": "basic-http",
"settings": {},
"cors": null,
"permissions": { "data/all": true, "xapi/all": true },
"pipeline": { "validate_statements": true, "authority": { "account": { "name": "trax", "homePage": "https://lrs.example.com" } } },
"store": "default",
"endpoint": "https://lrs.example.com/trax/api/gateway/clients/app",
"store_endpoint": "https://lrs.example.com/trax/api/gateway/clients/app/stores/default",
"xapi_endpoint": "https://lrs.example.com/trax/api/gateway/clients/app/stores/default/xapi",
"cmi5_endpoint": "https://lrs.example.com/trax/api/gateway/clients/app/stores/default/cmi5",
"created_at": "2024-06-01T09:00:00.000000Z",
"updated_at": "2024-06-01T09:00:00.000000Z",
"deleted_at": null
}
}
deleted_at is only set on revoked MCP clients. MCP clients (guard mcp) are listed by these endpoints too,
but they should be created and changed with the MCP clients endpoints, which enforce their
rules.
MCP access keys
An MCP access key is the bearer credential an AI assistant uses to reach the MCP server
(/trax/api/mcp). A key carries no store nor permissions: it gives access to the stores of the
MCP clients attached to it. Model: McpKey (table trax_mcp_keys).
POST /trax/api/gateway/clients/{client}/mcp-keys
GET /trax/api/gateway/clients/{client}/mcp-keys
PUT /trax/api/gateway/clients/{client}/mcp-keys/{key}
DELETE /trax/api/gateway/clients/{client}/mcp-keys/{key}
POST /trax/api/gateway/clients/{client}/mcp-keys/{key}/token
{key} is the key id.
Filters (GET .../mcp-keys)
Pass the query object; filters accepts only:
| Name | Type | Description |
|---|---|---|
search |
string | Free-text search over keys (name, description, slug, token prefix). |
revoked |
boolean | 1 lists the revoked keys instead of the active ones. |
Body (POST / PUT)
| Name | Type | Description |
|---|---|---|
name |
string | Key name. Required. |
description |
string | The intended use of the key, kept for audit. Required. |
expires_at |
ISO-8601 date-time | null | Optional expiry date. |
Operations
POST .../mcp-keyscreates a key and returns its plaintext token intoken. The token is returned only once: it is stored hashed and can't be retrieved later.POST .../mcp-keys/{key}/tokenreplaces the token of a key and returns the new one intoken, once. The previous token stops working immediately; the key keeps its MCP clients.DELETE .../mcp-keys/{key}revokes the key and all its MCP clients. They are kept for audit (seerevoked) until purged with themcp-access:purgeconsole command. Returns204with an empty body.
Example response (POST)
{
"data": {
"id": 1,
"slug": "0f8f6a43-6f5e-4f3c-9d0a-2c1d7a1b9e10",
"name": "Claude Desktop",
"description": "Analytics team, exploring the production store.",
"prefix": "trax_mcp_jJDpUMA",
"last_used_at": null,
"expires_at": null,
"created_at": "2026-10-01T09:00:00.000000Z",
"updated_at": "2026-10-01T09:00:00.000000Z"
},
"token": "trax_mcp_jJDpUMA…"
}
GET .../mcp-keys also returns deleted_at (revocation date) and clients_count (number of MCP clients
attached to the key) for each key. The token hash is never returned.
MCP clients
An MCP client gives an MCP access key access to one store, with its own permissions and
xAPI pipeline. It is a client with the mcp guard (table trax_clients), reached only through the MCP
server.
POST /trax/api/gateway/clients/{client}/mcp-clients
GET /trax/api/gateway/clients/{client}/mcp-clients
PUT /trax/api/gateway/clients/{client}/mcp-clients/{mcpclient}
GET /trax/api/gateway/clients/{client}/mcp-clients/{mcpclient}
DELETE /trax/api/gateway/clients/{client}/mcp-clients/{mcpclient}
{mcpclient} is the MCP client id.
Filters (GET .../mcp-clients)
Pass the query object; filters accepts only:
| Name | Type | Description |
|---|---|---|
search |
string | Free-text search over MCP clients (name / slug). |
store |
string | Restrict to the MCP clients bound to this store. |
mcp_key |
string | Restrict to the MCP clients of this key (key slug). |
revoked |
boolean | 1 lists the revoked MCP clients instead of the active ones. |
Body (POST / PUT)
| Name | Type | Description |
|---|---|---|
slug |
string (max 32) | Letters, digits, - and _ only. Stored with the mcp: prefix (e.g. mcp:analytics). Required on create, unique (revoked clients included); not accepted on update. |
mcp_key |
string | Slug of an active MCP access key. Required on create; not accepted on update. |
name |
string | Client name. Required. |
store |
string | Store this client is bound to. Required. A key can have only one active client per store. |
permissions |
object | {bundle: true} map; only data/all and xapi/statements/write are kept, other bundles are ignored. |
pipeline.* |
boolean | Same flags as for clients, except query_targeting, which is always off. |
pipeline.authority.account.name |
string | Authority account name applied to stored statements. Required. |
pipeline.authority.account.homePage |
URL | Authority account homePage. Required, valid URL. |
DELETE .../mcp-clients/{mcpclient} revokes the MCP client: it stops working immediately and is kept for
audit (see revoked) until purged. Returns 204 with an empty body.
Example response
{
"data": {
"id": 12,
"slug": "mcp:analytics",
"name": "Analytics",
"guard": "mcp",
"settings": {},
"cors": null,
"permissions": { "data/all": true, "xapi/statements/write": false },
"pipeline": { "validate_statements": true, "query_targeting": false, "authority": { "account": { "name": "mcp", "homePage": "https://lrs.example.com" } } },
"store": "default",
"mcp_key": "0f8f6a43-6f5e-4f3c-9d0a-2c1d7a1b9e10",
"mcp_key_name": "Claude Desktop",
"created_at": "2026-10-01T09:00:00.000000Z",
"updated_at": "2026-10-01T09:00:00.000000Z",
"deleted_at": null
}
}
The response also carries the endpoint, store_endpoint, xapi_endpoint and cmi5_endpoint fields of a
client, which are not used by MCP clients.
Users
Back-office users (administration console accounts). Model: User (table trax_users).
POST /trax/api/gateway/clients/{client}/users
GET /trax/api/gateway/clients/{client}/users
PUT /trax/api/gateway/clients/{client}/users/{user}
GET /trax/api/gateway/clients/{client}/users/{user}
DELETE /trax/api/gateway/clients/{client}/users/{user}
POST /trax/api/gateway/clients/{client}/me/change-password
Filters (GET .../users)
Pass the query object; filters accepts only:
| Name | Type | Description |
|---|---|---|
search |
string | Free-text search over users (name / email). |
role |
string | Restrict to this role. |
Body (POST / PUT)
| Name | Type | Description |
|---|---|---|
firstname |
string | Required. |
lastname |
string | Required. |
email |
Required, unique in trax_users (unicity ignores the current user on update). Only accepted on create in postRules; on update it is enforced via the ignore-unique rule. |
|
agent |
Agent IFI | null | Optional xAPI agent identifying this user. |
role |
enum | One of actor, analyst, manager, supervisor, admin. Required. |
stores |
array | Accessible stores, as {storeId: true} map. Required. |
password |
string | Password. Required on create, optional on update (omit to keep). Must satisfy the configured strength policy (min length, and optionally letters, numbers, symbols, mixed case, not-compromised). |
me/change-password (POST) — any authenticated user may change their own password by
re-authenticating with their current password.
| Name | Type | Description |
|---|---|---|
current |
string | The user's current password (current_password check). Required. |
new |
string | New password. Required, must be confirmed (send new_confirmation), different from current, and satisfy the strength policy. |
Returns 204 with an empty body.
Example response
{
"data": {
"id": 1,
"firstname": "Jane",
"lastname": "Doe",
"email": "jane@example.com",
"agent": { "mbox": "mailto:jane@example.com" },
"role": "admin",
"email_verified_at": null,
"created_at": "2024-06-01T09:00:00.000000Z",
"updated_at": "2024-06-01T09:00:00.000000Z",
"fullname": "Jane Doe",
"stores": { "1": true },
"store_ids": [1],
"store_slugs": ["default"]
}
}
password is never returned.
Connections
Remote connections used by background jobs (pull/push, clearing, indexing, …). There are three types —
LRS, DB and File — each with its own endpoints and body rules. Model: Connection
(table trax_connections). The {type} segment is the fixed type keyword; {connection} is the
connection id.
Common shape per type:
POST /trax/api/gateway/clients/{client}/connections/{type}
GET /trax/api/gateway/clients/{client}/connections/{type}
DELETE /trax/api/gateway/clients/{client}/connections/{type} # clear all of this type
PUT /trax/api/gateway/clients/{client}/connections/{type}/{connection}
GET /trax/api/gateway/clients/{client}/connections/{type}/{connection}
DELETE /trax/api/gateway/clients/{client}/connections/{type}/{connection}
GET .../connections/{type} returns all connections of that type (no filters). POST performs an
upsert (create or update) for the type. Deleting a single connection — or clearing all of a type —
returns 409 if any is currently used by a job. On LRS and DB connections, username / password are
stripped from responses; File connections have none.
Example response (a single connection; settings holds the per-type fields)
{
"data": {
"id": 3,
"type": "lrs",
"name": "Remote LRS",
"settings": { "endpoint": "https://remote.example.com/xapi", "supported_versions": ["1.0.3"], "reachable": true },
"created_at": "2024-06-01T09:00:00.000000Z",
"updated_at": "2024-06-01T09:00:00.000000Z"
}
}
LRS connections ({type} = lrs)
A connection to a remote xAPI LRS. On save, TRAX probes the target's About resource and caches the
supported xAPI versions (and a reachable flag) on the connection.
Body (POST / PUT)
| Name | Type | Description |
|---|---|---|
name |
string | Connection name. Required. |
endpoint |
URL | The remote LRS xAPI endpoint. Required, valid URL. |
username |
string | Basic-auth username. Required on create; optional on update (omit to keep). |
password |
string | Basic-auth password. Required on create; optional on update (omit to keep). |
DB connections ({type} = db)
A connection to an external database.
Body (POST / PUT)
| Name | Type | Description |
|---|---|---|
name |
string | Connection name. Required. |
driver |
enum | One of mysql, pgsql, mongodb, elasticsearch, opensearch. Required. |
host |
string | Database host. Required. |
database |
string | Database / index name. Required. |
username |
string | null | Optional username. |
password |
string | null | Optional password. |
prefix |
string | null | Optional table/collection prefix. |
File connections ({type} = file)
A connection to a filesystem target (JSONL export/import).
Body (POST / PUT)
| Name | Type | Description |
|---|---|---|
name |
string | Connection name. Required. |
folder |
string | Target folder path. Required. |
prefix |
string | null | Optional filename prefix. |