Sheets, Slides & Collaboration

Backbuild Sheets (spreadsheets) with cell comments, Backbuild Slides decks, the collaboration and realtime Yjs WebSocket transports, and offline sync.

21 endpoints. Generated from the OpenAPI 3.1 specification.

GET /v1/bbsheet/{documentId}/export

Export a spreadsheet

Streams a freshly materialized export artifact (SQLite, XLSX, CSV, or TSV) for a spreadsheet the caller can read. Authentication uses a JWT in the `token` query parameter (self-authenticating, like the WebSocket endpoint, because a browser anchor download cannot easily set `Authorization` headers). The handler verifies the JWT, checks `token_version` revocation, runs the effective-access gate (requires `resolved_kind=spreadsheet` and `can_read`), then drives the grid Durable Object export op and streams the decoded bytes. The response includes a `Content-Disposition: attachment` header. Exports are never cached (`Cache-Control: no-store`) and the content is bounded by the DO's the configured export-cell limit limit.

Auth One-time ?token= ticket

Parameters

NameInTypeRequiredDescription
documentId path string<uuid> yes Spreadsheet document identifier (UUID).
token query string yes A valid session JWT.
format query string (enum) yes Export format.
sheet_id query integer no Zero-based sheet (tab) index. Required by the DO for `csv`/`tsv`; optional for `sqlite`/`xlsx`.
header_row query string (enum) no Whether to include a header row in the export (`true` or `false`).
value_mode query string (enum) no Whether to export displayed (formatted) or raw cell values. Defaults to `displayed`.
filename query string no Optional base filename for the downloaded file (max 200 chars). Sanitized server-side; the extension is appended automatically.

Responses

StatusDescription
200 Export artifact streamed as a binary file download.
400 `VALIDATION_ERROR` (missing or invalid query parameters; export too large; unknown sheet), `INVALID_ID_FORMAT`.
401 `AUTH_TOKEN_INVALID` or `AUTH_TOKEN_EXPIRED`.
403 `PERMISSION_DENIED` (no read access or document is not a spreadsheet).
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
GET /v1/bbsheet/ws

Open BB Sheets grid WebSocket

Upgrades to a WebSocket connection to the `BbSheetGridDO` for a specific spreadsheet. Authentication uses the full session JWT passed as a `?token=` query parameter (not the `Authorization` header — the browser WebSocket API cannot set custom headers). Unlike `POST /v1/collaboration/ticket`, there is no intermediate ticket exchange; the JWT is verified directly. The handler checks `token_version` revocation, runs the spreadsheet effective-access gate (`resolved_kind` must be `spreadsheet`), and derives the socket capability (`read`/`write`) from `can_write`. The Durable Object key is `bbsheet:<orgId>:<documentId>`. The caller must send an `Upgrade: websocket` header.

Auth One-time ?token= ticket

Parameters

NameInTypeRequiredDescription
token query string yes A valid session JWT. Required because the browser WebSocket API cannot set `Authorization` headers.
documentId query string<uuid> yes Spreadsheet document identifier (UUID).

Responses

StatusDescription
101 WebSocket upgrade accepted. The connection is forwarded to the `BbSheetGridDO`.
400 `VALIDATION_ERROR` (missing or invalid query parameters) or 426 (missing `Upgrade: websocket` header).
401 `AUTH_TOKEN_INVALID` (JWT malformed or revoked) or `AUTH_TOKEN_EXPIRED` (JWT expired).
403 `PERMISSION_DENIED` (no read access, document is not a spreadsheet, or effective-access gate errored).
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
POST /v1/collaboration/ticket

Exchange a JWT for a single-use collaboration WebSocket ticket

Exchanges a valid session JWT (supplied in the standard `Authorization: Bearer` header) for a cryptographically random, single-use, short-lived (60 s) ticket stored in KV. The ticket is then passed as `?ticket=` on the `/v1/collaboration/ws` WebSocket upgrade. This two-step flow is required because the browser WebSocket API does not support custom headers during the HTTP upgrade handshake. Token-version revocation is checked before the ticket is issued.

Auth Session JWT (Bearer)

Request Body

FieldTypeRequiredDescription
scope string no Optional advisory scope string stored with the ticket. Not security-enforced; for client routing only.

Responses

StatusDescription
200 Ticket issued.
401 `AUTH_REQUIRED` (missing Authorization header), `AUTH_TOKEN_INVALID` (JWT malformed, revoked, or missing required claims), `AUTH_TOKEN_EXPIRED` (JWT expired).
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
ticket string 64-character hex-encoded single-use WebSocket ticket.
expiresInSeconds integer Ticket TTL in seconds (60).
GET /v1/collaboration/ws

