Org-scoped administrative surfaces: per-key settings toggles, custom-domain lifecycle, control policies, URL-slug availability, visibility rules, bootstrap context, CCPA consumer-privacy rights, and legal-agreement signing.
GET /v1/bootstrap
Bootstrap session context
Returns, in a single response, the first-paint data slices needed to render the authenticated user's application shell: profile, organizations, projects, settings, and any other areas gated for the caller's entitlements. The payload is assembled by a single stored procedure in one database round-trip. Each slice is gated independently — a missing feature or permission never fails the overall response.
The response carries `ETag` (weak hash) and `Cache-Control: private, max-age=15, stale-while-revalidate=60` headers. Clients should send `If-None-Match` with the stored ETag on subsequent calls; an unchanged payload returns `304 Not Modified` with no body.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
If-None-Match | header | string | no | Previously received weak ETag (e.g. `W/"a3f9b2c1"`). If the payload has not changed the server returns `304 Not Modified` with no body. |
Responses
| Status | Description |
200 | Bootstrap context. Includes ETag and Cache-Control headers for conditional GET support. |
304 | Not Modified — the payload has not changed since the provided `If-None-Match` ETag. No body is returned. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
user | object | null | The authenticated user's profile slice. |
organizations | array | null | Organizations the caller belongs to. |
projects | array | null | First-paint project slice for the active organization. |
settings | object | null | Org and user settings slice. |
GET /v1/ccpa/data-categories-collected
CCPA: data categories collected
Returns the categories of personal information Backbuild has collected about the authenticated consumer in the preceding 12 months, including the categories of sources, the business or commercial purposes for collection, and the categories of third parties with whom the information has been shared. Satisfies CCPA §1798.110 (right to know categories collected) and §1798.115 (right to know categories sold or shared) in the read-only, machine-readable form contemplated by §1798.130(a)(5).
The `since` parameter is informational — the enumerated categories are not window-dependent — but is recorded in the response for audit purposes.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
since | query | string<date-time> | no | Optional explicit start of the 12-month look-back window (RFC 3339 / ISO 8601). Defaults to 12 months before the request time when omitted. |
Responses
| Status | Description |
200 | CCPA data categories disclosure. |
400 | `VALIDATION_ERROR` — the `since` parameter is not a valid ISO 8601 datetime. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
consumer_user_id | string<uuid> | The authenticated consumer's user id. |
window_start | string<date-time> | Start of the look-back window (defaults to 12 months before the request). |
window_end | string<date-time> | End of the look-back window (time of the request). |
look_back_months | integer | Duration of the look-back window in months (always 12). |
sold_in_window | boolean | Whether any personal information was sold during the window. |
shared_for_cross_context_behavioural_advertising_in_window | boolean | Whether any personal information was shared for cross-context behavioural advertising during the window. |
categories | array of object | Enumerated categories of personal information. |
framework_references | array of string | Applicable statutory references. |
request_id | string | Correlation id for this disclosure request. |
POST /v1/ccpa/do-not-sell
CCPA opt-out: do not sell or share
Records that the authenticated consumer has exercised their CCPA/CPRA §1798.120 right to opt out of the sale or sharing of their personal information. The operation is idempotent — re-invocation by an already-opted-out consumer succeeds without advancing the original opt-out timestamp (the original instant anchors the §1798.135(c) 12-month wait-before-re-soliciting clock).
This endpoint is intentionally frictionless per CCPA §1798.135(a)(3): no MFA step-up is required. A valid authenticated session is required so the opt-out is bound to a verified consumer identity per §1798.130(a)(2) record-keeping obligations.
The request body may be omitted or sent as an empty JSON object `{}`. Any unknown keys are rejected with `400 VALIDATION_ERROR`.
Auth Session JWT (Bearer)
Request Body
Empty request body (strict object — no fields accepted).
{}
Responses
| Status | Description |
201 | Opt-out recorded (or confirmed as already active). Returns confirmation details. |
400 | `VALIDATION_ERROR` — the request body contains unexpected fields. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `FORBIDDEN` — the authenticated principal is not the consumer subject (callers may only opt themselves out). |
404 | `NOT_FOUND` — the authenticated user account does not exist. |
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 |
opted_out | boolean | Whether the consumer is now opted out of data sale and sharing. |
opted_out_at | string | null | Timestamp when the opt-out was first recorded (idempotent — this is the ORIGINAL opt-out instant, which anchors the §1798.135(c) 12-month wait-before-re-soliciting clock). |
idempotent | boolean | True if the consumer was already opted out before this call. |
GET /v1/legal-agreements/acceptances
List signed legal agreements
Returns all signed legal agreement acceptance records for the caller's organization, with optional filtering by template slug or status, and offset pagination. Gated by the `iam` system feature flag.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
template_slug | query | string | no | Filter by template slug (e.g. `dpa`). |
status | query | string (enum) | no | Filter by acceptance status. |
limit | query | integer | no | Maximum number of records to return (1–100, default 50). |
offset | query | integer | no | Number of records to skip. |
Responses
| Status | Description |
200 | Paginated list of acceptance records. |
400 | `VALIDATION_ERROR` — a query parameter has an invalid value. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `FORBIDDEN` — insufficient permissions to view agreements. |
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 |
acceptances | array of object | |
total_count | integer | Total matching records before pagination. |
GET /v1/legal-agreements/acceptances/{id}
Get a signed legal agreement
Returns a single legal agreement acceptance record by id. The acceptance must belong to the caller's organization. Gated by the `iam` system feature flag.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
id | path | string<uuid> | yes | Acceptance record identifier (UUIDv7). |
Responses
| Status | Description |
200 | The acceptance record. |
400 | `INVALID_ID_FORMAT` — the `id` is not a valid UUID. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `FORBIDDEN` — insufficient permissions to view agreements. |
404 | `NOT_FOUND` — the acceptance does not exist or belongs to another organization. |
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> | Acceptance record identifier (UUIDv7). |
org_id | string<uuid> | Organization that signed the agreement. |
template_id | string<uuid> | Template that was signed. |
template_slug | string | Slug of the signed template. |
document_hash | string | SHA-256 hex hash of the template content at time of signing. |
signature_hash | string | HMAC-SHA256 signature over the canonical signing payload, using the platform signing key. Provides non-repudiation. |
signer_name | string | Name of the signatory. |
signer_title | string | Title of the signatory. |
signer_email | string<email> | Email of the signatory. |
signer_company | string | Legal entity that signed. |
ip_address | string | IP address from which the signing request originated. |
user_agent | string | User-Agent header from the signing request. |
signed_at | string<date-time> | When the agreement was signed. |
pdf_generated | boolean | Whether a signed PDF was successfully generated and stored. |
status | string (enum) activesupersededrevoked | Current acceptance status. |
created_at | string<date-time> | When the acceptance record was created. |
GET /v1/legal-agreements/acceptances/{id}/pdf
Download signed agreement PDF
Downloads the signed PDF for a legal agreement acceptance. The PDF is served directly from durable object storage with `Content-Type: application/pdf` and `Content-Disposition: attachment`. The response carries `Cache-Control: private, no-store` to prevent caching of sensitive contract documents in shared or transparent caches. Gated by the `iam` system feature flag.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
id | path | string<uuid> | yes | Acceptance record identifier (UUIDv7). |
Responses
| Status | Description |
200 | The signed PDF binary. |
400 | `INVALID_ID_FORMAT` — the `id` is not a valid UUID. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `FORBIDDEN` — insufficient permissions to download agreements. |
404 | `NOT_FOUND` — the acceptance does not exist, belongs to another organization, or the signed PDF has not yet been stored. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/legal-agreements/sign
Sign a legal agreement
Signs a legal agreement template on behalf of the caller's organization. The signing flow:
1. Fetches the template and verifies its content hash for integrity.
2. Computes an HMAC-SHA256 signature over a canonical signing payload.
3. Records the acceptance in the database.
4. Generates a signed PDF and stores it durably.
5. Sends the signed PDF to the signer's email and any verified CC recipients.
PDF generation and durable storage are required for legal validity — if either step fails the acceptance record is rolled back and `500 INTERNAL_ERROR` is returned.
CC recipients must be active members of the signing organization; non-member addresses are rejected with `403 FORBIDDEN`. Maximum 5 CC recipients. Gated by the `iam` system feature flag.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
template_id | string<uuid> | yes | Identifier of the template to sign (must be an active template). |
signer_name | string | yes | Full legal name of the person signing on behalf of the organization. |
signer_title | string | yes | Job title of the signatory. |
signer_email | string<email> | yes | Email address of the signatory. A copy of the signed PDF is delivered here. |
signer_company | string | yes | Legal entity name of the signing organization. |
cc_recipients | array of object | no | Optional list of additional recipients (CC) for the signed-PDF email. Maximum 5 entries. Every CC email must belong to an active member of the signing organization — non-member addresses are rejected with `403 FORBIDDEN`. |
{
"template_id": "019d0000-0000-7000-8000-000000000001",
"signer_name": "Jane Smith",
"signer_title": "Chief Legal Officer",
"signer_email": "jane@acme.com",
"signer_company": "Acme Corp"
}
Responses
| Status | Description |
201 | Agreement signed and PDF stored. Returns the acceptance record plus `pdf_generated: true`. |
400 | `VALIDATION_ERROR` — a required field is missing, a field fails format validation, or the document integrity check failed. `UPLOAD_SUPPRESSED` — the generated PDF matched the platform deny list. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `FORBIDDEN` — insufficient permissions to sign agreements, or a CC recipient is not an active org member. |
404 | `NOT_FOUND` — the specified template does not exist or is not active. |
500 | `INTERNAL_ERROR` — PDF generation or durable storage failed; the acceptance record was rolled back. `DATABASE_ERROR` — the signing stored procedure failed. |
503 | `DATABASE_ERROR` — the upload suppression service was unavailable during the signing flow. The acceptance record was NOT committed. |
201 response body: data fields
| Field | Type | Description |
id | string<uuid> | Acceptance record identifier (UUIDv7). |
org_id | string<uuid> | Organization that signed the agreement. |
template_id | string<uuid> | Template that was signed. |
template_slug | string | Slug of the signed template. |
document_hash | string | SHA-256 hex hash of the template content at time of signing. |
signature_hash | string | HMAC-SHA256 signature over the canonical signing payload, using the platform signing key. Provides non-repudiation. |
signer_name | string | Name of the signatory. |
signer_title | string | Title of the signatory. |
signer_email | string<email> | Email of the signatory. |
signer_company | string | Legal entity that signed. |
ip_address | string | IP address from which the signing request originated. |
user_agent | string | User-Agent header from the signing request. |
signed_at | string<date-time> | When the agreement was signed. |
pdf_generated | boolean | Whether a signed PDF was successfully generated and stored. |
status | string (enum) activesupersededrevoked | Current acceptance status. |
created_at | string<date-time> | When the acceptance record was created. |
GET /v1/legal-agreements/templates
List active legal agreement templates
Returns the set of active legal agreement templates available for signing by the caller's organization (e.g. DPA, BAA, CCPA Addendum). Gated by the `iam` system feature flag.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | List of active templates. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `FORBIDDEN` — insufficient permissions to view agreement templates. |
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 |
templates | array of object | |
GET /v1/legal-agreements/templates/{slug}
Get a legal agreement template
Returns a single legal agreement template by slug, including its full markdown content. The slug is a short lowercase alphanumeric-with-hyphens identifier (e.g. `dpa`, `baa`). Gated by the `iam` system feature flag.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
slug | path | string | yes | Template slug (lowercase alphanumeric with hyphens, max 50 chars). |
Responses
| Status | Description |
200 | The template record with full markdown content. |
400 | `VALIDATION_ERROR` — the slug is empty, too long, or contains invalid characters. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `FORBIDDEN` — insufficient permissions to view agreement templates. |
404 | `NOT_FOUND` — no active template with that slug exists. |
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> | Template identifier (UUIDv7). |
slug | string | URL-safe slug identifying this template type (e.g. `dpa`, `baa`, `ccpa-addendum`). |
name | string | Human-readable template name. |
version | string | Template version string. |
content_hash | string | SHA-256 hex hash of the template markdown content (used for integrity verification). |
content_md | string | null | Full markdown content of the template (present on detail endpoint only). |
is_active | boolean | Whether the template is currently available for signing. |
created_at | string<date-time> | When the template was created. |
GET /v1/org/domains
List org custom domains
Returns all custom domains registered for the caller's organization, with optional status filter and offset pagination. Requires the `custom_domain.view` permission (held by owner/admin by default).
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
status | query | string (enum) | no | Filter by domain status. |
limit | query | integer | no | Maximum number of domains to return (1–200, default 50). |
offset | query | integer | no | Number of records to skip. |
Responses
| Status | Description |
200 | Paginated list of custom domains. |
400 | `INVALID_PARAMETER` — a query parameter has an invalid value. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `FORBIDDEN` — caller lacks `custom_domain.view` permission. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/org/domains
Register an org custom domain
Registers a new custom domain for the organization. The domain enters `pending_verification` state; call `POST /v1/org/domains/{domainId}/verify` to run DNS TXT verification. Requires `custom_domain.create` permission. The `api_base_url` must be an HTTPS URL (max 2048 chars); defaults to the environment's Backbuild API endpoint when omitted.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
domain | string | yes | Fully-qualified domain name to register (e.g. `app.acme.com`). Must match the pattern for valid hostnames (lowercase alphanumeric labels separated by dots). |
domain_type | string (enum) primaryaliassubdomain | no | Domain role classification. Defaults to `alias` when omitted. |
is_default | boolean | no | Whether this should be the default domain for the environment. Defaults to `true` when `domain_type` is `primary`. |
environment | string (enum) developmentstagingpreprodproduction | no | Target environment. Defaults to `production` when omitted. |
api_base_url | string | no | HTTPS URL for the Backbuild API that serves this domain (must begin with `https://`). Defaults to the standard endpoint for the chosen environment when omitted. |
{
"domain": "app.acme.com",
"domain_type": "primary",
"environment": "production"
}
Responses
| Status | Description |
201 | Domain registered. Returns the full domain record including the `dns_verification_token` to publish as a TXT record at `_backbuild-verify.<domain>`. |
400 | `VALIDATION_ERROR` — the domain name is invalid, a field fails validation, or the body is not valid JSON (`INVALID_JSON`). |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `FORBIDDEN` — caller lacks `custom_domain.create` permission. |
409 | `DOMAIN_ALREADY_EXISTS` — a domain with that hostname is already registered (globally unique). |
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> | Domain record identifier (UUIDv7). |
org_id | string<uuid> | Owning organization identifier. |
saas_package_id | string | null | SaaS package this domain is scoped to, or null for org-level domains. |
domain | string | Fully-qualified domain name (lowercase). |
domain_type | string (enum) primaryaliassubdomain | Classification of the domain's role. |
is_default | boolean | Whether this is the default domain for the environment. |
environment | string (enum) developmentstagingpreprodproduction | Target environment this domain serves. |
api_base_url | string | null | HTTPS API base URL associated with this domain. |
status | string (enum) pending_verificationactivesuspendeddeleted | Current lifecycle status. |
dns_verification_token | string | null | Opaque token to publish as a TXT record at `_backbuild-verify.<domain>` to prove ownership. |
verified_at | string | null | When the domain passed DNS verification. |
created_at | string<date-time> | When the record was created. |
updated_at | string<date-time> | When the record was last modified. |
GET /v1/org/domains/{domainId}
Get an org custom domain
Returns a single custom domain record by id. A domain not visible to the caller (wrong org or not found) is reported as `404 NOT_FOUND`. Requires `custom_domain.view` permission.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
domainId | path | string<uuid> | yes | Custom domain identifier (UUIDv7). |
Responses
| Status | Description |
200 | The custom domain record. |
400 | `INVALID_ID_FORMAT` — `domainId` is not a valid UUID. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `FORBIDDEN` — caller lacks `custom_domain.view` permission. |
404 | `NOT_FOUND` — domain does not exist or belongs to another organization. |
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> | Domain record identifier (UUIDv7). |
org_id | string<uuid> | Owning organization identifier. |
saas_package_id | string | null | SaaS package this domain is scoped to, or null for org-level domains. |
domain | string | Fully-qualified domain name (lowercase). |
domain_type | string (enum) primaryaliassubdomain | Classification of the domain's role. |
is_default | boolean | Whether this is the default domain for the environment. |
environment | string (enum) developmentstagingpreprodproduction | Target environment this domain serves. |
api_base_url | string | null | HTTPS API base URL associated with this domain. |
status | string (enum) pending_verificationactivesuspendeddeleted | Current lifecycle status. |
dns_verification_token | string | null | Opaque token to publish as a TXT record at `_backbuild-verify.<domain>` to prove ownership. |
verified_at | string | null | When the domain passed DNS verification. |
created_at | string<date-time> | When the record was created. |
updated_at | string<date-time> | When the record was last modified. |
DELETE /v1/org/domains/{domainId}
Delete an org custom domain
Soft-deletes a custom domain. The domain is set to `deleted` status and removed from active routing. Requires `custom_domain.delete` permission.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
domainId | path | string<uuid> | yes | Custom domain identifier (UUIDv7). |
Responses
| Status | Description |
200 | The domain was deleted. Returns the deleted domain record. |
400 | `INVALID_ID_FORMAT` — `domainId` is not a valid UUID. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `FORBIDDEN` — caller lacks `custom_domain.delete` permission. |
404 | `NOT_FOUND` — domain does not exist or belongs to another organization. |
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> | Domain record identifier (UUIDv7). |
org_id | string<uuid> | Owning organization identifier. |
saas_package_id | string | null | SaaS package this domain is scoped to, or null for org-level domains. |
domain | string | Fully-qualified domain name (lowercase). |
domain_type | string (enum) primaryaliassubdomain | Classification of the domain's role. |
is_default | boolean | Whether this is the default domain for the environment. |
environment | string (enum) developmentstagingpreprodproduction | Target environment this domain serves. |
api_base_url | string | null | HTTPS API base URL associated with this domain. |
status | string (enum) pending_verificationactivesuspendeddeleted | Current lifecycle status. |
dns_verification_token | string | null | Opaque token to publish as a TXT record at `_backbuild-verify.<domain>` to prove ownership. |
verified_at | string | null | When the domain passed DNS verification. |
created_at | string<date-time> | When the record was created. |
updated_at | string<date-time> | When the record was last modified. |
POST /v1/org/domains/{domainId}/verify
Verify an org custom domain
Triggers a real-time DNS-over-HTTPS TXT lookup for `_backbuild-verify.<domain>` and hands the observed token to the platform. If the TXT record matches the stored `dns_verification_token`, the domain transitions to `active`. DNS propagation delays are the caller's responsibility — if the record has not propagated yet, re-invoke after propagation. Requires `custom_domain.update` permission.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
domainId | path | string<uuid> | yes | Custom domain identifier (UUIDv7). |
Responses
| Status | Description |
200 | Verification attempted. Check `status` in the returned domain record — `active` means the TXT record was found; `pending_verification` means the record was not observed yet. |
400 | `INVALID_ID_FORMAT` — `domainId` is not a valid UUID. `VALIDATION_ERROR` — domain is already verified or is in an invalid state for verification. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `FORBIDDEN` — caller lacks `custom_domain.update` permission. |
404 | `NOT_FOUND` — domain does not exist or belongs to another organization. |
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> | Domain record identifier (UUIDv7). |
org_id | string<uuid> | Owning organization identifier. |
saas_package_id | string | null | SaaS package this domain is scoped to, or null for org-level domains. |
domain | string | Fully-qualified domain name (lowercase). |
domain_type | string (enum) primaryaliassubdomain | Classification of the domain's role. |
is_default | boolean | Whether this is the default domain for the environment. |
environment | string (enum) developmentstagingpreprodproduction | Target environment this domain serves. |
api_base_url | string | null | HTTPS API base URL associated with this domain. |
status | string (enum) pending_verificationactivesuspendeddeleted | Current lifecycle status. |
dns_verification_token | string | null | Opaque token to publish as a TXT record at `_backbuild-verify.<domain>` to prove ownership. |
verified_at | string | null | When the domain passed DNS verification. |
created_at | string<date-time> | When the record was created. |
updated_at | string<date-time> | When the record was last modified. |
GET /v1/org/settings/{key}
Get an org setting
Returns the current value for a single org-level configuration key. Readable by any active member of the organization. The key is a short slug (≤200 chars) identifying the setting; unknown keys return `404 NOT_FOUND`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
key | path | string | yes | Setting key slug (e.g. `conversation_public_sharing_allowed`). Maximum 200 characters. |
Responses
| Status | Description |
200 | The current setting value. |
400 | `VALIDATION_ERROR` — the key exceeds 200 characters or is empty. |
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` — no setting with that key exists for this organization. |
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 |
key | string | Setting key slug. |
value | string | null | Current setting value (stored as text; booleans appear as `"true"`/`"false"`). |
updated_at | string | null | When the setting was last modified. |
PUT /v1/org/settings/{key}
Upsert an org setting
Creates or replaces a single org-level configuration key. Requires admin or owner role (enforced by the stored procedure). The value is stored verbatim as text; the stored procedure normalises boolean-shaped strings. Only allowlisted keys can be written — unknown keys are rejected with `NOT_FOUND`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
key | path | string | yes | Setting key slug (e.g. `conversation_public_sharing_allowed`). Maximum 200 characters. |
Request Body
| Field | Type | Required | Description |
value | string | yes | New setting value (stored verbatim as text; the stored procedure normalises boolean-shaped strings). |
{
"value": "true"
}
Responses
| Status | Description |
200 | The setting was saved. Returns the updated setting record. |
400 | `VALIDATION_ERROR` — the key is invalid, the value exceeds 4096 characters, or the body is not valid JSON (`INVALID_JSON`). |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `FORBIDDEN` — the caller is not an admin or owner of the organization. |
404 | `NOT_FOUND` — the key is not in the allowlisted set of configurable settings. |
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 |
key | string | Setting key slug. |
value | string | null | Current setting value (stored as text; booleans appear as `"true"`/`"false"`). |
updated_at | string | null | When the setting was last modified. |
GET /v1/organizations
List organizations for the authenticated user
Returns all organizations the authenticated user is a member of, along with their active-organization context and roles. The list is RLS-scoped to the caller's account — the caller cannot enumerate organizations they do not belong to.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | List of the caller's organizations with membership context. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
organizations | array of object | Organizations the caller belongs to. |
POST /v1/organizations
Create an organization
Creates a new organization. The authenticated user becomes the owner. Requires the `org.update` permission on the current session. A URL-safe `slug` is auto-generated from the name when omitted; if a slug is supplied it must conform to the canonical grammar (lowercase alphanumeric groups separated by single hyphens, 3–63 chars, not UUID-shaped, not a reserved word). Returns the platform-assigned organization `id`.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
name | string | yes | Organization display name. |
slug | string | no | Optional canonical slug. Must be lowercase letters/numbers separated by single hyphens (no leading, trailing, or consecutive hyphens), not UUID-shaped, and not a reserved word. Auto-generated from the name when omitted. |
plan_tier | string (enum) freestarterprofessionalenterprise | no | Optional billing plan tier. |
org_type | string | no | Optional entity type (e.g. `llc`, `corp`, `nonprofit`). |
description | string | no | Optional description. |
logo_url | string<uri> | no | Optional logo URL. |
website | string<uri> | no | Optional website URL. |
billing_email | string<email> | no | Optional billing contact email. |
settings | object | no | Organization settings patch. All sub-objects are optional; only supplied keys are merged. |
{
"name": "Acme Corp",
"plan_tier": "starter"
}
Responses
| Status | Description |
201 | Organization created. The platform-assigned `id` is returned. |
400 | `INVALID_JSON` (unparseable body), `VALIDATION_ERROR` (a field failed validation, including a slug that fails the canonical grammar or is a reserved word). |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `PERMISSION_DENIED` — the caller lacks the `org.update` permission. |
409 | `CONFLICT` — an organization with the requested slug already exists. |
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> | The new organization's identifier (UUIDv7). |
GET /v1/organizations/{orgId}
Get an organization by UUID
Returns the full organization record for the given UUID. The caller must belong to the target organization; cross-tenant access returns `403 TENANT_ACCESS_DENIED`. A non-existent organization returns `404 ORG_NOT_FOUND`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
orgId | path | string<uuid> | yes | Organization identifier (UUIDv7). |
Responses
| Status | Description |
200 | The organization record. |
400 | `INVALID_ID_FORMAT` — `orgId` is not a valid UUID. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `TENANT_ACCESS_DENIED` — the caller is not a member of this organization. |
404 | `ORG_NOT_FOUND` — the organization does not exist. |
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> | Organization identifier (UUIDv7). |
name | string | Display name (1–255 characters). |
slug | string | null | Optional URL-safe slug (3–63 chars, canonical grammar). Null when not set. |
plan_tier | string (enum) freestarterprofessionalenterprisenull | Billing plan tier. |
logo_url | string | null | URL to the organization logo. |
is_active | boolean | Whether the organization is active. |
settings | object | Organization settings object. Contains profile, billing_address, shipping_address, policies, and contacts sub-objects. |
created_at | string<date-time> | Creation timestamp (platform-assigned). |
updated_at | string<date-time> | Last-update timestamp. |
PUT /v1/organizations/{orgId}
Update an organization
Updates organization fields. Requires the `org.update` permission. At least one field must be present. Top-level shorthand fields (`description`, `website`, `billing_email`, `org_type`) are merged into the `settings.profile` sub-object. Passing `slug: null` clears the optional slug; passing a slug string sets it (must satisfy the canonical grammar). A reserved or syntactically-invalid slug is rejected as `400 VALIDATION_ERROR`. A slug collision returns `409 CONFLICT`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
orgId | path | string<uuid> | yes | Organization identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
name | string | no | New display name. |
slug | string | null | no | New canonical slug (same grammar as create), or `null` to clear the slug. |
description | string | no | New description. |
logo_url | string | null | no | New logo URL, or `null` to clear. |
website | string | null | no | New website URL, or `null` to clear. |
billing_email | string<email> | no | New billing contact email. |
settings | object | no | Organization settings patch. All sub-objects are optional; only supplied keys are merged. |
Responses
| Status | Description |
200 | Organization updated successfully. |
400 | `INVALID_JSON` (unparseable body), `INVALID_ID_FORMAT` (bad UUID), `VALIDATION_ERROR` (field validation failed, reserved slug, or invalid slug grammar). |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `TENANT_ACCESS_DENIED` (cross-org access) or `PERMISSION_DENIED` (missing `org.update` permission). |
404 | `ORG_NOT_FOUND` — the organization does not exist. |
409 | `CONFLICT` — the requested slug is already taken by another organization. |
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 |
updated | boolean (enum) true | |
GET /v1/organizations/{orgId}/members
List organization members
Returns the members of an organization with optional filtering by role or status, and offset pagination. The caller must belong to the target organization.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
orgId | path | string<uuid> | yes | Organization identifier (UUIDv7). |
role | query | string | no | Filter members by role (e.g. `owner`, `admin`, `member`). Omit to return all roles. |
status | query | string | no | Filter members by status (e.g. `active`, `invited`, `suspended`). Omit to return all statuses. |
limit | query | integer | no | Maximum number of members to return (1–100). |
offset | query | integer | no | Number of members to skip for pagination. |
Responses
| Status | Description |
200 | List of organization members. |
400 | `INVALID_ID_FORMAT` (bad UUID) or `INVALID_PARAMETER` (query params out of range). |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `TENANT_ACCESS_DENIED` — the caller is not a member of this organization. |
404 | `ORG_NOT_FOUND` — the organization does not exist. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/organizations/{orgId}/members
Add or update an organization member
Adds a user to the organization or updates an existing member's role and/or status. Requires the `org.manage_members` permission. Role escalation is subject to a role-hierarchy gate in the stored procedure — a caller cannot grant a role higher than their own. Self-modification and demotion of the sole owner are rejected as `409 CONFLICT`. The `email` field is optional; when the target user is visible to the caller via RLS, the platform resolves it automatically.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
orgId | path | string<uuid> | yes | Organization identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
user_id | string<uuid> | yes | The user to add or update (UUIDv7). |
role | string | yes | Role to grant. Callers cannot grant a role higher than their own. |
status | string | no | Optional membership status. |
email | string<email> | no | Optional email. Required when adding a user not yet visible to the caller via RLS (e.g. a cross-tenant invite). |
{
"user_id": "019b0000-0000-7000-8000-000000000000",
"role": "member"
}
Responses
| Status | Description |
201 | Member added or updated. Returns the membership record identifier. |
400 | `INVALID_JSON` (unparseable body), `INVALID_ID_FORMAT` (bad UUID), `VALIDATION_ERROR` (field validation failed or payload rejected by the stored procedure). |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `TENANT_ACCESS_DENIED` (cross-org), `PERMISSION_DENIED` / `FORBIDDEN` (missing `org.manage_members` or role-hierarchy escalation denied), or `MEMBER_LIMIT_REACHED` (the organization's plan member limit is reached). |
404 | `USER_NOT_FOUND` — the target user does not exist. |
409 | `CONFLICT` — self-role-change attempt or demotion of the sole organization owner. |
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> | The membership record identifier. |
DELETE /v1/organizations/{orgId}/members/{userId}
Remove an organization member
Removes a user from the organization. Requires the `org.manage_members` permission. A caller cannot remove themselves — the route rejects this with `400 VALIDATION_ERROR` before reaching the stored procedure. Removing the sole owner is rejected by the stored procedure as `409 CONFLICT`. Cross-organization access returns `403 TENANT_ACCESS_DENIED`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
orgId | path | string<uuid> | yes | Organization identifier (UUIDv7). |
userId | path | string<uuid> | yes | The user to remove (UUIDv7). |
Responses
| Status | Description |
200 | Member removed. |
400 | `INVALID_ID_FORMAT` (bad UUID for `orgId` or `userId`) or `VALIDATION_ERROR` (caller attempting to remove themselves). |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `TENANT_ACCESS_DENIED` (cross-org) or `PERMISSION_DENIED` / `FORBIDDEN` (missing `org.manage_members` or SP authz denial). |
404 | `USER_NOT_FOUND` — the user is not a member of this organization. |
409 | `CONFLICT` — cannot remove the sole owner of the organization. |
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 |
removed | boolean (enum) true | |
GET /v1/organizations/{orgId}/policies
Get org control policies
Returns the current control policies for the specified organization: session idle timeout, container concurrency cap, container daily-hours cap, AI daily spend cap, and any extra policy fields. Readable by any active member of the organization. The `orgId` path parameter must match the caller's active organization (super-admins may access any org).
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
orgId | path | string<uuid> | yes | Organization identifier (UUIDv7). |
Responses
| Status | Description |
200 | The organization's current control policies. |
400 | `INVALID_ID_FORMAT` — `orgId` is not a valid UUID. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `TENANT_ACCESS_DENIED` — the caller's active organization does not match `orgId`. `FORBIDDEN` — the stored procedure rejected the request. |
404 | `ORG_NOT_FOUND` — the organization does not exist. |
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 |
org_id | string<uuid> | Organization identifier. |
session_inactivity_timeout_minutes | integer | null | Session idle timeout in minutes. Null means the platform default applies. |
max_concurrent_containers | integer | null | Maximum number of concurrently running containers for this org. Null means the platform default applies. |
container_daily_hours_cap | integer | null | Maximum total container-hours per day across the org. Null means no cap beyond the platform default. |
ai_daily_spend_cap_micros | integer | null | Maximum AI spend in a calendar day, denominated in micro-USD (1 USD = 1,000,000 micros). Null means no cap. |
extra_policies | object | null | Extensible JSON bag for additional policy fields added in later releases. |
updated_at | string | null | When policies were last modified. |
PUT /v1/organizations/{orgId}/policies
Update org control policies
Partially updates control policies for the specified organization. At least one field must be present. Passing `null` for a numeric field clears the organization-specific override and reverts to the platform default. Requires the `org.manage_settings` permission. The update stored procedure also mirrors the effective idle timeout into the session layer. The `orgId` must match the caller's active organization (super-admins may update any org).
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
orgId | path | string<uuid> | yes | Organization identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
session_inactivity_timeout_minutes | integer | null | no | Session idle timeout in minutes (0–525600 = up to 1 year). Null clears the org override. |
max_concurrent_containers | integer | null | no | Maximum simultaneous running containers (0–100000). Null clears the org override. |
container_daily_hours_cap | integer | null | no | Daily container-hours cap (0–1000000). Null clears the org override. |
ai_daily_spend_cap_micros | integer | null | no | Daily AI spend cap in micro-USD (0–1,000,000,000,000,000). Null clears the org override. |
extra_policies | object | no | Additional policy fields (arbitrary JSON object). Merged into the existing `extra_policies` by the stored procedure. |
{
"session_inactivity_timeout_minutes": 60,
"max_concurrent_containers": 10
}
Responses
| Status | Description |
200 | Policies updated. Returns the full updated policies record. |
400 | `INVALID_ID_FORMAT` — `orgId` is not a valid UUID. `VALIDATION_ERROR` — a field failed validation, an unrecognised field was supplied, or no fields were provided (`INVALID_JSON` if the body is not parseable JSON). |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `TENANT_ACCESS_DENIED` — `orgId` does not match the caller's active organization. `FORBIDDEN` — caller lacks `org.manage_settings` permission. |
404 | `ORG_NOT_FOUND` — the organization does not exist. |
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 |
org_id | string<uuid> | Organization identifier. |
session_inactivity_timeout_minutes | integer | null | Session idle timeout in minutes. Null means the platform default applies. |
max_concurrent_containers | integer | null | Maximum number of concurrently running containers for this org. Null means the platform default applies. |
container_daily_hours_cap | integer | null | Maximum total container-hours per day across the org. Null means no cap beyond the platform default. |
ai_daily_spend_cap_micros | integer | null | Maximum AI spend in a calendar day, denominated in micro-USD (1 USD = 1,000,000 micros). Null means no cap. |
extra_policies | object | null | Extensible JSON bag for additional policy fields added in later releases. |
updated_at | string | null | When policies were last modified. |
GET /v1/organizations/{orgId}/settings/auth
Get organization auth policy
Returns the effective authentication settings for the organization (platform defaults merged with any per-organization overrides). Any authenticated member of the organization may call this endpoint; it does not require elevated permissions. Used by the login flow and UI to render policy-dependent controls.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
orgId | path | string<uuid> | yes | Organization identifier (UUIDv7). |
Responses
| Status | Description |
200 | Effective auth settings for the organization. |
400 | `INVALID_ID_FORMAT` — `orgId` is not a valid UUID. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `TENANT_ACCESS_DENIED` — the caller is not a member of this organization. |
404 | `ORG_NOT_FOUND` — the organization does not exist. |
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 |
session_duration_days | integer | Maximum session lifetime in days. |
concurrent_sessions_per_user_limit | integer | Maximum concurrent active sessions per user. |
passkey_satisfies_primary | boolean | When true, a passkey satisfies the primary authentication factor. |
allow_password_login | boolean | Whether password-based login is permitted for this organization. |
PUT /v1/organizations/{orgId}/settings/auth
Update organization auth policy
Updates the organization's authentication policy. Requires the `org.update_auth_settings` permission (narrower than the general `org.update` — auth-policy changes have their own audit grant). At least one field must be provided. Disabling all authentication methods is rejected as `400 VALIDATION_ERROR`. Cross-tenant writes are rejected both at the route layer and inside the stored procedure.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
orgId | path | string<uuid> | yes | Organization identifier (UUIDv7). |
Request Body
| Field | Type | Required | Description |
passkey_satisfies_primary | boolean | no | Allow a passkey to satisfy the primary factor. |
allow_password_login | boolean | no | Enable or disable password-based login. |
session_duration_days | integer | no | Session lifetime in days. |
concurrent_sessions_per_user_limit | integer | no | Maximum concurrent sessions per user. |
Responses
| Status | Description |
200 | Auth settings updated. Returns the org id and the resulting effective settings. |
400 | `INVALID_JSON` (unparseable body), `INVALID_ID_FORMAT` (bad UUID), `VALIDATION_ERROR` (field validation failed, all auth methods disabled, or no fields provided). |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `TENANT_ACCESS_DENIED` (cross-org) or `PERMISSION_DENIED` / `FORBIDDEN` (missing `org.update_auth_settings` permission). |
404 | `ORG_NOT_FOUND` — the organization does not exist. |
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 |
org_id | string<uuid> | The updated organization's identifier. |
effective_settings | object | Effective authentication settings for an organization (platform defaults merged with per-org overrides). |
GET /v1/organizations/by/{idOrSlug}
Get an organization by slug or UUID
Accepts either a canonical slug or a raw UUID as a path segment, resolves it to the organization, enforces that the resolved organization matches the caller's JWT-pinned organization (super-admins exempt), and returns the full organization record. Cross-organization access and missing resources both return `404` (anti-enumeration).
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
idOrSlug | path | string | yes | Organization UUID or canonical slug. Maximum 256 characters. |
Responses
| Status | Description |
200 | The full organization record. |
400 | `INVALID_PARAMETER` — `idOrSlug` is empty or exceeds 256 characters. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | `NOT_FOUND` — the identifier does not exist, or it resolves to an organization other than the caller's JWT-pinned organization (anti-enumeration). |
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. |
200 response body: data fields
| Field | Type | Description |
id | string<uuid> | Organization identifier (UUIDv7). |
name | string | Display name (1–255 characters). |
slug | string | null | Optional URL-safe slug (3–63 chars, canonical grammar). Null when not set. |
plan_tier | string (enum) freestarterprofessionalenterprisenull | Billing plan tier. |
logo_url | string | null | URL to the organization logo. |
is_active | boolean | Whether the organization is active. |
settings | object | Organization settings object. Contains profile, billing_address, shipping_address, policies, and contacts sub-objects. |
created_at | string<date-time> | Creation timestamp (platform-assigned). |
updated_at | string<date-time> | Last-update timestamp. |
GET /v1/organizations/resolve
Resolve an organization slug or UUID to its canonical record
Resolves a slug (or a UUID passed as `?slug=`) to the canonical organization UUID and metadata. The resolved organization must match the caller's JWT-pinned organization; cross-organization slug lookups return `404` to prevent enumeration. UUID-form input receives `Sunset`, `Deprecation`, and `Link: rel="alternate"` headers pointing to the canonical slug URL. The response is `private, max-age=0` — never cached in intermediaries.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
slug | query | string | yes | Organization slug (canonical human-readable form) or raw UUID. Maximum 256 characters. |
Responses
| Status | Description |
200 | Resolved organization identifier and canonical slug. |
400 | `INVALID_PARAMETER` — `slug` is missing or exceeds 256 characters. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | `NOT_FOUND` — the slug does not exist, or it resolves to an organization other than the caller's JWT-pinned organization (anti-enumeration: both cases are indistinguishable). |
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. |
200 response body: data fields
| Field | Type | Description |
org_id | string<uuid> | Canonical organization UUID. |
canonical_slug | string | null | The organization's canonical slug, if one is set. Null when the organization has no slug. |
GET /v1/settings/ai-skills
List AI skills (settings panel)
Returns the AI skills configured for the active organization, for display in the Settings → AI Skills panel. The `/v1/settings/skills` path is an alias for this endpoint.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | List of AI skills. |
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/settings/alert-rules
List alert rules (settings panel)
Returns alert rules configured for the active organization, for display in the Settings → Alert Rules panel.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | List of alert rules. |
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/settings/api-keys
List API keys (settings panel)
Returns the organization API keys visible to the authenticated user, for display in the Settings → API Keys panel. This is a convenience wrapper over the API-keys data for use by the settings UI.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | List of API keys. |
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/settings/automation
List automation rules (settings panel)
Returns automation rules configured for the active organization, for display in the Settings → Automation panel.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | List of automation rules. |
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/settings/billing
Get billing overview (settings panel)
Returns the billing overview for the active organization, for display in the Settings → Billing panel.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Billing overview data. |
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/settings/integrations
List integrations (settings panel)
Returns integrations configured for the authenticated user and active organization, for display in the Settings → Integrations panel.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | List of integrations. |
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/settings/notifications
Get notifications (settings panel)
Returns the user's notifications for display in the Settings → Notifications panel. Returns up to 50 records.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | List of notifications. |
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/settings/org
Get all organization settings
Returns the full organization settings object for the authenticated user's active organization. The response is the raw settings blob stored for the organization.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | The organization's settings object. |
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/settings/org
Update organization settings (batch)
Replaces or merges the organization settings object. Requires the `org.manage_settings` permission (enforced both in this route and inside the stored procedure as defense-in-depth). Emits a real-time `org_settings` change notification to connected collaborators. Returns the resulting settings object.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
settings | object | yes | Settings key-value map. Bounded by the platform JSONB size and depth limits. |
Responses
| Status | Description |
200 | Settings updated. Returns the resulting settings object. |
400 | `VALIDATION_ERROR` — the `settings` field is missing, not an object, or exceeds the bounded JSONB size/depth limit. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `FORBIDDEN` — the caller lacks the `org.manage_settings` permission. |
404 | `NOT_FOUND` — the organization does not exist. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
GET /v1/settings/org/{key}
Get a specific organization setting by key
Returns a single organization setting value looked up by its string key. Returns `404 NOT_FOUND` when the key does not exist in the organization's settings.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
key | path | string | yes | The setting key (1–200 characters). |
Responses
| Status | Description |
200 | The setting value. |
400 | `VALIDATION_ERROR` — the key is empty or exceeds 200 characters. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | `NOT_FOUND` — the key does not exist in the organization's settings. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
GET /v1/settings/personalization
Get personalization settings
Returns the authenticated user's personalization preferences in a normalized shape (`themeMode`, `language`, `stayLoggedInHours`, `notifications`). This is a read-only normalized view over the raw preferences; the raw preferences are available at `GET /v1/settings/preferences`.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Normalized personalization 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. |
200 response body: data fields
| Field | Type | Description |
themeMode | string (enum) lightdarksystem | UI color scheme preference. |
language | string | BCP-47 language tag (e.g. `en`, `fr`, `pt-BR`). |
stayLoggedInHours | integer (enum) 1824168720 | Preferred session lifetime in hours. Must be one of `1`, `8`, `24`, `168`, or `720`. The platform additionally clamps this to the organization's `session_duration_days` cap. |
notifications | object | Notification preferences. |
PUT /v1/settings/personalization
Update personalization settings
Accepts a flat personalization object and persists it as user preferences. All fields are required. The `stayLoggedInHours` value must be one of the discrete allowed choices (`1`, `8`, `24`, `168`, `720`); arbitrary integers are rejected. Returns the resulting normalized personalization.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
themeMode | string (enum) lightdarksystem | yes | UI color scheme preference. |
language | string | yes | BCP-47 language tag (e.g. `en`, `fr`, `pt-BR`). |
stayLoggedInHours | integer (enum) 1824168720 | no | Preferred session lifetime in hours. Must be one of `1`, `8`, `24`, `168`, or `720`. The platform additionally clamps this to the organization's `session_duration_days` cap. |
notifications | object | yes | Notification preferences. |
Responses
| Status | Description |
200 | Personalization updated. Returns the resulting normalized settings. |
400 | `VALIDATION_ERROR` — a required field is missing, `themeMode`/`language` are invalid, `stayLoggedInHours` is not one of the allowed discrete values, or a notification boolean is not a boolean. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
themeMode | string (enum) lightdarksystem | UI color scheme preference. |
language | string | BCP-47 language tag (e.g. `en`, `fr`, `pt-BR`). |
stayLoggedInHours | integer (enum) 1824168720 | Preferred session lifetime in hours. Must be one of `1`, `8`, `24`, `168`, or `720`. The platform additionally clamps this to the organization's `session_duration_days` cap. |
notifications | object | Notification preferences. |
GET /v1/settings/preferences
Get user preferences
Returns the raw user preferences object for the authenticated user within their active organization context. See also `GET /v1/settings/personalization` for a normalized view.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Raw user preferences object. |
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/settings/preferences
Update user preferences (batch)
Replaces or merges the user's preference object within the active organization context. Accepts a bounded JSONB preferences object. Returns the resulting preferences.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
preferences | object | yes | Preference key-value map. Bounded by the platform JSONB size and depth limits. |
Responses
| Status | Description |
200 | Preferences updated. Returns the resulting preferences object. |
400 | `VALIDATION_ERROR` — the `preferences` field is missing, not an object, or exceeds the bounded JSONB size/depth limit. |
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/settings/preferences/{key}
Get a specific user preference by key
Returns a single preference value for the authenticated user, looked up by its string key.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
key | path | string | yes | The preference key (1–200 characters). |
Responses
| Status | Description |
200 | The preference value. |
400 | `VALIDATION_ERROR` — the key is empty or exceeds 200 characters. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | `NOT_FOUND` — the preference key does not exist for this user. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
GET /v1/settings/profile
Get user profile (settings panel)
Returns the authenticated user's profile data for display in the Settings → Profile panel. Retrieves the full user profile from the stored procedure when available; falls back to the session's auth context (userId, email, orgId) if the stored procedure is not yet available.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | User profile data. |
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/settings/security
Get security settings (settings panel)
Returns the security settings for the active organization, for display in the Settings → Security panel.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Organization security 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. |
GET /v1/settings/skills
List AI skills — alias
Alias for `GET /v1/settings/ai-skills`. Provided because the web app SkillsPanel calls this path. Returns the same data.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | List of AI skills. |
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/settings/sync-config
Get sync configuration
Returns the synchronization configuration for the authenticated user's active organization. Used by clients to initialize their offline/sync layer.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Organization sync configuration. |
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/settings/views
List views (settings panel)
Returns saved views for the authenticated user and active organization, for display in the Settings → Views panel. Returns up to 100 records.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | List of views. |
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/slugs/availability
Check slug availability
Advisory check for whether a proposed slug is available for a given resource kind (`org`, `project`, or `package`). Returns `{ available, reason }` — the response NEVER identifies the current owner (anti-enumeration). This endpoint is rate-limited per authenticated user (60 requests/minute per user) and should be called from a debounced editor field. The result is advisory; DB uniqueness enforcement remains authoritative on the write path.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
kind | query | string (enum) | yes | The resource kind to check. |
slug | query | string | yes | Candidate slug to check (1–256 characters). Any non-empty bounded string is accepted so the stored procedure can return a precise reason (`invalid_format`, `reserved`, `uuid_shaped`, `taken`) for editor feedback. |
Responses
| Status | Description |
200 | Advisory availability result. The `Cache-Control: private, max-age=0, must-revalidate` header is always set; do not share or cache this response. |
400 | `INVALID_PARAMETER` — `kind` or `slug` is missing or invalid. `VALIDATION_ERROR` — the stored procedure rejected the input (e.g. malformed slug). |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | `FORBIDDEN` — the caller lacks the create/update permission required for the requested `kind`. |
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. |
200 response body: data fields
| Field | Type | Description |
available | boolean | Whether the slug is available for use. |
reason | string | null | Machine-readable reason when `available` is false: `taken` (already in use), `reserved` (reserved platform word), `invalid_format` (slug does not meet format rules), `uuid_shaped` (looks like a UUID and is disallowed), or `error` (lookup could not be completed). |
GET /v1/users/{userId}/data-export
Export user data (GDPR Data Subject Access Request)
Returns a machine-readable JSON bundle of all personal data the platform holds for the given user, fulfilling the data subject access right (GDPR Art. 15) and data portability right (GDPR Art. 20). The caller must be either the data subject themselves or a super-admin. Requires a fresh MFA step-up (within the last 5 minutes) and a valid Cloudflare Turnstile proof-of-human token. Rate limited to one export per target user per hour. The response is served with `Content-Disposition: attachment` and `Cache-Control: no-store`. If the audit log was truncated at the 50 000-row platform cap, the response carries `X-Export-Truncated: true` and a top-level `truncated: true` field.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
userId | path | string<uuid> | yes | The user whose data to export (UUID). Must match the authenticated user's own id, or the caller must be a super-admin. |
cf-turnstile-response | header | string | yes | Cloudflare Turnstile proof-of-human token. Also accepted as `x-turnstile-token`. Required to prevent automated bulk PII scraping. |
Responses
| Status | Description |
200 | Full personal data export. The `data` field contains all PII and records associated with the user. The optional `truncated: true` top-level flag and `X-Export-Truncated: true` response header indicate the audit log was capped at the platform limit. |
400 | `VALIDATION_ERROR` — `userId` is not a valid UUID format. |
401 | `AUTH_REQUIRED` / `MFA_STEPUP_REQUIRED` — authentication or fresh MFA step-up is missing. Also returned when the Turnstile proof-of-human check fails. |
403 | `FORBIDDEN` — the caller is not the data subject and is not a super-admin. |
404 | `USER_NOT_FOUND` — the target user does not exist. |
429 | `RATE_LIMIT_EXCEEDED` — the one-export-per-hour limit for this target user has been reached. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/visibility/check
Check resource visibility
Evaluates whether the target principal (user or group) can see a given resource, based on the caller's organization's visibility rules. Returns a structured verdict from the stored procedure. Requires an authenticated session; the caller's organization and user id scope the rule evaluation.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
resource_type | string | yes | The type of resource to check (e.g. `project`, `document`). |
resource_id | string<uuid> | yes | Identifier of the resource to evaluate. |
target_user_id | string<uuid> | no | User to evaluate visibility for. Defaults to the authenticated caller when omitted. |
target_group_id | string | null | no | Group to evaluate visibility for (optional). |
{
"resource_type": "project",
"resource_id": "019d0000-0000-7000-8000-000000000000"
}
Responses
| Status | Description |
200 | Visibility verdict from the stored procedure. |
400 | `VALIDATION_ERROR` — a required field is missing or has an invalid 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. |
200 response body: data fields
| Field | Type | Description |
visible | boolean | Whether the target principal can see the resource. |
rule_applied | string | null | Identifier of the rule that determined the outcome, or null if the default applied. |
effective_scope | string | null | The scope level at which the decisive rule was matched. |
GET /v1/visibility/rules
List visibility rules
Returns visibility rules for the caller's organization, with optional filtering by resource type, resource id, rule type, or scope. Results are offset-paginated.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
resource_type | query | string | no | Filter by resource type (e.g. `project`, `document`). |
resource_id | query | string<uuid> | no | Filter by resource identifier (UUIDv7). |
rule_type | query | string (enum) | no | Filter by rule type. |
scope | query | string (enum) | no | Filter by visibility scope. |
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. |
Responses
| Status | Description |
200 | Paginated list of visibility rules. |
400 | `VALIDATION_ERROR` — a query parameter has an invalid value. |
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/visibility/rules
Create a visibility rule
Creates a new visibility rule for a resource within the caller's organization. For scopes other than `global`, a `scope_id` (the target user, role, group, or project id) is required. The stored procedure enforces authorization; the caller must have sufficient permissions to manage visibility for the target resource.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
resource_type | string | yes | The type of resource this rule applies to. |
resource_id | string<uuid> | yes | Identifier of the resource this rule applies to. |
rule_type | string (enum) allowdeny | no | Whether the rule grants (`allow`) or denies (`deny`) visibility. Defaults to `allow` when omitted. |
scope | string (enum) globalorguserrolegroupdepartmentprojectorg_hierarchy | yes | Scope at which the rule applies. `scope_id` is required for all values except `global`. |
scope_id | string<uuid> | no | Identifier of the scope target (required unless `scope` is `global`). |
priority | integer | no | Evaluation priority (0–1000; higher = evaluated first). Defaults to 0. |
conditions | object | no | Optional additional conditions (bounded JSON object). |
expires_at | string<date-time> | no | Optional expiry timestamp (ISO 8601). The rule is automatically inactive after this time. |
metadata | object | no | Optional metadata (bounded JSON object). |
{
"resource_type": "project",
"resource_id": "019d0000-0000-7000-8000-000000000000",
"scope": "org",
"rule_type": "allow"
}
Responses
| Status | Description |
201 | The visibility rule was created. |
400 | `VALIDATION_ERROR` — a field failed validation (e.g. `scope_id` missing for non-`global` scope, invalid scope value). |
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. |
201 response body: data fields
| Field | Type | Description |
id | string<uuid> | Rule identifier (UUIDv7). |
org_id | string<uuid> | Owning organization. |
resource_type | string | Resource type this rule applies to. |
resource_id | string<uuid> | Resource this rule applies to. |
rule_type | string (enum) allowdeny | Whether this rule grants or denies visibility. |
scope | string (enum) globalorguserrolegroupdepartmentprojectorg_hierarchy | The scope to which this rule applies. |
scope_id | string | null | Identifier of the scope target (e.g. user id, role id). Null for `global` scope. |
priority | integer | Evaluation priority (higher value = evaluated first). |
conditions | object | null | Optional additional conditions (arbitrary JSON). |
expires_at | string | null | When the rule expires. Null means the rule never expires. |
metadata | object | null | Arbitrary metadata attached to this rule. |
created_by | string | null | User who created the rule. |
created_at | string<date-time> | When the rule was created. |
DELETE /v1/visibility/rules/{id}
Delete a visibility rule
Deletes a visibility rule by id. The caller must have permission to manage visibility for the resource covered by the rule.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
id | path | string<uuid> | yes | Visibility rule identifier (UUIDv7). |
Responses
| Status | Description |
200 | The rule was deleted. |
400 | `INVALID_ID_FORMAT` — `id` is not a valid UUID. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | `NOT_FOUND` — rule 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 |
deleted | boolean (enum) true | |