Mailbox, messaging, domain management, calendar, scheduling, and email-list management for Backbuild organizations.
POST /v1/bbmail/attachments
Upload an attachment
Content-addresses an attachment to object storage under the caller's org/mailbox prefix. The caller must pass `mailboxId` as a query parameter and send the raw file bytes as the request body (`application/octet-stream`). Returns the SHA-256 content hash and byte length; pass the `sha256` in a subsequent send request. The per-file limit is 25 MiB. Returns `413 Payload Too Large` when the declared `Content-Length` or actual body exceeds 25 MiB.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
mailboxId | query | string<uuid> | yes | Mailbox identifier (UUIDv7) that will own the attachment. Caller must have `can_write` on this mailbox. |
Responses
| Status | Description |
201 | Attachment stored. Returns the SHA-256 hash and byte length for use in send requests. |
400 | `VALIDATION_ERROR` — empty body or `INVALID_ID_FORMAT` — invalid `mailboxId`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | `NOT_FOUND` — mailbox not found or caller lacks `can_write`. |
413 | `PAYLOAD_TOO_LARGE` — file exceeds 25 MiB. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
503 | `SERVICE_UNAVAILABLE` — attachment storage not configured. |
201 response body: data fields
| Field | Type | Description |
sha256 | string | Hex SHA-256 of the stored file. Use this value in `MessageSendRequest.attachments[].sha256`. |
size | integer | Stored byte length. |
contentType | string | Detected or declared MIME type. |
GET /v1/bbmail/attachments/{sha256}
Stream an attachment
Streams a previously-uploaded attachment by its SHA-256 content hash. The `mailboxId` query parameter is required. Non-executable content types are served inline with `nosniff`; all others are served as `application/octet-stream` with `Content-Disposition: attachment`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
sha256 | path | string | yes | SHA-256 hex digest of the attachment (64 lowercase hex characters). |
mailboxId | query | string<uuid> | yes | Mailbox identifier (UUIDv7). |
Responses
| Status | Description |
200 | Attachment bytes. |
400 | `INVALID_ID_FORMAT` or `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
GET /v1/bbmail/domains
List sending domains
Returns all mail sending domains linked to the caller's organization.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | List of domains. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/bbmail/domains
Link a sending domain
Links a domain to the caller's organization for use as a mail sending domain. Returns the domain record with the DNS records that must be published to verify ownership and configure routing.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
domain | string | yes | The domain name to add (e.g. `mail.example.com`). |
Responses
| Status | Description |
201 | Domain linked. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
409 | `CONFLICT` — domain already linked or quota exceeded. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
201 response body: data fields
| Field | Type | Description |
id | string<uuid> | |
org_id | string<uuid> | |
domain | string<hostname> | |
verified | boolean | |
dns_verified | boolean | |
ses_enabled | boolean | |
created_at | string<date-time> | |
GET /v1/bbmail/domains/{domainId}
Get a sending domain
Returns a single sending domain including its verification status and required DNS records.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
domainId | path | string<uuid> | yes | Domain identifier (UUIDv7). |
Responses
| Status | Description |
200 | Domain record. |
400 | `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
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
| Field | Type | Description |
id | string<uuid> | |
org_id | string<uuid> | |
domain | string<hostname> | |
verified | boolean | |
dns_verified | boolean | |
ses_enabled | boolean | |
created_at | string<date-time> | |
POST /v1/bbmail/domains/{domainId}/provision
Auto-provision Cloudflare DNS and email routing
Drives Cloudflare DNS and Email-Routing provisioning for a Cloudflare-hosted domain. Attempts provider-based ownership proof via the organization's connected Cloudflare account before provisioning. Returns a structured per-step result in all cases; inspect the `code` field to determine the outcome (`OK`, `PARTIAL`, `OWNERSHIP_NOT_PROVEN`, `DOMAIN_NOT_ON_CLOUDFLARE`, `NEEDS_PROVIDER_CONNECTION`, `DOMAIN_ALREADY_CLAIMED`).
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
domainId | path | string<uuid> | yes | Domain identifier (UUIDv7). |
Responses
| Status | Description |
200 | Provisioning succeeded or partially succeeded. Inspect `data.code` for the per-step result. |
400 | `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | The domain is already claimed by another organization (`DOMAIN_ALREADY_CLAIMED`). |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
409 | `OWNERSHIP_NOT_PROVEN` or `NEEDS_PROVIDER_CONNECTION`. |
422 | Domain is not present in the organization's connected Cloudflare account (`DOMAIN_NOT_ON_CLOUDFLARE`). |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/bbmail/domains/{domainId}/ses-onboard
Onboard domain to AWS SES for sending
Drives SES identity creation, Easy-DKIM, and MAIL-FROM configuration for a verified domain. Requires a proven ownership timestamp on the domain. Returns a structured per-step result; `503` when SES is not configured server-side.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
domainId | path | string<uuid> | yes | Domain identifier (UUIDv7). |
Responses
| Status | Description |
200 | SES onboarding succeeded or partially succeeded. |
400 | `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | `DOMAIN_NOT_FOUND` — domain does not exist in this organization. |
409 | `CONFLICT` — ownership not proven or an immutable state precondition was not met. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
503 | `SERVICE_UNAVAILABLE` — SES onboarding is not configured. |
POST /v1/bbmail/domains/{domainId}/ses-verify
Poll SES verification status
Polls SES for send-readiness (DKIM, MAIL-FROM) and performs an MX reachability probe for receive-readiness, persisting the results. Requires proven ownership. Returns `409` when ownership is not proven.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
domainId | path | string<uuid> | yes | Domain identifier (UUIDv7). |
Responses
| Status | Description |
200 | SES verification polling completed. |
400 | `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
409 | `CONFLICT` — ownership not proven. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
503 | `SERVICE_UNAVAILABLE` — SES is not configured. |
POST /v1/bbmail/domains/{domainId}/verify
Verify domain ownership via DNS TXT
Triggers an ownership verification check by performing a DNS-over-HTTPS lookup for the `_bbmail-verify.<domain>` TXT record and passing the observed value to the server. The server (not the route) makes the ownership decision. Returns the updated domain record with the new verification status.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
domainId | path | string<uuid> | yes | Domain identifier (UUIDv7). |
Responses
| Status | Description |
200 | Verification check completed. The body contains the updated domain record; inspect `ownership_verified_at` to determine if ownership was confirmed. |
400 | `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
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
| Field | Type | Description |
id | string<uuid> | |
org_id | string<uuid> | |
domain | string<hostname> | |
verified | boolean | |
dns_verified | boolean | |
ses_enabled | boolean | |
created_at | string<date-time> | |
POST /v1/bbmail/domains/{domainId}/verify-dns
Re-check published DNS records
Re-checks the live DNS records (MX, SPF, DKIM CNAME, DMARC) for a domain whose ownership has already been verified, and advances the per-record-class verification flags so the setup wizard can display per-step status. Requires `ownership_verified_at` to be set on the domain; returns `409 CONFLICT` otherwise.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
domainId | path | string<uuid> | yes | Domain identifier (UUIDv7). |
Responses
| Status | Description |
200 | DNS check completed. The body contains the updated verification flags. |
400 | `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
409 | `CONFLICT` — domain ownership must be verified before DNS verification. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
GET /v1/bbmail/filters
List message filters
Returns all message filters defined for the specified mailbox, ordered by `ordinal`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
mailboxId | query | string<uuid> | yes | Mailbox identifier (UUIDv7). |
Responses
| Status | Description |
200 | List of filters. |
400 | `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/bbmail/filters
Create a message filter
Creates a new message filter rule in the specified mailbox. `criteria` and `actions` are structured JSON objects validated server-side.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
mailboxId | string<uuid> | yes | Mailbox to add the filter to. |
criteria | object | yes | Filter matching criteria (from, to, subject, body, has_attachment). Schema enforced server-side. |
actions | object | yes | Filter actions to apply on match (label, archive, delete, mark_read, forward, star). Schema enforced server-side. |
ordinal | integer | no | Sort order for filter evaluation (default 0). |
enabled | boolean | no | Whether the filter is active (default true). |
Responses
| Status | Description |
201 | Filter created. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
201 response body: data fields
| Field | Type | Description |
id | string<uuid> | |
org_id | string<uuid> | |
mailbox_id | string<uuid> | |
name | string | |
criteria | object | Filter criteria (from/to/subject/body/has_attachment). |
actions | array of object | |
enabled | boolean | |
created_at | string<date-time> | |
PATCH /v1/bbmail/filters/{filterId}
Update a message filter
Updates one or more filter properties. `mailboxId` is required in the body.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
filterId | path | string<uuid> | yes | Filter identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
mailboxId | string<uuid> | yes | Mailbox that owns the filter. |
criteria | object | no | |
actions | object | no | |
ordinal | integer | no | |
enabled | boolean | no | |
Responses
| Status | Description |
200 | Updated filter. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
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
| Field | Type | Description |
id | string<uuid> | |
org_id | string<uuid> | |
mailbox_id | string<uuid> | |
name | string | |
criteria | object | Filter criteria (from/to/subject/body/has_attachment). |
actions | array of object | |
enabled | boolean | |
created_at | string<date-time> | |
DELETE /v1/bbmail/filters/{filterId}
Delete a message filter
Deletes a message filter. The `mailboxId` query parameter is required.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
filterId | path | string<uuid> | yes | Filter identifier (UUIDv7). |
mailboxId | query | string<uuid> | yes | Mailbox identifier (UUIDv7). |
Responses
| Status | Description |
200 | Filter deleted. |
400 | `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/bbmail/filters/{filterId}/run
Run a message filter
Authorizes and returns the validated filter specification so the mailbox Durable Object can apply it over its hot message index. The route does not mutate message state directly — mutation is handled via the WebSocket protocol in the Durable Object.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
filterId | path | string<uuid> | yes | Filter identifier (UUIDv7). |
mailboxId | query | string<uuid> | yes | Mailbox identifier (UUIDv7). |
Responses
| Status | Description |
200 | Filter spec authorized. The payload contains the filter spec for the Durable Object to execute. |
400 | `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/bbmail/inbound-smtp
Receive inbound message via SMTP hook (public webhook)
Public MTA-hook endpoint called by the self-hosted Stalwart inbound SMTP fleet at the DATA stage. Accepts a JSON envelope containing the raw RFC 822 message, SMTP envelope, and edge-computed SPF/DKIM/DMARC verdicts signed with an HMAC. After signature verification the handler resolves the recipient address to a mailbox, durably writes the raw message to object storage (the commit point), then asynchronously writes the catalog row and projects the message index. Returns `{ action: "discard" }` on success to instruct the MTA to drop the message from its spool. A `503` response signals a temporary failure; the MTA or its local spool should retry.
Auth Provider webhook signature
Request Body
| Field | Type | Required | Description |
context | object | no | MTA connection context. |
envelope | object | no | SMTP envelope. |
message | object | no | Raw message reference. |
spf_pass | boolean | no | SPF check outcome. |
dkim_pass | boolean | no | DKIM check outcome. |
dmarc_pass | boolean | no | DMARC check outcome. |
Responses
| Status | Description |
200 | Message accepted. `action: discard` instructs the MTA to remove the message from its spool. |
400 | Malformed request body. |
403 | HMAC signature verification failed. |
411 | Content-Length header is absent or invalid. |
413 | Request body exceeds the 25 MiB per-message limit. |
429 | Rate limit exceeded. |
503 | Service not configured or temporary upstream failure. The MTA should retry. |
GET /v1/bbmail/labels
List labels
Returns all labels in the specified mailbox including their hierarchy.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
mailboxId | query | string<uuid> | yes | Mailbox identifier (UUIDv7). |
Responses
| Status | Description |
200 | List of labels. |
400 | `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/bbmail/labels
Create a label
Creates a new label in the specified mailbox. Labels can be nested by supplying a `parentId`.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
mailboxId | string<uuid> | yes | Mailbox to create the label in. |
name | string | yes | Label display name. |
parentId | string<uuid> | no | Parent label for nesting. |
color | string | no | Optional color token. |
ordinal | integer | no | Sort order within the label list. |
Responses
| Status | Description |
201 | Label created. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
409 | 409 Conflict — the request conflicts with an existing resource or current state (unique constraint, optimistic-lock, duplicate). |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
201 response body: data fields
| Field | Type | Description |
id | string<uuid> | |
org_id | string<uuid> | |
mailbox_id | string<uuid> | |
name | string | |
color | string | |
created_at | string<date-time> | |
PATCH /v1/bbmail/labels/{labelId}
Update a label
Updates one or more label properties. `mailboxId` is required in the body. All other fields are optional.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
labelId | path | string<uuid> | yes | Label identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
mailboxId | string<uuid> | yes | Mailbox that owns the label. |
name | string | no | |
color | string | no | |
ordinal | integer | no | |
parentId | string<uuid> | no | |
Responses
| Status | Description |
200 | Updated label. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
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
| Field | Type | Description |
id | string<uuid> | |
org_id | string<uuid> | |
mailbox_id | string<uuid> | |
name | string | |
color | string | |
created_at | string<date-time> | |
DELETE /v1/bbmail/labels/{labelId}
Delete a label
Deletes a label from a mailbox. The `mailboxId` query parameter is required.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
labelId | path | string<uuid> | yes | Label identifier (UUIDv7). |
mailboxId | query | string<uuid> | yes | Mailbox identifier (UUIDv7). |
Responses
| Status | Description |
200 | Label deleted. |
400 | `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
GET /v1/bbmail/mailboxes
List mailboxes
Returns the mailboxes the caller owns or has been delegated access to within the authenticated organization.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | List of mailboxes. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/bbmail/mailboxes
Create a mailbox
Creates a new mailbox under a verified sending domain in the caller's organization. The organization is taken from the authenticated session and is never accepted in the request body.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
domainId | string<uuid> | yes | Domain identifier. |
localPart | string | yes | Local part (before `@`). |
displayName | string | no | Optional display name. |
planTier | string (enum) freepaid | no | Service tier for the mailbox (`free` or `paid`). |
Responses
| Status | Description |
201 | Mailbox created. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
404 | `NOT_FOUND` — the referenced domain does not exist or is not visible to this organization. |
409 | `CONFLICT` — a mailbox with that local-part already exists on this domain. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
201 response body: data fields
| Field | Type | Description |
id | string<uuid> | Mailbox identifier (UUIDv7). |
org_id | string<uuid> | Owning organization identifier. |
domain_id | string<uuid> | Associated domain identifier. |
local_part | string | Local part of the email address (the part before `@`). |
display_name | string | Optional display name. |
plan_tier | string (enum) freepaid | Service tier for the mailbox (`free` or `paid`). |
created_at | string<date-time> | |
updated_at | string<date-time> | |
GET /v1/bbmail/messages
List messages
Returns a paginated list of messages in the specified mailbox, optionally filtered by direction.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
mailboxId | query | string<uuid> | yes | Mailbox identifier (UUIDv7). |
direction | query | string (enum) | no | Filter by message direction. |
limit | query | integer | no | Maximum messages to return (1–100). |
offset | query | integer | no | Number of messages to skip. |
Responses
| Status | Description |
200 | Paginated message list. |
400 | `INVALID_ID_FORMAT` or `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
GET /v1/bbmail/messages/{messageId}
Get a message
Returns a single message by id. The `mailboxId` query parameter is required. A message the caller cannot access is reported as `404 NOT_FOUND`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
messageId | path | string<uuid> | yes | Message identifier (UUIDv7). |
mailboxId | query | string<uuid> | yes | Mailbox identifier (UUIDv7). |
Responses
| Status | Description |
200 | The message record. |
400 | `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
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
| Field | Type | Description |
id | string<uuid> | |
mailbox_id | string<uuid> | |
org_id | string<uuid> | |
direction | string (enum) inoutdraft | |
subject | string | |
from_addr | string | |
snippet | string | |
thread_key | string | |
size_bytes | integer | |
has_attachments | boolean | |
spam_verdict | string | |
r2_raw_key | string | Never echoed to the client. Present only in the internal ingest body; omitted from responses. |
body_raw | string | Raw RFC 2822 message body (present only in the `GET /messages/{messageId}` response when the object is available in storage). |
created_at | string<date-time> | |
POST /v1/bbmail/messages/{messageId}/labels
Apply or remove a message label (WebSocket-only operation)
Message label mutations are performed over the mailbox WebSocket (`GET /v1/bbmail/ws`), not via REST. Connect to the mailbox socket and send the `MSG_LABEL` operation; the change is applied in the mailbox Durable Object and durably audited via the signed audit flush. This REST endpoint exists to return a machine-readable error rather than silently returning `404`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
messageId | path | string<uuid> | yes | Message identifier (UUIDv7). |
Responses
| Status | Description |
400 | `INVALID_ID_FORMAT` — invalid `messageId`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
409 | `VALIDATION_ERROR` with `ws_only: true` — this operation must be performed over the mailbox WebSocket. |
POST /v1/bbmail/messages/{messageId}/move
Move a message (WebSocket-only operation)
Message-folder moves are performed over the mailbox WebSocket (`GET /v1/bbmail/ws`), not via REST. Connect to the mailbox socket and send the `MSG_MOVE` operation; the change is applied in the mailbox Durable Object and durably audited via the signed audit flush. This REST endpoint exists to return a machine-readable error rather than silently returning `404`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
messageId | path | string<uuid> | yes | Message identifier (UUIDv7). |
Responses
| Status | Description |
400 | `INVALID_ID_FORMAT` — invalid `messageId`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
409 | `VALIDATION_ERROR` with `ws_only: true` — this operation must be performed over the mailbox WebSocket. |
POST /v1/bbmail/messages/send
Send a message
Sends an outbound email from the specified mailbox. The `From` identity is resolved server-side from the mailbox record; callers cannot override it. All attachments must be pre-uploaded via `POST /v1/bbmail/attachments`; only content-addressed references (`sha256`) are accepted here. The combined `to + cc + bcc` count must not exceed the platform MAX_RECIPIENTS limit. In restricted (non-production) environments outbound recipients are checked against the org's verified domains and current org members. An optional `Idempotency-Key` header (max 256 chars) enables safe retries.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
mailboxId | string<uuid> | yes | Sending mailbox identifier. |
to | array of string | yes | Primary recipients (max 50). |
cc | array of string | no | CC recipients (max 50). |
bcc | array of string | no | BCC recipients (max 50). |
subject | string | yes | Message subject (RFC 5322 limit: 998 chars). |
html | string | no | HTML body (max 2 MiB). |
text | string | no | Plain-text body (max 2 MiB). |
replyTo | string<email> | no | Optional `Reply-To` address. |
inReplyTo | string | no | Message-ID of the message being replied to. |
attachments | array of object | no | Attached files (max 32). Each file must be pre-uploaded via POST /v1/bbmail/attachments. |
Responses
| Status | Description |
200 | Message accepted by the sending provider. |
400 | `VALIDATION_ERROR` — invalid recipients, `TOO_MANY_RECIPIENTS`, subject too long, too many attachments, or `ATTACHMENT_NOT_FOUND`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
402 | `QUOTA_EXCEEDED` — send quota exceeded; top up credits. |
403 | `FORBIDDEN` — cannot send from this mailbox or `RESTRICTED_ENV` recipient refusal. |
404 | `NOT_FOUND` — mailbox not found or access denied. |
409 | `CONFLICT` — all recipients suppressed or daily send cap reached. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
502 | `DATABASE_ERROR` — provider dispatch error. |
503 | `SERVICE_UNAVAILABLE` — email sending not configured, suppression check unavailable, or runtime unavailable. |
200 response body: data fields
| Field | Type | Description |
sent | boolean (enum) true | |
provider | string | Provider that accepted the message (e.g. `ses`). |
messageId | string | Provider-assigned message identifier. |
suppressed | array of string | Recipients that were silently suppressed (on the global suppression list). |
GET /v1/bbmail/settings
Get mailbox settings
Returns the caller's per-user preferences for the specified mailbox.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
mailboxId | query | string<uuid> | yes | Mailbox identifier (UUIDv7). |
Responses
| Status | Description |
200 | Current mailbox settings. |
400 | `INVALID_ID_FORMAT` — `mailboxId` is not a valid UUID. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
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
| Field | Type | Description |
mailbox_id | string<uuid> | |
reading_pane | string (enum) belowrightoff | |
density | string (enum) comfortablecozycompact | |
conversation_view | boolean | |
custom_signature_html | string | |
undo_send_seconds | integer (enum) 05102030 | |
mark_read_mode | string (enum) immediateafter_secondsmanual | |
mark_read_delay_ms | integer | |
updated_at | string<date-time> | |
PATCH /v1/bbmail/settings
Update mailbox settings
Upserts the caller's per-user preferences for the specified mailbox. All fields are optional; only supplied fields are updated.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
mailboxId | string<uuid> | yes | Mailbox whose settings to update. |
reading_pane | string (enum) belowrightoff | no | Reading pane layout. |
density | string (enum) comfortablecozycompact | no | Message list density. |
conversation_view | boolean | no | Group messages by conversation thread. |
custom_signature_html | string | no | HTML signature appended to outbound messages. Pass `null` to clear. |
undo_send_seconds | integer (enum) 05102030 | no | Undo-send delay in seconds. |
mark_read_mode | string (enum) immediateafter_secondsmanual | no | When messages are automatically marked read. |
mark_read_delay_ms | integer | no | Delay before marking read (applies when `mark_read_mode` is `after_seconds`). |
Responses
| Status | Description |
200 | Updated mailbox settings. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
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
| Field | Type | Description |
mailbox_id | string<uuid> | |
reading_pane | string (enum) belowrightoff | |
density | string (enum) comfortablecozycompact | |
conversation_view | boolean | |
custom_signature_html | string | |
undo_send_seconds | integer (enum) 05102030 | |
mark_read_mode | string (enum) immediateafter_secondsmanual | |
mark_read_delay_ms | integer | |
updated_at | string<date-time> | |
GET /v1/bbmail/ws
Open mailbox WebSocket
Upgrades an HTTP connection to a WebSocket channel connected to the caller's mailbox Durable Object. The caller must supply a one-time `token` query parameter (a short-lived JWT minted by the session) and the `mailboxId` to connect to. The server verifies the token, checks revocation, and runs the mailbox effective-access gate before forwarding the upgrade. A connection without `Upgrade: websocket` receives `426 Upgrade Required`. The capability (`read` or `write`) is derived from the access verdict and forwarded to the Durable Object, which re-verifies independently.
Authentication is via the `token` query parameter (`oneTimeTicket` scheme) — a standard `Authorization` header is not supported on WebSocket upgrades.
Auth One-time ?token= ticket
Parameters
| Name | In | Type | Required | Description |
token | query | string | yes | One-time mailbox connection ticket (short-lived JWT). Minted by an authenticated REST call; redeemable once. |
mailboxId | query | string<uuid> | yes | Mailbox identifier (UUIDv7) to connect to. |
Responses
| Status | Description |
101 | WebSocket handshake accepted. The connection is proxied to the mailbox Durable Object. Messages follow the BB Mail WS protocol. |
400 | `VALIDATION_ERROR` — `token` or `mailboxId` query parameter is missing or invalid. |
401 | `AUTH_TOKEN_INVALID` or `AUTH_TOKEN_EXPIRED` — the one-time token is malformed, expired, or has been revoked. |
403 | `PERMISSION_DENIED` — the caller has no read access to this mailbox (uniform deny; does not distinguish absent from forbidden). |
426 | `VALIDATION_ERROR` — the request did not include `Upgrade: websocket`. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/calendar/access-requests
Request calendar access
Submits an access request for a calendar by id or owner email. An optional email notification can be sent to the calendar owner.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
calendar_id | string<uuid> | no | Target calendar id. |
owner_email | string | no | Owner email to look up the calendar by. |
capability | string (enum) freebusydetailswrite | no | Requested access level. |
message | string | no | Optional message to the calendar owner. |
send_email | boolean | no | Send an email notification to the calendar owner. |
Responses
| Status | Description |
201 | Access request submitted. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
GET /v1/calendar/appointment-schedules
List appointment schedules
Returns the caller's appointment booking schedules. Optionally filter by `calendar_id`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
calendar_id | query | string<uuid> | no | Filter by calendar (UUIDv7). |
Responses
| Status | Description |
200 | Appointment schedules. |
400 | `INVALID_ID_FORMAT`. |
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. |
PUT /v1/calendar/appointment-schedules
Create or update an appointment schedule
Upserts an appointment booking schedule. Supply `id` to update an existing schedule; omit to create a new one. Returns `201` on create, `200` on update.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
id | string<uuid> | no | Omit to create; supply to update in-place. |
calendar_id | string<uuid> | yes | Calendar that owns the schedule. |
title | string | yes | |
slug | string | no | URL-safe booking page slug (auto-generated from title when omitted). |
slot_minutes | integer | no | Duration of each bookable slot in minutes. |
buffer_minutes | integer | no | Buffer time between appointments. |
max_per_day | integer | no | Maximum bookings per day (null = unlimited). |
availability | array of object | no | Weekly availability windows. Each item specifies a weekday/start/end window. |
booking_form | object | no | Custom fields to collect from bookers. Validated by the stored procedure. |
window_start | string | no | Earliest bookable date (ISO-8601). |
window_end | string | no | Latest bookable date (ISO-8601). |
conflict_calendar_ids | array of string | no | Calendars to check for conflicts when determining availability. |
Responses
| Status | Description |
200 | Appointment schedule updated. |
201 | Appointment schedule created. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
409 | 409 Conflict — the request conflicts with an existing resource or current state (unique constraint, optimistic-lock, duplicate). |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
GET /v1/calendar/appointment-schedules/{scheduleId}
Get an appointment schedule
Returns a single appointment booking schedule.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
scheduleId | path | string<uuid> | yes | Appointment schedule identifier (UUIDv7). |
Responses
| Status | Description |
200 | Appointment schedule. |
400 | `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
GET /v1/calendar/book/{slug}
Get public booking page (public)
Returns the public-safe appointment schedule metadata for a booking page slug, including optionally the freebusy-level busy intervals for a `[from, to]` window (clamped server-side to 62 days). An unknown slug returns `404`. Rate-limited per IP.
Public Public: no authentication
Parameters
| Name | In | Type | Required | Description |
slug | path | string | yes | Appointment schedule slug. |
from | query | string<date-time> | no | Busy-window start (ISO-8601). Required if `to` is provided. |
to | query | string<date-time> | no | Busy-window end (ISO-8601). Required if `from` is provided. |
Responses
| Status | Description |
200 | Booking page data. |
404 | `NOT_FOUND` — slug not found. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
POST /v1/calendar/book/{slug}
Create a booking (public)
Creates an appointment booking via the public booking page. Requires a valid Cloudflare Turnstile token in `cf-turnstile-response` (evaluated server-side; the field is stripped before storage). The server resolves the schedule by slug, conflict-checks the slot, and creates the event and confirmation email.
Public Public: no authentication
Request Body
| Field | Type | Required | Description |
booker_email | string<email> | yes | |
starts_at | string | yes | Requested slot start (ISO-8601 or RFC 3339). |
booker_name | string | no | |
answers | object | no | Answers to custom booking-form fields defined on the schedule. |
cf-turnstile-response | string | no | Cloudflare Turnstile challenge response token. Consumed server-side to prevent abuse; stripped before storage. |
Responses
| Status | Description |
201 | Booking created. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
404 | `NOT_FOUND` — slug not found or schedule is disabled. |
409 | `CONFLICT` — the requested time slot is no longer available. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
GET /v1/calendar/book/manage/{booking_token}
Get booking details for management (public)
Resolves a per-booking management token and returns the booker-safe booking details. Internal fields (`org_id`, owner user id, created event id) are never returned. Rate-limited per IP.
Public Public: no authentication
Parameters
| Name | In | Type | Required | Description |
booking_token | path | string | yes | Per-booking management token (16–256 URL-safe characters). |
Responses
| Status | Description |
200 | Booking details. |
404 | `NOT_FOUND` — token not found or expired. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
200 response body: data fields
| Field | Type | Description |
id | string<uuid> | |
schedule_title | string | |
starts_at | string<date-time> | |
ends_at | string<date-time> | |
attendee_name | string | |
attendee_email | string<email> | |
status | string (enum) confirmedcancelledrescheduled | |
notes | string | |
POST /v1/calendar/book/manage/{booking_token}
Cancel or reschedule a booking (public)
Cancels or reschedules a booking via the per-booking management token. Requires a valid Cloudflare Turnstile token in `cf-turnstile-response`. `reschedule` requires `starts_at`.
Public Public: no authentication
Parameters
| Name | In | Type | Required | Description |
booking_token | path | string | yes | Per-booking management token (16–256 URL-safe characters). |
Request Body
| Field | Type | Required | Description |
action | string (enum) cancelreschedule | yes | |
starts_at | string | no | New slot start (ISO-8601). Required when `action` is `reschedule`. |
reason | string | no | Optional cancellation or reschedule reason. |
cf-turnstile-response | string | no | Cloudflare Turnstile challenge response token. |
Responses
| Status | Description |
200 | Booking updated. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
404 | `NOT_FOUND` — token not found. |
409 | `CONFLICT` — requested reschedule slot is unavailable. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
GET /v1/calendar/calendars
List calendars
Returns the calendars visible to the caller in their organization. Pass `include_hidden=true` to include hidden calendars.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
include_hidden | query | boolean | no | Include hidden calendars when `true`. |
Responses
| Status | Description |
200 | List of calendars. |
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. |
POST /v1/calendar/calendars
Create a calendar
Creates a new calendar in the caller's organization. All fields are optional; defaults are assigned by the platform.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
name | string | no | |
kind | string (enum) primarysecondaryresourcesubscribed_urlinterestbirthday | no | |
timezone | string | no | |
default_color | integer | no | Color slot (0–11). |
description | string | no | |
public_visibility | string (enum) nonefreebusydetails | no | |
Responses
| Status | Description |
201 | Calendar created. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
201 response body: data fields
| Field | Type | Description |
id | string<uuid> | |
org_id | string<uuid> | |
owner_user_id | string<uuid> | |
name | string | |
color | string | |
timezone | string | |
hidden | boolean | |
default | boolean | |
created_at | string<date-time> | |
updated_at | string<date-time> | |
GET /v1/calendar/calendars/{calendarId}
Get a calendar
Returns a single calendar. A calendar the caller cannot see is reported as `404 NOT_FOUND`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
calendarId | path | string<uuid> | yes | Calendar identifier (UUIDv7). |
Responses
| Status | Description |
200 | Calendar record. |
400 | `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
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
| Field | Type | Description |
id | string<uuid> | |
org_id | string<uuid> | |
owner_user_id | string<uuid> | |
name | string | |
color | string | |
timezone | string | |
hidden | boolean | |
default | boolean | |
created_at | string<date-time> | |
updated_at | string<date-time> | |
PATCH /v1/calendar/calendars/{calendarId}
Update a calendar
Updates calendar properties. All fields are optional; `name: null` clears the name.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
calendarId | path | string<uuid> | yes | Calendar identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
name | string | no | |
description | string | no | |
timezone | string | no | |
default_color | integer | no | |
public_visibility | string (enum) nonefreebusydetails | no | |
status | string (enum) activehiddenarchived | no | |
Responses
| Status | Description |
200 | Updated calendar. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
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
| Field | Type | Description |
id | string<uuid> | |
org_id | string<uuid> | |
owner_user_id | string<uuid> | |
name | string | |
color | string | |
timezone | string | |
hidden | boolean | |
default | boolean | |
created_at | string<date-time> | |
updated_at | string<date-time> | |
DELETE /v1/calendar/calendars/{calendarId}
Delete a calendar
Deletes a calendar.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
calendarId | path | string<uuid> | yes | Calendar identifier (UUIDv7). |
Responses
| Status | Description |
200 | Calendar deleted. |
400 | `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
GET /v1/calendar/calendars/{calendarId}/acl
List calendar ACL entries
Returns the access-control list for a calendar. Pass `include_revoked=true` to include revoked grants.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
calendarId | path | string<uuid> | yes | Calendar identifier (UUIDv7). |
include_revoked | query | boolean | no | Include revoked grants when `true`. |
Responses
| Status | Description |
200 | ACL entries. |
400 | `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
PUT /v1/calendar/calendars/{calendarId}/acl
Grant or revoke a calendar share
Adds, updates, or revokes a share grant for a calendar. Requires `can_admin` on the calendar.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
calendarId | path | string<uuid> | yes | Calendar identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
action | string (enum) grantrevoke | no | |
share_id | string<uuid> | no | Share record to update (optional; omit to create). |
scope | string (enum) usergroupdepartmentprojectorgpublic | no | |
target_id | string | no | Target identifier (user id, group id, etc.). Null for org/public scope. |
is_public | boolean | no | |
recipient_org_id | string<uuid> | no | |
recipient_user_id | string<uuid> | no | |
capability | string (enum) freebusydetailswriteadmin | no | Access level to grant. |
Responses
| Status | Description |
200 | Share grant applied. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
GET /v1/calendar/calendars/{calendarId}/settings
Get per-calendar settings
Returns the caller's per-calendar settings.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
calendarId | path | string<uuid> | yes | Calendar identifier (UUIDv7). |
Responses
| Status | Description |
200 | Per-calendar settings. |
400 | `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
PATCH /v1/calendar/calendars/{calendarId}/settings
Update per-calendar settings
Updates the caller's per-calendar settings. Body is a free-form JSON object; `org_id` and `calendar_id` are pinned from the session and path.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
calendarId | path | string<uuid> | yes | Calendar identifier (UUIDv7). |
Request Body
Key-value settings bag; validated server-side.
Responses
| Status | Description |
200 | Updated settings. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
GET /v1/calendar/events
List events in a time window
Returns events across the caller's visible calendars within the `[from, to]` ISO-8601 window. Recurring event masters are expanded server-side into concrete occurrences within the window. `calendars` is an optional comma-separated list of calendar UUIDs to restrict the query.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
from | query | string<date-time> | yes | Window start (ISO-8601 timestamp). |
to | query | string<date-time> | yes | Window end (ISO-8601 timestamp). |
calendars | query | string | no | Comma-separated calendar UUIDs to restrict the query. |
Responses
| Status | Description |
200 | Events in the window. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
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. |
POST /v1/calendar/events
Create an event
Creates a new event (or recurring series master / override) in the specified calendar. Timing, attendees, RRULE, reminders, and conferencing are validated server-side.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
calendar_id | string<uuid> | yes | |
recurrence_role | string (enum) singlemasteroverride | no | |
series_master_id | string<uuid> | no | |
recurrence_id | string | no | |
title | string | no | |
description_html | string | no | |
location | string | no | |
starts_at | string | no | ISO-8601 timestamp or RFC 3339 date-time string. |
ends_at | string | no | |
start_date | string | no | All-day start date (YYYY-MM-DD). |
end_date | string | no | |
start_tz | string | no | |
end_tz | string | no | |
is_all_day | boolean | no | |
event_type | string | no | |
color_id | integer | no | |
visibility | string (enum) defaultpublicprivateconfidential | no | |
transparency | string (enum) opaquetransparent | no | |
status | string (enum) confirmedtentativecancelled | no | |
rrule | string | no | RFC 5545 RRULE. |
rdate | string | no | |
exdate | string | no | |
guests_can_invite | boolean | no | |
guests_can_modify | boolean | no | |
guests_can_see_others | boolean | no | |
conferencing | object | no | |
attachments | array of object | no | |
reminders_use_default | boolean | no | |
reminders | array of object | no | |
attendees | array of object | no | |
event_type_props | object | no | |
extended_props | object | no | |
Responses
| Status | Description |
201 | Event created. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
GET /v1/calendar/events/{eventId}
Get an event
Returns a single event. The `calendar_id` query parameter is required.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
eventId | path | string<uuid> | yes | Event identifier (UUIDv7). |
calendar_id | query | string<uuid> | yes | Calendar identifier (UUIDv7). |
Responses
| Status | Description |
200 | Event record. |
400 | `INVALID_ID_FORMAT` — `eventId` or `calendar_id` is invalid. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
PATCH /v1/calendar/events/{eventId}
Update an event
Updates event fields. `calendar_id` query parameter is required. For recurring events, `scope` controls whether the edit applies to `this` occurrence, `this_and_following`, or `all`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
eventId | path | string<uuid> | yes | Event identifier (UUIDv7). |
calendar_id | query | string<uuid> | yes | Calendar identifier (UUIDv7). |
scope | query | string (enum) | no | Recurrence edit scope (`this`, `this_and_following`, `all`). |
Request Body
| Field | Type | Required | Description |
calendar_id | string<uuid> | no | |
title | string | no | |
description_html | string | no | |
location | string | no | |
starts_at | string | no | |
ends_at | string | no | |
start_date | string | no | |
end_date | string | no | |
start_tz | string | no | |
end_tz | string | no | |
is_all_day | boolean | no | |
visibility | string (enum) defaultpublicprivateconfidential | no | |
transparency | string (enum) opaquetransparent | no | |
status | string (enum) confirmedtentativecancelled | no | |
rrule | string | no | |
rdate | string | no | |
exdate | string | no | |
conferencing | object | no | |
reminders_use_default | boolean | no | |
reminders | array of object | no | |
attendees | array of object | no | |
Responses
| Status | Description |
200 | Updated event. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
DELETE /v1/calendar/events/{eventId}
Delete an event
Deletes an event. `calendar_id` query parameter is required. For recurring events, `scope` and `recurrence_id` control which occurrences are removed.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
eventId | path | string<uuid> | yes | Event identifier (UUIDv7). |
calendar_id | query | string<uuid> | yes | Calendar identifier (UUIDv7). |
scope | query | string (enum) | no | Recurrence delete scope. |
recurrence_id | query | string | no | Specific recurrence occurrence id. |
Responses
| Status | Description |
200 | Event deleted. |
400 | `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/calendar/events/{eventId}/move
Move event to another calendar
Moves an event from one calendar to another within the same organization.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
eventId | path | string<uuid> | yes | Event identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
source_calendar_id | string<uuid> | yes | Calendar to move the event from. |
dest_calendar_id | string<uuid> | yes | Calendar to move the event to. |
Responses
| Status | Description |
200 | Event moved. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/calendar/events/{eventId}/publish
Publish or unpublish an event
Publishes an event to a public render token, or unpublishes it. `calendar_id` query parameter is required.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
eventId | path | string<uuid> | yes | Event identifier (UUIDv7). |
calendar_id | query | string<uuid> | yes | Calendar identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
calendar_id | string<uuid> | no | Owning calendar. Overridden by the query parameter. |
action | string (enum) publishunpublish | no | `publish` issues a public render token; `unpublish` revokes it. |
show_fields | array of string | no | Allowlist of event fields to expose in the public render. |
Responses
| Status | Description |
200 | Event publish state updated. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
PUT /v1/calendar/events/{eventId}/reminders
Set event reminders
Replaces the caller's reminder settings for an event.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
eventId | path | string<uuid> | yes | Event identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
calendar_id | string<uuid> | no | Owning calendar (optional; resolved from event when omitted). |
reminders_use_default | boolean | no | When `true`, apply the calendar's default reminder rules instead of the explicit `reminders` list. |
reminders | array of object | no | Explicit reminder definitions. Each item is a JsonObject validated by the stored procedure. |
Responses
| Status | Description |
200 | Reminders updated. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/calendar/events/{eventId}/rsvp
RSVP to an event
Records the caller's RSVP response for an event invitation. Supports proposing an alternative time.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
eventId | path | string<uuid> | yes | Event identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
response_status | string (enum) accepteddeclinedtentativeneedsAction | no | RSVP response. |
comment | string | no | Optional message to the organizer. |
proposed_start | string | no | Counter-proposed start (ISO-8601 timestamp). |
proposed_end | string | no | Counter-proposed end (ISO-8601 timestamp). |
proposed_message | string | no | |
additional_guests | array of object | no | |
Responses
| Status | Description |
200 | RSVP recorded. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
GET /v1/calendar/feeds/{token}/basic.ics
Download ICS calendar feed (public)
Resolves a secret or public ICS feed token and returns a well-formed `text/calendar` iCalendar document. The token is validated constant-time; an invalid, revoked, or visibility-`none` token returns `404 NOT_FOUND` with no distinguishing information. Rate-limited per IP at 120 requests per minute.
Public Public: no authentication
Parameters
| Name | In | Type | Required | Description |
token | path | string | yes | High-entropy feed token (16–256 URL-safe characters). |
Responses
| Status | Description |
200 | iCalendar feed. |
404 | `NOT_FOUND` — feed token not found or visibility is `none`. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
GET /v1/calendar/freebusy
Query free/busy
Returns busy intervals for one or more calendars or users within the `[from, to]` window. `calendars` and `users` are optional comma-separated UUID lists.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
from | query | string<date-time> | yes | Window start (ISO-8601). |
to | query | string<date-time> | yes | Window end (ISO-8601). |
calendars | query | string | no | Comma-separated calendar UUIDs. |
users | query | string | no | Comma-separated user UUIDs. |
Responses
| Status | Description |
200 | Free/busy intervals. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
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. |
GET /v1/calendar/public/{render_token}
Get a published event (public)
Resolves a high-entropy render token and returns the published, server-redacted event JSON. The token is validated constant-time; an invalid, revoked, or missing token returns `404`. The raw token is never echoed in the response.
Public Public: no authentication
Parameters
| Name | In | Type | Required | Description |
render_token | path | string | yes | High-entropy render token (16–256 URL-safe characters). |
Responses
| Status | Description |
200 | Published event. |
404 | `NOT_FOUND` — token not found or revoked. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
200 response body: data fields
| Field | Type | Description |
event | object | Server-redacted event fields. |
GET /v1/calendar/search
Search events
Full-text search across the caller's visible events. `q` is required; `who`, `where`, `from`, `to`, and `limit` (1–200) are optional filters.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
q | query | string | yes | Search query string. |
who | query | string | no | Filter by attendee name or email. |
where | query | string | no | Filter by location. |
from | query | string<date-time> | no | Search window start (ISO-8601). |
to | query | string<date-time> | no | Search window end (ISO-8601). |
limit | query | integer | no | Max results (1–200). |
Responses
| Status | Description |
200 | Search results. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
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. |
GET /v1/calendar/settings
Get account-wide calendar settings
Returns the caller's account-wide calendar preferences.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Account calendar settings. |
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. |
PATCH /v1/calendar/settings
Update account-wide calendar settings
Updates the caller's account-wide calendar preferences. Body is a free-form JSON object; `org_id` is pinned from the session.
Auth Session JWT (Bearer)
Request Body
Settings key-value bag.
Responses
| Status | Description |
200 | Updated settings. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
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. |
GET /v1/calendar/sync
List calendar sync connections
Returns the caller's external calendar provider connections. Optionally filter by `provider`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
provider | query | string (enum) | no | Filter by provider (`google`, `microsoft`, `caldav`). |
Responses
| Status | Description |
200 | Sync connections. |
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. |
POST /v1/calendar/sync/connect
Connect a calendar sync provider
Stores encrypted provider credentials and creates a sync connection. For CalDAV, supply `caldav_password` (plaintext over HTTPS); it is encrypted server-side before storage and is never returned. For Google and Microsoft, use the OAuth flow (`/sync/oauth/{provider}/start`) to obtain tokens and call this endpoint with encrypted token fields, or complete the OAuth flow directly via the OAuth callback routes.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
provider | string (enum) googlemicrosoftcaldav | yes | External calendar provider. |
provider_account_email | string | yes | Email address for the provider account. |
secret_kind | string | yes | Type of credential being stored (e.g. `oauth2_refresh`, `app_password`). |
encrypted_refresh_token | string | no | |
encrypted_access_token | string | no | |
token_expires_at | string | no | |
scopes | array of string | no | |
caldav_base_url | string | no | CalDAV principal URL. Required when `provider` is `caldav`. |
caldav_password | string | no | CalDAV / app-specific password. Sent in plaintext over HTTPS; encrypted server-side. Required when `provider` is `caldav` and `secret_kind` is `app_password`. |
create_integration_state | boolean | no | |
Responses
| Status | Description |
201 | Sync connection created. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/calendar/sync/links
Link a provider calendar to a BB calendar
Creates a sync link pairing an external provider calendar with a Backbuild calendar for bidirectional or one-way sync.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
calendar_id | string<uuid> | yes | Backbuild calendar to pair. |
connection_id | string<uuid> | yes | Sync connection to use. |
external_calendar_id | string | yes | Provider-side calendar identifier (opaque string from the provider). |
provider | string (enum) googlemicrosoftcaldav | no | |
sync_direction | string (enum) bidirectionalpull_onlypush_only | no | Sync direction (default `bidirectional`). |
window_start | string | no | Earliest date for back-fill (ISO-8601). |
window_end | string | no | |
Responses
| Status | Description |
201 | Sync link created. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
409 | 409 Conflict — the request conflicts with an existing resource or current state (unique constraint, optimistic-lock, duplicate). |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
DELETE /v1/calendar/sync/links/{linkId}
Remove a calendar sync link
Removes the sync link between a provider calendar and a Backbuild calendar.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
linkId | path | string<uuid> | yes | Sync link identifier (UUIDv7). |
Responses
| Status | Description |
200 | Sync link removed. |
400 | `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
GET /v1/calendar/sync/oauth/google/callback
Google Calendar OAuth callback (browser redirect)
Handles the Google OAuth authorization callback. Validates the CSRF `state` parameter and one-time nonce, exchanges the authorization code for tokens, encrypts them, and stores the connection. Redirects the browser to the calendar settings page with `connected=google` or `sync_error=<reason>` on failure. A `?error=access_denied` from the provider redirects immediately without a token exchange.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
code | query | string | no | Authorization code from Google. |
state | query | string | no | CSRF state token from the `/start` response. |
error | query | string | no | Provider error code (e.g. `access_denied`). |
Responses
| Status | Description |
302 | Redirect to calendar settings page. |
400 | `VALIDATION_ERROR` — missing/invalid `code`/`state`, or scope mismatch. |
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. |
POST /v1/calendar/sync/oauth/google/callback
Google Calendar OAuth callback (SPA form post)
Same as the GET callback but for SPAs that capture the authorization code client-side and POST `{ code, state }` as a JSON body.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
code | string | no | |
state | string | no | |
Responses
| Status | Description |
302 | Redirect to calendar settings page. |
400 | `VALIDATION_ERROR` or `AUTH_OAUTH_FAILED`. |
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. |
GET /v1/calendar/sync/oauth/google/start
Start Google Calendar OAuth flow
Generates the Google consent URL for the Calendar sync OAuth flow. Returns the authorization URL and a CSRF-bound state token. The client should redirect the user to the returned `url`. Requires the `calendar` feature flag.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Authorization URL generated. |
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. |
503 | `SERVICE_UNAVAILABLE` — Google calendar sync is not configured. |
200 response body: data fields
| Field | Type | Description |
url | string<uri> | Provider authorization URL. Redirect the user here to start the consent flow. |
state | string | CSRF state token. Pass this back in the callback `state` parameter. |
GET /v1/calendar/sync/oauth/microsoft/callback
Microsoft Calendar OAuth callback (browser redirect)
Handles the Microsoft OAuth callback — same contract as the Google GET callback.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
code | query | string | no | |
state | query | string | no | |
error | query | string | no | |
Responses
| Status | Description |
302 | Redirect to calendar settings page. |
400 | `VALIDATION_ERROR` or `AUTH_OAUTH_FAILED`. |
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. |
POST /v1/calendar/sync/oauth/microsoft/callback
Microsoft Calendar OAuth callback (SPA form post)
Same as the GET callback but accepts `{ code, state }` as a JSON body from an SPA.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
code | string | no | |
state | string | no | |
Responses
| Status | Description |
302 | Redirect to calendar settings page. |
400 | `VALIDATION_ERROR` or `AUTH_OAUTH_FAILED`. |
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. |
GET /v1/calendar/sync/oauth/microsoft/start
Start Microsoft Calendar OAuth flow
Generates the Microsoft identity platform consent URL for the Calendar sync OAuth flow. Returns the authorization URL and CSRF state token. Requires the `calendar` feature flag.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Authorization URL generated. |
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. |
503 | `SERVICE_UNAVAILABLE` — Microsoft calendar sync is not configured. |
200 response body: data fields
| Field | Type | Description |
url | string<uri> | Provider authorization URL. Redirect the user here to start the consent flow. |
state | string | CSRF state token. Pass this back in the callback `state` parameter. |
GET /v1/calendar/sync/providers/{connectionId}/calendars
List provider calendars for a connection
Fetches the list of calendars from the connected external provider (Google or Microsoft) for use in the sync picker. Refreshes the access token server-side if needed; the token is never returned to the caller. CalDAV connections are not supported by this endpoint.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
connectionId | path | string<uuid> | yes | Sync connection identifier (UUIDv7). |
Responses
| Status | Description |
200 | Provider calendar list. |
400 | `INVALID_ID_FORMAT` or `VALIDATION_ERROR` (CalDAV connection). |
401 | `AUTH_OAUTH_FAILED` — the connection must be re-linked. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
502 | `EXTERNAL_SERVICE_ERROR` — provider API request failed. |
503 | `SERVICE_UNAVAILABLE` — encryption not configured. |
GET /v1/calendar/task-lists
List task lists
Returns the caller's task lists.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Task lists. |
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. |
PUT /v1/calendar/task-lists
Create, rename, or delete a task list
Upserts a task list. `action` must be `create`, `rename`, or `delete`. `list_id` is required for `rename` and `delete`; `title` is required for `create` and `rename`.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
action | string (enum) createrenamedelete | yes | |
list_id | string<uuid> | no | Required for `rename` and `delete`. |
title | string | no | Required for `create` and `rename`. |
Responses
| Status | Description |
200 | Task list operation applied. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/calendar/tasks
Create a task
Creates a new task in the specified task list.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
list_id | string<uuid> | yes | Task list to add the task to. |
title | string | yes | |
notes | string | no | |
due_at | string | no | Due date/time (ISO-8601 or RFC 3339). |
ordinal | integer | no | Ordinal position within the list. |
Responses
| Status | Description |
201 | Task created. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
PATCH /v1/calendar/tasks/{taskId}
Update a task
Updates task fields. All fields are optional.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
taskId | path | string<uuid> | yes | Task identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
title | string | no | |
notes | string | no | |
due_at | string | no | |
status | string (enum) needsActioncompleted | no | |
Responses
| Status | Description |
200 | Updated task. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
DELETE /v1/calendar/tasks/{taskId}
Delete a task
Deletes a task. Pass `cascade=true` to also delete sub-tasks.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
taskId | path | string<uuid> | yes | Task identifier (UUIDv7). |
cascade | query | boolean | no | Delete sub-tasks recursively. |
Responses
| Status | Description |
200 | Task deleted. |
400 | `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/calendar/tasks/{taskId}/complete
Complete or reopen a task
Marks a task completed or reopens it. Pass `{ "completed": false }` to reopen.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
taskId | path | string<uuid> | yes | Task identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
completed | boolean | no | Set `false` to reopen the task. Defaults to `true`. |
Responses
| Status | Description |
200 | Task completion state updated. |
400 | `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/calendar/tasks/{taskId}/move
Move a task
Moves a task to a different list and/or changes its ordinal position.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
taskId | path | string<uuid> | yes | Task identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
list_id | string<uuid> | no | Destination task list (optional; omit to reorder within the current list). |
ordinal | integer | no | Ordinal position in the destination list. |
Responses
| Status | Description |
200 | Task moved. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
GET /v1/calendar/ws
Open calendar WebSocket
Upgrades to a WebSocket channel connected to the calendar Durable Object. The caller supplies a one-time `token` (JWT) and the `calendarId`. The server verifies the token, checks revocation, and runs the four-bit calendar access gate (`can_read_freebusy` / `can_read_details` / `can_write` / `can_admin`) before forwarding the upgrade. The derived capability (`freebusy`, `read`, or `write`) is passed to the Durable Object, which re-verifies independently. A request without `Upgrade: websocket` receives `426`.
Auth One-time ?token= ticket
Parameters
| Name | In | Type | Required | Description |
token | query | string | yes | One-time calendar connection ticket (short-lived JWT). |
calendarId | query | string<uuid> | yes | Calendar identifier (UUIDv7). |
Responses
| Status | Description |
101 | WebSocket handshake accepted. |
400 | `VALIDATION_ERROR`. |
401 | `AUTH_TOKEN_INVALID` or `AUTH_TOKEN_EXPIRED`. |
403 | `PERMISSION_DENIED` — no calendar access (uniform deny). |
426 | `VALIDATION_ERROR` — not a WebSocket upgrade. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
GET /v1/email/unsubscribe
Unsubscribe confirmation page (public)
Browser-clickable GET endpoint for the RFC 2369 `List-Unsubscribe` header. Verifies the HMAC-signed `token` query parameter and renders a confirmation HTML page with a submit button. Does NOT mutate state — the form POSTs the verified token back to this endpoint to trigger the actual unsubscription. Link prefetchers and crawlers that follow the link will see only the confirmation page and cannot unsubscribe the recipient.
Public Public: no authentication
Parameters
| Name | In | Type | Required | Description |
token | query | string | yes | HMAC-SHA256-signed unsubscribe token (≤ 4096 chars). |
Responses
| Status | Description |
200 | Confirmation page HTML. |
400 | Missing, oversized, or cryptographically invalid token. |
429 | Rate limit exceeded. |
503 | Unsubscribe endpoint not configured. |
POST /v1/email/unsubscribe
One-click unsubscribe (public)
RFC 8058 one-click `List-Unsubscribe-Post` endpoint and confirmation form submission handler. Verifies the HMAC-signed token (via `?token=` query param, `application/x-www-form-urlencoded` body field, or JSON `token` field), then sets the marketing objection flag on the email address and adds it to the suppression list. Returns `{ unsubscribed: true, email: "..." }` on success. Per-IP rate-limited before any HMAC or database work.
Public Public: no authentication
Parameters
| Name | In | Type | Required | Description |
token | query | string | no | HMAC-SHA256-signed unsubscribe token (≤ 4096 chars). Can alternatively be supplied in the request body. |
Request Body
| Field | Type | Required | Description |
token | string | no | |
Responses
| Status | Description |
200 | Unsubscription recorded. |
400 | Missing, oversized, or cryptographically invalid token. |
429 | Rate limit exceeded. |
500 | Internal error. |
503 | Endpoint not configured. |
POST /v1/helpdesk/auto-dispatch
Set auto-dispatch for a category
Enables or disables automatic dispatch for a helpdesk category. ELEVATED: requires MFA step-up (human path); SP enforces elevated grant floor for API-key path.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
category_key | string | yes | |
auto_dispatch | boolean | yes | |
saas_package_id | string | no | Optional SaaS package scope (hex UUID). |
project_id | string<uuid> | no | |
dispatch_policy | object | no | |
Responses
| Status | Description |
200 | Auto-dispatch setting saved. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | MFA step-up required. `error.code`: `MFA_STEPUP_REQUIRED`. |
POST /v1/helpdesk/categories
Create or update a helpdesk dispatch category
Creates or updates a helpdesk category configuration entry, including inheritance columns, auto-dispatch settings, and dispatch-policy overrides. SP self-gates on `support.config` / `org.update`.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
key | string | yes | Category key. |
label | string | yes | Category display label. |
saas_package_id | string | no | SaaS package scope (hex UUID). |
project_id | string<uuid> | no | Project scope. |
sort_order | integer | no | Sort order. |
is_active | boolean | no | |
overrides_key | string | no | Parent category key this entry overrides. |
is_shadow_disabled | boolean | no | |
auto_dispatch | boolean | no | |
dispatch_policy | object | no | Dispatch policy configuration. |
Responses
| Status | Description |
200 | Category saved. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Insufficient permissions. `error.code`: `FORBIDDEN`. |
DELETE /v1/helpdesk/categories/{categoryId}
Delete a helpdesk category
Deletes a helpdesk category row by ID. SP self-gates on `support.config`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
categoryId | path | string<uuid> | yes | Category ID. |
Responses
| Status | Description |
200 | Category deleted. |
400 | Invalid ID format. `error.code`: `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Insufficient permissions. `error.code`: `FORBIDDEN`. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
GET /v1/helpdesk/categories/effective
List effective helpdesk categories
Returns the merged effective category set for a given `saas_package_id` and/or `project_id` tuple. This is the single source of truth for the ticket editor. SP self-gates on `support.read`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
saas_package_id | query | string | no | SaaS package ID (hex UUID) to scope effective categories. |
project_id | query | string<uuid> | no | Project ID to scope effective categories. |
Responses
| Status | Description |
200 | Effective category list. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
GET /v1/helpdesk/category-workers
List VW-to-category assignments
Returns virtual worker assignments for helpdesk categories. Supports optional `category_key`, `saas_package_id`, and `project_id` filters.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
category_key | query | string | no | |
saas_package_id | query | string | no | |
project_id | query | string<uuid> | no | |
Responses
| Status | Description |
200 | Worker assignment list. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
POST /v1/helpdesk/category-workers
Assign a virtual worker to a helpdesk category
Associates a virtual worker with a helpdesk dispatch category. Optionally scoped to a SaaS package or project. The virtual worker must be accessible to the caller (cross-org reject enforced at SP).
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
category_key | string | yes | Category to assign the worker to. |
virtual_worker_id | string<uuid> | yes | Virtual worker ID. |
saas_package_id | string | no | Optional SaaS package scope (hex UUID). |
project_id | string<uuid> | no | Optional project scope. |
priority | integer | no | Assignment priority (lower = higher priority). |
is_enabled | boolean | no | |
Responses
| Status | Description |
201 | Worker assigned. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Insufficient permissions. `error.code`: `FORBIDDEN`. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
DELETE /v1/helpdesk/category-workers/{assignmentId}
Remove a VW-to-category assignment
Removes a virtual worker assignment by assignment ID. SP self-gates on `support.config`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
assignmentId | path | string<uuid> | yes | Assignment ID. |
Responses
| Status | Description |
200 | Assignment removed. |
400 | Invalid ID format. `error.code`: `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Insufficient permissions. `error.code`: `FORBIDDEN`. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
POST /v1/helpdesk/pool-policy
Set container pool policy
Configures the container pool limits and timing policy for the organization's helpdesk workers. Requires MFA step-up.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
max_slots_per_container | integer | no | |
max_containers_per_worker | integer | no | |
max_worker_containers_per_org | integer | no | |
idle_container_grace_seconds | integer | no | |
pool_floor_per_worker | integer | no | |
Responses
| Status | Description |
200 | Pool policy saved. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | MFA step-up required. `error.code`: `MFA_STEPUP_REQUIRED`. |
GET /v1/helpdesk/pool-policy/get
Get container pool policy
Returns the organization's container pool policy (max slots, idle grace period, pool floor, etc.). Read-only; no MFA step-up required.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Pool policy. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
GET /v1/helpdesk/pool-status
Get live container pool status
Returns live per-virtual-worker container and slot occupancy. Optionally filtered by `virtual_worker_id`. SP self-gates on `support.read`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
virtual_worker_id | query | string<uuid> | no | Filter to a single virtual worker. |
Responses
| Status | Description |
200 | Pool status. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
GET /v1/helpdesk/slot-config
Get container slot configuration
Returns the per-worker container slot count configuration.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Slot configuration. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
POST /v1/helpdesk/slot-config
Set container slot count for a worker
Configures the maximum number of concurrent container slots for a virtual worker (1–16). Requires MFA step-up.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
virtual_worker_id | string<uuid> | yes | Virtual worker ID. |
slot_count | integer | yes | Maximum number of concurrent slots for this worker. |
Responses
| Status | Description |
200 | Slot config saved. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | MFA step-up required. `error.code`: `MFA_STEPUP_REQUIRED`. |
GET /v1/integrations/cloudflare/authorize
Get Cloudflare OAuth authorization URL
Returns the Cloudflare OAuth (PKCE) authorization URL. Accepts an optional `?purpose=` parameter (`dns` or `worker_sync`) to tailor the requested scopes. Feature-flag gated.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
purpose | query | string (enum) | no | Intended use of the Cloudflare connection; influences requested scopes. |
Responses
| Status | Description |
200 | Authorization URL and PKCE challenge generated. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
503 | Cloudflare OAuth not configured. `error.code`: `SERVICE_UNAVAILABLE`. |
200 response body: data fields
| Field | Type | Description |
url | string<uri> | The provider authorization URL to redirect the user to. |
POST /v1/integrations/cloudflare/connect
Connect Cloudflare via authorization code
Completes the Cloudflare PKCE OAuth flow. Validates the CSRF `state` JWT, exchanges `code` for tokens, and stores the encrypted credential. Applies a scope-allowlist to prevent scope-confusion attacks. Feature-flag gated.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
code | string | yes | OAuth authorization code from the provider. |
state | string | yes | CSRF state value from the authorize redirect. |
Responses
| Status | Description |
200 | Cloudflare connection established. |
400 | Validation error. `error.code`: `VALIDATION_ERROR` or `INVALID_JSON`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | CSRF state validation failed. `error.code`: `AUTH_OAUTH_FAILED`. |
503 | Cloudflare OAuth not configured. `error.code`: `SERVICE_UNAVAILABLE`. |
POST /v1/integrations/cloudflare/disconnect
Disconnect Cloudflare integration
Revokes and removes the stored Cloudflare OAuth credential for the caller's organization.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Cloudflare integration disconnected. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
GET /v1/integrations/github/authorize
Get GitHub OAuth authorization URL
Returns the GitHub OAuth authorization URL the client should redirect the user to. The `state` is a signed CSRF JWT (HS256, 10-minute expiry) that must be round-tripped back to `/v1/integrations/github/callback`. Feature-flag gated; returns 503 when the GitHub OAuth application is not configured.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Authorization URL generated. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
503 | GitHub OAuth not configured. `error.code`: `SERVICE_UNAVAILABLE`. |
200 response body: data fields
| Field | Type | Description |
url | string<uri> | The provider authorization URL to redirect the user to. |
GET /v1/integrations/github/callback
Handle GitHub OAuth callback
Completes the GitHub OAuth flow. Exchanges `code` for an access token, stores the encrypted credential, and returns the connection record. `state` is validated against the signed CSRF JWT issued by the authorize endpoint. Feature-flag gated.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
code | query | string | yes | OAuth authorization code from GitHub. |
state | query | string | yes | CSRF state value from the authorize redirect. |
Responses
| Status | Description |
200 | GitHub connection created or updated. |
400 | Missing or invalid query parameters. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | CSRF state validation failed. `error.code`: `AUTH_OAUTH_FAILED`. |
503 | GitHub OAuth not configured. `error.code`: `SERVICE_UNAVAILABLE`. |
200 response body: data fields
| Field | Type | Description |
id | string<uuid> | Connection record ID. |
org_id | string<uuid> | |
status | string | Connection status (e.g., `active`). |
created_at | string<date-time> | |
POST /v1/integrations/github/connect
Connect GitHub via authorization code
Exchanges a GitHub OAuth authorization code for a stored connection. Validates the `state` CSRF JWT, stores the encrypted OAuth token, and links the connection to the caller's organization. Feature-flag gated.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
code | string | yes | OAuth authorization code from GitHub. |
state | string | yes | CSRF state value from the authorize redirect. |
Responses
| Status | Description |
200 | GitHub connection established. |
400 | Validation error. `error.code`: `VALIDATION_ERROR` or `INVALID_JSON`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | CSRF state validation failed or feature disabled. `error.code`: `AUTH_OAUTH_FAILED` or `FEATURE_DISABLED`. |
503 | GitHub OAuth not configured. `error.code`: `SERVICE_UNAVAILABLE`. |
200 response body: data fields
| Field | Type | Description |
id | string<uuid> | Connection record ID. |
org_id | string<uuid> | |
status | string | Connection status (e.g., `active`). |
created_at | string<date-time> | |
POST /v1/integrations/github/disconnect
Disconnect GitHub integration
Revokes the stored GitHub OAuth credential and removes the connection record for the caller's organization.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | GitHub integration disconnected. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
GET /v1/integrations/github/repos
List accessible GitHub repositories
Returns repositories accessible via the caller's connected GitHub account. Feature-flag gated.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Repository list. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
503 | GitHub not connected or not configured. `error.code`: `SERVICE_UNAVAILABLE` or `PROVIDER_NOT_CONNECTED`. |
200 response body: data fields
| Field | Type | Description |
repos | array of object | |
POST /v1/integrations/github/repos/attach
Attach a GitHub repository to the organization
Links a GitHub repository (identified by owner, name, and full name) to the caller's organization. Feature-flag gated.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
repoOwner | string | yes | GitHub owner login. |
repoName | string | yes | GitHub repository name. |
repoFullName | string | yes | Full repository name (owner/repo). |
defaultBranch | string | no | Default branch name. |
isPrivate | boolean | no | Whether the repository is private. |
githubRepoId | integer | no | Numeric GitHub repository ID (optional). |
Responses
| Status | Description |
200 | Repository attached. |
400 | Validation error. `error.code`: `VALIDATION_ERROR` or `INVALID_JSON`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
409 | 409 Conflict — the request conflicts with an existing resource or current state (unique constraint, optimistic-lock, duplicate). |
POST /v1/integrations/github/repos/detach
Detach a GitHub repository from the organization
Removes a previously linked GitHub repository from the caller's organization.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
repo_id | string<uuid> | yes | ID of the repository attachment to remove. |
Responses
| Status | Description |
200 | Repository detached. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
GET /v1/integrations/google/authorize
Get Google OAuth authorization URL
Returns the Google OAuth authorization URL. Accepts an optional `?products=` comma-separated list of Backbuild product keys to tailor the requested scopes. The `state` is a signed CSRF JWT. Feature-flag gated.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
products | query | string | no | Comma-separated Backbuild product keys to scope the Google OAuth request. |
Responses
| Status | Description |
200 | Authorization URL generated. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
503 | Google OAuth not configured. `error.code`: `SERVICE_UNAVAILABLE`. |
200 response body: data fields
| Field | Type | Description |
url | string<uri> | The provider authorization URL to redirect the user to. |
POST /v1/integrations/google/connect
Connect Google via authorization code
Completes the Google OAuth flow. Validates the CSRF `state` JWT, exchanges `code` for tokens, and stores the encrypted credential. Feature-flag gated.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
code | string | yes | OAuth authorization code from the provider. |
state | string | yes | CSRF state value from the authorize redirect. |
Responses
| Status | Description |
200 | Google connection established. |
400 | Validation error. `error.code`: `VALIDATION_ERROR` or `INVALID_JSON`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | CSRF state validation failed. `error.code`: `AUTH_OAUTH_FAILED`. |
503 | Google OAuth not configured. `error.code`: `SERVICE_UNAVAILABLE`. |
POST /v1/integrations/google/disconnect
Disconnect Google integration
Revokes and removes the stored Google OAuth credential for the caller's organization.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Google integration disconnected. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
GET /v1/notifications
List notifications
Returns a paginated list of notifications for the authenticated user, optionally filtered by channel, type, read status, or time range. Supports `page`/`pageSize` pagination.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
page | query | integer | no | Page number (1-based). |
pageSize | query | integer | no | Items per page. |
channel | query | string (enum) | no | Filter by delivery channel. |
notification_type | query | string (enum) | no | Filter by notification type. |
is_read | query | string (enum) | no | Filter by read status. |
since | query | string<date-time> | no | Return notifications created after this ISO timestamp. |
until | query | string<date-time> | no | Return notifications created before this ISO timestamp. |
Responses
| Status | Description |
200 | Notification list. |
400 | Invalid query parameters. `error.code`: `INVALID_PARAMETER`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | Database failure. `error.code`: `DATABASE_ERROR`. |
200 response body: data fields
| Field | Type | Description |
notifications | array of object | |
pagination | object | Pagination metadata. Endpoints use either page/pageSize or limit/offset style; fields present depend on the endpoint. |
POST /v1/notifications
Create a notification
Creates a notification for the caller or, with `notification.create` permission, for another user. `action_url` must be a Backbuild platform domain. Cross-user creation requires `notification.create` permission; otherwise `403 INSUFFICIENT_PERMISSIONS` is returned.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
title | string | yes | Notification title. |
body | string | no | Optional notification body text. |
notification_type | string (enum) infosuccesswarningerroraction_required | yes | Semantic type of the notification. |
channel | string (enum) in_appemailpushslack | no | Delivery channel. |
target_user_id | string<uuid> | no | Target user; defaults to the caller. Creating for another user requires `notification.create` permission. |
resource_type | string | no | Type of the linked resource (e.g., `ticket`, `project`). |
resource_id | string<uuid> | no | ID of the linked resource. |
action_url | string<uri> | no | Call-to-action URL; must be a Backbuild platform domain. |
priority | string (enum) lownormalhighurgent | no | Delivery priority. |
expires_at | string<date-time> | no | Expiry timestamp; notification auto-hides after this. |
metadata | object | no | Bounded JSON metadata (max 32 KB). |
Responses
| Status | Description |
201 | Notification created. |
400 | Validation error. `error.code`: `VALIDATION_ERROR` or `INVALID_JSON`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Cross-user notification without permission. `error.code`: `INSUFFICIENT_PERMISSIONS`. |
500 | Database failure. `error.code`: `DATABASE_ERROR`. |
201 response body: data fields
| Field | Type | Description |
id | string<uuid> | |
title | string | |
body | string | null | |
notification_type | string (enum) infosuccesswarningerroraction_required | |
channel | string | null | |
is_read | boolean | |
created_at | string<date-time> | |
expires_at | string | null | |
action_url | string | null | |
PATCH /v1/notifications/{notificationId}
Mark a notification read/unread
Toggles the read status of a single notification. Only the notification's target user may update it.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
notificationId | path | string<uuid> | yes | Notification ID. |
Request Body
| Field | Type | Required | Description |
is_read | boolean | yes | Set to `true` to mark as read, `false` to mark as unread. |
Responses
| Status | Description |
200 | Notification updated. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | Database failure. `error.code`: `DATABASE_ERROR`. |
200 response body: data fields
| Field | Type | Description |
id | string<uuid> | |
title | string | |
body | string | null | |
notification_type | string (enum) infosuccesswarningerroraction_required | |
channel | string | null | |
is_read | boolean | |
created_at | string<date-time> | |
expires_at | string | null | |
action_url | string | null | |
DELETE /v1/notifications/{notificationId}
Delete a notification
Permanently deletes a notification. Only the notification's target user may delete it.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
notificationId | path | string<uuid> | yes | Notification ID. |
Responses
| Status | Description |
200 | Notification deleted. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | Database failure. `error.code`: `DATABASE_ERROR`. |
POST /v1/notifications/bulk-mark-read
Bulk mark notifications as read
Marks up to 100 notifications as read in a single operation. Only the caller's own notifications may be targeted.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
notification_ids | array of string | yes | Array of notification IDs to mark as read. |
Responses
| Status | Description |
200 | Notifications marked as read. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | Database failure. `error.code`: `DATABASE_ERROR`. |
GET /v1/rdp/audit-log
List RDP audit log entries
Returns paginated RDP audit log entries. Requires `rdp.admin` permission. Supports cursor-based pagination (base64url-encoded JSON `{occurred_at, id}`) and optional filters. Response carries `Cache-Control: no-store`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
cursor | query | string | no | Pagination cursor (opaque base64url-encoded value). |
limit | query | integer | no | Maximum results to return. |
action | query | string | no | Filter by audit action name. |
device_id | query | string<uuid> | no | Filter by device ID. |
actor_user_id | query | string<uuid> | no | Filter by actor user ID. |
session_id | query | string<uuid> | no | Filter by session ID. |
since | query | string<date-time> | no | Return entries after this timestamp. |
until | query | string<date-time> | no | Return entries before this timestamp. |
Responses
| Status | Description |
200 | Audit log entries. |
400 | Invalid parameter or cursor. `error.code`: `INVALID_PARAMETER`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Insufficient permissions. `error.code`: `FORBIDDEN`. |
POST /v1/rdp/audit-log/export
Export RDP audit log as CSV
Exports up to 5,000 RDP audit log entries as a CSV file. Supports the same filters as the list endpoint. CSV values are sanitized against formula-injection (OWASP). Requires `rdp.admin` permission.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
max_rows | integer | no | Maximum rows to export (default 5000). |
action | string | no | |
device_id | string<uuid> | no | |
actor_user_id | string<uuid> | no | |
session_id | string<uuid> | no | |
since | string<date-time> | no | |
until | string<date-time> | no | |
Responses
| Status | Description |
200 | CSV file attachment. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Insufficient permissions. `error.code`: `FORBIDDEN`. |
GET /v1/rdp/devices
List registered RDP devices
Returns registered RDP devices for the caller's organization. Supports optional filters `include_inactive`, `host_only`, and `viewer_only`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
include_inactive | query | string (enum) | no | Include deregistered devices. |
host_only | query | string (enum) | no | Return only host-capable devices. |
viewer_only | query | string (enum) | no | Return only viewer-capable devices. |
Responses
| Status | Description |
200 | Device list. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
POST /v1/rdp/devices
Register an RDP device
Registers a device for use with remote desktop. The device submits its post-quantum identity bundle including KEM and signature algorithm IDs. Feature-flag gated for write operations.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
device_identifier | string | yes | |
device_name | string | yes | |
os_family | string (enum) windowsmacoslinuxiosandroidwebother | yes | |
os_version | string | yes | |
app_version | string | yes | |
capabilities | object | no | Optional device capabilities (max 8 KB). |
pq_kem_alg_id | string | yes | Post-quantum KEM algorithm identifier. |
pq_sig_alg_id | string | yes | Post-quantum signature algorithm identifier. |
pq_identity_bundle | object | yes | Post-quantum identity bundle (max 32 KB). |
Responses
| Status | Description |
201 | Device registered. |
400 | Validation error. `error.code`: `VALIDATION_ERROR` or `INVALID_JSON`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Feature not enabled. `error.code`: `FEATURE_DISABLED`. |
DELETE /v1/rdp/devices/{deviceId}
Deregister an RDP device
Removes a device from the RDP registry. Feature-flag gated.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
deviceId | path | string<uuid> | yes | Device ID. |
Responses
| Status | Description |
200 | Device deregistered. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Feature not enabled. `error.code`: `FEATURE_DISABLED`. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
POST /v1/rdp/devices/{hostId}/trust
Grant viewer trust to a host device
Grants a viewer device permission to connect to the specified host device, binding the trust to an expected public-key hash. Feature-flag gated.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
hostId | path | string<uuid> | yes | Host device ID. |
Request Body
| Field | Type | Required | Description |
viewer_device_id | string<uuid> | yes | |
expected_pubkey_hash | string | yes | Hash of the viewer's expected public key. |
permissions | object | yes | Permission set granted to the viewer (max 4 KB). |
Responses
| Status | Description |
200 | Trust granted. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Feature not enabled. `error.code`: `FEATURE_DISABLED`. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
409 | Public key mismatch detected. `error.code`: `PUBKEY_MISMATCH`. |
DELETE /v1/rdp/devices/{hostId}/trust
Revoke viewer trust from a host device
Removes a viewer device's trust relationship with a host device.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
hostId | path | string<uuid> | yes | Host device ID. |
Request Body
| Field | Type | Required | Description |
viewer_device_id | string<uuid> | yes | Viewer device to untrust. |
Responses
| Status | Description |
200 | Trust revoked. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
GET /v1/rdp/my-data-export
Export the caller's RDP data (GDPR Art. 15)
Returns all RDP device registrations, sessions, and audit events for the authenticated caller. GDPR Article 15 self-service data access. Response carries `Cache-Control: no-store, private`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
since | query | string<date-time> | no | Export data after this timestamp. |
until | query | string<date-time> | no | Export data before this timestamp. |
max_rows | query | integer | no | Maximum number of records to include. |
Responses
| Status | Description |
200 | Caller's RDP data export. |
400 | Invalid parameter. `error.code`: `INVALID_PARAMETER`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
POST /v1/rdp/my-data-forget
Erase the caller's RDP data (GDPR Art. 17)
Pseudonymizes or deletes the caller's RDP device registrations, sessions, and audit records. GDPR Article 17 self-service erasure. Optionally scoped to a single organization.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
org_id | string<uuid> | no | Optional: scope erasure to a single organization. |
Responses
| Status | Description |
200 | Erasure completed. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
POST /v1/rdp/sessions
Authorize an RDP session
Creates and authorizes a remote desktop session between a host and viewer device. Validates the post-quantum algorithm negotiation. Returns `409 CRYPTO_FLOOR_VIOLATION` (HTTP 426 Upgrade Required) if the negotiated cipher suites fall below the organization's security floor.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
host_device_id | string<uuid> | yes | |
viewer_device_id | string<uuid> | yes | |
viewer_user_id | string<uuid> | yes | |
viewer_pubkey_hash | string | yes | |
signaling_session_id | string | yes | |
kem_alg_negotiated | string | yes | |
sig_alg_negotiated | string | yes | |
aead_alg_negotiated | string | yes | |
Responses
| Status | Description |
201 | Session authorized. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Insufficient permissions. `error.code`: `PERMISSION_DENIED`. |
426 | Negotiated cipher suite below org security floor. `error.code`: `CRYPTO_FLOOR_VIOLATION`. |
DELETE /v1/rdp/sessions/{sessionId}
End an RDP session
Terminates an active RDP session, recording the end reason and final byte counters.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
sessionId | path | string<uuid> | yes | Session ID. |
Request Body
| Field | Type | Required | Description |
end_reason | string | yes | |
ice_connection_type | string | no | |
total_bytes_in | integer | no | |
total_bytes_out | integer | no | |
Responses
| Status | Description |
200 | Session ended. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
GET /v1/rdp/sessions/{sessionId}/consent
Poll session consent status (viewer)
Returns the current host consent status for a session. Used by the viewer to poll whether the host has granted or denied access. Includes seconds remaining in the consent window.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
sessionId | path | string<uuid> | yes | Session ID. |
Responses
| Status | Description |
200 | Consent status. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Caller is not a session participant. `error.code`: `FORBIDDEN`. |
POST /v1/rdp/sessions/{sessionId}/consent
Respond to a session consent request (host)
Host grants or denies a pending viewer connection. The session's `host_consent_status` transitions to `granted` or `denied`. Returns `409` with `consent_already_decided` if a decision was already made, or `410` with `session_ended` if the session is terminated.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
sessionId | path | string<uuid> | yes | Session ID. |
Request Body
| Field | Type | Required | Description |
decision | string (enum) granteddenied | yes | Host consent decision. |
Responses
| Status | Description |
200 | Consent decision recorded. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Caller is not the session host. `error.code`: `FORBIDDEN`. |
409 | Consent already decided. `error.code`: `consent_already_decided`. |
410 | Session has ended. `error.code`: `session_ended`. |
GET /v1/rdp/sessions/{sessionId}/diagnostics
Get RDP session diagnostics
Returns session diagnostics including ICE connection stats and byte counters. Accessible by session participants and admins.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
sessionId | path | string<uuid> | yes | Session ID. |
Responses
| Status | Description |
200 | Session diagnostics. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Not a session participant or admin. `error.code`: `FORBIDDEN`. |
POST /v1/rdp/sessions/{sessionId}/heartbeat
Send a session heartbeat
Keeps a session alive and records incremental byte counters. TURN relay usage is attributed from the canonical ICE connection type recorded by the server, not the client-supplied value.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
sessionId | path | string<uuid> | yes | Session ID. |
Request Body
| Field | Type | Required | Description |
ice_connection_type | string | no | ICE connection type (e.g., `relay`, `srflx`, `host`). |
bytes_in_delta | integer | yes | Bytes received since last heartbeat. |
bytes_out_delta | integer | yes | Bytes sent since last heartbeat. |
Responses
| Status | Description |
200 | Heartbeat recorded. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
POST /v1/rdp/sessions/{sessionId}/signaling-token
Issue a WebRTC signaling token
Issues an HMAC-signed one-time signaling token for joining the RDP signaling DO. The token encodes the caller's role (`host` or `viewer`), a unique `jti`, and the DO session ID. Returns `403 CONSENT_PENDING` if the host has not yet responded to the consent prompt, or `403 CONSENT_DENIED` if access was denied.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
sessionId | path | string<uuid> | yes | Session ID. |
Request Body
| Field | Type | Required | Description |
role | string (enum) hostviewer | yes | The role the caller will play in the signaling session. |
Responses
| Status | Description |
200 | Signaling token issued. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Consent pending or denied. `error.code`: `CONSENT_PENDING` or `CONSENT_DENIED`. |
200 response body: data fields
| Field | Type | Description |
token | string | Signed signaling token. |
expires_at | string<date-time> | |
do_session_id | string | Durable Object session ID. |
ws_url | string | WebSocket upgrade path for the signaling connection. |
POST /v1/rdp/sessions/{sessionId}/turn-credentials
Issue TURN relay credentials
Issues RFC 5766 TURN credentials for the session. Checks the per-org 24-hour bandwidth quota (fail-closed); returns `429 quota_exceeded` if exhausted. Credentials are bound to the caller's user ID and source IP — mismatched heartbeats will not attribute relay bytes to prevent credential-sharing abuse.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
sessionId | path | string<uuid> | yes | Session ID. |
Responses
| Status | Description |
200 | TURN credentials. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Org context missing. `error.code`: `FORBIDDEN`. |
429 | 24-hour TURN bandwidth quota exceeded. `error.code`: `quota_exceeded`. |
503 | TURN quota DO unreachable or relay not configured. `error.code`: `INTERNAL_ERROR` or `SERVICE_UNAVAILABLE`. |
200 response body: data fields
| Field | Type | Description |
username | string | TURN username (bound to expiry, session, user, and IP). |
credential | string | HMAC-derived TURN credential. |
ttl | integer | Credential TTL in seconds. |
uris | array of string | TURN server URIs (`turn:` or `turns:` scheme only). |
GET /v1/rdp/signal/{doSessionId}
Upgrade to WebRTC signaling WebSocket
Upgrades the connection to a WebSocket for WebRTC signaling. The caller must present a valid HMAC-signed signaling token via the `?token=` query parameter, the `X-RDP-Signaling-Token` header, or the `X-RDP-Token` header. The token must be bound to the requested `doSessionId`. Returns `426` if the `Upgrade: websocket` header is absent.
Auth One-time ?token= ticket
Parameters
| Name | In | Type | Required | Description |
doSessionId | path | string | yes | Durable Object signaling session ID (org-scoped: `<orgId>:<signalingSessionId>`). |
token | query | string | no | HMAC-signed signaling token (alternative to header). |
Responses
| Status | Description |
101 | WebSocket upgrade accepted; signaling session established. |
400 | Invalid session ID format. `error.code`: `INVALID_ID_FORMAT`. |
401 | Missing, invalid, or expired signaling token. `error.code`: `UNAUTHORIZED`. |
426 | WebSocket upgrade header missing. `error.code`: `VALIDATION_ERROR`. |
GET /v1/rdp/turn-quota
Get TURN relay bandwidth quota
Returns the organization's current TURN relay bandwidth usage within the rolling 24-hour window. Requires `rdp.admin` permission.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | TURN quota status. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Insufficient permissions. `error.code`: `FORBIDDEN`. |
200 response body: data fields
| Field | Type | Description |
bytes_used_24h | integer | Bytes used in the rolling 24-hour window. |
bytes_cap | integer | Per-org 24-hour byte cap. |
issuances_24h | integer | Number of TURN credential issuances in the window. |
window_ms | integer | Window duration in milliseconds. |
window_started_at | integer | Window start timestamp (Unix ms). |
GET /v1/secrets/admin-recovery/{targetUserId}
Get admin recovery materials for a user
Returns the recovery materials needed to re-seal a user's secrets identity during an admin-initiated password reset. Requires `org.manage_members` or `secrets.recover` permission and MFA step-up.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
targetUserId | path | string<uuid> | yes | Target user ID. |
Responses
| Status | Description |
200 | Recovery materials. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Insufficient permissions or MFA step-up required. `error.code`: `PERMISSION_DENIED` or `MFA_STEPUP_REQUIRED`. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
POST /v1/secrets/admin-recovery/{targetUserId}/reset
Reset a user's secrets vault (admin recovery)
Re-seals a user's secrets identity with a new sealed private-key blob. Used to reset access when the user has lost their master password. Requires `org.manage_members` or `secrets.recover` permission and MFA step-up. The new `kdf` parameters must meet the platform floor.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
targetUserId | path | string<uuid> | yes | Target user ID. |
Request Body
| Field | Type | Required | Description |
sealedPrivBlob | string | yes | |
saltUser | string | yes | |
kdf | object | yes | Argon2 KDF parameters. Must meet the platform floor: `mem_kib` ≥ 19456, `iters` ≥ 2. |
Responses
| Status | Description |
200 | Identity reset. |
400 | Validation error or KDF below floor. `error.code`: `VALIDATION_ERROR` or `CRYPTO_FLOOR_VIOLATION`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Insufficient permissions or MFA step-up required. `error.code`: `PERMISSION_DENIED` or `MFA_STEPUP_REQUIRED`. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
GET /v1/secrets/ai/vaults
List vault metadata (AI-accessible)
Returns vault names and types for the caller's organization. No ciphertext or key material is ever included. Intended for AI agents to enumerate available vaults without decrypting content.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Vault metadata list. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
GET /v1/secrets/ai/vaults/{vaultId}/items
List vault item metadata (AI-accessible)
Returns item names, types, and field names for a vault — never ciphertext or decrypted values. Intended for AI agents to discover available secret slots.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
vaultId | path | string<uuid> | yes | Vault ID. |
Responses
| Status | Description |
200 | Item metadata list. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
GET /v1/secrets/identity
Get secrets identity for the caller
Returns the caller's encrypted secrets identity blob (sealed private key, salt, KDF parameters). Used by the client to re-derive the vault key without reinitializing.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Secrets identity blob. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | Identity not initialized. `error.code`: `NOT_FOUND`. |
200 response body: data fields
| Field | Type | Description |
sealedPrivBlob | string | |
saltUser | string | |
kdf | object | Argon2 KDF parameters. Must meet the platform floor: `mem_kib` ≥ 19456, `iters` ≥ 2. |
pubKey | string | |
POST /v1/secrets/init
Initialize the secrets vault for a user
One-time initialization that creates the caller's zero-knowledge identity in the secrets vault. Requires MFA step-up and MFA verification. Rate-limited to 5 requests per 15 minutes per user/IP. The `kdf` parameters must meet the platform floor: `mem_kib` ≥ 19456, `iters` ≥ 2.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
sealedPrivBlob | string | yes | Encrypted private-key blob. |
saltUser | string | yes | User-specific KDF salt. |
kdf | object | yes | Argon2 KDF parameters. Must meet the platform floor: `mem_kib` ≥ 19456, `iters` ≥ 2. |
pubKey | string | yes | Public key for vault key wrapping. |
Responses
| Status | Description |
200 | Vault initialized. |
400 | Validation error or KDF below floor. `error.code`: `VALIDATION_ERROR` or `CRYPTO_FLOOR_VIOLATION`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | MFA step-up required. `error.code`: `MFA_STEPUP_REQUIRED`. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
POST /v1/secrets/lock
Lock the secrets vault session
Invalidates the current secrets session, clearing the vault unlock state.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Vault locked. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
PUT /v1/secrets/master-password
Change the master password
Re-wraps the sealed private-key blob with a new KDF-derived key. Requires MFA step-up and MFA verification. Rate-limited to 12 requests per minute. The new `kdf` parameters must meet the platform KDF floor.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
sealedPrivBlob | string | yes | |
saltUser | string | yes | |
kdf | object | yes | Argon2 KDF parameters. Must meet the platform floor: `mem_kib` ≥ 19456, `iters` ≥ 2. |
Responses
| Status | Description |
200 | Master password changed. |
400 | Validation error or KDF below floor. `error.code`: `VALIDATION_ERROR` or `CRYPTO_FLOOR_VIOLATION`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | MFA step-up required. `error.code`: `MFA_STEPUP_REQUIRED`. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
DELETE /v1/secrets/purge
Purge the caller's secrets identity
Permanently deletes the caller's zero-knowledge secrets identity and all associated vault memberships. Irreversible. Requires MFA step-up and MFA verification.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Identity purged. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | MFA step-up required. `error.code`: `MFA_STEPUP_REQUIRED`. |
GET /v1/secrets/server-escrow-pubkey
Get server escrow public key
Returns the server's KEM public key used to wrap the vault key for VW (Virtual Worker) vaults. Enables placeholder substitution without exposing human-vault ciphertext.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Server escrow public key. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | Escrow key unavailable. `error.code`: `INTERNAL_ERROR`. |
200 response body: data fields
| Field | Type | Description |
kemPublic | string | Base64-encoded KEM public key. |
POST /v1/secrets/substitute
Substitute secret placeholders in text
Resolves `{{secret:<vaultId>/<itemId>/<field>}}` placeholders in the provided text with their decrypted values from VW (Virtual Worker) vaults. Human ZK vaults are never server-decryptable and their placeholders are left intact. Requires `secrets.substitute` scope (container/VW token). The returned text is never logged or re-stored by the server. Input text must be ≤ 100,000 characters.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
text | string | yes | Input text containing `{{secret:...}}` placeholders to resolve. |
Responses
| Status | Description |
200 | Text with placeholders resolved. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
200 response body: data fields
| Field | Type | Description |
text | string | Text with resolved placeholders. |
substituted | integer | Number of placeholders successfully resolved. |
GET /v1/secrets/sync/bindings
List secret sync bindings
Returns sync bindings for a vault (and optionally a specific item). Requires `vaultId` (UUID) as a query parameter; callers without vault membership receive 404. Any vault member may read bindings; write operations require manager or owner role.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
vaultId | query | string<uuid> | yes | Vault ID (required; membership-gates the listing). |
itemId | query | string<uuid> | no | Narrow results to a specific vault item. |
Responses
| Status | Description |
200 | Binding list. |
400 | Validation error or missing vaultId. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | Vault not found or caller is not a member. `error.code`: `NOT_FOUND`. |
POST /v1/secrets/sync/bindings
Create or update a secret sync binding
Creates or updates a binding that maps a vault item field to a provider destination (e.g., a Cloudflare Workers secret). Requires vault manager or owner role and MFA step-up. The `connectionId` must be the caller's own active connection for the provider. The `locator` must lie within the connection's pinned scope (TOCTOU-validated).
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
id | string<uuid> | no | Existing binding ID for update; omit to create. |
vaultId | string<uuid> | yes | |
itemId | string<uuid> | yes | |
fieldPath | string | yes | Field path within the vault item. |
provider | string | yes | Provider key (e.g., `cloudflare`). |
connectionId | string<uuid> | yes | Must be the caller's own active connection for this provider. |
locator | object | yes | Provider-specific destination locator (e.g., Worker script name). |
destSecretName | string | yes | Destination secret name at the provider. |
generatable | boolean | no | |
overlapEnabled | boolean | no | |
rotateEverySeconds | integer | no | |
Responses
| Status | Description |
200 | Binding created or updated. |
400 | Validation or locator scope error. `error.code`: `VALIDATION_ERROR`, `PROVIDER_UNAVAILABLE`, or `LOCATOR_SCOPE`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | MFA step-up required, insufficient vault role, or connection mismatch. `error.code`: `MFA_STEPUP_REQUIRED`, `FORBIDDEN`, or `PROVIDER_NOT_CONNECTED`. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
409 | 409 Conflict — the request conflicts with an existing resource or current state (unique constraint, optimistic-lock, duplicate). |
DELETE /v1/secrets/sync/bindings/{bindingId}
Delete a secret sync binding
Soft-deletes a sync binding. Requires vault manager or owner role and MFA step-up.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
bindingId | path | string<uuid> | yes | Binding ID. |
Responses
| Status | Description |
200 | Binding deleted. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | MFA step-up required or insufficient vault role. `error.code`: `MFA_STEPUP_REQUIRED` or `FORBIDDEN`. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
GET /v1/secrets/sync/cloudflare/scripts
List Cloudflare Workers scripts
Returns script names from the connected Cloudflare account for use as sync binding targets. Returns an empty list if not connected or lacking `workers:read` scope.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Script name list. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
GET /v1/secrets/sync/providers
List secret sync providers
Returns available secret sync providers (e.g., Cloudflare Workers Secrets) and the caller's connection status for each. No secret values are included.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Provider list with connection status. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
POST /v1/secrets/sync/push
Push secret field values to external providers
Sends client-decrypted field values to their configured external provider destinations (Mode A interactive sync). Each binding is processed independently — one failure does not stop others. The `value` field is write-only: it is never logged, audited, or returned. Requires vault manager or owner role and MFA step-up. Up to 50 syncs per request.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
vaultId | string<uuid> | yes | |
itemId | string<uuid> | yes | |
syncs | array of object | yes | |
Responses
| Status | Description |
200 | Sync results per binding. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | MFA step-up required or insufficient vault role. `error.code`: `MFA_STEPUP_REQUIRED` or `FORBIDDEN`. |
200 response body: data fields
| Field | Type | Description |
results | array of object | |
GET /v1/secrets/trash
List trashed vault items
Returns all items in the caller's trash across their vaults.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Trash item list. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
POST /v1/secrets/trash/{itemId}/restore
Restore a trashed vault item
Restores a previously trashed vault item back to its vault.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
itemId | path | string<uuid> | yes | Trashed item ID. |
Responses
| Status | Description |
200 | Item restored. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
DELETE /v1/secrets/trash/empty
Empty the trash
Permanently deletes all trashed vault items. Requires MFA step-up.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Trash emptied. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | MFA step-up required. `error.code`: `MFA_STEPUP_REQUIRED`. |
POST /v1/secrets/unlock
Unlock the secrets vault session
Authenticates the caller's zero-knowledge vault session using their sealed private-key blob. Returns an encrypted session token. Requires MFA step-up and MFA verification. Rate-limited to 12 requests per minute per user/IP. On failure always returns 401 with no oracle information.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
sealedPrivBlob | string | yes | Encrypted private-key blob. |
saltUser | string | yes | User-specific KDF salt. |
kdf | object | yes | Argon2 KDF parameters. Must meet the platform floor: `mem_kib` ≥ 19456, `iters` ≥ 2. |
Responses
| Status | Description |
200 | Vault unlocked; encrypted session token returned. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | Authentication required or unlock failed. `error.code`: `UNAUTHORIZED` or `AUTH_REQUIRED`. |
403 | MFA step-up required. `error.code`: `MFA_STEPUP_REQUIRED`. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
200 response body: data fields
| Field | Type | Description |
sessionToken | string | Encrypted secrets session token. |
expiresAt | string<date-time> | |
GET /v1/secrets/vaults
List secrets vaults
Returns all vaults the caller is a member of within the active environment. Only metadata is returned — no ciphertext.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Vault list. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
200 response body: data fields
| Field | Type | Description |
vaults | array of object | |
POST /v1/secrets/vaults
Create a secrets vault
Creates a new secrets vault in the active environment. Vaults are zero-knowledge by default; a `virtual_worker` vault also carries a server-escrow key wrap for automated substitution.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
name | string | yes | |
description | string | no | |
type | string (enum) personalteamvirtual_worker | yes | Vault type. `virtual_worker` vaults carry a server-escrow key wrap. |
sealedVaultKey | string | yes | Vault key sealed to the creator's public key. |
serverEscrowWrap | string | no | Vault key wrapped to the server escrow KEM public key (required for `virtual_worker` type). |
Responses
| Status | Description |
201 | Vault created. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
201 response body: data fields
| Field | Type | Description |
id | string<uuid> | |
name | string | |
type | string | |
created_at | string<date-time> | |
role | string | Caller's role in this vault. |
GET /v1/secrets/vaults/{vaultId}
Get vault metadata
Returns metadata for a specific vault. Membership is required to access the vault. No ciphertext is returned.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
vaultId | path | string<uuid> | yes | Vault ID. |
Responses
| Status | Description |
200 | Vault metadata. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
200 response body: data fields
| Field | Type | Description |
id | string<uuid> | |
name | string | |
type | string | |
created_at | string<date-time> | |
role | string | Caller's role in this vault. |
PATCH /v1/secrets/vaults/{vaultId}
Update vault metadata
Updates the name or description of a vault. Requires vault owner or manager role.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
vaultId | path | string<uuid> | yes | Vault ID. |
Request Body
| Field | Type | Required | Description |
name | string | no | Vault display name. |
description | string | no | Optional vault description. |
Responses
| Status | Description |
200 | Vault updated. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Insufficient vault role. `error.code`: `FORBIDDEN`. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
200 response body: data fields
| Field | Type | Description |
id | string<uuid> | |
name | string | |
type | string | |
created_at | string<date-time> | |
role | string | Caller's role in this vault. |
DELETE /v1/secrets/vaults/{vaultId}
Delete a vault
Permanently deletes a vault and all its encrypted items. Requires vault owner role. Requires MFA step-up.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
vaultId | path | string<uuid> | yes | Vault ID. |
Responses
| Status | Description |
200 | Vault deleted. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | MFA step-up required or insufficient vault role. `error.code`: `MFA_STEPUP_REQUIRED` or `FORBIDDEN`. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
GET /v1/secrets/vaults/{vaultId}/items
List vault items (metadata only)
Returns item metadata for all items in a vault. The server never returns ciphertext from the AI-accessible metadata endpoint — only name, type, created-at, and tags.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
vaultId | path | string<uuid> | yes | Vault ID. |
Responses
| Status | Description |
200 | Item metadata list. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
POST /v1/secrets/vaults/{vaultId}/items
Create a vault item
Stores an encrypted vault item. The encrypted content blob is passed through opaque — the server never decrypts it. Requires vault membership.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
vaultId | path | string<uuid> | yes | Vault ID. |
Request Body
| Field | Type | Required | Description |
name | string | yes | Item display name. |
type | string | yes | Item type (e.g., `login`, `note`, `api_key`). |
encContent | string | yes | Encrypted item content blob (opaque to server). |
itemSalt | string | yes | Per-item salt for AAD derivation. |
tags | array of string | no | Optional searchable tags. |
Responses
| Status | Description |
201 | Item created. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Not a vault member. `error.code`: `FORBIDDEN`. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
GET /v1/secrets/vaults/{vaultId}/items/{itemId}
Get an encrypted vault item
Returns the encrypted content blob for a vault item. Only vault members may retrieve items. The server does not decrypt the content.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
vaultId | path | string<uuid> | yes | Vault ID. |
itemId | path | string<uuid> | yes | Item ID. |
Responses
| Status | Description |
200 | Encrypted item. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Not a vault member. `error.code`: `FORBIDDEN`. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
PUT /v1/secrets/vaults/{vaultId}/items/{itemId}
Update a vault item
Replaces the encrypted content blob of an existing vault item. Requires vault membership.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
vaultId | path | string<uuid> | yes | Vault ID. |
itemId | path | string<uuid> | yes | Item ID. |
Request Body
| Field | Type | Required | Description |
name | string | yes | Item display name. |
type | string | yes | Item type (e.g., `login`, `note`, `api_key`). |
encContent | string | yes | Encrypted item content blob (opaque to server). |
itemSalt | string | yes | Per-item salt for AAD derivation. |
tags | array of string | no | Optional searchable tags. |
Responses
| Status | Description |
200 | Item updated. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Not a vault member. `error.code`: `FORBIDDEN`. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
DELETE /v1/secrets/vaults/{vaultId}/items/{itemId}
Delete a vault item
Moves an item to the trash. Requires vault membership.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
vaultId | path | string<uuid> | yes | Vault ID. |
itemId | path | string<uuid> | yes | Item ID. |
Responses
| Status | Description |
200 | Item moved to trash. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Not a vault member. `error.code`: `FORBIDDEN`. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
GET /v1/secrets/vaults/{vaultId}/members
List vault members
Returns the membership list for a vault. Only vault members may view this list. Non-human members cannot be added.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
vaultId | path | string<uuid> | yes | Vault ID. |
Responses
| Status | Description |
200 | Vault member list. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
POST /v1/secrets/vaults/{vaultId}/members
Add a member to a vault
Adds a user to a vault with an assigned role (`member`, `manager`, or `owner`). Requires vault manager or owner role. Non-human accounts cannot be added (`403 TARGET_NOT_ELIGIBLE`).
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
vaultId | path | string<uuid> | yes | Vault ID. |
Request Body
| Field | Type | Required | Description |
user_id | string<uuid> | yes | User to add. |
role | string (enum) membermanagerowner | yes | Vault role. |
sealed_vault_key | string | yes | Client-encrypted vault key sealed to the new member's public key. |
Responses
| Status | Description |
200 | Member added. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Non-human target or insufficient role. `error.code`: `TARGET_NOT_ELIGIBLE` or `FORBIDDEN`. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
DELETE /v1/secrets/vaults/{vaultId}/members/{userId}
Remove a member from a vault
Removes a user from a vault. Requires vault manager or owner role.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
vaultId | path | string<uuid> | yes | Vault ID. |
userId | path | string<uuid> | yes | User ID to remove. |
Responses
| Status | Description |
200 | Member removed. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Insufficient vault role. `error.code`: `FORBIDDEN`. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
GET /v1/themes
List themes
Returns all themes available to the caller's organization, including system themes and custom org themes.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Theme list. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
200 response body: data fields
| Field | Type | Description |
themes | array of object | |
POST /v1/themes
Create a theme
Creates a new custom theme. The request must include either `theme_data` (a complete theme object) or all three of `colors`, `typography`, and `layout`. The `name` is required and must be 1–255 characters.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
name | string | yes | Theme display name. |
description | string | no | |
is_dark | boolean | no | |
is_default | boolean | no | |
status | string (enum) activedraftarchived | no | |
colors | object | no | Color token map. |
typography | object | no | Typography token map. |
layout | object | no | Layout token map. |
theme_data | object | no | Complete theme data object (alternative to colors+typography+layout). |
Responses
| Status | Description |
201 | Theme created. |
400 | Validation error. `error.code`: `VALIDATION_ERROR` or `INVALID_JSON`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
201 response body: data fields
| Field | Type | Description |
id | string<uuid> | |
name | string | |
status | string (enum) activedraftarchived | |
is_dark | boolean | |
is_default | boolean | |
created_at | string<date-time> | |
GET /v1/themes/{themeId}
Get a theme
Returns the full definition of a theme by ID.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
themeId | path | string<uuid> | yes | Theme ID. |
Responses
| Status | Description |
200 | Theme details. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
200 response body: data fields
| Field | Type | Description |
id | string<uuid> | |
name | string | |
status | string (enum) activedraftarchived | |
is_dark | boolean | |
is_default | boolean | |
created_at | string<date-time> | |
PUT /v1/themes/{themeId}
Update a theme
Replaces a theme's definition. Only custom org themes may be modified. The same `theme_data` vs `colors+typography+layout` rule applies as on create.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
themeId | path | string<uuid> | yes | Theme ID. |
Request Body
| Field | Type | Required | Description |
name | string | yes | Theme display name. |
description | string | no | |
is_dark | boolean | no | |
is_default | boolean | no | |
status | string (enum) activedraftarchived | no | |
colors | object | no | Color token map. |
typography | object | no | Typography token map. |
layout | object | no | Layout token map. |
theme_data | object | no | Complete theme data object (alternative to colors+typography+layout). |
Responses
| Status | Description |
200 | Theme updated. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Attempting to modify a system theme. `error.code`: `FORBIDDEN`. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
409 | Duplicate theme name. `error.code`: `CONFLICT`. |
200 response body: data fields
| Field | Type | Description |
id | string<uuid> | |
name | string | |
status | string (enum) activedraftarchived | |
is_dark | boolean | |
is_default | boolean | |
created_at | string<date-time> | |
GET /v1/tickets
List support tickets
Returns a paginated list of helpdesk tickets for the caller's organization. Supports limit/offset pagination and optional status/priority filters.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
limit | query | integer | no | Maximum number of records to return. Default and ceiling are endpoint-specific (commonly default 25–50, max 100). |
offset | query | integer | no | Number of records to skip for offset pagination. |
status | query | string (enum) | no | Filter by ticket status. |
priority | query | string (enum) | no | Filter by ticket priority. |
Responses
| Status | Description |
200 | Ticket list. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
200 response body: data fields
| Field | Type | Description |
tickets | array of object | |
pagination | object | Pagination metadata. Endpoints use either page/pageSize or limit/offset style; fields present depend on the endpoint. |
POST /v1/tickets
Create a support ticket
Creates a new helpdesk support ticket. Request body is capped at 768 KB. An optional `repro` object attaches a structured issue-reproduction recording to the ticket.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
title | string | yes | Ticket title. |
body | string | no | Initial ticket description (up to 100,000 characters). |
saas_package_id | string | no | SaaS package ID (hex UUID format) to scope the ticket. |
category | string | no | Category key. |
priority | string (enum) lownormalhighurgent | no | Ticket priority. |
source | string (enum) webchatapi | no | Origin channel. |
context | object | no | Arbitrary JSON context object (max 32 KB). |
repro | object | no | Optional structured issue-reproduction recording. |
Responses
| Status | Description |
201 | Ticket created. |
400 | Validation error. `error.code`: `VALIDATION_ERROR` or `INVALID_JSON`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
413 | Request body exceeds the 768 KB limit. `error.code`: `PAYLOAD_TOO_LARGE`. |
201 response body: data fields
| Field | Type | Description |
id | string<uuid> | |
title | string | |
status | string (enum) opentriagein_progresswaiting_customerresolvedclosed | |
priority | string (enum) lownormalhighurgent | |
category | string | null | |
created_at | string<date-time> | |
updated_at | string<date-time> | |
GET /v1/tickets/{ticketId}
Get a support ticket
Returns full ticket details including messages and metadata.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
ticketId | path | string<uuid> | yes | Ticket ID. |
Responses
| Status | Description |
200 | Ticket details. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
200 response body: data fields
| Field | Type | Description |
id | string<uuid> | |
title | string | |
status | string (enum) opentriagein_progresswaiting_customerresolvedclosed | |
priority | string (enum) lownormalhighurgent | |
category | string | null | |
created_at | string<date-time> | |
updated_at | string<date-time> | |
PATCH /v1/tickets/{ticketId}
Update a support ticket
Updates mutable ticket fields (priority, category). All fields are optional.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
ticketId | path | string<uuid> | yes | Ticket ID. |
Request Body
| Field | Type | Required | Description |
priority | string (enum) lownormalhighurgent | no | |
category | string | no | |
Responses
| Status | Description |
200 | Ticket updated. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
200 response body: data fields
| Field | Type | Description |
id | string<uuid> | |
title | string | |
status | string (enum) opentriagein_progresswaiting_customerresolvedclosed | |
priority | string (enum) lownormalhighurgent | |
category | string | null | |
created_at | string<date-time> | |
updated_at | string<date-time> | |
GET /v1/tickets/{ticketId}/agent
Get full ticket details (agent view)
Returns full ticket details including internal messages and agent metadata. Intended for helpdesk agents.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
ticketId | path | string<uuid> | yes | Ticket ID. |
Responses
| Status | Description |
200 | Full ticket (agent view). |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | Insufficient permissions. `error.code`: `FORBIDDEN`. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
PATCH /v1/tickets/{ticketId}/assign
Assign a ticket
Assigns a ticket to a human agent, AI agent, virtual worker, or unassigns it.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
ticketId | path | string<uuid> | yes | Ticket ID. |
Request Body
| Field | Type | Required | Description |
assignee_kind | string (enum) humanagentvirtual_workerunassigned | yes | Type of assignee. |
assignee_id | string<uuid> | no | ID of the assignee. Required unless `assignee_kind` is `unassigned`. |
Responses
| Status | Description |
200 | Ticket assigned. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
200 response body: data fields
| Field | Type | Description |
id | string<uuid> | |
title | string | |
status | string (enum) opentriagein_progresswaiting_customerresolvedclosed | |
priority | string (enum) lownormalhighurgent | |
category | string | null | |
created_at | string<date-time> | |
updated_at | string<date-time> | |
POST /v1/tickets/{ticketId}/csat
Submit CSAT rating for a ticket
Records a customer satisfaction score (1–5) and optional comment for a resolved or closed ticket.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
ticketId | path | string<uuid> | yes | Ticket ID. |
Request Body
| Field | Type | Required | Description |
score | integer | yes | CSAT score from 1 (very dissatisfied) to 5 (very satisfied). |
comment | string | no | Optional free-text comment. |
Responses
| Status | Description |
200 | CSAT recorded. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
POST /v1/tickets/{ticketId}/merge
Merge a ticket into another
Merges this ticket into a target ticket identified by `target_id`. The source ticket is closed after merging.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
ticketId | path | string<uuid> | yes | Ticket ID to merge from. |
Request Body
| Field | Type | Required | Description |
target_id | string<uuid> | yes | ID of the ticket to merge into. |
Responses
| Status | Description |
200 | Tickets merged. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
POST /v1/tickets/{ticketId}/messages
Add a message to a ticket
Appends a message to an existing ticket. Supports `text` and `latex` body formats. Attachments can reference documents or sheets by ID. Up to 10 attachments are allowed.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
ticketId | path | string<uuid> | yes | Ticket ID. |
Request Body
| Field | Type | Required | Description |
body | string | yes | Message body. |
visibility | string (enum) publicinternal | no | Message visibility; `internal` is only visible to agents. |
body_format | string (enum) textlatex | no | Formatting hint for the message body. |
attachments | array of object | no | |
Responses
| Status | Description |
201 | Message added. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
GET /v1/tickets/{ticketId}/repro
Get ticket issue-reproduction recording
Returns the structured issue-reproduction recording (ZA appendix) attached to the ticket at creation.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
ticketId | path | string<uuid> | yes | Ticket ID. |
Responses
| Status | Description |
200 | Reproduction recording. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
PATCH /v1/tickets/{ticketId}/snooze
Snooze or unsnooze a ticket
Sets or clears the snooze time on a ticket. Pass `snooze_until: null` to unsnooze.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
ticketId | path | string<uuid> | yes | Ticket ID. |
Request Body
| Field | Type | Required | Description |
snooze_until | string | null | no | ISO 8601 timestamp to snooze until, or `null` to unsnooze. |
Responses
| Status | Description |
200 | Snooze updated. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
200 response body: data fields
| Field | Type | Description |
id | string<uuid> | |
title | string | |
status | string (enum) opentriagein_progresswaiting_customerresolvedclosed | |
priority | string (enum) lownormalhighurgent | |
category | string | null | |
created_at | string<date-time> | |
updated_at | string<date-time> | |
POST /v1/tickets/{ticketId}/status
Update ticket status
Transitions a ticket to a new status.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
ticketId | path | string<uuid> | yes | Ticket ID. |
Request Body
| Field | Type | Required | Description |
status | string (enum) opentriagein_progresswaiting_customerresolvedclosed | yes | New ticket status. |
Responses
| Status | Description |
200 | Status updated. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
200 response body: data fields
| Field | Type | Description |
id | string<uuid> | |
title | string | |
status | string (enum) opentriagein_progresswaiting_customerresolvedclosed | |
priority | string (enum) lownormalhighurgent | |
category | string | null | |
created_at | string<date-time> | |
updated_at | string<date-time> | |
POST /v1/tickets/{ticketId}/watch
Toggle watching a ticket
Toggles the caller's watch status on a ticket (watch/unwatch).
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
ticketId | path | string<uuid> | yes | Ticket ID. |
Responses
| Status | Description |
200 | Watch status toggled. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
GET /v1/tickets/{ticketId}/watchers
Get ticket watchers
Returns the list of users watching this ticket.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
ticketId | path | string<uuid> | yes | Ticket ID. |
Responses
| Status | Description |
200 | Watcher list. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
GET /v1/tickets/attach-documents
Search documents attachable to a ticket
Returns a list of documents accessible to the caller that can be attached to a ticket message. Supports optional `q` search parameter.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
q | query | string | no | Search query to filter documents. |
Responses
| Status | Description |
200 | Attachable document list. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
GET /v1/tickets/canned-responses
List canned responses
Returns saved canned responses for the caller's organization.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Canned response list. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
POST /v1/tickets/canned-responses
Create a canned response
Creates a new canned response for use in ticket replies.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
name | string | yes | |
body | string | yes | |
category_key | string | no | |
Responses
| Status | Description |
201 | Canned response created. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
DELETE /v1/tickets/canned-responses/{cannedId}
Delete a canned response
Deletes a saved canned response by ID.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
cannedId | path | string<uuid> | yes | Canned response ID. |
Responses
| Status | Description |
200 | Canned response deleted. |
400 | Invalid ID format. `error.code`: `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
GET /v1/tickets/categories
List ticket categories
Returns the ticket category taxonomy for the caller's organization.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Category list. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
POST /v1/tickets/categories
Create a ticket category
Creates a new ticket category.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
key | string | yes | |
label | string | yes | |
description | string | no | |
parent_key | string | no | |
Responses
| Status | Description |
201 | Category created. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
DELETE /v1/tickets/categories/{categoryId}
Delete a ticket category
Deletes a ticket category by ID.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
categoryId | path | string<uuid> | yes | Category ID. |
Responses
| Status | Description |
200 | Category deleted. |
400 | Invalid ID format. `error.code`: `INVALID_ID_FORMAT`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
GET /v1/tickets/mine
List the caller's own tickets
Returns tickets submitted by the authenticated user.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
limit | query | integer | no | Maximum number of tickets to return. |
Responses
| Status | Description |
200 | Caller's ticket list. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
GET /v1/tickets/requester-categories
List ticket categories for requesters
Returns the categories visible to a requester when filing a ticket. Supports optional `saas_package_id` filter.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
saas_package_id | query | string | no | SaaS package scope. |
Responses
| Status | Description |
200 | Requester category list. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
GET /v1/tickets/routing-rules
List ticket routing rules
Returns all routing rules defined for the caller's organization.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Routing rule list. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
POST /v1/tickets/routing-rules
Create a ticket routing rule
Creates a new routing rule for automatic ticket assignment based on category and priority.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
category_key | string | yes | Category to match. |
priority | string (enum) lownormalhighurgent | no | |
assignee_kind | string (enum) humanagentvirtual_worker | yes | |
assignee_id | string<uuid> | no | |
is_enabled | boolean | no | |
Responses
| Status | Description |
201 | Routing rule created. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
PUT /v1/tickets/routing-rules/{ruleId}
Update a ticket routing rule
Replaces a routing rule definition.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
ruleId | path | string<uuid> | yes | Routing rule ID. |
Request Body
| Field | Type | Required | Description |
category_key | string | yes | Category to match. |
priority | string (enum) lownormalhighurgent | no | |
assignee_kind | string (enum) humanagentvirtual_worker | yes | |
assignee_id | string<uuid> | no | |
is_enabled | boolean | no | |
Responses
| Status | Description |
200 | Routing rule updated. |
400 | Validation error. `error.code`: `VALIDATION_ERROR`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
DELETE /v1/tickets/routing-rules/{ruleId}
Delete a ticket routing rule
Deletes an existing ticket routing rule.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
ruleId | path | string<uuid> | yes | Routing rule ID. |
Responses
| Status | Description |
200 | Routing rule deleted. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |