Skip to content

REST API Reference

LokAI exposes a REST API at /api/v1 for third-party integrations, alongside a type-safe tRPC endpoint at /trpc for first-party clients (Studio, CLI).

Base URL: http://localhost:3000/api/v1

All requests must include an Authorization: Bearer <token> header.

Current bearer token types:

  • Supabase JWTs for human sessions
  • personal access tokens (PATs)
  • workspace access tokens (WATs)

PATs and WATs are both scope-aware machine identities. PATs are additionally bounded by the owning user's effective permissions.

  • Workspaces/workspaces
  • Access/workspaces/:workspaceId/roles, /workspaces/:workspaceId/capabilities, /workspaces/:workspaceId/grants
  • Projects/workspaces/:workspaceId/projects
  • Translation Keys/projects/:projectId/keys
  • Translations/keys/:keyId/translations
  • Glossary/workspaces/:workspaceId/glossary
  • Tenants/workspaces/:workspaceId/tenants
  • Export/projects/:projectId/export

Current REST access surface:

GET /api/v1/workspaces/:workspaceId/roles
GET /api/v1/workspaces/:workspaceId/capabilities
GET /api/v1/workspaces/:workspaceId/grants
POST /api/v1/workspaces/:workspaceId/grants
PATCH /api/v1/workspaces/:workspaceId/grants/:grantId
DELETE /api/v1/workspaces/:workspaceId/grants/:grantId
GET /api/v1/workspaces/:workspaceId/audit/access
GET /api/v1/workspaces/:workspaceId/access-tokens
POST /api/v1/workspaces/:workspaceId/access-tokens
POST /api/v1/workspaces/:workspaceId/access-tokens/:id/rotate
DELETE /api/v1/workspaces/:workspaceId/access-tokens/:id
GET /api/v1/me/effective-permissions?workspace_id=:workspaceId
GET /api/v1/me/access-tokens?workspace_id=:workspaceId
POST /api/v1/me/access-tokens
POST /api/v1/me/access-tokens/:id/rotate?workspace_id=:workspaceId
DELETE /api/v1/me/access-tokens/:id?workspace_id=:workspaceId

GET /api/v1/workspaces/:workspaceId/capabilities is the REST debugging surface for effective plan state.

The response includes:

  • capabilities[] for boolean feature gates
  • quotas.workspace[] always
  • quotas.project when project_id is supplied
  • quotas.tenant when tenant_id is supplied
  • quotas.user when user_id is supplied

This endpoint is especially useful for inspecting scoped limits such as:

  • keys_per_project
  • base_languages_per_project
  • rules_per_tenant
  • pats_per_user

The data model already supports teams and custom roles, but the current shipped surface keeps those areas clearly deferred:

  • no REST team CRUD
  • no custom-role CRUD
  • read-only role listing through /roles

Export routes live under:

/api/v1/workspaces/:workspaceId/projects/:projectId/export
GET /api/v1/workspaces/:workspaceId/projects/:projectId/export

Returns supported formats and available query parameters.

GET /api/v1/workspaces/:workspaceId/projects/:projectId/export/:format

If the export resolves to a single file, the route may return that file directly. If multiple output files are generated, the response is a ZIP archive.

GET /api/v1/workspaces/:workspaceId/projects/:projectId/export/bulk/:format

This endpoint always returns a ZIP archive and is the preferred endpoint for automation.

| Parameter | Type | Description | | --------------- | --------------------- | --------------------------------------------------------------------------------- | | languages | string | Comma-separated language codes such as fr,de,ja | | version | latest \| validated | Export the latest translation state or only validated/published content | | status | legacy enum | Legacy alias. validated, approved, and published map to version=validated | | namespace | string | Filter keys by namespace pattern | | tags | string | Comma-separated tag filter | | include_empty | true \| false | Include keys without translation text |

| Parameter | Type | Description | | -------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | | content_mode | per_language \| multilingual | multilingual is currently supported for JSON and YAML only | | structure_template | string | JSON-encoded template using placeholders, $for loops, and $if conditionals | | include_metadata | true \| false | Supported for json, json-nested, and yaml; mainly affects the default export shape when no custom structure_template is used |

| Parameter | Type | Description | | --------------- | -------- | ---------------------------------------------------------------------------------------- | | path_template | string | Archive path template using {language}, {variant}, {tenant}, {file}, and {ext} |

| Parameter | Type | Description | | ----------------- | --------------- | ----------------------------------- | | tenant_id | string | Export a single tenant variant | | tenant_ids | string | Comma-separated tenant IDs or all | | include_vanilla | true \| false | Include the base non-tenant variant |

If tenant features are disabled on the workspace, the export route rejects tenant-specific parameters.

Archive responses are named using:

{project-slug}-{latest|validated}-{YYYY-MM-DD}.zip

Supported tokens:

  • {language}
  • {variant}
  • {tenant}: alias for {variant}
  • {file}
  • {ext}

Examples:

{language}/{file}.{ext}
{file}.{language}.{ext}
{variant}/{language}/{file}.{ext}
{language}/{variant}/{file}.{ext}
{file}.{variant}.{language}.{ext}
GET /api/v1/workspaces/:workspaceId/projects/:projectId/export/bulk/yaml?languages=en,fr,es&content_mode=multilingual

This produces one YAML file per logical file path, with all selected languages embedded in the same document.

{
"$for": "keys",
"$as": "key",
"$body": {
"name": "{{key.name}}",
"translations": {
"$for": "key.translations",
"$as": "translation",
"$body": {
"language": "{{translation.language}}",
"text": "{{translation.text}}"
}
}
}
}

Successful file downloads typically include:

  • Content-Type
  • Content-Disposition
  • Cache-Control: no-store

For ZIP downloads, Content-Disposition contains the archive filename to use on disk.

Glossary routes live under:

/api/v1/workspaces/:workspaceId/glossary
GET /api/v1/workspaces/:workspaceId/glossary/export?format=json|yaml|csv

Returns a downloadable attachment (Content-Disposition + format-specific Content-Type).

POST /api/v1/workspaces/:workspaceId/glossary/import
Content-Type: application/json
{
"format": "json",
"content": "{ \"entries\": [ ... ] }"
}

Response payload:

{
"success": true,
"data": {
"created": 2,
"updated": 5,
"failed": 0,
"errors": []
}
}