diff --git a/sqlite-cloud/_nav.ts b/sqlite-cloud/_nav.ts
index 0d3a9ad..cf09cb9 100644
--- a/sqlite-cloud/_nav.ts
+++ b/sqlite-cloud/_nav.ts
@@ -95,6 +95,12 @@ const sidebarNav: SidebarNavStruct = [
type: "inner",
level: 1,
},
+ {
+ title: "Management API",
+ filePath: "sqlite-sync-cloudsync-management-api",
+ type: "inner",
+ level: 1,
+ },
{
title: "Best Practices",
filePath: "sqlite-sync-best-practices",
@@ -113,9 +119,9 @@ const sidebarNav: SidebarNavStruct = [
type: "inner",
level: 1,
},
- { title: "API Reference", type: "inner", level: 1 },
+ { title: "Client API Reference", type: "inner", level: 1 },
{
- title: "API Overview",
+ title: "Overview",
filePath: "sqlite-sync-api-reference",
type: "inner",
level: 2,
diff --git a/sqlite-cloud/platform/cloudsync.mdx b/sqlite-cloud/platform/cloudsync.mdx
index 3760fd8..a7e2389 100644
--- a/sqlite-cloud/platform/cloudsync.mdx
+++ b/sqlite-cloud/platform/cloudsync.mdx
@@ -34,10 +34,11 @@ When combined with [Row-Level Security (RLS)](/docs/rls), CloudSync allows you t
You can enable and manage CloudSync for your databases directly from the SQLite Cloud dashboard. Select a database from the left panel — the list shows all databases in your project along with their CloudSync status. The right panel has four tabs: **Database Setup**, **Client Integration**, **Devices**, and **Metrics**.
+If you prefer automation, you can also register databases, inspect tables, and enable CloudSync programmatically with the [Management API](/docs/sqlite-sync-cloudsync-management-api). That page documents the workspace-scoped management endpoints used with a `workspace-admin` key.
+
### Enabling and Disabling CloudSync
When CloudSync is not yet active for a database, the right panel shows a brief explanation and an **Enable CloudSync** button. Clicking it opens a confirmation dialog; after confirming, the database is registered with the sync service and the tabbed view appears.
-
To disable CloudSync, click the **Disable CloudSync** button in the top-right corner of the panel and confirm in the dialog that appears.
{/* */}
diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference.md
index 30ed886..1706e3e 100644
--- a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference.md
+++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference.md
@@ -1,6 +1,6 @@
---
-title: "SQLite-Sync API Reference"
-description: "Comprehensive SQLite-Sync API reference for configuration, filters, block-level LWW, helpers, schema changes, and networking."
+title: "Client API Reference"
+description: "Reference for the SQLite Sync client runtime functions for configuration, filters, block-level LWW, helpers, schema changes, and networking."
category: platform
status: publish
slug: sqlite-sync-api-reference
diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/block-lww.md b/sqlite-cloud/sqlite-ai/sqlite-sync/block-lww.md
index 3c48b4b..d50ae80 100644
--- a/sqlite-cloud/sqlite-ai/sqlite-sync/block-lww.md
+++ b/sqlite-cloud/sqlite-ai/sqlite-sync/block-lww.md
@@ -127,4 +127,4 @@ SELECT cloudsync_set_column('docs', 'body', 'algo', 'block');
- **Mixed columns**: A table can have both regular and block-level LWW columns.
- **Transparent reads**: The base column always contains the current full text.
-For API details, see the [API Reference](/docs/sqlite-sync-api-reference).
+For API details, see the [Client API Reference](/docs/sqlite-sync-api-reference).
diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/cloudsync-management-api.md b/sqlite-cloud/sqlite-ai/sqlite-sync/cloudsync-management-api.md
new file mode 100644
index 0000000..7d391b0
--- /dev/null
+++ b/sqlite-cloud/sqlite-ai/sqlite-sync/cloudsync-management-api.md
@@ -0,0 +1,411 @@
+---
+title: "Management API"
+description: "Register and manage SQLite Sync databases programmatically with a workspace-admin management API key."
+category: platform
+status: publish
+slug: sqlite-sync-cloudsync-management-api
+---
+
+You can register and manage CloudSync databases programmatically without using the dashboard UI.
+
+This page covers only the `/v1` management endpoints that are available when you authenticate with a workspace-scoped management API key that has the `workspace-admin` role. It intentionally excludes workspace management, org-wide key management, and `/v1/admin` platform-admin endpoints.
+
+## Authentication
+
+```http
+Authorization: Bearer
+```
+
+- Base URL: `https://cloudsync.sqlite.ai`
+- Use a management API key with the `workspace-admin` role. In the [SQLite Cloud Dashboard](https://dashboard.sqlitecloud.io/), go to your project, then **CloudSync** > **API Keys**.
+- The workspace is derived from the key itself.
+- You cannot override the workspace with headers, query parameters, or path segments.
+
+Use this API from backend services, CI, or trusted automation. Client apps should use the [Client API Reference](/docs/sqlite-sync-api-reference) instead.
+
+## Request and Response Conventions
+
+- Send `Content-Type: application/json` for all `POST`, `PUT`, and `PATCH` bodies.
+- Successful responses use the envelope `{"data": ...}`.
+- List responses may also include a `meta` object.
+- Error responses use a top-level `errors` array.
+
+Example error response:
+
+```json
+{
+ "errors": [
+ {
+ "status": "404",
+ "code": "not_found",
+ "title": "Not Found",
+ "detail": "managed database not found"
+ }
+ ]
+}
+```
+
+## Quickstart
+
+Start with a workspace-level management API key from your project's **CloudSync** > **API Keys** page in the dashboard:
+
+```bash
+export BASE_URL="https://cloudsync.sqlite.ai"
+export APIKEY=""
+```
+
+### 1. Register a Database
+
+This creates the managed database entry in CloudSync and returns the CloudSync Database ID as `managedDatabaseId`.
+
+```bash
+curl --request POST "$BASE_URL/v1/databases" \
+ --header "Authorization: Bearer $APIKEY" \
+ --header "Content-Type: application/json" \
+ --data '{
+ "label": "Primary DB",
+ "connectionString": "sqlitecloud://project.sqlite.cloud:8860?apikey=xxxx",
+ "provider": "sqlitecloud",
+ "flavor": "sqlitecloud",
+ "databaseName": "appdb"
+ }'
+```
+
+Response:
+
+```json
+{
+ "data": {
+ "managedDatabaseId": "db_xxxxxxxxxxxxxxxxxxxxxxxx"
+ }
+}
+```
+
+Use that value as `MGMT_DB_ID` in the next calls.
+
+```bash
+export MGMT_DB_ID="db_xxxxxxxxxxxxxxxxxxxxxxxx"
+```
+
+### 2. List Registered Databases
+
+Useful when you want to recover the managed database ID later.
+
+```bash
+curl --request GET "$BASE_URL/v1/databases" \
+ --header "Authorization: Bearer $APIKEY"
+```
+
+### 3. Check Available CloudSync Tables
+
+```bash
+curl --request GET "$BASE_URL/v1/databases/$MGMT_DB_ID/cloudsync/tables" \
+ --header "Authorization: Bearer $APIKEY"
+```
+
+### 4. Enable CloudSync for Tables
+
+```bash
+curl --request POST "$BASE_URL/v1/databases/$MGMT_DB_ID/cloudsync/enable" \
+ --header "Authorization: Bearer $APIKEY" \
+ --header "Content-Type: application/json" \
+ --data '{
+ "tables": ["users", "orders"]
+ }'
+```
+
+## What a `workspace-admin` Key Can Manage
+
+With a workspace-scoped management key, you can:
+
+- inspect the authenticated organization with `GET /v1/orgs`
+- register, list, read, update, delete, and verify managed databases in the key's workspace
+- list, enable, and disable CloudSync tables for those databases
+- manage Expo notification credentials and inspect notification status
+- list and remove registered devices
+
+It cannot:
+
+- list or mutate workspaces
+- create, list, or revoke management API keys
+- use `/v1/admin/*` endpoints
+
+## Endpoint Summary
+
+| Area | Endpoints |
+| --- | --- |
+| Organization | `GET /v1/orgs` |
+| Databases | `POST /v1/databases`, `GET /v1/databases`, `GET /v1/databases/:databaseID`, `PATCH /v1/databases/:databaseID`, `DELETE /v1/databases/:databaseID`, `GET /v1/databases/:databaseID/connection` |
+| CloudSync tables | `GET /v1/databases/:databaseID/cloudsync/tables`, `POST /v1/databases/:databaseID/cloudsync/enable`, `POST /v1/databases/:databaseID/cloudsync/disable` |
+| Notifications | `PUT /v1/databases/:databaseID/notifications/expo-access-token`, `GET /v1/databases/:databaseID/notifications/expo-access-token`, `DELETE /v1/databases/:databaseID/notifications/expo-access-token`, `GET /v1/databases/:databaseID/notifications/status` |
+| Devices | `GET /v1/databases/:databaseID/devices`, `DELETE /v1/databases/:databaseID/devices/:siteId` |
+
+## Organization
+
+### `GET /v1/orgs`
+
+Returns the organization associated with the API key.
+
+```bash
+curl "$BASE_URL/v1/orgs" \
+ --header "Authorization: Bearer $APIKEY"
+```
+
+```json
+{
+ "data": {
+ "organizationId": "org_xxxxxxxxxxxxxxxxxxxxxxxx",
+ "slug": "acme",
+ "name": "Acme Corp",
+ "status": "active"
+ }
+}
+```
+
+## Databases
+
+### `POST /v1/databases`
+
+Registers a new managed database.
+
+Required fields:
+
+- `label`
+- `connectionString`
+- `provider` — `postgres` or `sqlitecloud`
+- `flavor` — for example `vanilla`, `supabase`, or `sqlitecloud`
+- `databaseName`
+
+Optional fields:
+
+- `schemaName` — Postgres only
+- `jwtAllowedIssuers`
+- `jwtExpectedAudiences`
+- `jwksUri`
+- `jwtSecret`
+
+Important behavior for workspace-scoped keys:
+
+- omit `workspaceId`
+- the created database is automatically attached to the workspace derived from the key
+
+CloudSync verifies the tenant database connection before registration is persisted. If verification fails, the database is not registered.
+
+Common database failure codes include `database_paused`, `database_auth_failed`, `database_unreachable`, `database_permission_denied`, `database_cloudsync_not_ready`, and `database_error`.
+
+### `GET /v1/databases`
+
+Lists managed databases visible to the key.
+
+Example:
+
+```bash
+curl "$BASE_URL/v1/databases" \
+ --header "Authorization: Bearer $APIKEY"
+```
+
+### `GET /v1/databases/:databaseID`
+
+Fetches a single managed database in the workspace.
+
+```bash
+curl "$BASE_URL/v1/databases/$MGMT_DB_ID" \
+ --header "Authorization: Bearer $APIKEY"
+```
+
+### `PATCH /v1/databases/:databaseID`
+
+Updates metadata, auth settings, and connection details. Only the fields you send are modified.
+
+Supported fields:
+
+- `label`
+- `connectionString`
+- `jwtAllowedIssuers`
+- `jwtExpectedAudiences`
+- `jwksUri`
+- `jwtSecret`
+
+Notes:
+
+- when `connectionString` is provided, CloudSync verifies the new connection before storing it
+- omitting `jwtSecret` leaves the current secret unchanged
+- sending `"jwtSecret": ""` clears the current secret
+- `jwtSecret` is write-only and is never returned by read endpoints
+
+Example:
+
+```bash
+curl --request PATCH "$BASE_URL/v1/databases/$MGMT_DB_ID" \
+ --header "Authorization: Bearer $APIKEY" \
+ --header "Content-Type: application/json" \
+ --data '{
+ "label": "Primary DB (updated)",
+ "jwtAllowedIssuers": ["https://project.supabase.co/auth/v1"],
+ "jwtExpectedAudiences": ["authenticated"],
+ "jwksUri": "https://project.supabase.co/auth/v1/.well-known/jwks.json",
+ "jwtSecret": ""
+ }'
+```
+
+### `DELETE /v1/databases/:databaseID`
+
+Deletes a managed database record.
+
+Before removal, CloudSync attempts to:
+
+1. list CloudSync-managed tenant tables
+2. disable enabled tables
+3. delete pending jobs for the managed database
+
+Cleanup is best effort. The database record is still deleted even if one of those cleanup steps reports warnings.
+
+```bash
+curl --request DELETE "$BASE_URL/v1/databases/$MGMT_DB_ID" \
+ --header "Authorization: Bearer $APIKEY"
+```
+
+### `GET /v1/databases/:databaseID/connection`
+
+Runs a live connectivity check against the managed database's stored connection details.
+
+```bash
+curl "$BASE_URL/v1/databases/$MGMT_DB_ID/connection" \
+ --header "Authorization: Bearer $APIKEY"
+```
+
+Success response:
+
+```json
+{
+ "data": {
+ "ok": true,
+ "checkedAt": "2025-01-01T00:00:00Z"
+ }
+}
+```
+
+Failure response:
+
+```json
+{
+ "data": {
+ "ok": false,
+ "checkedAt": "2025-01-01T00:00:00Z",
+ "failure": {
+ "code": "database_unreachable",
+ "message": "tenant database is unreachable",
+ "retryable": true
+ }
+ }
+}
+```
+
+## CloudSync Tables
+
+### `GET /v1/databases/:databaseID/cloudsync/tables`
+
+Lists tables and whether CloudSync is enabled for each one.
+
+```bash
+curl "$BASE_URL/v1/databases/$MGMT_DB_ID/cloudsync/tables" \
+ --header "Authorization: Bearer $APIKEY"
+```
+
+```json
+{
+ "data": [
+ { "name": "users", "enabled": true },
+ { "name": "orders", "enabled": false }
+ ]
+}
+```
+
+### `POST /v1/databases/:databaseID/cloudsync/enable`
+
+Enables CloudSync for a non-empty list of tables.
+
+```bash
+curl --request POST "$BASE_URL/v1/databases/$MGMT_DB_ID/cloudsync/enable" \
+ --header "Authorization: Bearer $APIKEY" \
+ --header "Content-Type: application/json" \
+ --data '{"tables": ["users", "orders"]}'
+```
+
+### `POST /v1/databases/:databaseID/cloudsync/disable`
+
+Disables CloudSync for a non-empty list of tables.
+
+```bash
+curl --request POST "$BASE_URL/v1/databases/$MGMT_DB_ID/cloudsync/disable" \
+ --header "Authorization: Bearer $APIKEY" \
+ --header "Content-Type: application/json" \
+ --data '{"tables": ["orders"]}'
+```
+
+## Notifications
+
+### `PUT /v1/databases/:databaseID/notifications/expo-access-token`
+
+Sets or rotates the Expo access token used to send push notifications.
+
+```bash
+curl --request PUT "$BASE_URL/v1/databases/$MGMT_DB_ID/notifications/expo-access-token" \
+ --header "Authorization: Bearer $APIKEY" \
+ --header "Content-Type: application/json" \
+ --data '{"expoAccessToken": "expo-access-token-value"}'
+```
+
+### `GET /v1/databases/:databaseID/notifications/expo-access-token`
+
+Returns metadata about the Expo access token, not the token value itself.
+
+```bash
+curl "$BASE_URL/v1/databases/$MGMT_DB_ID/notifications/expo-access-token" \
+ --header "Authorization: Bearer $APIKEY"
+```
+
+### `DELETE /v1/databases/:databaseID/notifications/expo-access-token`
+
+Removes the Expo access token from the database.
+
+```bash
+curl --request DELETE "$BASE_URL/v1/databases/$MGMT_DB_ID/notifications/expo-access-token" \
+ --header "Authorization: Bearer $APIKEY"
+```
+
+### `GET /v1/databases/:databaseID/notifications/status`
+
+Returns the current push notification status for a managed database.
+
+`status` can be `enabled`, `disabled`, or `paused`. When `status` is `paused`, `reason` explains why. Currently supported pause reasons include `expo_unauthorized`.
+
+```bash
+curl "$BASE_URL/v1/databases/$MGMT_DB_ID/notifications/status" \
+ --header "Authorization: Bearer $APIKEY"
+```
+
+## Devices
+
+### `GET /v1/databases/:databaseID/devices`
+
+Lists registered devices for a managed database.
+
+Query parameters:
+
+- `page` — default `1`
+- `page_size` — default `50`, max `500`
+
+```bash
+curl "$BASE_URL/v1/databases/$MGMT_DB_ID/devices?page=1&page_size=50" \
+ --header "Authorization: Bearer $APIKEY"
+```
+
+### `DELETE /v1/databases/:databaseID/devices/:siteId`
+
+Removes a registered device by `siteId`. Associated push tokens are removed as well.
+
+```bash
+curl --request DELETE "$BASE_URL/v1/databases/$MGMT_DB_ID/devices/site_123" \
+ --header "Authorization: Bearer $APIKEY"
+```
diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/getting-started.md b/sqlite-cloud/sqlite-ai/sqlite-sync/getting-started.md
index 34c7833..d41d81a 100644
--- a/sqlite-cloud/sqlite-ai/sqlite-sync/getting-started.md
+++ b/sqlite-cloud/sqlite-ai/sqlite-sync/getting-started.md
@@ -101,3 +101,4 @@ Back on Device A, calling `cloudsync_network_sync()` will pull Device B's change
For token-based authentication (required for RLS), use `cloudsync_network_set_token()` instead of `cloudsync_network_set_apikey()`.
+If you want to register the managed database and enable tables programmatically instead of using the dashboard, see [Management API](/docs/sqlite-sync-cloudsync-management-api). That flow uses a workspace-level management API key and is separate from the client authentication used by `cloudsync_network_set_apikey()` and `cloudsync_network_set_token()`.