Organizations & Users

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.

55 endpoints. Generated from the OpenAPI 3.1 specification.

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

NameInTypeRequiredDescription
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

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
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

StatusDescription
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
FieldTypeDescription
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

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
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

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
id path string<uuid> yes Acceptance record identifier (UUIDv7).

Responses

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
id path string<uuid> yes Acceptance record identifier (UUIDv7).

Responses

StatusDescription
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

FieldTypeRequiredDescription
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

StatusDescription
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
FieldTypeDescription
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

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
slug path string yes Template slug (lowercase alphanumeric with hyphens, max 50 chars).

Responses

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
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

StatusDescription
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

FieldTypeRequiredDescription
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

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
domainId path string<uuid> yes Custom domain identifier (UUIDv7).

Responses

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
domainId path string<uuid> yes Custom domain identifier (UUIDv7).

Responses

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
domainId path string<uuid> yes Custom domain identifier (UUIDv7).

Responses

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
key path string yes Setting key slug (e.g. `conversation_public_sharing_allowed`). Maximum 200 characters.

Responses

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
key path string yes Setting key slug (e.g. `conversation_public_sharing_allowed`). Maximum 200 characters.

Request Body

FieldTypeRequiredDescription
value string yes New setting value (stored verbatim as text; the stored procedure normalises boolean-shaped strings).
{
  "value": "true"
}

Responses

StatusDescription
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
FieldTypeDescription
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

StatusDescription
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
FieldTypeDescription
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

FieldTypeRequiredDescription
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

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
orgId path string<uuid> yes Organization identifier (UUIDv7).

Responses

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
orgId path string<uuid> yes Organization identifier (UUIDv7).

Request Body

FieldTypeRequiredDescription
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

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
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

StatusDescription
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

NameInTypeRequiredDescription
orgId path string<uuid> yes Organization identifier (UUIDv7).

Request Body

FieldTypeRequiredDescription
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

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
orgId path string<uuid> yes Organization identifier (UUIDv7).
userId path string<uuid> yes The user to remove (UUIDv7).

Responses

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
orgId path string<uuid> yes Organization identifier (UUIDv7).

Responses

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
orgId path string<uuid> yes Organization identifier (UUIDv7).

Request Body

FieldTypeRequiredDescription
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

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
orgId path string<uuid> yes Organization identifier (UUIDv7).

Responses

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
orgId path string<uuid> yes Organization identifier (UUIDv7).

Request Body

FieldTypeRequiredDescription
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

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
idOrSlug path string yes Organization UUID or canonical slug. Maximum 256 characters.

Responses

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
slug query string yes Organization slug (canonical human-readable form) or raw UUID. Maximum 256 characters.

Responses

StatusDescription
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
FieldTypeDescription
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

StatusDescription
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

StatusDescription
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

StatusDescription
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

StatusDescription
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

StatusDescription
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

StatusDescription
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

StatusDescription
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

StatusDescription
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

FieldTypeRequiredDescription
settings object yes Settings key-value map. Bounded by the platform JSONB size and depth limits.

Responses

StatusDescription
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

NameInTypeRequiredDescription
key path string yes The setting key (1–200 characters).

Responses

StatusDescription
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

StatusDescription
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
FieldTypeDescription
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

FieldTypeRequiredDescription
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

StatusDescription
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
FieldTypeDescription
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

StatusDescription
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

FieldTypeRequiredDescription
preferences object yes Preference key-value map. Bounded by the platform JSONB size and depth limits.

Responses

StatusDescription
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

NameInTypeRequiredDescription
key path string yes The preference key (1–200 characters).

Responses

StatusDescription
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

StatusDescription
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

StatusDescription
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

StatusDescription
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

StatusDescription
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

StatusDescription
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

NameInTypeRequiredDescription
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

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
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

StatusDescription
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

FieldTypeRequiredDescription
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

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
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

StatusDescription
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

FieldTypeRequiredDescription
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

StatusDescription
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
FieldTypeDescription
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

NameInTypeRequiredDescription
id path string<uuid> yes Visibility rule identifier (UUIDv7).

Responses

StatusDescription
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
FieldTypeDescription
deleted boolean (enum) true