Open collaboration WebSocket

Upgrades to a WebSocket connection to the `CollaborationDO` for the caller's organization. The preferred authentication path uses a single-use `?ticket=` obtained from `POST /v1/collaboration/ticket`. A deprecated fallback accepts a direct JWT as `?token=` (a deprecation warning is logged; this path will be removed in a future release). The DO key is `collab:<orgId>`. The caller must send an `Upgrade: websocket` header.

Auth One-time ?token= ticket

Parameters

NameInTypeRequiredDescription
ticket query string no Single-use ticket obtained from `POST /v1/collaboration/ticket`. Preferred authentication path.
token query string no **Deprecated.** Session JWT passed directly in the query string. Will be removed in a future release.

Responses

StatusDescription
101 WebSocket upgrade accepted. The connection is forwarded to the `CollaborationDO`.
400 `VALIDATION_ERROR` (neither `ticket` nor `token` supplied, or the Upgrade header is missing).
401 `AUTH_TOKEN_INVALID` (ticket invalid/expired, JWT malformed/revoked), `AUTH_TOKEN_EXPIRED` (JWT expired).
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
GET /v1/preferences/offline-sync

Get offline sync preferences (client shortcut)

Returns a simplified offline sync preferences summary derived from `api.sync_preferences_get`. This is a client-facing shortcut that normalizes the user's sync settings into a flat object (`enabled`, `max_items`, `sync_on_reconnect`, `storage_limit_mb`). On any database error it returns safe defaults rather than an error response, ensuring the client always has a usable baseline.

Auth Session JWT (Bearer)

Responses

StatusDescription
200 Offline sync preferences summary (or safe defaults on error).
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
200 response body: data fields
FieldTypeDescription
enabled boolean Whether offline sync is enabled (`auto_sync`).
max_items integer Maximum items to sync (currently always 500).
sync_on_reconnect boolean Whether to sync automatically on reconnect (`auto_sync`).
storage_limit_mb integer Local storage limit in MB (`max_local_size_mb`, default 50).
POST /v1/projects/{projectId}/bbsheets

Create a BB Sheets spreadsheet

Atomically creates a spreadsheet catalog row and the backing `bb.bbsheet_documents` row via `api.bbsheet_create`, then grants the creating user WRITE access. After creation the spreadsheet is accessible via the grid WebSocket at `/v1/bbsheet/ws`. `org_id` is pinned from the session and is never accepted in the body. The body is strict — unknown keys are rejected with `VALIDATION_ERROR`. Requires the `documents` system feature flag.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
projectId path string<uuid> yes Project identifier (UUIDv7).

Request Body

FieldTypeRequiredDescription
name string yes Spreadsheet display name (trimmed, 1–500 chars).
fromTemplateId string<uuid> no Optional template spreadsheet id to copy the initial grid state from.
{
  "name": "Q2 Budget Tracker"
}

Responses

StatusDescription
201 Spreadsheet created. The full document record is returned under `data.document`.
400 `INVALID_JSON` (unparseable body), `VALIDATION_ERROR` (a field failed schema validation; unknown keys are rejected by the strict schema), `INVALID_ID_FORMAT` (malformed projectId).
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 `FORBIDDEN` (no `document.create` permission or project membership; enforced by the stored procedure).
404 `NOT_FOUND` (project not found or not visible to caller).
409 `CONFLICT` (duplicate spreadsheet in this project).
500 `DATABASE_ERROR` (unrecognized SP error) or `INTERNAL_ERROR` (unexpected server error).
201 response body: data fields
FieldTypeDescription
document any The created spreadsheet document record.
GET /v1/projects/{projectId}/bbsheets/{documentId}/comments

List spreadsheet cell comments

Returns all cell comments and their replies for the specified spreadsheet. Serves as the seed source for the client-side comment adapter; comments anchor to cell rectangles via packed integer coordinates. Authorization (project membership + effective spreadsheet READ access) is enforced entirely by `api.bbsheet_comments_list`.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
projectId path string<uuid> yes Project identifier (UUIDv7).
documentId path string<uuid> yes Spreadsheet document identifier (UUIDv7).

Responses

