REST API reference
Authenticate with a dxb_ access token and call the Doxbrix /api/v1 endpoints for projects, pages, search, AI, keys, tokens, and Git sync, with scopes and error
The Doxbrix REST API lets you automate the same work you do in the app: list projects, read and update pages, search, ask the project's assistant, manage assistant keys and access tokens, and control Git sync. This page describes authentication, request and response conventions, every supported endpoint with its required scope, and the error codes you handle in scripts.
The dxb CLI, the TypeScript SDK, and the MCP server all call this API, so the scopes and errors below apply to them too.
Scope of this reference
- Base URL:
https://app.doxbrix.com/api/v1 - Format: JSON request and response bodies. Send
Content-Type: application/jsonwith every request that has a body. - Included: the public
/api/v1endpoints listed on this page. - Not included: the bundle and deployment endpoints that
dxb pushuses internally. Use the CLI for those workflows.
Authentication
Send a personal access token as a bearer token in the Authorization header. Tokens start with dxb_. To create one, see Create and revoke access tokens.
curl https://app.doxbrix.com/api/v1/me \
-H "Authorization: Bearer $DOXBRIX_TOKEN"{ "id": "7b1e2c4d-5f60-4a71-8b92-a3b4c5d6e7f8", "email": "teammate@example.com", "name": "Sam Rivera" }A request without a valid token returns 401 with the code unauthorized. Requests from the Doxbrix app itself can use the signed-in session instead of a token; a session request from another origin is rejected with 403 and the code invalid_origin.
Scopes
Each endpoint requires one scope. A token can only call endpoints whose scope it holds, and a request with a missing scope returns 403 with the code insufficient_scope.
| Scope | Grants |
|---|---|
docs:read | Read pages, spaces, structure, search, quality, components, validation, import conversion, export, Git status and conflicts |
docs:write | Create and update pages and spaces, change structure, publish, resolve conflicts, run a Git sync. Includes docs:read. |
project:read | List and read projects and their settings |
project:admin | Create projects, update settings, manage assistant keys and project tokens, connect or disconnect Git. Includes project:read. |
ai:use | Ask the project's AI assistant |
agent:run | Run agent tasks |
analytics:read | Read analytics |
billing:read | Read billing information |
tokens:manage | List, create, and revoke your own workspace tokens |
A token created without explicit scopes receives docs:read, docs:write, and project:read.
Project-scoped tokens
A project-scoped token works only for one project. Requests for other projects return 404. A project-scoped token cannot list, create, or revoke workspace tokens; those requests return 403 with the code forbidden.
Request conventions
- Project identifiers. Wherever a path contains
:projectId, you can pass the project UUID or its slug, for examplepocketbase-docs. - Page identifiers.
:pageIdand body fields such asspaceId,parentId, andnavItemIdare UUIDs. - Access checks. Beyond the token scope, you also need a role in the project that allows the action. For example, updating a page requires editor access and connecting Git requires admin access. See Roles and permissions.
Errors
Every error response is JSON with a human-readable error message and, in most cases, a stable code:
{
"error": "This token is missing the 'docs:write' scope.",
"code": "insufficient_scope",
"requestId": "0f3a8c1e-2b7d-4e59-9a10-6c4d2e8f1b37"
}Authentication failures and unexpected server errors also include a requestId field and an x-request-id response header. Include the request ID when you contact support.
| Status | Code | Cause | What to do |
|---|---|---|---|
| 400 | invalid_json | The body is not valid JSON. | Fix the JSON syntax. |
| 400 | invalid_payload | A field is missing or out of range. The message names the first problem. | Correct the field and retry. |
| 400 | invalid_scope | A requested token scope does not exist. | Use a scope from the table above. |
| 400 | invalid_status | The status filter is not a valid page status. | Use draft, in_review, published, unpublished, or archived. |
| 400 | invalid_query | The search query is shorter than 2 characters. | Send a longer q. |
| 400 | connect_failed | The Git connection could not be created. | Check the repository name, branch, and credentials. |
| 400 | publish_failed | The page could not be published. | Read the message and fix the page. |
| 401 | unauthorized | The token is missing, invalid, expired, or revoked. | Send a valid dxb_ token. |
| 402 | git_sync_unavailable | Git sync is not available for the project's plan or connection. | See Plans and limits reference. |
| 402 or 403 | plan-specific code | The workspace plan does not include the feature or a limit was reached. Some responses include details. | Upgrade the plan or reduce usage. |
| 403 | insufficient_scope | The token lacks the endpoint's scope. | Create a token with the scope. |
| 403 | forbidden | A project-scoped token tried to manage workspace tokens. | Use a workspace token. |
| 403 | scope_escalation | A token tried to create a token with scopes it does not have. | Request only scopes the calling token holds. |
| 403 | invalid_origin | A session request came from another origin. | Use a bearer token. |
| 404 | not_found | The project or page does not exist or you cannot access it. | Check the ID and your project role. |
| Varies | lifecycle_error | The page cannot move to the requested state, for example during review. | Check the page's review state in the app. |
| 429 | rate_limited | Too many requests. The Retry-After header gives the wait in seconds. | Wait, then retry. |
| 500 | internal_error | An unexpected server error. | Retry later and report the request ID. |
Account and tokens
| Method | Path | Scope | Description |
|---|---|---|---|
GET | /me | any | Returns the authenticated user's id, email, and name. |
GET | /auth/tokens | tokens:manage | Lists your non-revoked tokens as { "tokens": [...] }. |
POST | /auth/tokens | tokens:manage | Creates a token. Returns 201 with { "token": { ..., "value": "dxb_..." } }. |
DELETE | /auth/tokens/:tokenId | tokens:manage | Revokes one of your tokens. |
The dxb login command uses the device authorization endpoints /auth/device/start, /auth/device/approve, and /auth/device/poll. Use dxb login rather than calling them directly.
Create a token
| Field | Type | Required | Constraints |
|---|---|---|---|
name | string | yes | 1–80 characters |
scopes | string[] | no | Up to 16 scopes. Defaults to docs:read, docs:write, project:read. |
expiresInDays | integer | no | 1–3650. Omit for no expiry. |
curl -X POST https://app.doxbrix.com/api/v1/auth/tokens \
-H "Authorization: Bearer $DOXBRIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"ci-docs-lint","scopes":["docs:read"],"expiresInDays":90}'The raw token value is returned only in this response. A token can grant only scopes it already holds, and a new token never expires later than the token that created it. Token creation with a bearer token is limited to 30 requests per hour per user.
Projects
| Method | Path | Scope | Description |
|---|---|---|---|
GET | /projects | project:read | Lists projects you can access. |
POST | /projects | project:admin | Creates a project. Returns 201. |
GET | /projects/:projectId | project:read | Returns one project by UUID or slug. |
GET | /projects/:projectId/settings | project:read | Reads project basics. |
PATCH | /projects/:projectId/settings | project:admin | Updates only the basics you send. |
GET | /projects/:projectId/quality | docs:read | Returns quality scores for each saved page. |
GET | /projects/:projectId/export | docs:read | Exports the project as { "basePath": "", "files": [...] }. |
Create a project accepts name (1–60 characters, required), slug (lowercase letters, digits, and hyphens, up to 80), description (up to 160), visibility (public or private), editorMode (block or wysiwyg), and seedTemplate (boolean). Projects created through the API are empty unless seedTemplate is true.
Update settings accepts:
| Field | Type | Constraints |
|---|---|---|
name | string | 1–120 characters |
description | string | Up to 2,000 characters |
visibility | string | public or private |
theme | string | system, light, or dark |
primaryColor | string | Hex color such as #4f46e5 |
fontFamily | string | Up to 200 characters |
fontSize | integer | 12–22 |
layout | string | docs, help_center, or agent |
curl -X PATCH https://app.doxbrix.com/api/v1/projects/pocketbase-docs/settings \
-H "Authorization: Bearer $DOXBRIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"theme":"dark","primaryColor":"#4f46e5"}'Spaces and structure
| Method | Path | Scope | Description |
|---|---|---|---|
GET | /projects/:projectId/spaces | docs:read | Lists spaces with id, name, and slug. |
POST | /projects/:projectId/spaces | docs:write | Creates a space from name (1–80 characters) and optional locale. Returns 201. |
GET | /projects/:projectId/structure | docs:read | Returns spaces and the navigation tree with IDs. |
PATCH | /projects/:projectId/structure | docs:write | Renames or moves one navigation item or space. |
The structure PATCH body takes one operation, selected by op:
op | Other fields |
|---|---|
rename_item | navItemId, title (1–200 characters) |
move_item | navItemId, optional parentId (null for top level), optional position (0-based) |
rename_space | spaceId, name (1–80 characters) |
move_space | spaceId, position (0-based) |
curl -X PATCH https://app.doxbrix.com/api/v1/projects/pocketbase-docs/structure \
-H "Authorization: Bearer $DOXBRIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"op":"rename_item","navItemId":"9a8b7c6d-5e4f-4a3b-9c2d-1e0f9a8b7c6d","title":"Install PocketBase"}'Pages
| Method | Path | Scope | Description |
|---|---|---|---|
GET | /projects/:projectId/pages | docs:read | Lists pages as { "data": [...], "total": n }. |
POST | /projects/:projectId/pages | docs:write | Creates a draft page. Returns 201 with { "page": {...} }. |
GET | /pages/:pageId | docs:read | Returns one page. Add ?content=1 to include content. |
PATCH | /pages/:pageId | docs:write | Replaces the page body with markdown (up to 400,000 characters). |
POST | /pages/:pageId/publish | docs:write | Publishes the page, or submits it for review when the project requires approval. |
List pages accepts the query parameters space (a space filter), status (draft, in_review, published, unpublished, or archived), and limit.
Create a page accepts spaceId (required), title (1–200 characters, required), parentId (optional, or null), and content (optional Markdown).
curl -X POST https://app.doxbrix.com/api/v1/projects/pocketbase-docs/pages \
-H "Authorization: Bearer $DOXBRIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"spaceId":"2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f","title":"Back up your data","content":"## Before you begin\n\nStop the server."}'Publish follows the project's approval rules and never skips review:
{ "status": "in_review", "published": false, "message": "Submitted for review, this project requires approval before publishing." }When no approval is required, the response has "status": "published", "published": true, and the message Page published. For the approval rules, see Page lifecycle and approval policies.
Search, AI, and content tools
| Method | Path | Scope | Description |
|---|---|---|---|
GET | /projects/:projectId/search | docs:read | Searches the project. Query: q (at least 2 characters), limit, locale. Returns { "query", "hits" }. |
POST | /projects/:projectId/ai/ask | ai:use | Asks the project's assistant. Body: message (up to 4,000 characters) or messages, optional pageId and locale. |
GET | /components | docs:read | Returns the live block catalog. |
POST | /validate | docs:read | Checks a draft without saving it. Body: markdown (up to 200,000 characters), optional title. |
POST | /import/file | docs:read | Converts one document (docx, pdf, html, md, or txt) to Markdown. Body: filename, base64. |
POST | /import/convert | docs:read | Converts a source tree (up to 5,000 files of up to 2 MB each) into Doxbrix pages and docs.json. Body: files as { "path", "content" } objects. |
curl "https://app.doxbrix.com/api/v1/projects/pocketbase-docs/search?q=backup&limit=5" \
-H "Authorization: Bearer $DOXBRIX_TOKEN"Assistant keys and project tokens
| Method | Path | Scope | Description |
|---|---|---|---|
GET | /projects/:projectId/keys | project:admin | Lists assistant keys. |
POST | /projects/:projectId/keys | project:admin | Creates an assistant key from label (1–80 characters), optional allowedOrigins (URLs), and optional allowPrivate. Returns 201 with the raw value once. |
DELETE | /projects/:projectId/keys/:keyId | project:admin | Revokes an assistant key. |
GET | /projects/:projectId/tokens | project:admin | Lists active project-scoped tokens. |
POST | /projects/:projectId/tokens | project:admin | Creates a project-scoped token from name, optional scopes, and optional expiresInDays (1–3650). Returns 201 with the raw value once. |
DELETE | /projects/:projectId/tokens/:tokenId | project:admin | Revokes a project-scoped token. |
Headless assistant
POST /assistant/ask and POST /assistant/ask/stream answer reader questions from an external website or backend. They do not use access tokens. Send the assistant key in the X-Assistant-Key header instead. Browser calls must come from an origin on the key's allow list; otherwise the API returns 403 with Origin not allowed for this key. The stream endpoint returns server-sent events. For setup, see Embed the assistant on another website.
Git sync
| Method | Path | Scope | Description |
|---|---|---|---|
GET | /projects/:projectId/git | docs:read | Returns the connection and recent runs as { "connection": ... }. |
POST | /projects/:projectId/git | project:admin | Connects, or creates, a repository. Returns 201. |
DELETE | /projects/:projectId/git | project:admin | Disconnects the repository. Pages remain in Doxbrix. |
POST | /projects/:projectId/git/preview | project:admin | Checks a connection without saving it. |
POST | /projects/:projectId/git/sync | docs:write | Pulls the latest commits now. Returns { "run": ... }. |
POST | /projects/:projectId/git/pause | project:admin | Pauses or resumes sync with { "paused": true } or false. |
GET | /projects/:projectId/git/conflicts | docs:read | Lists unresolved conflicts. |
POST | /projects/:projectId/git/conflicts | docs:write | Resolves one conflict with { "pageId", "keep": "editor" } or "git". |
Connect a repository accepts:
| Field | Type | Required | Description |
|---|---|---|---|
repoFullName | string | yes | Repository, such as acme/docs |
provider | string | unless accountId is set | github, gitlab, github_enterprise, or gitlab_self_managed |
accountId | string | no | A connected Git account; its provider and credentials are used |
branch | string | no | Defaults to main |
basePath | string | no | Docs folder in a monorepo |
token | string | no | Provider token, when you don't use a connected account |
installationId | string | no | GitHub App installation ID |
host | string | no | Enterprise or self-managed host URL |
outboundMode | string | no | push or pr |
conflictPolicy | string | no | git_wins or editor_wins |
createRepo | boolean | no | Create the repository |
repoPrivate | boolean | no | Make a created repository private |
curl -X POST https://app.doxbrix.com/api/v1/projects/pocketbase-docs/git \
-H "Authorization: Bearer $DOXBRIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"provider":"github","repoFullName":"acme/docs","branch":"main","basePath":"docs","outboundMode":"pr","conflictPolicy":"git_wins","token":"github_pat_example"}'For the full workflow, see Sync a project with a Git repository and Resolve Git sync conflicts.
