Skip to main content
The control plane exposes a JSON API used by its own interface. It is documented here for monitoring, automation, and debugging.
This API is designed for the application’s own browser client and is not versioned for external consumers. Endpoint shapes can change between releases. For installation automation, /api/health, /api/setup, and the versioned /api/admin/provision manifest are the stable entry points.

Authentication

Most endpoints require a session cookie issued at login and signed with BETTER_AUTH_SECRET. Requests are authorized per record: handlers verify that the authenticated user owns the object being accessed.

Public endpoints

Public
Liveness and readiness probe. Executes select 1 against PostgreSQL.Returns 200 {"ok":true} when healthy and 503 {"ok":false} when the database is unreachable.
Public
Reports installation setup state.
required is true only when setup has not completed and no users exist.
Public, one-time
Creates the first administrator in a single transaction and permanently closes public setup.Returns 403 when the claim token does not match.
Public
Branding, setup state, and SSO button configuration needed before login. Served with cache-control: no-store. Contains no credentials or user data.
Public
Authentication routes: sign-in, sign-out, session, and OIDC callbacks at /api/auth/oauth2/callback/<provider-key>.

Session endpoints

Session
Returns {user} with only id, name, email, role, enabled, mustChangePassword, providerSettingsEnabled, and mcpSettingsEnabled. No session object or credentials are included. All responses use cache-control: no-store; unauthenticated requests return 401 and disabled accounts return 403. This profile contract does not change Better Auth’s separate /api/auth/* response contracts, which can include session credentials.
Session
Returns { providers, canEdit, modelTiers } for the user’s community catalogue or the shared managed installation. modelTiers is the ordered array of { value, label } definitions. API keys are never returned; each provider carries a hasApiKey flag. Custom headers are decrypted for authorized editors so they remain editable.
Session
Creates a provider from a name, base URL, optional API key, and optional headers.
Session
Updates a provider. Omitting the API key leaves the stored one unchanged.
Session
Deletes a provider and its models. If it owned the default model, the oldest remaining enabled model is promoted.
Session
Validates a provider by requesting <base URL>/models through the outbound guard.
Session · Provider edit access
Replaces the ordered tier definitions with { "tiers": [...] } and returns { "modelTiers": [...] }. Community users edit their own catalogue; managed installation changes require an administrator. The same provider-settings permissions apply as for model edits.
Supply 1–32 definitions, with unique positive integer IDs up to 2147483647. Labels are trimmed, nonempty, at most 40 characters, and unique ignoring case. IDs remain stable across rename/reorder operations; array order controls display. Removing an ID referenced by any model, including disabled models, returns 409. Reassign or delete those models before removing the tier. New catalogues start with Low (1), Medium (2), High (3), and Maximum (4).
Session
Creates a model with a provider model ID, display name, an explicit tier referencing a configured tier ID, context window, and maximum output tokens. The first model becomes the default.
Session
Updates a model, including its configured tier, making it the default, or toggling enabled. Default changes release the previous holder first.
Session
Deletes a model, promoting a replacement default when needed.
Session
Lists the user’s conversations. ?archived=1 lists archived conversations instead.
Session
Creates a conversation. A conversation cannot start in an archived project.
Session
Updates a conversation: title renames it, archived archives or restores it, and projectId moves it into a project, or out of one with null. Moving a standalone conversation into a project moves its files too, keeping their paths unless one is taken, in which case they all move into one folder named after the conversation; the response reports movedArtifacts and artifactFolder. A conversation cannot move while a response is running, or into an archived project.
Session
Deletes a conversation and its messages.

Saved-message acknowledgements and retries

POST /api/chat/start accepts a chatId, a message with a client-generated id and parts, and a model decision. It durably saves/enqueues the input and returns 201 { messageId }; this acknowledges admission, not the model’s reply. POST /api/chat/turn-inputs similarly saves a queued input and returns { input }, whose id is the submitted message identity. Keep the same message ID, endpoint and request body when retrying a lost or unreadable acknowledgement. A retry may return an already-applied or cancelled queued input; it must not enqueue it again. Changed content/model/ownership is not a retry and can return 409 input_conflict. Do not switch a network-uncertain start request to the queue endpoint or invent a new ID. The browser stores an owner- and conversation-scoped submission receipt before sending. While a save is pending the draft is disabled. If its outcome is uncertain, Retry saved submission resends the stored request, including after reload; editing stays disabled until acknowledged. Browser storage must remain available. Clearing site data or switching browsers removes that local recovery receipt: inspect the saved conversation/inbox before submitting a replacement. There is no automatic expiry or silent re-submission of uncertain receipts.
Session
The streaming chat endpoint. Resolves the model, decrypts credentials, ensures the workspace is running, and streams text, reasoning, and tool calls back to the browser for a saved messageId (or explicit resume). detach: true returns 202 { admitted: true, assistantId } instead of a duplicate stream; the browser follows /api/chat/CHAT_ID/stream. Disconnect is not Stop. Messages and tool results are persisted as they complete. A request states its model decision with modelPinned: true with a modelId pins that model to the conversation, false follows the current default. Without modelPinned, its modelId runs for that turn only, otherwise the conversation’s pinned model, otherwise the default.
Session
Renames a project, or archives and restores it with archived. Owners and admins only. An archived project is hidden from every member’s sidebar and runs no new responses until it is restored; nothing in it is deleted.
Session
Returns { servers, canEdit } for the signed-in user, including known tools, enabled/trust state, and hasHeaders, but never header values or encrypted envelopes. Add ?id=SERVER_ID to load { server, canEdit } with decrypted headers for editing. Detail requires edit access and uses cache-control: no-store.
Session · MCP edit access
Adds a server with name, url, transport (http or sse, default http), optional headers (a string-to-string object), and enabled (default true). Headers are encrypted at rest. New servers require testing and trust before use.
Session · MCP edit access
Accepts id and any configuration fields from POST. Omitted headers are preserved; headers: {} clears them. Changing the URL, transport, or headers requires renewed trust. Renaming or enabling/disabling alone does not.
Session · MCP edit access
Removes an MCP server.
Session · MCP edit access
Body: { "id": "server-id" }. Test discovers tools and reports drift without granting trust. Trust accepts the current tool definitions.
When mcpSettingsEnabled is false, a non-admin user can still list and select configured servers in chat, but cannot add, edit, delete, test, trust, or read stored headers. These restrictions are enforced server-side with 403 mcp_settings_disabled, in both editions. Admins retain access. A userId on self-service endpoints never switches ownership.

Artifact endpoints

Session
Lists, searches, previews, stats, or downloads remote artifacts for an authorized project/chat context.
Session
Uploads browser files into the active project’s or standalone chat’s artifact namespace. Artifact metadata includes the immutable id used by canonical [filename](artifact://<artifact-id>) message references.
Session
Moves or renames remote artifacts within one authorized namespace.
Session
Deletes a remote artifact or directory prefix.
Workspace
Streaming workspace-identity API used by r5dchat artifacts. Reads, stats, and deletes accept a namespace path or immutable artifact id. Requires x-artifact-scope; the server resolves it and re-checks project membership or standalone-chat participation before reading or mutating bytes.

Workspace endpoints

Session
Current workspace phase: running, starting, stopped, or disabled, plus a readiness flag and the mode.
Session
Starts the workspace and waits for readiness.
Session
Requests an immediate scale to zero, clearing active leases.

Admin endpoints

Admin
Lists all users.
Admin
Creates a user account directly. In the community edition, the optional providerSettingsEnabled boolean controls provider settings access (default true). In both editions, optional mcpSettingsEnabled controls MCP settings access (default true).
Admin
Updates a user’s role, enabled state, or (community edition) providerSettingsEnabled. Send { "id": "user-id", "providerSettingsEnabled": false } to restrict one user. Send { "all": true, "providerSettingsEnabled": false } to restrict all current non-admin accounts in one operation; use true to restore access. Administrators retain provider access, and newly created accounts are unaffected by earlier bulk changes.In both editions, send { "id": "user-id", "mcpSettingsEnabled": false } to restrict one user’s MCP settings, or { "all": true, "mcpSettingsEnabled": false } for all current non-admin users. Use true to restore access. This is independent of provider and account access; administrators remain able to configure servers for any user.
Admin
Available in both editions. GET lists the target user’s servers; add &id=SERVER_ID to load all configuration fields including decrypted headers. POST, PATCH, and DELETE use the same bodies and id query parameter as /api/mcp, scoped to that user, even when their MCP settings are disabled. Missing userId returns 400; unknown users or servers owned by a different user return 404. List and mutation responses do not expose header values.
Admin
Tests or trusts a server for the specified user. Body: { "id": "server-id" }. Use these after creating or changing a server on the user’s behalf.
Admin · Community
GET lists that user’s providers with editable headers and their ordered modelTiers definitions. POST, PATCH, and DELETE use the same bodies and id query parameter as /api/providers, scoped to the specified user. They work even when that user’s provider settings are disabled. API keys remain write-only. A missing user ID returns 400; an unknown user, or a provider owned by another user, returns 404.
Admin · Community
Tests that user’s provider and discovers its models. Body: { "id": "provider-id" }.
Admin · Community
POST, PATCH, and DELETE manage models for the specified user using the same bodies and id query parameter as /api/models. Provider/model ownership and default-model rules remain scoped to that user.
Admin · Community
Replaces the specified user’s tier definitions, even when their provider settings are disabled. Uses the same {tiers} body, {modelTiers} response, validation, and in-use removal rules as /api/model-tiers. Requires userId. Managed administrators instead use /api/model-tiers for the shared installation catalogue.
Admin
Returns branding and OIDC configuration. Client secrets are not returned in plaintext.
Admin
Updates branding and OIDC configuration.
Admin
Applies a versioned, repeatable installation manifest. Version 1 can upsert users and roles, configure branding and OIDC, seed providers and models, and import conversations. Imported conversations receive the same owner, participant preference, and artifact-namespace records as conversations created through the interface. Existing conversations with the same ID are left untouched, so rerunning a migration cannot overwrite subsequent user work.Manifests put each user’s private credentials in users[].providers. Users created without passwords authenticate through OIDC after exact, verified-email linking is enabled. Every model in the manifest must explicitly set tier to a configured positive integer ID. Optional modelTiers defines an ordered array of { value, label } at the root for managed installations or on each users[] entry for community catalogues. Omitting it retains existing definitions (new catalogues get the initial four defaults). The same limits, unique labels/IDs, membership, and in-use removal rules as /api/model-tiers apply. This community example uses three custom tiers in nonnumeric order:
API keys and OIDC client secrets are encrypted immediately with SETTINGS_ENCRYPTION_KEY and are never returned. Stream manifests from a protected process and avoid shell tracing or ordinary build artifacts.
Admin
Streams one artifact into an existing conversation or project during a data migration. Send multipart/form-data with exactly one of chatId or projectId, plus artifactId (UUID), importSource, path, file, and optional mediaType and RFC 3339 createdAt fields.artifactId lets an importer write canonical artifact://<artifact-id> links into conversation messages before uploading bytes. importSource makes the operation repeatable: retrying the same source, ID, namespace, and path returns the existing record with skipped: true; reusing a source for a different target returns 409. The upload limit is ARTIFACT_MAX_UPLOAD_BYTES.
Admin
Validates OIDC discovery and client credentials against the real provider before enabling it.
Admin
Creates an invitation for a new account.
Public
Redeems an invitation to create an account.

Workspace-authenticated endpoints

Workspace
Backs the r5dchat conversation commands. Authenticates with the workspace bearer identity, then re-checks that the workspace’s user owns the requested conversation. Supports overview, single-turn, and full-read modes in Markdown or JSON.

Errors

Errors return a JSON body with a machine-readable code:

Monitoring

Use /api/health for liveness and readiness. It is unauthenticated and checks database connectivity, making it a meaningful signal rather than a static response.