StatusDescription
200 All comments (including replies) for the spreadsheet.
400 `INVALID_ID_FORMAT` (malformed projectId or documentId).
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 `FORBIDDEN` (no READ access to the spreadsheet).
404 `NOT_FOUND` (project or document not found).
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
comments array of object Cell comment threads with embedded replies.
POST /v1/projects/{projectId}/bbsheets/{documentId}/comments

Create a cell comment on a spreadsheet

Creates a new comment thread anchored to a cell rectangle in the spreadsheet. The anchor is specified as two packed integer coordinates (`anchorFrom`/`anchorTo`) produced by the client's pure `cellAnchor` module. An optional client-provided `commentId` (UUID) is used as the database row id so the client list stays consistent. Authorization is enforced by `api.bbsheet_comment_create` via the `spreadsheet` effective-access gate. The body is strict — unknown keys are rejected.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
projectId path string<uuid> yes Project identifier (UUIDv7).
documentId path string<uuid> yes Spreadsheet document identifier (UUIDv7).

Request Body

FieldTypeRequiredDescription
commentId string<uuid> no Optional client-provided comment id (UUIDv7). Used as the database row id so the client list stays consistent.
anchorFrom integer yes Packed integer for the top-left of the anchored cell rectangle (non-negative, < 2,000,000,000).
anchorTo integer yes Packed integer for the bottom-right of the anchored cell rectangle (non-negative, < 2,000,000,000).
body string yes Comment body text (1–5000 chars).
authorName string no Optional display name for the author (up to 200 chars).

Responses

StatusDescription
201 Comment created.
400 `INVALID_JSON`, `VALIDATION_ERROR` (body field failed validation or unknown key present), `INVALID_ID_FORMAT`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 `FORBIDDEN` (no COMMENT access to the spreadsheet).
404 `NOT_FOUND` (project or document not found).
409 `CONFLICT` (duplicate commentId).
500 `DATABASE_ERROR` (unrecognized SP error) or `INTERNAL_ERROR`.
201 response body: data fields
FieldTypeDescription
comment any
PATCH /v1/projects/{projectId}/bbsheets/{documentId}/comments/{commentId}

Resolve or reopen a cell comment

Toggles the resolved state of a comment thread via `api.bbsheet_comment_resolve`. The body is strict — only `resolved` is accepted. Requires the comment author or an org admin role (enforced by the stored procedure).

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
projectId path string<uuid> yes Project identifier (UUIDv7).
documentId path string<uuid> yes Spreadsheet document identifier (UUIDv7).
commentId path string<uuid> yes Comment identifier (UUIDv7).

Request Body

FieldTypeRequiredDescription
resolved boolean yes `true` to resolve the comment thread; `false` to reopen it.

Responses

StatusDescription
200 Comment updated.
400 `INVALID_JSON`, `VALIDATION_ERROR`, `INVALID_ID_FORMAT`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 `FORBIDDEN` (not the comment author or an org admin).
404 `NOT_FOUND` (project, document, or comment not found).
500 `DATABASE_ERROR` (unrecognized SP error) or `INTERNAL_ERROR`.
200 response body: data fields
FieldTypeDescription
comment any
DELETE /v1/projects/{projectId}/bbsheets/{documentId}/comments/{commentId}

Delete a cell comment thread

Deletes a comment thread and all its replies via `api.bbsheet_comment_delete`. Requires the comment author or an org admin role (enforced by the stored procedure).

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
projectId path string<uuid> yes Project identifier (UUIDv7).
documentId path string<uuid> yes Spreadsheet document identifier (UUIDv7).
commentId path string<uuid> yes Comment identifier (UUIDv7).

Responses

StatusDescription
200 Comment deleted.
400 `INVALID_ID_FORMAT` (malformed path parameter).
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 `FORBIDDEN` (not the comment author or an org admin).
404 `NOT_FOUND` (project, document, or comment not found).
500 `DATABASE_ERROR` (unrecognized SP error) or `INTERNAL_ERROR`.
200 response body: data fields
FieldTypeDescription
deleted boolean (enum) true Always true on success.
POST /v1/projects/{projectId}/bbsheets/{documentId}/comments/{commentId}/assign

Assign a cell comment to an org member

Assigns a comment thread to an active organization member and optionally sends a notification via `api.bbsheet_comment_assign`. The assignee must be an existing org member (enforced by the stored procedure). The body is strict — unknown keys are rejected.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
projectId path string<uuid> yes Project identifier (UUIDv7).
documentId path string<uuid> yes Spreadsheet document identifier (UUIDv7).
commentId path string<uuid> yes Comment identifier (UUIDv7).

Request Body

FieldTypeRequiredDescription
assigneeUserId string<uuid> yes User id of the assignee (must be an active org member).
assigneeName string no Optional display name for the assignee (up to 200 chars).

Responses

StatusDescription
200 Comment assigned.
400 `INVALID_JSON`, `VALIDATION_ERROR`, `INVALID_ID_FORMAT`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 `FORBIDDEN` (no COMMENT access or insufficient permissions).
404 `NOT_FOUND` (project, document, comment, or assignee not found).
500 `DATABASE_ERROR` (unrecognized SP error) or `INTERNAL_ERROR`.
200 response body: data fields
FieldTypeDescription
comment any
notified boolean Whether the assignee was notified.
POST /v1/projects/{projectId}/bbsheets/{documentId}/comments/{commentId}/assignment-done

Mark a comment assignment as done

Marks the assignment task on a comment as completed via `api.bbsheet_comment_assignment_done`. Only the assignee or a project admin can perform this action (enforced by the stored procedure). No request body is required.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
projectId path string<uuid> yes Project identifier (UUIDv7).
documentId path string<uuid> yes Spreadsheet document identifier (UUIDv7).
commentId path string<uuid> yes Comment identifier (UUIDv7).

Responses

StatusDescription
200 Assignment marked done.
400 `INVALID_ID_FORMAT` (malformed path parameter).
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 `FORBIDDEN` (not the assignee or a project admin).
404 `NOT_FOUND` (project, document, or comment not found).
500 `DATABASE_ERROR` (unrecognized SP error) or `INTERNAL_ERROR`.
200 response body: data fields
FieldTypeDescription
comment any
POST /v1/projects/{projectId}/bbsheets/{documentId}/comments/{commentId}/replies

Reply to a cell comment

Appends a reply to an existing comment thread via `api.bbsheet_comment_reply_create`. An optional client-provided `replyId` is used as the database row id. The body is strict — unknown keys are rejected.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
projectId path string<uuid> yes Project identifier (UUIDv7).
documentId path string<uuid> yes Spreadsheet document identifier (UUIDv7).
commentId path string<uuid> yes Parent comment identifier (UUIDv7).

Request Body

FieldTypeRequiredDescription
replyId string<uuid> no Optional client-provided reply id (UUIDv7). Used as the database row id.
body string yes Reply body text (1–5000 chars).
authorName string no Optional display name for the reply author (up to 200 chars).

Responses

StatusDescription
201 Reply created.
400 `INVALID_JSON`, `VALIDATION_ERROR`, `INVALID_ID_FORMAT`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 `FORBIDDEN` (no COMMENT access to the spreadsheet).
404 `NOT_FOUND` (project, document, or comment not found).
409 `CONFLICT` (duplicate replyId).
500 `DATABASE_ERROR` (unrecognized SP error) or `INTERNAL_ERROR`.
201 response body: data fields
FieldTypeDescription
reply any
DELETE /v1/projects/{projectId}/bbsheets/{documentId}/comments/{commentId}/replies/{replyId}

Delete a reply from a cell comment

Deletes a single reply from a comment thread via `api.bbsheet_comment_reply_delete`. Requires the reply author or an org admin role (enforced by the stored procedure).

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
projectId path string<uuid> yes Project identifier (UUIDv7).
documentId path string<uuid> yes Spreadsheet document identifier (UUIDv7).
commentId path string<uuid> yes Parent comment identifier (UUIDv7).
replyId path string<uuid> yes Reply identifier (UUIDv7).

Responses

StatusDescription
200 Reply deleted.
400 `INVALID_ID_FORMAT` (malformed path parameter).
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 `FORBIDDEN` (not the reply author or an org admin).
404 `NOT_FOUND` (project, document, comment, or reply not found).
500 `DATABASE_ERROR` (unrecognized SP error) or `INTERNAL_ERROR`.
200 response body: data fields
FieldTypeDescription
deleted boolean (enum) true
POST /v1/projects/{projectId}/bbslides

Create a BB Slides deck

Atomically creates a presentation deck (catalog row with `content_type='application/x-bbslides'`), a backing `bb.bbprove_documents` row, and the owner WRITE grant via `api.bbslides_create`. The deck reuses the BB Docs editor and its CRDT transport lives at `/v1/yjs/ws`. `org_id` is pinned from the session and is never accepted in the body. The body is strict — unknown keys are rejected. Requires the `documents` system feature flag.

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
projectId path string<uuid> yes Project identifier (UUIDv7).

Request Body

FieldTypeRequiredDescription
name string yes Deck display name (trimmed, 1–500 chars).
fromTemplateId string<uuid> no Optional template deck id to copy the initial content from.
{
  "name": "Product Launch Deck"
}

Responses

StatusDescription
201 Deck created. The full document record is returned under `data.document`.
400 `INVALID_JSON`, `VALIDATION_ERROR` (body field failed or unknown key present), `INVALID_ID_FORMAT`.
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 `FORBIDDEN` (no `document.create` permission or project membership).
404 `NOT_FOUND` (project not found).
409 `CONFLICT` (duplicate deck in this project).
500 `DATABASE_ERROR` (unrecognized SP error) or `INTERNAL_ERROR`.
201 response body: data fields
FieldTypeDescription
document any
GET /v1/sync/{resourceType}

Delta-sync pull for offline sync

Serves the offline sync engine's bulk download (omit `since`) and incremental changed-since pulls (`since` epoch-ms) with keyset pagination. Supports 6 resource types: `entities`, `relationships`, `documents`, `tasks`, `comments`, `specs`. Incremental items may carry `_deleted: true` tombstones so clients can evict rows. Response is camelCased to the client contract (`items`, `hasMore`, `nextCursor`, `watermark`).

Auth Session JWT (Bearer)

Parameters

NameInTypeRequiredDescription
resourceType path string (enum) yes The resource type to sync. Must be one of the 6 supported types; any other value is a 404.
since query integer no Epoch milliseconds timestamp (non-negative integer up to 15 digits). When supplied, returns only records changed after this timestamp (incremental pull). Omit for a full bulk download.
limit query integer no Maximum number of records to return per page (1–500, default 500).
cursor query string no Keyset pagination cursor in the format `<epoch-microseconds>:<uuid>` (max 200 chars).
project_ids query string no Comma-separated list of project UUIDs to filter by (max 50 IDs).

Responses

StatusDescription
200 Sync page.
400 `VALIDATION_ERROR` (malformed `since`, `limit`, `cursor`, or `project_ids`).
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 `FORBIDDEN` (offline sync is not enabled for this resource type in the org config).
404 `NOT_FOUND` (unknown resource type — not in the 6-type allowlist).
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
items array of object Records in this sync page. May include `_deleted: true` tombstones for deleted records.
hasMore boolean Whether more records exist beyond this page.
nextCursor string Keyset cursor for the next page in the format `<epoch-microseconds>:<uuid>`. Absent when `hasMore` is false.
watermark any Server-side high-water mark for use as `since` on the next incremental pull.
GET /v1/sync/config

Get organization offline sync configuration

Returns the organization's offline sync configuration, which determines which entity types are allowed for offline access. If no configuration exists, returns a default with an empty allowed-types list. Organization and RLS scope are derived from the access token.

Auth Session JWT (Bearer)

Responses

StatusDescription
200 The organization sync configuration (or default).
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
org_id string<uuid> Organization identifier.
allowed_sync_types array of enum entitiesrelationshipsdocumentstaskscommentsspecs Resource types the organization permits for offline sync.
max_offline_size_mb integer Maximum total offline storage permitted (MB, 10–10000).
sync_interval_seconds integer Minimum sync interval in seconds (30–86400).
metadata object Optional bounded metadata object.
PUT /v1/sync/config

Update organization offline sync configuration

Replaces the organization's offline sync configuration. Requires the `org.update` permission. Updates which entity types are permitted for offline sync and optional storage/interval caps. Per-org policy is enforced inside the stored procedures via `bb.org_sync_configs`.

Auth Session JWT (Bearer)

Request Body

FieldTypeRequiredDescription
allowed_sync_types array of enum entitiesrelationshipsdocumentstaskscommentsspecs yes Resource types to allow for offline sync (0–20 items).
max_offline_size_mb integer no Optional maximum total offline storage (MB, 10–10000).
sync_interval_seconds integer no Optional minimum sync interval (seconds, 30–86400).
metadata object no Optional bounded metadata object.

Responses

StatusDescription
200 Updated sync configuration.
400 `INVALID_JSON` or `VALIDATION_ERROR` (invalid field value, out-of-range limit, or disallowed sync type).
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
403 `PERMISSION_DENIED` (missing `org.update` permission).
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
org_id string<uuid> Organization identifier.
allowed_sync_types array of enum entitiesrelationshipsdocumentstaskscommentsspecs Resource types the organization permits for offline sync.
max_offline_size_mb integer Maximum total offline storage permitted (MB, 10–10000).
sync_interval_seconds integer Minimum sync interval in seconds (30–86400).
metadata object Optional bounded metadata object.
GET /v1/sync/preferences

Get user offline sync preferences

Returns the authenticated user's offline sync preferences within their current organization. If no preferences exist, returns defaults (empty enabled types, `auto_sync: true`, `sync_on_wifi_only: false`, `max_local_size_mb: 500`).

Auth Session JWT (Bearer)

Responses

StatusDescription
200 The user's sync preferences (or defaults).
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
user_id string<uuid> User identifier.
org_id string<uuid> Organization identifier.
enabled_sync_types array of enum entitiesrelationshipsdocumentstaskscommentsspecs Resource types the user has opted into syncing (must be a subset of the org's `allowed_sync_types`).
auto_sync boolean Whether automatic background sync is enabled.
sync_on_wifi_only boolean Whether to sync only on Wi-Fi connections.
max_local_size_mb integer Maximum local storage the user allows for offline data (MB, 10–5000).
metadata object Optional bounded metadata object.
PUT /v1/sync/preferences

Update user offline sync preferences

Replaces the authenticated user's offline sync preferences. The requested `enabled_sync_types` must be a subset of the organization's `allowed_sync_types`; types not permitted by the org config are rejected with `VALIDATION_ERROR`.

Auth Session JWT (Bearer)

Request Body

FieldTypeRequiredDescription
enabled_sync_types array of enum entitiesrelationshipsdocumentstaskscommentsspecs yes Resource types to opt into syncing (must be allowed by the org config; 0–20 items).
auto_sync boolean no Whether to enable automatic background sync.
sync_on_wifi_only boolean no Whether to restrict sync to Wi-Fi connections only.
max_local_size_mb integer no Maximum local storage to allow for offline data (MB, 10–5000).
metadata object no Optional bounded metadata object.

Responses

StatusDescription
200 Updated sync preferences.
400 `INVALID_JSON`, `VALIDATION_ERROR` (field validation failure, or requested types not allowed by org config).
401 401 Unauthorized — missing, expired, malformed, or revoked credentials.
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.
200 response body: data fields
FieldTypeDescription
user_id string<uuid> User identifier.
org_id string<uuid> Organization identifier.
enabled_sync_types array of enum entitiesrelationshipsdocumentstaskscommentsspecs Resource types the user has opted into syncing (must be a subset of the org's `allowed_sync_types`).
auto_sync boolean Whether automatic background sync is enabled.
sync_on_wifi_only boolean Whether to sync only on Wi-Fi connections.
max_local_size_mb integer Maximum local storage the user allows for offline data (MB, 10–5000).
metadata object Optional bounded metadata object.
GET /v1/yjs/ws

Open Yjs CRDT document WebSocket

Upgrades to a WebSocket connection to the `YjsDocDO` for a specific document. Used by BB Docs, BB Slides, and entity collaborative editing. Authentication is performed via the JWT in the `token` query parameter. The handler verifies the JWT, checks `token_version` revocation, and runs the `api.yjs_document_effective_access` gate to resolve the server-authoritative document kind (`bbprove_document` for BB Docs / BB Slides, or `entity`). The client-supplied `?docKind=` is intentionally ignored; the kind is resolved server-side to prevent doc-kind spoofing attacks. The derived capability (`read`/`write`) and access level are forwarded to the DO; the DO re-verifies on join. The DO key is `yjs:<orgId>:<documentId>`.

Auth One-time ?token= ticket

Parameters

NameInTypeRequiredDescription
token query string yes A valid session JWT.
documentId query string<uuid> yes Document identifier (UUID). Used by both `bbprove_document` and `entity` kinds.
docKind query string (enum) no **Ignored by the server.** Accepted for backward-compatibility with existing clients but never trusted; the server resolves the document kind from `documentId`.

Responses

StatusDescription
101 WebSocket upgrade accepted. The connection is forwarded to the `YjsDocDO`.
400 `VALIDATION_ERROR` (missing or invalid query parameters, or missing `Upgrade: websocket` header).
401 `AUTH_TOKEN_INVALID` (JWT malformed or revoked), `AUTH_TOKEN_EXPIRED` (JWT expired).
403 `PERMISSION_DENIED` (no read access, document not found under caller org, or effective-access gate errored fail-closed).
500 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side.