Sutra Admin API Reference
This static fallback includes the OpenAPI YAML so AI apps and non-JS clients can read the reference directly. In a browser, the interactive reference loads after JavaScript runs.
Download the OpenAPI YAML
---
openapi: 3.0.3
info:
title: Sutra Admin API
version: 1.1.0
license:
name: Proprietary
url: https://sutra.co/terms
description: |
Server-to-server Admin API for Sutra spaces, memberships, custom properties,
content, plans, surveys, coupons, broadcasts, automations, and page design drafts.
The Admin API accepts JSON only and authenticates with bearer credentials:
dedicated Sutra API tokens or OAuth-issued MCP access tokens. Silver and Gold
users can create tokens from Settings → Sutra API or authenticate the Sutra
MCP server with OAuth.
It is intentionally not callable from browser JavaScript: production responses do not
include CORS headers.
Start with the Guide tab for the API mental model, common workflows,
ID prefixes, scopes, pagination, idempotency, and error handling.
servers:
- url: https://api.sutra.co/api/admin/v1
tags:
- name: Me
description: Inspect the current API token user and their limited membership-space inventory.
- name: Spaces
description: Read and manage spaces authorized for the token user.
- name: Members
description: Add, update, remove, and inspect space memberships.
- name: Contacts
description: Inspect CRM contacts and update their member-property values.
- name: Member Properties
description: Manage custom member property definitions and per-member values.
- name: Space Properties
description: Manage custom space property definitions and per-space values.
- name: Invitations
description: Create, update, resend, and inspect invitations.
- name: Content
description: Manage content blocks inside spaces.
- name: Document
description: Read and mutate the visible Tiptap document inside spaces.
- name: Media
description: Create upload sessions, external media references, and read media processing status.
- name: Messages
description: Manage discussion messages inside spaces.
- name: Reflections
description: Manage reflections attached to messages.
- name: Surveys
description: Manage surveys and read survey submissions.
- name: Plans
description: Read and manage plans, enrollments, payments, and coupons.
- name: Broadcasts
description: Create drafts, send broadcasts, and inspect delivery status.
- name: Automations
description: "List automations, author automations and steps (incl. conditional logic & branching) with automations:manage, and manage member enrollments."
- name: Design
description: Read, validate, draft, publish, restore, and import assets for rendered space page designs.
security:
- bearerAuth: []
paths:
"/design/capabilities":
get:
tags:
- Design
summary: Get design capabilities
description: "Required scope: `design:read`. Returns the generated schema and exact per-node, UI-backed appearance contract used by Design API and MCP clients."
operationId: getAdminApiDesignCapabilities
x-required-scope: design:read
responses:
'200':
description: Design capability manifest.
content:
application/json:
schema:
"$ref": "#/components/schemas/DesignCapabilitiesResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
"/design/assets/import":
post:
tags:
- Design
summary: Import a design asset
description: "Required scope: `assets:write`. Fetches a public image URL, validates it, and re-hosts it on Sutra-controlled storage for use in design JSON."
operationId: importAdminApiDesignAsset
x-required-scope: assets:write
parameters:
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/DesignAssetImportRequest"
responses:
'201':
description: Asset imported.
content:
application/json:
schema:
"$ref": "#/components/schemas/DesignAssetResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
'422':
"$ref": "#/components/responses/ValidationFailed"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
"/spaces/{space_id}/design":
get:
tags:
- Design
summary: Get current space design
description: "Required scope: `design:read`. Returns the current rendered Tiptap design nodes, digest, protected-content summaries, and published URL for a space."
operationId: getAdminApiSpaceDesign
x-required-scope: design:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
responses:
'200':
description: Current page design.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpaceDesignResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/design/validate":
post:
tags:
- Design
summary: Validate design nodes
description: "Required scope: `design:write`. Validates proposed Tiptap design nodes and returns structured diagnostics without saving a draft."
operationId: validateAdminApiSpaceDesign
x-required-scope: design:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/DesignValidationRequest"
responses:
'200':
description: Design diagnostics.
content:
application/json:
schema:
"$ref": "#/components/schemas/DesignValidationResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
'422':
"$ref": "#/components/responses/ValidationFailed"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/design_drafts":
post:
tags:
- Design
summary: Create or update a design draft
description: "Required scope: `design:write`. Creates or updates the caller's open draft for a `client_draft_key` after validating `base_digest` against current live content."
operationId: createOrUpdateAdminApiDesignDraft
x-required-scope: design:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/DesignDraftMutationRequest"
responses:
'201':
description: Design draft created or updated.
content:
application/json:
schema:
"$ref": "#/components/schemas/DesignDraftMutationResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'409':
"$ref": "#/components/responses/Conflict"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
'422':
"$ref": "#/components/responses/ValidationFailed"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
"/spaces/{space_id}/design_drafts/{draft_id}":
get:
tags:
- Design
summary: Get a design draft
description: "Required scope: `design:read`. Returns draft nodes, digests, diagnostics, and the web-session preview URL."
operationId: getAdminApiDesignDraft
x-required-scope: design:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/DesignDraftId"
responses:
'200':
description: Design draft.
content:
application/json:
schema:
"$ref": "#/components/schemas/DesignDraftResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'429':
"$ref": "#/components/responses/RateLimited"
patch:
tags:
- Design
summary: Fully replace a design draft
description: "Required scope: `design:write`. Replaces the complete node document of an existing open draft after validating `base_digest` against current live content. Use the node-patch endpoint for incremental changes."
operationId: updateAdminApiDesignDraft
x-required-scope: design:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/DesignDraftId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/DesignDraftMutationRequest"
responses:
'200':
description: Design draft updated.
content:
application/json:
schema:
"$ref": "#/components/schemas/DesignDraftMutationResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/Conflict"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
'422':
"$ref": "#/components/responses/ValidationFailed"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
"/spaces/{space_id}/design_drafts/{draft_id}/publish":
post:
tags:
- Design
summary: Publish a design draft
description: "Required scope: `design:publish`. Publishes a draft when its `base_digest` is still current and destructive omissions have been explicitly confirmed."
operationId: publishAdminApiDesignDraftForSpace
x-required-scope: design:publish
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/DesignDraftId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: false
content:
application/json:
schema:
"$ref": "#/components/schemas/DesignDraftPublishRequest"
responses:
'200':
description: Draft published.
content:
application/json:
schema:
"$ref": "#/components/schemas/DesignDraftPublishResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/Conflict"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
'422':
"$ref": "#/components/responses/ValidationFailed"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/design_drafts/{draft_id}/restore":
post:
tags:
- Design
summary: Restore a published design draft
description: "Required scope: `design:publish`. Restores the pre-publish backup for a published draft, with live-digest protection unless explicitly forced."
operationId: restoreAdminApiDesignDraftForSpace
x-required-scope: design:publish
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/DesignDraftId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: false
content:
application/json:
schema:
"$ref": "#/components/schemas/DesignDraftRestoreRequest"
responses:
'200':
description: Draft restored.
content:
application/json:
schema:
"$ref": "#/components/schemas/DesignDraftRestoreResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/Conflict"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
'422':
"$ref": "#/components/responses/ValidationFailed"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/design_drafts/{draft_id}/preview_link":
post:
tags:
- Design
summary: Mint a shareable preview link for a draft
description: "Required scope: `design:read`. Returns a short-lived (~15 min), signed, read-only link that opens this draft's rendered preview in a browser with no Sutra login required. The token grants read-only preview of this single draft and nothing else."
operationId: createAdminApiDesignDraftPreviewLinkForSpace
x-required-scope: design:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/DesignDraftId"
responses:
'200':
description: Signed preview link.
content:
application/json:
schema:
"$ref": "#/components/schemas/DesignDraftPreviewLinkResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'429':
"$ref": "#/components/responses/RateLimited"
"/design_drafts/{draft_id}/publish":
post:
tags:
- Design
summary: Publish a design draft
description: "Required scope: `design:publish`. Publishes an authorized draft by draft id; this is the endpoint used by MCP clients after draft creation."
operationId: publishAdminApiDesignDraft
x-required-scope: design:publish
parameters:
- "$ref": "#/components/parameters/DesignDraftId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: false
content:
application/json:
schema:
"$ref": "#/components/schemas/DesignDraftPublishRequest"
responses:
'200':
description: Draft published.
content:
application/json:
schema:
"$ref": "#/components/schemas/DesignDraftPublishResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/Conflict"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
'422':
"$ref": "#/components/responses/ValidationFailed"
'429':
"$ref": "#/components/responses/RateLimited"
"/design_drafts/{draft_id}/restore":
post:
tags:
- Design
summary: Restore a published design draft
description: "Required scope: `design:publish`. Restores a published draft by draft id; this is the endpoint used by MCP clients for rollback."
operationId: restoreAdminApiDesignDraft
x-required-scope: design:publish
parameters:
- "$ref": "#/components/parameters/DesignDraftId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: false
content:
application/json:
schema:
"$ref": "#/components/schemas/DesignDraftRestoreRequest"
responses:
'200':
description: Draft restored.
content:
application/json:
schema:
"$ref": "#/components/schemas/DesignDraftRestoreResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/Conflict"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
'422':
"$ref": "#/components/responses/ValidationFailed"
'429':
"$ref": "#/components/responses/RateLimited"
"/design_drafts/{draft_id}/preview_link":
post:
tags:
- Design
summary: Mint a shareable preview link for a draft
description: "Required scope: `design:read`. Returns a short-lived (~15 min), signed, read-only link that opens this draft's rendered preview in a browser with no Sutra login required. Resolves the draft by id; this is the endpoint used by MCP clients after draft creation. The token grants read-only preview of this single draft and nothing else."
operationId: createAdminApiDesignDraftPreviewLink
x-required-scope: design:read
parameters:
- "$ref": "#/components/parameters/DesignDraftId"
responses:
'200':
description: Signed preview link.
content:
application/json:
schema:
"$ref": "#/components/schemas/DesignDraftPreviewLinkResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'429':
"$ref": "#/components/responses/RateLimited"
"/me":
get:
tags:
- Me
summary: Show the current token, application, and user
description: |
No scope required beyond a valid token. Returns the authenticated API application,
the token's user (email included), and the token's own metadata — its scopes,
environment, expiry, and any space-grant restrictions. Useful for confirming exactly
what a token can access.
operationId: showAdminApiMe
responses:
'200':
description: The current application, user, and token.
content:
application/json:
schema:
type: object
required:
- application
- user
- token
properties:
application:
type: object
properties:
id:
type: string
name:
type: string
status:
type: string
user:
"$ref": "#/components/schemas/User"
token:
type: object
properties:
id:
type: string
pattern: "^tok_"
name:
type: string
prefix:
type: string
scopes:
type: array
items:
type: string
environment:
type: string
enum:
- live
- test
expires_at:
type: string
format: date-time
nullable: true
space_grants:
type: array
items:
type: string
description: Space public IDs the token is restricted to; empty means all manageable spaces.
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
"/me/membership_spaces":
get:
tags:
- Me
summary: List the token user's membership spaces
description: |
Required scope: `membership_spaces:read`.
Lists active standard/readonly spaces where the API token's user has a non-disabled membership.
The response includes only basic space metadata plus the token user's own membership state.
It does not grant access to member lists, content, messages, properties, payments, or other
admin subresources. Token space restrictions, when present, are applied as an exact security limit.
operationId: listAdminApiMembershipSpaces
x-required-scope: membership_spaces:read
parameters:
- "$ref": "#/components/parameters/Limit"
- "$ref": "#/components/parameters/Cursor"
responses:
'200':
description: Cursor-paginated membership spaces.
content:
application/json:
schema:
"$ref": "#/components/schemas/MembershipSpaceListResponse"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'422':
"$ref": "#/components/responses/ValidationFailed"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces":
get:
tags:
- Spaces
summary: List authorized spaces
description: "Required scope: `spaces:read`."
operationId: listAdminApiSpaces
x-required-scope: spaces:read
parameters:
- "$ref": "#/components/parameters/Limit"
- "$ref": "#/components/parameters/Cursor"
- "$ref": "#/components/parameters/SearchQuery"
- "$ref": "#/components/parameters/SpaceStateFilter"
- "$ref": "#/components/parameters/SpaceTypeFilter"
- "$ref": "#/components/parameters/SpacePrivacyFilter"
responses:
'200':
description: Cursor-paginated spaces.
content:
application/json:
schema:
type: object
required:
- data
- pagination
properties:
data:
type: array
items:
"$ref": "#/components/schemas/Space"
pagination:
"$ref": "#/components/schemas/Pagination"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'422':
"$ref": "#/components/responses/ValidationFailed"
'429':
"$ref": "#/components/responses/RateLimited"
'400':
"$ref": "#/components/responses/BadRequest"
post:
tags:
- Spaces
summary: Create a space
description: |
Required scope: `spaces:write`.
Creates a new active top-level space for the API user when `parent_id` is omitted.
Include `parent_id`, or use `POST /spaces/{space_id}/children`, to create a direct
child under an authorized parent. Tokens restricted to specific spaces must
create under an authorized parent.
operationId: createAdminApiSpace
x-required-scope: spaces:write
parameters:
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/SpaceCreateRequest"
examples:
contentSpace:
value:
name: Onboarding Program
description: Start here.
type: content
privacy: open
responses:
'201':
description: Space created.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpaceResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
"/spaces/{space_id}/design_drafts/{draft_id}/nodes":
patch:
tags:
- Design
summary: Atomically patch design draft nodes
description: "Required scope: `design:write`. Applies ordered UID-based insert, update, delete, and move operations to an open draft. Requires the current draft content digest and validates the complete recomposed draft before saving."
operationId: patchAdminApiDesignDraftNodes
x-required-scope: design:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/DesignDraftId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/DesignDraftPatchRequest"
responses:
'200':
description: Draft patched; returns compact affected-node metadata and the next draft digest.
content:
application/json:
schema:
"$ref": "#/components/schemas/DesignDraftPatchResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/Conflict"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
'422':
"$ref": "#/components/responses/ValidationFailed"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
"/spaces/{space_id}":
get:
tags:
- Spaces
summary: Get an authorized space
description: "Required scope: `spaces:read`."
operationId: getAdminApiSpace
x-required-scope: spaces:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
responses:
'200':
description: Space.
content:
application/json:
schema:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/Space"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
patch:
tags:
- Spaces
summary: Update a space
description: "Required scope: `spaces:write`."
operationId: updateAdminApiSpace
x-required-scope: spaces:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/SpaceUpdateRequest"
responses:
'200':
description: Updated space.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpaceResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
delete:
tags:
- Spaces
summary: Delete a space
description: "Required scope: `spaces:write`. Marks the space deleted and queues existing cleanup work. The response includes the deleted space payload with `deleted: true`."
operationId: deleteAdminApiSpace
x-required-scope: spaces:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
responses:
'200':
description: Deleted space.
content:
application/json:
schema:
"$ref": "#/components/schemas/DeletedSpaceResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/settings":
patch:
tags:
- Spaces
summary: Update a space's behavioral settings
description: "Required scope: `spaces:write`. Updates behavioral settings
(scheduling, membership, content behavior, sidebar/page display,
registration display, SEO, members map, Cobolt indexing, and list/post
display). Partial updates: only the keys present are written; explicit
null clears nullable fields. Scheduling gates and their times must
arrive together (e.g. launch_on_date with launch_time). While
launch_on_date is true with a future launch_time, the space state reads
as pending and any settings write re-pends it. Changing display fields
propagates to children when apply_to_sub_spaces is on; toggling
cobolt_indexing_excluded purges or restores the subtree's AI index."
operationId: updateAdminApiSpaceSettings
x-required-scope: spaces:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/SpaceSettingsUpdateRequest"
responses:
'200':
description: Updated space (detail shape with nested settings).
content:
application/json:
schema:
"$ref": "#/components/schemas/SpaceResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/spaces/{space_id}/appearance":
patch:
tags:
- Spaces
summary: Update a space's appearance
description: "Required scope: `spaces:write`. Updates theme colors,
fonts, accent palette, gradients, corner style, density, and hidden
layout elements. Tier-gated to professional/organization accounts.
Null clears a theme override (falling back to defaults). WARNING:
writing any base color cascades the parent's FULL current theme —
including fonts, font weights, corner style, density, accents,
gradients, sidebar style, and the logo file — to every descendant
space."
operationId: updateAdminApiSpaceAppearance
x-required-scope: spaces:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/SpaceAppearanceUpdateRequest"
responses:
'200':
description: Updated space (detail shape with nested appearance).
content:
application/json:
schema:
"$ref": "#/components/schemas/SpaceResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/spaces/{space_id}/images":
post:
tags:
- Spaces
summary: Set or remove a space image from a URL
description: "Required scope: `spaces:write`. Downloads the image at
source_url and stores it as the space's cover (banner, center-cropped
toward 2400×600, never upscaled), logo (cropped to 250×80,
professional/organization only), thumbnail (list-card image, cropped
to 600×300), or meta (social-share image, cropped to 1200×630).
source_url: null removes the image. Processing runs synchronously in
the request (multiple ImageMagick passes + storage writes) — keep
source files reasonably sized (hard cap 25 MB). Unlike the web app,
cover writes only the banner (never the thumbnail). Setting a
thumbnail protects it from post-driven auto-generation; removing it
re-arms auto-generation. Logo changes propagate to all descendant
spaces."
operationId: setAdminApiSpaceImage
x-required-scope: spaces:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/SpaceImageRequest"
responses:
'200':
description: The stored image.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpaceImageResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/spaces/{space_id}/payment":
patch:
tags:
- Spaces
summary: Enable, disable, or configure paid access (plans system)
description: "Required scope: `spaces:write`. Manages the space's payment
gate and checkout toggles for the plans system (legacy single-price
config is neither readable nor writable through this API). Enabling
requires at least one active plan (`no_active_plans`) and a connected
Stripe account (`stripe_not_connected`) — both otherwise produce
reachable dead-ends. Disabling is a guarded teardown: it returns 409
(`live_enrollments`) while live enrollments exist unless force: true,
which also cancels their Stripe subscriptions; active plans are
soft-deactivated and privacy moves to target_privacy (default
private). Disabling a space that was never payment-private is a
success no-op."
operationId: updateAdminApiSpacePayment
x-required-scope: spaces:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/SpacePaymentUpdateRequest"
responses:
'200':
description: Updated space (detail shape with nested payment).
content:
application/json:
schema:
"$ref": "#/components/schemas/SpaceResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/spaces/{space_id}/website":
get:
tags:
- Spaces
summary: Read a space's website-mode state
description: "Required scope: `spaces:read`. Website mode is root-scoped:
any managed space resolves to its website root. Returns whether website
mode is enabled, the header_hidden flag (Funnel mode), the
show_spaces_in_page flag, and the header/footer share-block config
pointers (shbk_ IDs)."
operationId: getAdminApiSpaceWebsite
x-required-scope: spaces:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
responses:
'200':
description: The website-mode state of the resolved root.
content:
application/json:
schema:
"$ref": "#/components/schemas/WebsiteStateResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
patch:
tags:
- Spaces
summary: Enable/disable website mode and repoint the header/footer
description: "Required scope: `spaces:write`. Operates on the resolved
website root. enabled: true is tier-gated (Silver plan or above —
otherwise 422 upgrade_required) and, on first enable, auto-creates a
default header (a navbar) and footer; enabled: false preserves the
configs so re-enabling is lossless. header_config_id/footer_config_id
must reference a site_header/site_footer share block in the same space
(null clears the pointer). Set header_hidden: true for Funnel mode
(website mode with the shared site header hidden site-wide; the header
config is preserved, so header_hidden: false toggles back to Website). A
single call may both enable and repoint."
operationId: updateAdminApiSpaceWebsite
x-required-scope: spaces:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/SpaceWebsiteUpdateRequest"
responses:
'200':
description: The updated website-mode state.
content:
application/json:
schema:
"$ref": "#/components/schemas/WebsiteStateResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/spaces/{space_id}/share_block_configs":
get:
tags:
- Spaces
summary: List a space's share-block configs
description: "Required scope: `spaces:read`. Lists the site_header,
site_footer, and generic share blocks for the space's website root."
operationId: listAdminApiShareBlockConfigs
x-required-scope: spaces:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
responses:
'200':
description: The share-block configs.
content:
application/json:
schema:
"$ref": "#/components/schemas/ShareBlockConfigListResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
post:
tags:
- Spaces
summary: Create a share-block config
description: "Required scope: `spaces:write`. For a website header use kind
site_header with content set to a single navbar node referencing a
NavbarConfig; for a footer use kind site_footer with freeform blocks.
name must be unique within the space."
operationId: createAdminApiShareBlockConfig
x-required-scope: spaces:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/ShareBlockConfigCreateRequest"
responses:
'201':
description: The created share-block config.
content:
application/json:
schema:
"$ref": "#/components/schemas/ShareBlockConfigResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/spaces/{space_id}/share_block_configs/{id}":
get:
tags:
- Spaces
summary: Get a share-block config
description: "Required scope: `spaces:read`."
operationId: getAdminApiShareBlockConfig
x-required-scope: spaces:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/ShareBlockConfigId"
responses:
'200':
description: The share-block config.
content:
application/json:
schema:
"$ref": "#/components/schemas/ShareBlockConfigResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
patch:
tags:
- Spaces
summary: Update a share-block config
description: "Required scope: `spaces:write`. Updates name, content, or
style. Kind is immutable through this endpoint."
operationId: updateAdminApiShareBlockConfig
x-required-scope: spaces:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/ShareBlockConfigId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/ShareBlockConfigUpdateRequest"
responses:
'200':
description: The updated share-block config.
content:
application/json:
schema:
"$ref": "#/components/schemas/ShareBlockConfigResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
delete:
tags:
- Spaces
summary: Delete a share-block config
description: "Required scope: `spaces:write`. Returns 409 config_in_use if
the block is the active website header or footer — repoint or disable
website mode first."
operationId: deleteAdminApiShareBlockConfig
x-required-scope: spaces:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/ShareBlockConfigId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
responses:
'200':
description: The deleted share-block config.
content:
application/json:
schema:
"$ref": "#/components/schemas/DeletedResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/navbar_configs":
get:
tags:
- Spaces
summary: List a space's navbar configs
description: "Required scope: `spaces:read`. Lists the navbar configs
(header link sets + style) for the space's website root."
operationId: listAdminApiNavbarConfigs
x-required-scope: spaces:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
responses:
'200':
description: The navbar configs.
content:
application/json:
schema:
"$ref": "#/components/schemas/NavbarConfigListResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
post:
tags:
- Spaces
summary: Create a navbar config
description: "Required scope: `spaces:write`. Creates a navbar (links +
style) for a website header; reference it from a site_header share
block's navbar node via navbarConfigId. name must be unique within the
space."
operationId: createAdminApiNavbarConfig
x-required-scope: spaces:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/NavbarConfigCreateRequest"
responses:
'201':
description: The created navbar config.
content:
application/json:
schema:
"$ref": "#/components/schemas/NavbarConfigResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/spaces/{space_id}/navbar_configs/{id}":
get:
tags:
- Spaces
summary: Get a navbar config
description: "Required scope: `spaces:read`."
operationId: getAdminApiNavbarConfig
x-required-scope: spaces:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/NavbarConfigId"
responses:
'200':
description: The navbar config.
content:
application/json:
schema:
"$ref": "#/components/schemas/NavbarConfigResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
patch:
tags:
- Spaces
summary: Update a navbar config
description: "Required scope: `spaces:write`. Updates name, links, or
style."
operationId: updateAdminApiNavbarConfig
x-required-scope: spaces:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/NavbarConfigId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/NavbarConfigUpdateRequest"
responses:
'200':
description: The updated navbar config.
content:
application/json:
schema:
"$ref": "#/components/schemas/NavbarConfigResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
delete:
tags:
- Spaces
summary: Delete a navbar config
description: "Required scope: `spaces:write`. A site_header still
referencing it by navbarConfigId will render an empty nav until
repointed."
operationId: deleteAdminApiNavbarConfig
x-required-scope: spaces:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/NavbarConfigId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
responses:
'200':
description: The deleted navbar config.
content:
application/json:
schema:
"$ref": "#/components/schemas/DeletedResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/navbar_configs/{id}/duplicate":
post:
tags:
- Spaces
summary: Duplicate a navbar config
description: "Required scope: `spaces:write`. Copies the navbar's links and
style under a new unique name."
operationId: duplicateAdminApiNavbarConfig
x-required-scope: spaces:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/NavbarConfigId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
responses:
'201':
description: The duplicated navbar config.
content:
application/json:
schema:
"$ref": "#/components/schemas/NavbarConfigResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/children":
get:
tags:
- Spaces
summary: List direct child spaces
description: "Required scope: `spaces:read`."
operationId: listAdminApiSpaceChildren
x-required-scope: spaces:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/Limit"
- "$ref": "#/components/parameters/Cursor"
responses:
'200':
description: Cursor-paginated child spaces.
content:
application/json:
schema:
type: object
required:
- data
- pagination
properties:
data:
type: array
items:
"$ref": "#/components/schemas/Space"
pagination:
"$ref": "#/components/schemas/Pagination"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
post:
tags:
- Spaces
summary: Create a direct child space
description: "Required scope: `spaces:write`."
operationId: createAdminApiSpaceChild
x-required-scope: spaces:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/SpaceCreateRequest"
responses:
'201':
description: Child space created.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpaceResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/spaces/{space_id}/children/{child_space_id}":
put:
tags:
- Spaces
summary: Attach an existing child space
description: "Required scope: `spaces:write`. Creates or updates a true parent-child relationship and places the child in the requested surface. Use `sp_...` IDs, not slugs."
operationId: attachAdminApiSpaceChild
x-required-scope: spaces:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- name: child_space_id
in: path
required: true
schema:
type: string
pattern: "^sp_"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
placement:
"$ref": "#/components/schemas/PlacementRequest"
responses:
'200':
description: Child attached.
content:
application/json:
schema:
"$ref": "#/components/schemas/ChildAttachmentResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
delete:
tags:
- Spaces
summary: Detach a child space
description: "Required scope: `spaces:write`. Removes only the selected parent-child relationship and matching document card; it does not delete the child space."
operationId: detachAdminApiSpaceChild
x-required-scope: spaces:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- name: child_space_id
in: path
required: true
schema:
type: string
pattern: "^sp_"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
responses:
'200':
description: Child detached.
content:
application/json:
schema:
"$ref": "#/components/schemas/ChildAttachmentResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
"/spaces/{space_id}/children/{child_space_id}/placement":
patch:
tags:
- Spaces
summary: Update child placement
description: "Required scope: `spaces:write`. Moves a child between collection/document surfaces, changes order, or repairs a missing display node."
operationId: updateAdminApiSpaceChildPlacement
x-required-scope: spaces:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- name: child_space_id
in: path
required: true
schema:
type: string
pattern: "^sp_"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
placement:
"$ref": "#/components/schemas/PlacementRequest"
responses:
'200':
description: Placement updated.
content:
application/json:
schema:
"$ref": "#/components/schemas/ChildAttachmentResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
"/spaces/{space_id}/children/reorder":
patch:
tags:
- Spaces
summary: Reorder direct child spaces
description: "Required scope: `spaces:write`."
operationId: reorderAdminApiSpaceChildren
x-required-scope: spaces:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
space_ids:
type: array
items:
type: string
pattern: "^sp_"
children:
type: array
items:
type: string
pattern: "^sp_"
example:
space_ids:
- sp_childAexample00000001
- sp_childBexample00000002
responses:
'200':
description: Children reordered.
content:
application/json:
schema:
"$ref": "#/components/schemas/ReorderResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
"/document/capabilities":
get:
tags:
- Document
summary: Get document capabilities
description: "Required scope: `content:read`. Returns supported Tiptap nodes and reserved-node policy for document writes."
operationId: getAdminApiDocumentCapabilities
x-required-scope: content:read
responses:
'200':
description: Document capability manifest.
content:
application/json:
schema:
type: object
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
"/document/special_block_types":
get:
tags:
- Document
summary: List special block types
description: "Required scope: `content:read`. Returns first-class configurable special block types: info_box, icon_text, quote, badge, divider, and contact_form."
operationId: listAdminApiSpecialBlockTypes
x-required-scope: content:read
responses:
'200':
description: Special block type metadata.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpecialBlockTypesResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
"/spaces/{space_id}/document":
get:
tags:
- Document
summary: Get the Tiptap document
description: "Required scope: `content:read`."
operationId: getAdminApiSpaceDocument
x-required-scope: content:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
responses:
'200':
description: Tiptap document.
content:
application/json:
schema:
"$ref": "#/components/schemas/TiptapDocumentResponse"
'404':
"$ref": "#/components/responses/NotFound"
put:
tags:
- Document
summary: Replace the Tiptap document
description: "Required scope: `content:write`. Full replacement requires `base_revision` or `force: true` and rejects managed space-card removals. actionbutton nodes must include a non-empty `attrs.buttonText`. Mutation responses may include top-level `warnings` and `repairs` arrays when the submitted document is canonicalized."
operationId: replaceAdminApiSpaceDocument
x-required-scope: content:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/TiptapDocumentWriteRequest"
responses:
'200':
description: Document replaced.
content:
application/json:
schema:
"$ref": "#/components/schemas/TiptapDocumentResponse"
'409':
"$ref": "#/components/responses/Conflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
"/spaces/{space_id}/document/nodes":
post:
tags:
- Document
summary: Insert document nodes
description: "Required scope: `content:write`. Inserts Tiptap nodes and refreshes the content-block mirror. actionbutton nodes must include a non-empty `attrs.buttonText`. Mutation responses may include top-level `warnings` and `repairs` arrays when the submitted nodes are canonicalized."
operationId: insertAdminApiSpaceDocumentNodes
x-required-scope: content:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
- "$ref": "#/components/parameters/CompactResponseMode"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/TiptapNodeInsertRequest"
responses:
'201':
description: Nodes inserted.
content:
application/json:
schema:
"$ref": "#/components/schemas/TiptapDocumentMutationResponse"
'409':
"$ref": "#/components/responses/Conflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
"/spaces/{space_id}/document/nodes/{node_uid}":
patch:
tags:
- Document
summary: Update a document node
description: "Required scope: `content:write`. actionbutton replacements must include a non-empty `attrs.buttonText`. Mutation responses may include top-level `warnings` and `repairs` arrays when the submitted node is canonicalized."
operationId: updateAdminApiSpaceDocumentNode
x-required-scope: content:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- name: node_uid
in: path
required: true
schema:
type: string
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
- "$ref": "#/components/parameters/CompactResponseMode"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/TiptapNodeUpdateRequest"
responses:
'200':
description: Node updated.
content:
application/json:
schema:
"$ref": "#/components/schemas/TiptapDocumentMutationResponse"
'404':
"$ref": "#/components/responses/NotFound"
'422':
"$ref": "#/components/responses/ValidationFailed"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
delete:
tags:
- Document
summary: Delete a document node
description: "Required scope: `content:write`. Managed space cards must be detached through child placement endpoints."
operationId: deleteAdminApiSpaceDocumentNode
x-required-scope: content:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- name: node_uid
in: path
required: true
schema:
type: string
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
- "$ref": "#/components/parameters/CompactResponseMode"
responses:
'200':
description: Node deleted.
content:
application/json:
schema:
"$ref": "#/components/schemas/TiptapDocumentMutationResponse"
'404':
"$ref": "#/components/responses/NotFound"
'422':
"$ref": "#/components/responses/ValidationFailed"
"/spaces/{space_id}/document/nodes/{node_uid}/placement":
patch:
tags:
- Document
summary: Move a document node
description: "Required scope: `content:write`."
operationId: moveAdminApiSpaceDocumentNode
x-required-scope: content:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- name: node_uid
in: path
required: true
schema:
type: string
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
- "$ref": "#/components/parameters/CompactResponseMode"
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
placement:
"$ref": "#/components/schemas/DocumentPlacementRequest"
base_revision:
type: string
responses:
'200':
description: Node moved.
content:
application/json:
schema:
"$ref": "#/components/schemas/TiptapDocumentMutationResponse"
'404':
"$ref": "#/components/responses/NotFound"
'422':
"$ref": "#/components/responses/ValidationFailed"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/spaces/{space_id}/document/special_block_types":
get:
tags:
- Document
summary: List document special block types
description: "Required scope: `content:read`. Includes space-scoped contact_form member-property bindings."
operationId: listAdminApiDocumentSpecialBlockTypes
x-required-scope: content:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
responses:
'200':
description: Special block type metadata.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpecialBlockTypesResponse"
'404':
"$ref": "#/components/responses/NotFound"
"/spaces/{space_id}/document/special_blocks":
get:
tags:
- Document
summary: List document special blocks
description: "Required scope: `content:read`. Lists first-class special blocks found in the visible document."
operationId: listAdminApiDocumentSpecialBlocks
x-required-scope: content:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
responses:
'200':
description: Special blocks.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpecialBlocksResponse"
'404':
"$ref": "#/components/responses/NotFound"
post:
tags:
- Document
summary: Create a document special block
description: "Required scope: `content:write`. Creates info_box, icon_text, quote, badge, divider, or contact_form without hand-authoring raw Tiptap node JSON."
operationId: createAdminApiDocumentSpecialBlock
x-required-scope: content:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/SpecialBlockCreateRequest"
responses:
'201':
description: Special block created.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpecialBlockMutationResponse"
'409':
"$ref": "#/components/responses/Conflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
"/spaces/{space_id}/document/special_blocks/{node_uid}":
get:
tags:
- Document
summary: Get a document special block
description: "Required scope: `content:read`."
operationId: getAdminApiDocumentSpecialBlock
x-required-scope: content:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/NodeUid"
responses:
'200':
description: Special block.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpecialBlockMutationResponse"
'404':
"$ref": "#/components/responses/NotFound"
patch:
tags:
- Document
summary: Update a document special block
description: "Required scope: `content:write`. Omitted config keys preserve the existing block where possible."
operationId: updateAdminApiDocumentSpecialBlock
x-required-scope: content:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/NodeUid"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/SpecialBlockUpdateRequest"
responses:
'200':
description: Special block updated.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpecialBlockMutationResponse"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/Conflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
delete:
tags:
- Document
summary: Delete a document special block
description: "Required scope: `content:write`."
operationId: deleteAdminApiDocumentSpecialBlock
x-required-scope: content:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/NodeUid"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
responses:
'200':
description: Special block deleted.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpecialBlockMutationResponse"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/Conflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
"/spaces/{space_id}/registration_page":
get:
tags:
- Document
summary: Get the registration page draft and published documents
description: "Required scope: `content:read`. Returns both the editable registration page draft and the currently published live registration page."
operationId: getAdminApiSpaceRegistrationPage
x-required-scope: content:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
responses:
'200':
description: Registration page state.
content:
application/json:
schema:
"$ref": "#/components/schemas/RegistrationPageResponse"
'404':
"$ref": "#/components/responses/NotFound"
put:
tags:
- Document
summary: Replace the editable registration page draft
description: "Required scope: `content:write`. Replaces the editable registration page draft; visitors keep seeing the current published page until `POST /spaces/{space_id}/registration_page/publish`. Full replacement requires `base_revision` or `force: true`."
operationId: replaceAdminApiSpaceRegistrationPage
x-required-scope: content:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/TiptapDocumentWriteRequest"
responses:
'200':
description: Registration page draft replaced.
content:
application/json:
schema:
"$ref": "#/components/schemas/RegistrationPageResponse"
'409':
"$ref": "#/components/responses/Conflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
"/spaces/{space_id}/registration_page/nodes":
post:
tags:
- Document
summary: Insert registration page draft nodes
description: "Required scope: `content:write`. Inserts Tiptap nodes into the editable registration page draft."
operationId: insertAdminApiSpaceRegistrationPageNodes
x-required-scope: content:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/TiptapNodeInsertRequest"
responses:
'201':
description: Registration page draft nodes inserted.
content:
application/json:
schema:
"$ref": "#/components/schemas/RegistrationPageResponse"
'409':
"$ref": "#/components/responses/Conflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
"/spaces/{space_id}/registration_page/nodes/{node_uid}":
patch:
tags:
- Document
summary: Update a registration page draft node
description: "Required scope: `content:write`."
operationId: updateAdminApiSpaceRegistrationPageNode
x-required-scope: content:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- name: node_uid
in: path
required: true
schema:
type: string
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/TiptapNodeUpdateRequest"
responses:
'200':
description: Registration page draft node updated.
content:
application/json:
schema:
"$ref": "#/components/schemas/RegistrationPageResponse"
'404':
"$ref": "#/components/responses/NotFound"
'422':
"$ref": "#/components/responses/ValidationFailed"
delete:
tags:
- Document
summary: Delete a registration page draft node
description: "Required scope: `content:write`."
operationId: deleteAdminApiSpaceRegistrationPageNode
x-required-scope: content:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- name: node_uid
in: path
required: true
schema:
type: string
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
responses:
'200':
description: Registration page draft node deleted.
content:
application/json:
schema:
"$ref": "#/components/schemas/RegistrationPageResponse"
'404':
"$ref": "#/components/responses/NotFound"
'422':
"$ref": "#/components/responses/ValidationFailed"
"/spaces/{space_id}/registration_page/nodes/{node_uid}/placement":
patch:
tags:
- Document
summary: Move a registration page draft node
description: "Required scope: `content:write`."
operationId: moveAdminApiSpaceRegistrationPageNode
x-required-scope: content:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- name: node_uid
in: path
required: true
schema:
type: string
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
placement:
"$ref": "#/components/schemas/DocumentPlacementRequest"
base_revision:
type: string
responses:
'200':
description: Registration page draft node moved.
content:
application/json:
schema:
"$ref": "#/components/schemas/RegistrationPageResponse"
'404':
"$ref": "#/components/responses/NotFound"
'422':
"$ref": "#/components/responses/ValidationFailed"
"/spaces/{space_id}/registration_page/special_block_types":
get:
tags:
- Document
summary: List registration page special block types
description: "Required scope: `content:read`. Includes space-scoped contact_form member-property bindings for the editable registration page draft."
operationId: listAdminApiRegistrationPageSpecialBlockTypes
x-required-scope: content:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
responses:
'200':
description: Special block type metadata.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpecialBlockTypesResponse"
'404':
"$ref": "#/components/responses/NotFound"
"/spaces/{space_id}/registration_page/special_blocks":
get:
tags:
- Document
summary: List registration page special blocks
description: "Required scope: `content:read`. Lists first-class special blocks found in the editable registration page draft."
operationId: listAdminApiRegistrationPageSpecialBlocks
x-required-scope: content:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
responses:
'200':
description: Special blocks.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpecialBlocksResponse"
'404':
"$ref": "#/components/responses/NotFound"
post:
tags:
- Document
summary: Create a registration page special block
description: "Required scope: `content:write`. Creates a first-class special block in the editable registration page draft."
operationId: createAdminApiRegistrationPageSpecialBlock
x-required-scope: content:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/SpecialBlockCreateRequest"
responses:
'201':
description: Special block created.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpecialBlockMutationResponse"
'409':
"$ref": "#/components/responses/Conflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
"/spaces/{space_id}/registration_page/special_blocks/{node_uid}":
get:
tags:
- Document
summary: Get a registration page special block
description: "Required scope: `content:read`."
operationId: getAdminApiRegistrationPageSpecialBlock
x-required-scope: content:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/NodeUid"
responses:
'200':
description: Special block.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpecialBlockMutationResponse"
'404':
"$ref": "#/components/responses/NotFound"
patch:
tags:
- Document
summary: Update a registration page special block
description: "Required scope: `content:write`. Omitted config keys preserve the existing block where possible."
operationId: updateAdminApiRegistrationPageSpecialBlock
x-required-scope: content:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/NodeUid"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/SpecialBlockUpdateRequest"
responses:
'200':
description: Special block updated.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpecialBlockMutationResponse"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/Conflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
delete:
tags:
- Document
summary: Delete a registration page special block
description: "Required scope: `content:write`."
operationId: deleteAdminApiRegistrationPageSpecialBlock
x-required-scope: content:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/NodeUid"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
responses:
'200':
description: Special block deleted.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpecialBlockMutationResponse"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/Conflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
"/spaces/{space_id}/registration_page/publish":
post:
tags:
- Document
summary: Publish the registration page draft
description: "Required scopes: `content:write` and `spaces:write`. Copies the editable registration page draft to the live registration page and enables the space registration gate."
operationId: publishAdminApiSpaceRegistrationPage
x-required-scopes:
- content:write
- spaces:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
responses:
'200':
description: Registration page draft published.
content:
application/json:
schema:
"$ref": "#/components/schemas/RegistrationPageResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
"/spaces/{space_id}/media_uploads":
post:
tags:
- Media
summary: Create a media upload session
description: "Required scope: `media:write`. Returns a presigned PUT URL and optionally inserts a placeholder media node into the document. Send `base_revision` to guard placeholder insertion against concurrent document edits."
operationId: createAdminApiMediaUpload
x-required-scope: media:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/MediaUploadCreateRequest"
responses:
'201':
description: Media upload session created.
content:
application/json:
schema:
"$ref": "#/components/schemas/MediaResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'422':
"$ref": "#/components/responses/ValidationFailed"
'503':
"$ref": "#/components/responses/ServiceUnavailable"
"/spaces/{space_id}/media_references":
post:
tags:
- Media
summary: Create an external media reference
description: "Required scope: `media:write`. Creates or reuses an external Loom, YouTube, or Vimeo media reference and optionally inserts an embed node into the document."
operationId: createAdminApiMediaReference
x-required-scope: media:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/MediaReferenceCreateRequest"
responses:
'201':
description: External media reference created.
content:
application/json:
schema:
"$ref": "#/components/schemas/MediaResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'422':
"$ref": "#/components/responses/ValidationFailed"
"/media_uploads/{media_id}":
get:
tags:
- Media
summary: Get media upload and processing status
description: "Required scope: `media:read`."
operationId: getAdminApiMediaUpload
x-required-scope: media:read
parameters:
- "$ref": "#/components/parameters/MediaId"
responses:
'200':
description: Media status.
content:
application/json:
schema:
"$ref": "#/components/schemas/MediaResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
delete:
tags:
- Media
summary: Cancel a pending media upload
description: "Required scope: `media:write`. Marks a pending upload abandoned. It does not delete uploaded S3 objects."
operationId: cancelAdminApiMediaUpload
x-required-scope: media:write
parameters:
- "$ref": "#/components/parameters/MediaId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
- name: remove_document_node
in: query
required: false
schema:
type: boolean
description: Remove the placeholder node when the upload is still pending.
responses:
'200':
description: Media upload abandoned.
content:
application/json:
schema:
"$ref": "#/components/schemas/MediaResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'422':
"$ref": "#/components/responses/ValidationFailed"
"/media_uploads/{media_id}/complete":
post:
tags:
- Media
summary: Complete a media upload
description: "Required scope: `media:write`. Verifies the uploaded object and queues video processing when needed."
operationId: completeAdminApiMediaUpload
x-required-scope: media:write
parameters:
- "$ref": "#/components/parameters/MediaId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: false
content:
application/json:
schema:
"$ref": "#/components/schemas/MediaUploadCompleteRequest"
responses:
'200':
description: Media upload completed or already complete.
content:
application/json:
schema:
"$ref": "#/components/schemas/MediaResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'422':
"$ref": "#/components/responses/ValidationFailed"
'503':
"$ref": "#/components/responses/ServiceUnavailable"
"/spaces/{space_id}/members":
get:
tags:
- Members
summary: List members for a space
description: "Required scope: `members:read`. Property filters require `member_properties:read`."
operationId: listAdminApiSpaceMembers
x-required-scope: members:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/Limit"
- "$ref": "#/components/parameters/Cursor"
- "$ref": "#/components/parameters/UserIdFilter"
- "$ref": "#/components/parameters/EmailFilter"
- "$ref": "#/components/parameters/SearchQuery"
- "$ref": "#/components/parameters/MemberRoleFilter"
- "$ref": "#/components/parameters/MemberStateFilter"
- "$ref": "#/components/parameters/MemberPropertyFilters"
- "$ref": "#/components/parameters/MemberPropertyKeyFilter"
- "$ref": "#/components/parameters/MemberPropertyValueFilter"
responses:
'200':
description: Cursor-paginated members.
content:
application/json:
schema:
"$ref": "#/components/schemas/MemberListResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
post:
tags:
- Members
summary: Add a member to a space
description: |
Required scope: `members:write`.
Adds an existing user by `user_id` or resolves/creates a user from a normalized email address.
Email addresses are returned in responses only when the token also has `members.email:read`.
operationId: createAdminApiSpaceMember
x-required-scope: members:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/MemberCreateRequest"
examples:
byEmail:
value:
email: ada@example.com
first_name: Ada
last_name: Lovelace
username: ada
role: member
responses:
'201':
description: Member created.
content:
application/json:
schema:
"$ref": "#/components/schemas/MemberResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'409':
"$ref": "#/components/responses/Conflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/spaces/{space_id}/members/{member_id}":
get:
tags:
- Members
summary: Get a member from a space
description: "Required scope: `members:read`."
operationId: getAdminApiSpaceMember
x-required-scope: members:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/MemberId"
responses:
'200':
description: Member.
content:
application/json:
schema:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/Member"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
patch:
tags:
- Members
summary: Update member metadata
description: "Required scope: `members:write`."
operationId: updateAdminApiSpaceMember
x-required-scope: members:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/MemberId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/MemberUpdateRequest"
responses:
'200':
description: Updated member.
content:
application/json:
schema:
"$ref": "#/components/schemas/MemberResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
delete:
tags:
- Members
summary: Delete a member from a space
description: |
Required scope: `members:write`.
Removes the membership and descendant memberships for the same user within the target hierarchy.
This operation can cancel subscriptions and always requires an `Idempotency-Key`.
operationId: deleteAdminApiSpaceMember
x-required-scope: members:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/MemberId"
- "$ref": "#/components/parameters/IdempotencyKeyRequired"
responses:
'200':
description: Member removed.
content:
application/json:
schema:
"$ref": "#/components/schemas/DeletedMemberResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'502':
"$ref": "#/components/responses/UpstreamError"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/members/{member_id}/approve":
post:
tags:
- Members
summary: Approve a pending member
description: "Required scope: `members:write`."
operationId: approveAdminApiSpaceMember
x-required-scope: members:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/MemberId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
responses:
'200':
description: Approved member.
content:
application/json:
schema:
"$ref": "#/components/schemas/MemberResponse"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/members/bulk":
post:
tags:
- Members
summary: Add up to 100 members
description: "Required scope: `members:write`. Bulk operations are not transactional. The response contains one result per submitted item and always requires an `Idempotency-Key`."
operationId: bulkCreateAdminApiSpaceMembers
x-required-scope: members:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyRequired"
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
minItems: 1
maxItems: 100
items:
"$ref": "#/components/schemas/MemberCreateRequest"
responses:
'207':
description: Per-item member creation results.
content:
application/json:
schema:
"$ref": "#/components/schemas/BulkMemberResponse"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/spaces/{space_id}/members/bulk_delete":
post:
tags:
- Members
summary: Remove up to 100 members
description: "Required scope: `members:write`. Bulk removal uses POST because the request requires a JSON body. The operation requires an `Idempotency-Key` and returns one result per submitted item."
operationId: bulkDeleteAdminApiSpaceMembers
x-required-scope: members:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyRequired"
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
minItems: 1
maxItems: 100
items:
type: object
additionalProperties: false
anyOf:
- required:
- member_id
- required:
- id
properties:
member_id:
type: string
pattern: "^mem_"
id:
type: string
pattern: "^mem_"
responses:
'207':
description: Per-item member removal results.
content:
application/json:
schema:
"$ref": "#/components/schemas/BulkDeletedMemberResponse"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/members":
get:
tags:
- Members
summary: List members
description: "Required scope: `members:read`. Lists members across the token's authorized spaces. A single user can appear more than once when they belong to multiple authorized spaces. Deduplicate by user_id client-side only when that is desired. Property filters require `member_properties:read` and a `space_id` filter."
operationId: listAdminApiMembers
x-required-scope: members:read
parameters:
- "$ref": "#/components/parameters/Limit"
- "$ref": "#/components/parameters/Cursor"
- "$ref": "#/components/parameters/SpaceIdFilter"
- "$ref": "#/components/parameters/UserIdFilter"
- "$ref": "#/components/parameters/EmailFilter"
- "$ref": "#/components/parameters/SearchQuery"
- "$ref": "#/components/parameters/MemberRoleFilter"
- "$ref": "#/components/parameters/MemberStateFilter"
- "$ref": "#/components/parameters/MemberPropertyFilters"
- "$ref": "#/components/parameters/MemberPropertyKeyFilter"
- "$ref": "#/components/parameters/MemberPropertyValueFilter"
responses:
'200':
description: Cursor-paginated members.
content:
application/json:
schema:
"$ref": "#/components/schemas/MemberListResponse"
examples:
duplicateUserAcrossSpaces:
value:
data:
- id: mem_7kBx9qR2nLp4vWm1tYz3hJ
space_id: sp_rootExample0000000001
user_id: usr_memberExample000001
state: active
role:
created_at: '2026-04-27T10:00:00Z'
updated_at: '2026-04-27T10:00:00Z'
user:
id: usr_memberExample000001
first_name: Ada
last_name: Lovelace
name: Ada Lovelace
username: ada
avatar_url:
- id: mem_2mYd8uS4qLp4vWm1tYz9kP
space_id: sp_childExample000000002
user_id: usr_memberExample000001
state: active
role:
created_at: '2026-04-27T10:05:00Z'
updated_at: '2026-04-27T10:05:00Z'
user:
id: usr_memberExample000001
first_name: Ada
last_name: Lovelace
name: Ada Lovelace
username: ada
avatar_url:
pagination:
limit: 25
next_cursor:
has_more: false
'403':
"$ref": "#/components/responses/Forbidden"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/contacts":
get:
tags:
- Contacts
summary: List contacts
description: "Required scope: `members:read`. Lists non-member CRM contacts for the space. Email fields and email filtering require `members.email:read`. Property filters require `member_properties:read`."
operationId: listAdminApiSpaceContacts
x-required-scope: members:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/Limit"
- "$ref": "#/components/parameters/Cursor"
- "$ref": "#/components/parameters/EmailFilter"
- "$ref": "#/components/parameters/SearchQuery"
- "$ref": "#/components/parameters/MemberPropertyFilters"
- "$ref": "#/components/parameters/MemberPropertyKeyFilter"
- "$ref": "#/components/parameters/MemberPropertyValueFilter"
responses:
'200':
description: Cursor-paginated contacts.
content:
application/json:
schema:
"$ref": "#/components/schemas/ContactListResponse"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'422':
"$ref": "#/components/responses/ValidationFailed"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/contacts/{contact_id}":
get:
tags:
- Contacts
summary: Get a contact
description: "Required scope: `members:read`. Email is present only with `members.email:read`."
operationId: getAdminApiSpaceContact
x-required-scope: members:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/ContactId"
responses:
'200':
description: Contact.
content:
application/json:
schema:
"$ref": "#/components/schemas/ContactResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/member_properties":
get:
tags:
- Member Properties
summary: List member properties for a space
description: "Required scope: `member_properties:read`. Lists custom property definitions that apply to members in the space."
operationId: listAdminApiSpaceMemberProperties
x-required-scope: member_properties:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/Limit"
- "$ref": "#/components/parameters/Cursor"
responses:
'200':
description: Cursor-paginated member property definitions.
content:
application/json:
schema:
"$ref": "#/components/schemas/MemberPropertyListResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
post:
tags:
- Member Properties
summary: Create a member property
description: "Required scope: `member_properties:write`."
operationId: createAdminApiSpaceMemberProperty
x-required-scope: member_properties:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/MemberPropertyWriteRequest"
responses:
'201':
description: Member property created.
content:
application/json:
schema:
"$ref": "#/components/schemas/MemberPropertyResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/spaces/{space_id}/member_properties/reorder":
patch:
tags:
- Member Properties
summary: Reorder member properties
description: "Required scope: `member_properties:write`."
operationId: reorderAdminApiSpaceMemberProperties
x-required-scope: member_properties:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/MemberPropertyReorderRequest"
responses:
'200':
description: Member properties reordered.
content:
application/json:
schema:
"$ref": "#/components/schemas/MemberPropertyReorderResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/member_properties/{member_property_id}":
get:
tags:
- Member Properties
summary: Get a member property
description: "Required scope: `member_properties:read`."
operationId: getAdminApiMemberProperty
x-required-scope: member_properties:read
parameters:
- "$ref": "#/components/parameters/MemberPropertyId"
responses:
'200':
description: Member property.
content:
application/json:
schema:
"$ref": "#/components/schemas/MemberPropertyResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
patch:
tags:
- Member Properties
summary: Update a member property
description: "Required scope: `member_properties:write`."
operationId: updateAdminApiMemberProperty
x-required-scope: member_properties:write
parameters:
- "$ref": "#/components/parameters/MemberPropertyId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/MemberPropertyWriteRequest"
responses:
'200':
description: Updated member property.
content:
application/json:
schema:
"$ref": "#/components/schemas/MemberPropertyResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
delete:
tags:
- Member Properties
summary: Delete a member property
description: "Required scope: `member_properties:write`."
operationId: deleteAdminApiMemberProperty
x-required-scope: member_properties:write
parameters:
- "$ref": "#/components/parameters/MemberPropertyId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
responses:
'200':
description: Deleted member property.
content:
application/json:
schema:
"$ref": "#/components/schemas/DeletedMemberPropertyResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/members/properties/bulk":
patch:
tags:
- Member Properties
summary: Bulk update property values for members
description: "Required scopes: `members:write`, `member_properties:write`. Updates up to 100 members. The operation requires an `Idempotency-Key` and returns one result per submitted item."
operationId: bulkUpdateAdminApiSpaceMemberPropertyValues
x-required-scope: members:write member_properties:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyRequired"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/BulkMemberPropertyValuesUpdateRequest"
responses:
'207':
description: Per-item member property update results.
content:
application/json:
schema:
"$ref": "#/components/schemas/BulkPropertyValueUpdateResponse"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/members/{member_id}/properties":
get:
tags:
- Member Properties
summary: List property values for a member
description: "Required scopes: `members:read`, `member_properties:read`. Requires both `members:read` and `member_properties:read`."
operationId: listAdminApiSpaceMemberPropertyValues
x-required-scope: members:read member_properties:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/MemberId"
responses:
'200':
description: Member property values.
content:
application/json:
schema:
"$ref": "#/components/schemas/MemberPropertyValueListResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
patch:
tags:
- Member Properties
summary: Update property values for a member
description: "Required scopes: `members:write`, `member_properties:write`. Requires both `members:write` and `member_properties:write`. Setting a property value to `null` clears that value."
operationId: updateAdminApiSpaceMemberPropertyValues
x-required-scope: members:write member_properties:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/MemberId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/MemberPropertyValuesUpdateRequest"
responses:
'200':
description: Updated member property values.
content:
application/json:
schema:
"$ref": "#/components/schemas/MemberPropertyValueListResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/spaces/{space_id}/contacts/properties/bulk":
patch:
tags:
- Member Properties
summary: Bulk update property values for contacts
description: "Required scopes: `members:write`, `member_properties:write`. Updates up to 100 contacts. The operation requires an `Idempotency-Key` and returns one result per submitted item."
operationId: bulkUpdateAdminApiSpaceContactPropertyValues
x-required-scope: members:write member_properties:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyRequired"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/BulkContactPropertyValuesUpdateRequest"
responses:
'207':
description: Per-item contact property update results.
content:
application/json:
schema:
"$ref": "#/components/schemas/BulkPropertyValueUpdateResponse"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/contacts/{contact_id}/properties":
get:
tags:
- Member Properties
summary: List property values for a contact
description: "Required scopes: `members:read`, `member_properties:read`. Contacts use the same member-property definitions as members."
operationId: listAdminApiSpaceContactPropertyValues
x-required-scope: members:read member_properties:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/ContactId"
responses:
'200':
description: Contact property values.
content:
application/json:
schema:
"$ref": "#/components/schemas/MemberPropertyValueListResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'429':
"$ref": "#/components/responses/RateLimited"
patch:
tags:
- Member Properties
summary: Update property values for a contact
description: "Required scopes: `members:write`, `member_properties:write`. Setting a property value to `null` clears that value."
operationId: updateAdminApiSpaceContactPropertyValues
x-required-scope: members:write member_properties:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/ContactId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/MemberPropertyValuesUpdateRequest"
responses:
'200':
description: Updated contact property values.
content:
application/json:
schema:
"$ref": "#/components/schemas/MemberPropertyValueListResponse"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'422':
"$ref": "#/components/responses/ValidationFailed"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/spaces/{space_id}/space_properties":
get:
tags:
- Space Properties
summary: List space properties for a space
description: "Required scope: `space_properties:read`. Lists custom property definitions owned by the space."
operationId: listAdminApiSpaceProperties
x-required-scope: space_properties:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/Limit"
- "$ref": "#/components/parameters/Cursor"
responses:
'200':
description: Cursor-paginated space property definitions.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpacePropertyListResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
post:
tags:
- Space Properties
summary: Create a space property
description: "Required scope: `space_properties:write`."
operationId: createAdminApiSpaceProperty
x-required-scope: space_properties:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/SpacePropertyWriteRequest"
responses:
'201':
description: Space property created.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpacePropertyResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/spaces/{space_id}/space_properties/reorder":
patch:
tags:
- Space Properties
summary: Reorder space properties
description: "Required scope: `space_properties:write`."
operationId: reorderAdminApiSpaceProperties
x-required-scope: space_properties:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/SpacePropertyReorderRequest"
responses:
'200':
description: Space properties reordered.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpacePropertyReorderResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/space_properties/{space_property_id}":
get:
tags:
- Space Properties
summary: Get a space property
description: "Required scope: `space_properties:read`."
operationId: getAdminApiSpaceProperty
x-required-scope: space_properties:read
parameters:
- "$ref": "#/components/parameters/SpacePropertyId"
responses:
'200':
description: Space property.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpacePropertyResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
patch:
tags:
- Space Properties
summary: Update a space property
description: "Required scope: `space_properties:write`."
operationId: updateAdminApiSpaceProperty
x-required-scope: space_properties:write
parameters:
- "$ref": "#/components/parameters/SpacePropertyId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/SpacePropertyWriteRequest"
responses:
'200':
description: Updated space property.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpacePropertyResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
delete:
tags:
- Space Properties
summary: Delete a space property
description: "Required scope: `space_properties:write`."
operationId: deleteAdminApiSpaceProperty
x-required-scope: space_properties:write
parameters:
- "$ref": "#/components/parameters/SpacePropertyId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
responses:
'200':
description: Deleted space property.
content:
application/json:
schema:
"$ref": "#/components/schemas/DeletedSpacePropertyResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/properties":
get:
tags:
- Space Properties
summary: List property values for a space
description: "Required scopes: `spaces:read`, `space_properties:read`. Requires both `spaces:read` and `space_properties:read`. For child spaces in a list, showcase, events space, course, or section, values use the parent space's property definitions."
operationId: listAdminApiSpacePropertyValues
x-required-scope: spaces:read space_properties:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
responses:
'200':
description: Space property values.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpacePropertyValueListResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
patch:
tags:
- Space Properties
summary: Update property values for a space
description: "Required scopes: `spaces:write`, `space_properties:write`. Requires both `spaces:write` and `space_properties:write`. Setting a property value to `null` clears that value."
operationId: updateAdminApiSpacePropertyValues
x-required-scope: spaces:write space_properties:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/SpacePropertyValuesUpdateRequest"
responses:
'200':
description: Updated space property values.
content:
application/json:
schema:
"$ref": "#/components/schemas/SpacePropertyValueListResponse"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/spaces/{space_id}/invitations":
get:
tags:
- Invitations
summary: List invitations for a space
description: "Required scope: `invitations:read`."
operationId: listAdminApiSpaceInvitations
x-required-scope: invitations:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/Limit"
- "$ref": "#/components/parameters/Cursor"
- "$ref": "#/components/parameters/InvitationEmailFilter"
- "$ref": "#/components/parameters/InvitationStateFilter"
- "$ref": "#/components/parameters/InvitationRoleFilter"
responses:
'200':
description: Cursor-paginated invitations.
content:
application/json:
schema:
"$ref": "#/components/schemas/InvitationListResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
post:
tags:
- Invitations
summary: Create an invitation
description: "Required scope: `invitations:write`."
operationId: createAdminApiSpaceInvitation
x-required-scope: invitations:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/InvitationCreateRequest"
responses:
'201':
description: Invitation created.
content:
application/json:
schema:
"$ref": "#/components/schemas/InvitationResponse"
'409':
"$ref": "#/components/responses/IdempotencyConflict"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/spaces/{space_id}/invitations/{invitation_id}":
get:
tags:
- Invitations
summary: Get an invitation
description: "Required scope: `invitations:read`."
operationId: getAdminApiSpaceInvitation
x-required-scope: invitations:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/InvitationId"
responses:
'200':
description: Invitation.
content:
application/json:
schema:
"$ref": "#/components/schemas/InvitationResponse"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
patch:
tags:
- Invitations
summary: Update an invitation
description: "Required scope: `invitations:write`."
operationId: updateAdminApiSpaceInvitation
x-required-scope: invitations:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/InvitationId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/InvitationUpdateRequest"
responses:
'200':
description: Updated invitation.
content:
application/json:
schema:
"$ref": "#/components/schemas/InvitationResponse"
'404':
"$ref": "#/components/responses/NotFound"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
delete:
tags:
- Invitations
summary: Delete an invitation
description: "Required scope: `invitations:write`."
operationId: deleteAdminApiSpaceInvitation
x-required-scope: invitations:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/InvitationId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
responses:
'200':
description: Deleted invitation.
content:
application/json:
schema:
"$ref": "#/components/schemas/DeletedInvitationResponse"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/invitations/{invitation_id}/resend":
post:
tags:
- Invitations
summary: Resend an invitation email
description: "Required scope: `invitations:write`."
operationId: resendAdminApiSpaceInvitation
x-required-scope: invitations:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/InvitationId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
responses:
'200':
description: Invitation resent.
content:
application/json:
schema:
"$ref": "#/components/schemas/ResentInvitationResponse"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/invitations/bulk":
post:
tags:
- Invitations
summary: Create up to 100 invitations
description: "Required scope: `invitations:write`."
operationId: bulkCreateAdminApiSpaceInvitations
x-required-scope: invitations:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyRequired"
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
maxItems: 100
items:
"$ref": "#/components/schemas/InvitationCreateRequest"
responses:
'207':
description: Per-item invitation creation results.
content:
application/json:
schema:
"$ref": "#/components/schemas/BulkInvitationResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/spaces/{space_id}/content":
get:
tags:
- Content
summary: List content blocks for a space
description: "Required scope: `content:read`."
operationId: listAdminApiSpaceContent
x-required-scope: content:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/Limit"
- "$ref": "#/components/parameters/Cursor"
responses:
'200':
description: Cursor-paginated content blocks.
content:
application/json:
schema:
"$ref": "#/components/schemas/ContentBlockListResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
post:
tags:
- Content
summary: Create a content block
description: "Required scope: `content:write`."
operationId: createAdminApiSpaceContentBlock
x-required-scope: content:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/ContentBlockWriteRequest"
responses:
'201':
description: Content block created.
content:
application/json:
schema:
"$ref": "#/components/schemas/ContentBlockResponse"
'422':
"$ref": "#/components/responses/ValidationFailed"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/spaces/{space_id}/content/reorder":
patch:
tags:
- Content
summary: Reorder content blocks
description: "Required scope: `content:write`."
operationId: reorderAdminApiSpaceContent
x-required-scope: content:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
block_ids:
type: array
items:
type: string
pattern: "^blk_"
content_ids:
type: array
items:
type: string
pattern: "^blk_"
responses:
'200':
description: Content reordered.
content:
application/json:
schema:
"$ref": "#/components/schemas/ReorderResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/content/{block_id}":
get:
tags:
- Content
summary: Get a content block
description: "Required scope: `content:read`."
operationId: getAdminApiContentBlock
x-required-scope: content:read
parameters:
- "$ref": "#/components/parameters/BlockId"
responses:
'200':
description: Content block.
content:
application/json:
schema:
"$ref": "#/components/schemas/ContentBlockResponse"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
patch:
tags:
- Content
summary: Update a content block
description: "Required scope: `content:write`."
operationId: updateAdminApiContentBlock
x-required-scope: content:write
parameters:
- "$ref": "#/components/parameters/BlockId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/ContentBlockWriteRequest"
responses:
'200':
description: Updated content block.
content:
application/json:
schema:
"$ref": "#/components/schemas/ContentBlockResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
delete:
tags:
- Content
summary: Delete a content block
description: "Required scope: `content:write`."
operationId: deleteAdminApiContentBlock
x-required-scope: content:write
parameters:
- "$ref": "#/components/parameters/BlockId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
responses:
'200':
description: Deleted content block.
content:
application/json:
schema:
"$ref": "#/components/schemas/DeletedContentBlockResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/messages":
get:
tags:
- Messages
summary: List messages for a space
description: "Required scope: `messages:read`."
operationId: listAdminApiSpaceMessages
x-required-scope: messages:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/Limit"
- "$ref": "#/components/parameters/Cursor"
- "$ref": "#/components/parameters/UserIdFilter"
responses:
'200':
description: Cursor-paginated messages.
content:
application/json:
schema:
"$ref": "#/components/schemas/MessageListResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
post:
tags:
- Messages
summary: Create a message
description: "Required scope: `messages:write`."
operationId: createAdminApiSpaceMessage
x-required-scope: messages:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/MessageWriteRequest"
responses:
'201':
description: Message created.
content:
application/json:
schema:
"$ref": "#/components/schemas/MessageResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/messages/{message_id}":
get:
tags:
- Messages
summary: Get a message
description: "Required scope: `messages:read`."
operationId: getAdminApiMessage
x-required-scope: messages:read
parameters:
- "$ref": "#/components/parameters/MessageId"
responses:
'200':
description: Message.
content:
application/json:
schema:
"$ref": "#/components/schemas/MessageResponse"
'404':
"$ref": "#/components/responses/NotFound"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
patch:
tags:
- Messages
summary: Update a message
description: "Required scope: `messages:write`."
operationId: updateAdminApiMessage
x-required-scope: messages:write
parameters:
- "$ref": "#/components/parameters/MessageId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/MessageWriteRequest"
responses:
'200':
description: Updated message.
content:
application/json:
schema:
"$ref": "#/components/schemas/MessageResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
delete:
tags:
- Messages
summary: Delete a message
description: "Required scope: `messages:write`."
operationId: deleteAdminApiMessage
x-required-scope: messages:write
parameters:
- "$ref": "#/components/parameters/MessageId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
responses:
'200':
description: Deleted message.
content:
application/json:
schema:
"$ref": "#/components/schemas/DeletedMessageResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
"/messages/{message_id}/reflections":
get:
tags:
- Reflections
summary: List reflections on a message
description: "Required scope: `reflections:read`."
operationId: listAdminApiMessageReflections
x-required-scope: reflections:read
parameters:
- "$ref": "#/components/parameters/MessageId"
- "$ref": "#/components/parameters/Limit"
- "$ref": "#/components/parameters/Cursor"
responses:
'200':
description: Cursor-paginated reflections.
content:
application/json:
schema:
"$ref": "#/components/schemas/ReflectionListResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
post:
tags:
- Reflections
summary: Create a reflection on a message
description: "Required scope: `reflections:write`."
operationId: createAdminApiMessageReflection
x-required-scope: reflections:write
parameters:
- "$ref": "#/components/parameters/MessageId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/ReflectionWriteRequest"
responses:
'201':
description: Reflection created.
content:
application/json:
schema:
"$ref": "#/components/schemas/ReflectionResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/reflections/{reflection_id}":
get:
tags:
- Reflections
summary: Get a reflection
description: "Required scope: `reflections:read`."
operationId: getAdminApiReflection
x-required-scope: reflections:read
parameters:
- "$ref": "#/components/parameters/ReflectionId"
responses:
'200':
description: Reflection.
content:
application/json:
schema:
"$ref": "#/components/schemas/ReflectionResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
patch:
tags:
- Reflections
summary: Update a reflection
description: "Required scope: `reflections:write`."
operationId: updateAdminApiReflection
x-required-scope: reflections:write
parameters:
- "$ref": "#/components/parameters/ReflectionId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/ReflectionWriteRequest"
responses:
'200':
description: Updated reflection.
content:
application/json:
schema:
"$ref": "#/components/schemas/ReflectionResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
delete:
tags:
- Reflections
summary: Delete a reflection
description: "Required scope: `reflections:write`."
operationId: deleteAdminApiReflection
x-required-scope: reflections:write
parameters:
- "$ref": "#/components/parameters/ReflectionId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
responses:
'200':
description: Deleted reflection.
content:
application/json:
schema:
"$ref": "#/components/schemas/DeletedReflectionResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/surveys":
get:
tags:
- Surveys
summary: List surveys for a space
description: "Required scope: `surveys:read`."
operationId: listAdminApiSpaceSurveys
x-required-scope: surveys:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/Limit"
- "$ref": "#/components/parameters/Cursor"
- "$ref": "#/components/parameters/SearchQuery"
- "$ref": "#/components/parameters/SurveyTypeFilter"
responses:
'200':
description: Cursor-paginated surveys.
content:
application/json:
schema:
"$ref": "#/components/schemas/SurveyListResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
post:
tags:
- Surveys
summary: Create a survey
description: "Required scope: `surveys:write`."
operationId: createAdminApiSpaceSurvey
x-required-scope: surveys:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/SurveyWriteRequest"
responses:
'201':
description: Survey created.
content:
application/json:
schema:
"$ref": "#/components/schemas/SurveyResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/surveys/{survey_id}":
get:
tags:
- Surveys
summary: Get a survey and its questions
description: "Required scope: `surveys:read`."
operationId: getAdminApiSurvey
x-required-scope: surveys:read
parameters:
- "$ref": "#/components/parameters/SurveyId"
responses:
'200':
description: Survey.
content:
application/json:
schema:
"$ref": "#/components/schemas/SurveyResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
patch:
tags:
- Surveys
summary: Update a survey
description: "Required scope: `surveys:write`."
operationId: updateAdminApiSurvey
x-required-scope: surveys:write
parameters:
- "$ref": "#/components/parameters/SurveyId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/SurveyWriteRequest"
responses:
'200':
description: Updated survey.
content:
application/json:
schema:
"$ref": "#/components/schemas/SurveyResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
delete:
tags:
- Surveys
summary: Delete a survey
description: "Required scope: `surveys:write`."
operationId: deleteAdminApiSurvey
x-required-scope: surveys:write
parameters:
- "$ref": "#/components/parameters/SurveyId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
responses:
'200':
description: Deleted survey.
content:
application/json:
schema:
"$ref": "#/components/schemas/DeletedSurveyResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
"/surveys/{survey_id}/submissions":
get:
tags:
- Surveys
summary: List survey submissions
description: "Required scope: `survey_submissions:read`."
operationId: listAdminApiSurveySubmissions
x-required-scope: survey_submissions:read
parameters:
- "$ref": "#/components/parameters/SurveyId"
- "$ref": "#/components/parameters/Limit"
- "$ref": "#/components/parameters/Cursor"
responses:
'200':
description: Cursor-paginated survey submissions.
content:
application/json:
schema:
"$ref": "#/components/schemas/SurveySubmissionListResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
"/surveys/{survey_id}/submissions/{submission_id}":
get:
tags:
- Surveys
summary: Get a survey submission
description: "Required scope: `survey_submissions:read`."
operationId: getAdminApiSurveySubmission
x-required-scope: survey_submissions:read
parameters:
- "$ref": "#/components/parameters/SurveyId"
- "$ref": "#/components/parameters/SubmissionId"
responses:
'200':
description: Survey submission.
content:
application/json:
schema:
"$ref": "#/components/schemas/SurveySubmissionResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/plans":
get:
tags:
- Plans
summary: List plans for a space
description: "Required scope: `plans:read`."
operationId: listAdminApiSpacePlans
x-required-scope: plans:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/Limit"
- "$ref": "#/components/parameters/Cursor"
- "$ref": "#/components/parameters/SearchQuery"
- "$ref": "#/components/parameters/PlanStatusFilter"
- "$ref": "#/components/parameters/PlanFrequencyFilter"
responses:
'200':
description: Cursor-paginated plans.
content:
application/json:
schema:
"$ref": "#/components/schemas/PlanListResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
post:
tags:
- Plans
summary: Create a plan
description: "Required scope: `plans:write`."
operationId: createAdminApiSpacePlan
x-required-scope: plans:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/PlanWriteRequest"
responses:
'201':
description: Plan created.
content:
application/json:
schema:
"$ref": "#/components/schemas/PlanResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/plans/{plan_id}":
get:
tags:
- Plans
summary: Get a plan
description: "Required scope: `plans:read`."
operationId: getAdminApiPlan
x-required-scope: plans:read
parameters:
- "$ref": "#/components/parameters/PlanId"
responses:
'200':
description: Plan.
content:
application/json:
schema:
"$ref": "#/components/schemas/PlanResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
patch:
tags:
- Plans
summary: Update a plan
description: "Required scope: `plans:write`."
operationId: updateAdminApiPlan
x-required-scope: plans:write
parameters:
- "$ref": "#/components/parameters/PlanId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/PlanWriteRequest"
responses:
'200':
description: Updated plan.
content:
application/json:
schema:
"$ref": "#/components/schemas/PlanResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
delete:
tags:
- Plans
summary: Deactivate a plan
description: "Required scope: `plans:write`."
operationId: deleteAdminApiPlan
x-required-scope: plans:write
parameters:
- "$ref": "#/components/parameters/PlanId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
responses:
'200':
description: Deactivated plan.
content:
application/json:
schema:
"$ref": "#/components/schemas/DeletedPlanResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
"/plans/{plan_id}/enrollments":
get:
tags:
- Plans
summary: List enrollments for a plan
description: "Required scope: `enrollments:read`."
operationId: listAdminApiPlanEnrollments
x-required-scope: enrollments:read
parameters:
- "$ref": "#/components/parameters/PlanId"
- "$ref": "#/components/parameters/Limit"
- "$ref": "#/components/parameters/Cursor"
responses:
'200':
description: Cursor-paginated enrollments.
content:
application/json:
schema:
"$ref": "#/components/schemas/EnrollmentListResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
"/enrollments/{enrollment_id}":
get:
tags:
- Plans
summary: Get an enrollment
description: "Required scope: `enrollments:read`."
operationId: getAdminApiEnrollment
x-required-scope: enrollments:read
parameters:
- "$ref": "#/components/parameters/EnrollmentId"
responses:
'200':
description: Enrollment.
content:
application/json:
schema:
"$ref": "#/components/schemas/EnrollmentResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/payments":
get:
tags:
- Plans
summary: List payments for a space
description: "Required scope: `payments:read`."
operationId: listAdminApiSpacePayments
x-required-scope: payments:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/Limit"
- "$ref": "#/components/parameters/Cursor"
- "$ref": "#/components/parameters/UserIdFilter"
- "$ref": "#/components/parameters/PaymentStatusFilter"
responses:
'200':
description: Cursor-paginated payments.
content:
application/json:
schema:
"$ref": "#/components/schemas/PaymentListResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
"/payments/{payment_id}":
get:
tags:
- Plans
summary: Get a payment
description: "Required scope: `payments:read`."
operationId: getAdminApiPayment
x-required-scope: payments:read
parameters:
- "$ref": "#/components/parameters/PaymentId"
responses:
'200':
description: Payment.
content:
application/json:
schema:
"$ref": "#/components/schemas/PaymentResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/coupons":
get:
tags:
- Plans
summary: List coupons for a space
description: "Required scope: `coupons:read`."
operationId: listAdminApiSpaceCoupons
x-required-scope: coupons:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/Limit"
- "$ref": "#/components/parameters/Cursor"
- "$ref": "#/components/parameters/SearchQuery"
- "$ref": "#/components/parameters/CouponStatusFilter"
responses:
'200':
description: Cursor-paginated coupons.
content:
application/json:
schema:
"$ref": "#/components/schemas/CouponListResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
post:
tags:
- Plans
summary: Create a coupon
description: "Required scope: `coupons:write`."
operationId: createAdminApiSpaceCoupon
x-required-scope: coupons:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/CouponWriteRequest"
responses:
'201':
description: Coupon created.
content:
application/json:
schema:
"$ref": "#/components/schemas/CouponResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/coupons/{coupon_id}":
get:
tags:
- Plans
summary: Get a coupon
description: "Required scope: `coupons:read`."
operationId: getAdminApiCoupon
x-required-scope: coupons:read
parameters:
- "$ref": "#/components/parameters/CouponId"
responses:
'200':
description: Coupon.
content:
application/json:
schema:
"$ref": "#/components/schemas/CouponResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
patch:
tags:
- Plans
summary: Update a coupon
description: "Required scope: `coupons:write`. Coupon discount type is immutable after creation."
operationId: updateAdminApiCoupon
x-required-scope: coupons:write
parameters:
- "$ref": "#/components/parameters/CouponId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/CouponUpdateRequest"
responses:
'200':
description: Updated coupon.
content:
application/json:
schema:
"$ref": "#/components/schemas/CouponResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
delete:
tags:
- Plans
summary: Deactivate a coupon
description: "Required scope: `coupons:write`."
operationId: deleteAdminApiCoupon
x-required-scope: coupons:write
parameters:
- "$ref": "#/components/parameters/CouponId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
responses:
'200':
description: Deactivated coupon.
content:
application/json:
schema:
"$ref": "#/components/schemas/DeletedCouponResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/broadcasts":
get:
tags:
- Broadcasts
summary: List broadcasts for a space
description: "Required scope: `broadcasts:read`."
operationId: listAdminApiSpaceBroadcasts
x-required-scope: broadcasts:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/Limit"
- "$ref": "#/components/parameters/Cursor"
- "$ref": "#/components/parameters/SearchQuery"
- "$ref": "#/components/parameters/BroadcastStatusFilter"
responses:
'200':
description: Cursor-paginated broadcasts.
content:
application/json:
schema:
"$ref": "#/components/schemas/BroadcastListResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
post:
tags:
- Broadcasts
summary: Create a draft broadcast
description: "Required scope: `broadcasts:write`. Creating a broadcast never sends it. Use `POST /broadcasts/{broadcast_id}/send` to enqueue delivery."
operationId: createAdminApiSpaceBroadcast
x-required-scope: broadcasts:write
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/BroadcastWriteRequest"
responses:
'201':
description: Draft broadcast created.
content:
application/json:
schema:
"$ref": "#/components/schemas/BroadcastResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
"/broadcasts/{broadcast_id}":
get:
tags:
- Broadcasts
summary: Get a broadcast
description: "Required scope: `broadcasts:read`."
operationId: getAdminApiBroadcast
x-required-scope: broadcasts:read
parameters:
- "$ref": "#/components/parameters/BroadcastId"
responses:
'200':
description: Broadcast.
content:
application/json:
schema:
"$ref": "#/components/schemas/BroadcastResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
patch:
tags:
- Broadcasts
summary: Update a draft broadcast
description: "Required scope: `broadcasts:write`."
operationId: updateAdminApiBroadcast
x-required-scope: broadcasts:write
parameters:
- "$ref": "#/components/parameters/BroadcastId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/BroadcastWriteRequest"
responses:
'200':
description: Updated broadcast.
content:
application/json:
schema:
"$ref": "#/components/schemas/BroadcastResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
'413':
"$ref": "#/components/responses/PayloadTooLarge"
'415':
"$ref": "#/components/responses/UnsupportedMediaType"
delete:
tags:
- Broadcasts
summary: Delete a broadcast
description: "Required scope: `broadcasts:write`."
operationId: deleteAdminApiBroadcast
x-required-scope: broadcasts:write
parameters:
- "$ref": "#/components/parameters/BroadcastId"
- "$ref": "#/components/parameters/IdempotencyKeyOptional"
responses:
'200':
description: Deleted broadcast.
content:
application/json:
schema:
"$ref": "#/components/schemas/DeletedBroadcastResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
"/broadcasts/{broadcast_id}/send":
post:
tags:
- Broadcasts
summary: Send a broadcast
description: "Required scope: `broadcasts:send`. Enqueues asynchronous delivery and requires an `Idempotency-Key`."
operationId: sendAdminApiBroadcast
x-required-scope: broadcasts:send
parameters:
- "$ref": "#/components/parameters/BroadcastId"
- "$ref": "#/components/parameters/IdempotencyKeyRequired"
responses:
'202':
description: Broadcast delivery queued.
content:
application/json:
schema:
"$ref": "#/components/schemas/BroadcastSendResponse"
'409':
"$ref": "#/components/responses/Conflict"
'400':
"$ref": "#/components/responses/BadRequest"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
"/broadcasts/{broadcast_id}/delivery_status":
get:
tags:
- Broadcasts
summary: Get broadcast delivery status
description: "Required scope: `broadcasts:read`."
operationId: getAdminApiBroadcastDeliveryStatus
x-required-scope: broadcasts:read
parameters:
- "$ref": "#/components/parameters/BroadcastId"
responses:
'200':
description: Broadcast delivery status.
content:
application/json:
schema:
"$ref": "#/components/schemas/BroadcastDeliveryStatusResponse"
'401':
"$ref": "#/components/responses/Unauthorized"
'400':
"$ref": "#/components/responses/BadRequest"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
"/spaces/{space_id}/automations":
get:
tags:
- Automations
summary: List automations on a space
description: "Required scope: `automations:read`. Returns only automations (not legacy interactive journeys)."
operationId: listAdminApiAutomations
x-required-scope: automations:read
parameters:
- "$ref": "#/components/parameters/SpaceId"
- "$ref": "#/components/parameters/Limit"
- "$ref": "#/components/parameters/Cursor"
responses:
'200':
description: Paginated list of automations.
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
"$ref": "#/components/schemas/Automation"
pagination:
"$ref": "#/components/schemas/Pagination"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
post:
tags:
- Automations
summary: Create an automation
description: "Required scope: `automations:manage`. `trigger_type` is a trigger key from `GET /automations/capabilities` (e.g. `person_registered`). One automation per trigger type per space; `survey_completed` is not authorable yet."
operationId: createAdminApiAutomation
x-required-scope: automations:manage
parameters:
- "$ref": "#/components/parameters/SpaceId"
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- trigger_type
properties:
trigger_type:
type: string
description: Trigger key (see capabilities), e.g. person_registered
name:
type: string
responses:
'201':
description: The created automation with its steps.
content:
application/json:
schema:
type: object
properties:
data:
"$ref": "#/components/schemas/AutomationDetail"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'409':
description: An automation for this trigger already exists on the space.
'422':
description: Validation failed (unknown or deferred trigger_type).
'429':
"$ref": "#/components/responses/RateLimited"
"/automations/capabilities":
get:
tags:
- Automations
summary: Automation authoring capabilities
description: "Required scope: `automations:read`. Discovery payload: trigger types, action types (with params, id-references, deactivation support, and plan gating), and the condition rule catalog. Optional `space_id` scopes the conditional-step allowance. Call this before authoring."
operationId: getAdminApiAutomationCapabilities
x-required-scope: automations:read
parameters:
- name: space_id
in: query
required: false
schema:
type: string
responses:
'200':
description: Capabilities payload.
content:
application/json:
schema:
type: object
properties:
data:
type: object
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'429':
"$ref": "#/components/responses/RateLimited"
"/automations/{automation_id}":
get:
tags:
- Automations
summary: Get automation details
description: "Required scope: `automations:read`. Returns the automation with its steps."
operationId: getAdminApiAutomation
x-required-scope: automations:read
parameters:
- "$ref": "#/components/parameters/AutomationId"
responses:
'200':
description: Automation with steps.
content:
application/json:
schema:
type: object
properties:
data:
"$ref": "#/components/schemas/AutomationDetail"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'429':
"$ref": "#/components/responses/RateLimited"
patch:
tags:
- Automations
summary: Update an automation (rename / activate / pause)
description: "Required scope: `automations:manage`."
operationId: updateAdminApiAutomation
x-required-scope: automations:manage
parameters:
- "$ref": "#/components/parameters/AutomationId"
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
active:
type: boolean
responses:
'200':
description: The updated automation.
content:
application/json:
schema:
type: object
properties:
data:
"$ref": "#/components/schemas/Automation"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'429':
"$ref": "#/components/responses/RateLimited"
delete:
tags:
- Automations
summary: Delete an automation
description: "Required scope: `automations:manage`. Refuses with 409 if active enrollments exist unless `force=true` (which cancels them)."
operationId: deleteAdminApiAutomation
x-required-scope: automations:manage
parameters:
- "$ref": "#/components/parameters/AutomationId"
- name: force
in: query
required: false
schema:
type: boolean
responses:
'200':
description: Deletion result.
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
description: Active enrollments present; pass force=true to cancel and delete.
'429':
"$ref": "#/components/responses/RateLimited"
"/automations/{automation_id}/steps":
get:
tags:
- Automations
summary: List automation steps
description: "Required scope: `automations:read`. Steps in order with id, action_type, params (public ids), and edges (next/on_yes/on_no)."
operationId: listAdminApiAutomationSteps
x-required-scope: automations:read
parameters:
- "$ref": "#/components/parameters/AutomationId"
responses:
'200':
description: Ordered steps.
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
"$ref": "#/components/schemas/AutomationStep"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'429':
"$ref": "#/components/responses/RateLimited"
post:
tags:
- Automations
summary: Add a step
description: "Required scope: `automations:manage`. `action_type` and `params` per `GET /automations/capabilities`. Optional edges next/on_yes/on_no (astep_ ids); omit for linear append."
operationId: createAdminApiAutomationStep
x-required-scope: automations:manage
parameters:
- "$ref": "#/components/parameters/AutomationId"
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/AutomationStepCreateInput"
responses:
'201':
description: The created step.
content:
application/json:
schema:
type: object
properties:
data:
"$ref": "#/components/schemas/AutomationStep"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'422':
description: Validation failed (bad action, params, edges, or plan gate).
'429':
"$ref": "#/components/responses/RateLimited"
"/automations/{automation_id}/steps/reorder":
post:
tags:
- Automations
summary: Reorder steps (linear flows)
description: "Required scope: `automations:manage`. Re-chains execution to the given order. Linear automations only — branched graphs use the replace endpoint."
operationId: reorderAdminApiAutomationSteps
x-required-scope: automations:manage
parameters:
- "$ref": "#/components/parameters/AutomationId"
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- order
properties:
order:
type: array
items:
type: string
responses:
'200':
description: Reordered steps.
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'422':
description: Branched automation, or order did not list every step.
'429':
"$ref": "#/components/responses/RateLimited"
"/automations/{automation_id}/steps/replace":
post:
tags:
- Automations
summary: Replace the step graph (diff/upsert)
description: "Required scope: `automations:manage`. One-shot graph: temp_id for new steps, id (astep_) for existing; omitted steps are removed and their enrollments migrate. Wire edges with next/on_yes/on_no. Preferred for building or branching."
operationId: replaceAdminApiAutomationSteps
x-required-scope: automations:manage
parameters:
- "$ref": "#/components/parameters/AutomationId"
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- steps
properties:
steps:
type: array
items:
"$ref": "#/components/schemas/AutomationStepCreateInput"
responses:
'200':
description: The resulting step graph.
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'422':
description: Validation failed.
'429':
"$ref": "#/components/responses/RateLimited"
"/automations/{automation_id}/steps/{step_id}":
patch:
tags:
- Automations
summary: Update a step
description: "Required scope: `automations:manage`."
operationId: updateAdminApiAutomationStep
x-required-scope: automations:manage
parameters:
- "$ref": "#/components/parameters/AutomationId"
- name: step_id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
"$ref": "#/components/schemas/AutomationStepInput"
responses:
'200':
description: The updated step.
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'422':
description: Validation failed.
'429':
"$ref": "#/components/responses/RateLimited"
delete:
tags:
- Automations
summary: Delete a step
description: "Required scope: `automations:manage`. In-flight enrollments migrate to the successor (or cancel if it's the last step); deleting a condition prunes its branch subtree."
operationId: deleteAdminApiAutomationStep
x-required-scope: automations:manage
parameters:
- "$ref": "#/components/parameters/AutomationId"
- name: step_id
in: path
required: true
schema:
type: string
responses:
'200':
description: Deletion result.
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'429':
"$ref": "#/components/responses/RateLimited"
"/automations/{automation_id}/members":
get:
tags:
- Automations
summary: List members enrolled in an automation
description: "Required scope: `automations:read`. Filter by `status` (ongoing or completed)."
operationId: listAdminApiAutomationMembers
x-required-scope: automations:read
parameters:
- "$ref": "#/components/parameters/AutomationId"
- "$ref": "#/components/parameters/Limit"
- "$ref": "#/components/parameters/Cursor"
- name: status
in: query
schema:
type: string
enum:
- ongoing
- completed
description: Filter by enrollment status.
responses:
'200':
description: Paginated list of automation enrollments.
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
"$ref": "#/components/schemas/AutomationMember"
pagination:
"$ref": "#/components/schemas/Pagination"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'429':
"$ref": "#/components/responses/RateLimited"
post:
tags:
- Automations
summary: Add a member to an automation
description: "Required scope: `automations:write`. Triggers the automation flow for the member. Identify the member by `member_id`, `user_id`, or `email`."
operationId: addAdminApiAutomationMember
x-required-scope: automations:write
parameters:
- "$ref": "#/components/parameters/AutomationId"
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
member_id:
type: string
pattern: "^mem_"
description: Member ID — must belong to the automation's space.
user_id:
type: string
pattern: "^usr_"
description: User ID — alternative to member_id.
email:
type: string
format: email
description: User email — alternative to member_id or user_id.
responses:
'201':
description: Member enrolled in automation.
content:
application/json:
schema:
type: object
properties:
data:
"$ref": "#/components/schemas/AutomationMember"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'409':
description: Member is already enrolled.
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
'429':
"$ref": "#/components/responses/RateLimited"
"/automations/{automation_id}/members/{enrollment_id}":
get:
tags:
- Automations
summary: Get a member's automation enrollment
description: "Required scope: `automations:read`."
operationId: getAdminApiAutomationMember
x-required-scope: automations:read
parameters:
- "$ref": "#/components/parameters/AutomationId"
- "$ref": "#/components/parameters/AutomationEnrollmentId"
responses:
'200':
description: Automation enrollment details.
content:
application/json:
schema:
type: object
properties:
data:
"$ref": "#/components/schemas/AutomationMember"
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'429':
"$ref": "#/components/responses/RateLimited"
delete:
tags:
- Automations
summary: Remove a member from an automation
description: "Required scope: `automations:write`. Stops the automation flow for this member."
operationId: removeAdminApiAutomationMember
x-required-scope: automations:write
parameters:
- "$ref": "#/components/parameters/AutomationId"
- "$ref": "#/components/parameters/AutomationEnrollmentId"
responses:
'200':
description: Member removed from automation.
content:
application/json:
schema:
type: object
properties:
data:
type: object
properties:
id:
type: string
pattern: "^aenr_"
removed:
type: boolean
'401':
"$ref": "#/components/responses/Unauthorized"
'403':
"$ref": "#/components/responses/Forbidden"
'404':
"$ref": "#/components/responses/NotFound"
'429':
"$ref": "#/components/responses/RateLimited"
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: opaque
description: Use an API token with the sutra_live_sk_ prefix. Query-param tokens are rejected.
parameters:
Limit:
name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 25
Cursor:
name: cursor
in: query
schema:
type: string
pattern: "^cur_"
description: Opaque cursor returned from the previous page.
SpaceId:
name: space_id
in: path
required: true
schema:
type: string
pattern: "^sp_"
NodeUid:
name: node_uid
in: path
required: true
schema:
type: string
description: Tiptap node attrs.uid.
DesignDraftId:
name: draft_id
in: path
required: true
schema:
type: string
pattern: "^dsdft_"
CompactResponseMode:
name: response_mode
in: query
required: false
schema:
type: string
enum:
- compact
description: For incremental document mutations, omit the full document and return only the new revision/digest plus canonical changed nodes or affected UIDs.
ShareBlockConfigId:
name: id
in: path
required: true
schema:
type: string
pattern: "^shbk_"
NavbarConfigId:
name: id
in: path
required: true
schema:
type: string
pattern: "^nvbr_"
MemberId:
name: member_id
in: path
required: true
schema:
type: string
pattern: "^mem_"
ContactId:
name: contact_id
in: path
required: true
schema:
type: string
pattern: "^contact_"
MemberPropertyId:
name: member_property_id
in: path
required: true
schema:
type: string
pattern: "^mprop_"
SpacePropertyId:
name: space_property_id
in: path
required: true
schema:
type: string
pattern: "^sprop_"
SpaceIdFilter:
name: space_id
in: query
schema:
type: string
pattern: "^sp_"
UserIdFilter:
name: user_id
in: query
schema:
type: string
pattern: "^usr_"
EmailFilter:
name: email
in: query
schema:
type: string
format: email
description: Exact-match only. Requires members.email:read.
MemberPropertyFilters:
name: property_filters
in: query
style: deepObject
explode: true
schema:
type: object
additionalProperties: true
description: Filter people by member-property key or `mprop_` id, for example `property_filters[in_person_workshop]=Sweden`. Requires `member_properties:read`.
MemberPropertyKeyFilter:
name: property_key
in: query
schema:
type: string
description: Member-property key or `mprop_` id to filter by. Use with `property_value`. Requires `member_properties:read`.
MemberPropertyValueFilter:
name: property_value
in: query
schema:
type: string
description: Exact member-property value for `property_key`. Select values may use option names or option values.
SearchQuery:
name: q
in: query
schema:
type: string
description: Case-insensitive text search. Matches vary by endpoint — spaces
search by name or URL slug, members by name/email, surveys by title, etc.
SpaceStateFilter:
name: state
in: query
schema:
type: string
enum:
- active
- archived
- pending
description: Filter spaces by state. pending = scheduled to launch
(launch_on_date with a future launch_time).
SpaceTypeFilter:
name: type
in: query
schema:
type: string
description: Filter spaces by type (e.g. content, forum).
SpacePrivacyFilter:
name: privacy
in: query
schema:
type: string
enum:
- open
- private
- payment
- closed
- secret
description: Filter spaces by privacy level. Writes accept open, private,
and payment; closed and secret are legacy values that may still exist
on older spaces.
MemberRoleFilter:
name: role
in: query
schema:
type: string
enum:
- member
- editor
- moderator
description: Filter members by role.
MemberStateFilter:
name: state
in: query
schema:
type: string
enum:
- active
- pending
description: Filter members by state.
SurveyTypeFilter:
name: type
in: query
schema:
type: string
description: Filter surveys by type.
BroadcastStatusFilter:
name: status
in: query
schema:
type: string
enum:
- draft
- scheduled
- sent
description: Filter broadcasts by status.
PlanStatusFilter:
name: status
in: query
schema:
type: string
description: Filter plans by status.
PlanFrequencyFilter:
name: frequency
in: query
schema:
type: string
description: Filter plans by billing frequency.
InvitationEmailFilter:
name: email
in: query
schema:
type: string
format: email
description: Search invitations by email (ILIKE). Requires members.email:read.
InvitationStateFilter:
name: state
in: query
schema:
type: string
enum:
- pending
- accepted
- declined
description: Filter invitations by state.
InvitationRoleFilter:
name: role
in: query
schema:
type: string
enum:
- member
- editor
- moderator
description: Filter invitations by role.
PaymentStatusFilter:
name: status
in: query
schema:
type: string
description: Filter payments by status.
CouponStatusFilter:
name: status
in: query
schema:
type: string
description: Filter coupons by status.
IdempotencyKeyOptional:
name: Idempotency-Key
in: header
required: false
schema:
type: string
minLength: 8
maxLength: 255
description: Optional for single-item mutations. Reusing the same key returns the original completed response.
IdempotencyKeyRequired:
name: Idempotency-Key
in: header
required: true
schema:
type: string
minLength: 8
maxLength: 255
description: Required for non-atomic or externally side-effecting mutations.
InvitationId:
name: invitation_id
in: path
required: true
schema:
type: string
pattern: "^inv_"
BlockId:
name: block_id
in: path
required: true
schema:
type: string
pattern: "^blk_"
MessageId:
name: message_id
in: path
required: true
schema:
type: string
pattern: "^blk_"
ReflectionId:
name: reflection_id
in: path
required: true
schema:
type: string
pattern: "^reply_"
SurveyId:
name: survey_id
in: path
required: true
schema:
type: string
pattern: "^surv_"
SubmissionId:
name: submission_id
in: path
required: true
schema:
type: string
description: Stable survey submission identifier returned by the submissions list.
PlanId:
name: plan_id
in: path
required: true
schema:
type: string
pattern: "^plan_"
EnrollmentId:
name: enrollment_id
in: path
required: true
schema:
type: string
pattern: "^enr_"
PaymentId:
name: payment_id
in: path
required: true
schema:
type: string
pattern: "^pay_"
CouponId:
name: coupon_id
in: path
required: true
schema:
type: string
pattern: "^cpn_"
BroadcastId:
name: broadcast_id
in: path
required: true
schema:
type: string
pattern: "^bcst_"
AutomationId:
name: automation_id
in: path
required: true
schema:
type: string
pattern: "^auto_"
AutomationEnrollmentId:
name: enrollment_id
in: path
required: true
schema:
type: string
pattern: "^aenr_"
MediaId:
name: media_id
in: path
required: true
schema:
type: string
pattern: "^media_"
responses:
BadRequest:
description: Invalid JSON request body or unsupported Accept header.
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
Unauthorized:
description: Missing, invalid, expired, revoked, or rotated token.
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
Forbidden:
description: Insufficient scope or suspended/deleted application.
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
NotFound:
description: Resource does not exist or is outside the token user's authorized spaces.
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
ValidationFailed:
description: Request syntax or cursor validation failed.
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
RateLimited:
description: Public API rate limit exceeded.
headers:
Retry-After:
schema:
type: integer
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
Conflict:
description: The request conflicts with the current resource state.
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
IdempotencyConflict:
description: The supplied idempotency key is already being used for a different request or an in-flight request.
headers:
Retry-After:
schema:
type: integer
description: Present when the original request is still processing.
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
UnsupportedMediaType:
description: Requests with a body must use Content-Type application/json.
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
PayloadTooLarge:
description: Request body exceeds the maximum allowed size.
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
UpstreamError:
description: A required upstream side effect failed after authentication and validation.
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
ServiceUnavailable:
description: Required upload infrastructure is not configured or temporarily unavailable.
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
schemas:
MembershipSpaceListResponse:
type: object
required:
- data
- pagination
properties:
data:
type: array
items:
"$ref": "#/components/schemas/MembershipSpace"
pagination:
"$ref": "#/components/schemas/Pagination"
MembershipSpace:
type: object
required:
- id
- name
- type
- state
- privacy
- created_at
- updated_at
- membership
- admin_access
properties:
id:
type: string
pattern: "^sp_"
name:
type: string
type:
type: string
nullable: true
state:
type: string
privacy:
type: string
nullable: true
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
parent_id:
type: string
nullable: true
pattern: "^sp_"
placement:
"$ref": "#/components/schemas/PlacementResult"
membership:
"$ref": "#/components/schemas/MembershipSpaceMembership"
admin_access:
type: boolean
description: True when the token can use this space with normal Admin API space subresources.
MembershipSpaceMembership:
type: object
required:
- state
- role
- joined_at
properties:
state:
type: string
enum:
- active
- pending
role:
type: string
nullable: true
joined_at:
type: string
format: date-time
MemberListResponse:
type: object
required:
- data
- pagination
properties:
data:
type: array
items:
"$ref": "#/components/schemas/Member"
pagination:
"$ref": "#/components/schemas/Pagination"
ContactListResponse:
type: object
required:
- data
- pagination
properties:
data:
type: array
items:
"$ref": "#/components/schemas/Contact"
pagination:
"$ref": "#/components/schemas/Pagination"
ContactResponse:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/Contact"
Space:
type: object
required:
- id
- name
- slug
- url
- type
- state
- pod_type
- privacy
- created_at
- updated_at
properties:
id:
type: string
pattern: "^sp_"
name:
type: string
slug:
type: string
nullable: true
description: URL slug for the space.
url:
type: string
format: uri
nullable: true
description: Canonical public URL for the space (null when no public URL is available).
type:
type: string
state:
type: string
pod_type:
type: string
enum:
- standard
- readonly
privacy:
type: string
nullable: true
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
description:
type: string
nullable: true
description: Detail reads (GET/PATCH a single space) only.
visibility:
type: string
description: '"public" or "". Detail reads only.'
size:
type: integer
nullable: true
description: Member limit (null = unlimited). Detail reads only.
resource_editing:
type: string
nullable: true
description: Detail reads only.
allow_reflections:
type: boolean
nullable: true
description: Detail reads only.
show_members:
type: boolean
nullable: true
description: Detail reads only.
hangout_link:
type: string
nullable: true
description: Detail reads only.
abstract_text:
type: string
nullable: true
description: Detail reads only.
emojicon:
type: string
nullable: true
description: Detail reads only.
block_until_registered:
type: boolean
nullable: true
description: Detail reads only.
block_until_approved:
type: boolean
nullable: true
description: Detail reads only.
allow_members_to_invite:
type: boolean
nullable: true
description: Detail reads only.
circle_creation:
type: array
items:
type: string
description: Detail reads only.
present_as:
type: string
nullable: true
description: Detail reads only.
use_legacy_registration_page:
type: boolean
nullable: true
description: Detail reads only.
url_handle:
type: string
nullable: true
description: Shareable-link handle. Detail reads only.
settings:
"$ref": "#/components/schemas/SpaceSettings"
description: Behavioral settings. Detail reads only.
appearance:
"$ref": "#/components/schemas/SpaceAppearance"
description: Theme and layout. Detail reads only.
payment:
"$ref": "#/components/schemas/SpacePayment"
description: Payment gate and checkout toggles. Detail reads only.
SpacePayment:
type: object
description: Paid-access state (plans system). enabled is computed from
the full gate (payment privacy AND space_plans_enabled AND an active
plan) — never trust space_plans_enabled alone, because a fresh
settings row force-sets it. Stripe credentials are never exposed.
properties:
enabled:
type: boolean
description: Whether paid access is fully on (visitors can purchase).
privacy:
type: string
nullable: true
circle_payment:
type: string
nullable: true
description: Client checkout routing value ("plans" when enabled
through this API).
space_plans_enabled:
type: boolean
nullable: true
active_plans_count:
type: integer
can_accept_charges:
type: boolean
description: Whether the connected Stripe account can take charges.
allow_multiple_space_plan_selections:
type: boolean
nullable: true
guest_checkout_enabled:
type: boolean
nullable: true
guest_invitation_message:
type: string
nullable: true
terms_enabled:
type: boolean
nullable: true
terms_link_label:
type: string
nullable: true
terms_content:
type: string
nullable: true
WebsiteState:
type: object
properties:
space_id:
type: string
pattern: "^sp_"
description: The resolved website root's ID.
enabled:
type: boolean
show_spaces_in_page:
type: boolean
header_config_id:
type: string
nullable: true
pattern: "^shbk_"
footer_config_id:
type: string
nullable: true
pattern: "^shbk_"
header_detached:
type: boolean
footer_detached:
type: boolean
header_hidden:
type: boolean
description: Funnel mode — website mode is on but the shared site
header is hidden site-wide. The header config is preserved.
WebsiteStateResponse:
type: object
properties:
data:
"$ref": "#/components/schemas/WebsiteState"
SpaceWebsiteUpdateRequest:
type: object
properties:
enabled:
type: boolean
description: true enables website mode (Silver+; otherwise 422
upgrade_required) and auto-creates a default header + footer on first
enable; false disables it while preserving the configs.
show_spaces_in_page:
type: boolean
description: Show child spaces inline in the page while in website
mode. Persisted as a preference; never re-set in the same call that
disables website mode.
header_config_id:
type: string
nullable: true
pattern: "^shbk_"
description: A site_header share block to use as the header, or null to
clear. Must be a site_header in the same space.
footer_config_id:
type: string
nullable: true
pattern: "^shbk_"
description: A site_footer share block to use as the footer, or null to
clear. Must be a site_footer in the same space.
header_hidden:
type: boolean
description: "Funnel mode: true keeps website mode on but hides the
shared site header site-wide (the header config is preserved); false
shows it again (Website mode). Only meaningful while website mode is
enabled. Display mode = Normal (enabled:false), Website
(enabled:true), Funnel (enabled:true + header_hidden:true)."
ShareBlockConfig:
type: object
properties:
id:
type: string
pattern: "^shbk_"
name:
type: string
kind:
type: string
enum:
- generic
- site_header
- site_footer
content:
type: array
description: Tiptap node array. A site_header is typically a single
navbar node referencing a NavbarConfig.
items:
type: object
additionalProperties: true
style:
type: object
additionalProperties: true
usage_count:
type: integer
WebsiteStyleWarnings:
type: array
description: >-
Advisory style/link warnings returned on share-block and navbar
create/update. The write still succeeded; these flag input the renderer
ignores — e.g. CSS at the top level of a style instead of under
style.styles, an unknown navbar field, a bad enum value, or a malformed
link. Present only when there are issues.
items:
type: object
properties:
code:
type: string
example: css_at_top_level
path:
type: string
example: style.background-color
message:
type: string
ShareBlockConfigResponse:
type: object
properties:
data:
"$ref": "#/components/schemas/ShareBlockConfig"
warnings:
"$ref": "#/components/schemas/WebsiteStyleWarnings"
ShareBlockConfigListResponse:
type: object
properties:
data:
type: array
items:
"$ref": "#/components/schemas/ShareBlockConfig"
ShareBlockConfigCreateRequest:
type: object
required:
- name
properties:
name:
type: string
description: Unique within the space.
kind:
type: string
enum:
- generic
- site_header
- site_footer
default: generic
content:
type: array
items:
type: object
additionalProperties: true
style:
type: object
additionalProperties: true
ShareBlockConfigUpdateRequest:
type: object
properties:
name:
type: string
content:
type: array
items:
type: object
additionalProperties: true
style:
type: object
additionalProperties: true
NavbarConfig:
type: object
properties:
id:
type: string
pattern: "^nvbr_"
name:
type: string
links:
type: array
items:
type: object
additionalProperties: true
style:
type: object
additionalProperties: true
usage_count:
type: integer
NavbarConfigResponse:
type: object
properties:
data:
"$ref": "#/components/schemas/NavbarConfig"
warnings:
"$ref": "#/components/schemas/WebsiteStyleWarnings"
NavbarConfigListResponse:
type: object
properties:
data:
type: array
items:
"$ref": "#/components/schemas/NavbarConfig"
NavbarConfigCreateRequest:
type: object
required:
- name
properties:
name:
type: string
description: Unique within the space.
links:
type: array
items:
type: object
additionalProperties: true
style:
type: object
additionalProperties: true
NavbarConfigUpdateRequest:
type: object
properties:
name:
type: string
links:
type: array
items:
type: object
additionalProperties: true
style:
type: object
additionalProperties: true
DeletedResponse:
type: object
properties:
data:
type: object
additionalProperties: true
description: "The deleted resource payload with deleted: true."
SpacePaymentUpdateRequest:
type: object
properties:
enabled:
type: boolean
description: true turns paid access on (writes payment privacy,
plans checkout routing, and the plans flag) after the
preconditions pass. false tears it down.
force:
type: boolean
description: With enabled false, cancels live Stripe subscriptions
(active, trialing, pending, past_due, requires_action) instead of
returning 409.
target_privacy:
type: string
enum:
- open
- private
default: private
description: Privacy the space moves to on disable.
allow_multiple_space_plan_selections:
type: boolean
description: Requires all active plans (including hidden ones) to
share one currency and one billing family.
guest_checkout_enabled:
type: boolean
description: Rejected while any active plan has prerequisites.
guest_invitation_message:
type: string
nullable: true
terms_enabled:
type: boolean
terms_link_label:
type: string
nullable: true
terms_content:
type: string
nullable: true
SpaceAppearance:
type: object
description: Resolved theme values (JSONB-first with legacy column
fallback) plus hidden layout elements. Returned on detail reads;
written via PATCH /spaces/{space_id}/appearance.
properties:
header_color:
type: string
nullable: true
header_link_color:
type: string
nullable: true
primary_button_background_color:
type: string
nullable: true
primary_button_text_color:
type: string
nullable: true
secondary_button_background_color:
type: string
nullable: true
secondary_button_text_color:
type: string
nullable: true
background_color:
type: string
nullable: true
secondary_background_color:
type: string
nullable: true
default_text_color:
type: string
nullable: true
sub_header_text_color:
type: string
nullable: true
sidebar_background_color:
type: string
nullable: true
sidebar_text_color:
type: string
nullable: true
default_link_color:
type: string
nullable: true
default_badge_color:
type: string
nullable: true
default_badge_text_color:
type: string
nullable: true
heading_font:
type: string
nullable: true
body_font:
type: string
nullable: true
registration_page_background_color:
type: string
nullable: true
registration_page_default_text_color:
type: string
nullable: true
registration_page_sidebar_background_color:
type: string
nullable: true
registration_page_sidebar_text_color:
type: string
nullable: true
registration_page_button_background_color:
type: string
nullable: true
registration_page_button_text_color:
type: string
nullable: true
registration_page_link_color:
type: string
nullable: true
registration_page_heading_font:
type: string
nullable: true
registration_page_body_font:
type: string
nullable: true
accent_color:
type: string
nullable: true
accents:
type: array
nullable: true
items:
type: string
gradients:
type: object
nullable: true
additionalProperties:
type: string
corner_style:
type: string
nullable: true
density:
type: string
nullable: true
heading_font_weight:
type: string
nullable: true
body_font_weight:
type: string
nullable: true
hidden_layout_elements:
type: array
items:
type: string
enum:
- sidebar
- header
- cover
- title
- breadcrumbs
SpaceImageRequest:
type: object
required:
- kind
- source_url
properties:
kind:
type: string
enum:
- cover
- logo
- thumbnail
- meta
description: 'cover: page banner (center-cropped toward 2400×600,
jpg/jpeg/gif/png/webp). logo: 250×80 crop, jpg/jpeg/gif/png,
tier-gated. thumbnail: list-card image, 600×300 crop,
jpg/jpeg/gif/png/webp. meta: social-share image, 1200×630 crop,
jpg/jpeg/gif/png.'
source_url:
type: string
format: uri
nullable: true
description: Public http(s) URL of the image to ingest, or null to
remove the current image.
SpaceImageResponse:
type: object
required:
- data
properties:
data:
type: object
required:
- id
- kind
properties:
id:
type: string
pattern: "^sp_"
kind:
type: string
enum:
- cover
- logo
- thumbnail
- meta
url:
type: string
nullable: true
description: Stored image URL (null after removal).
SpaceAppearanceUpdateRequest:
type: object
description: 'Partial update: only the keys present are written. Null
clears a theme override. Colors are hex strings like #1a2b3c. Writing
any base color cascades the full current theme to all descendants.'
properties:
header_color:
type: string
nullable: true
header_link_color:
type: string
nullable: true
primary_button_background_color:
type: string
nullable: true
primary_button_text_color:
type: string
nullable: true
secondary_button_background_color:
type: string
nullable: true
secondary_button_text_color:
type: string
nullable: true
background_color:
type: string
nullable: true
secondary_background_color:
type: string
nullable: true
default_text_color:
type: string
nullable: true
sub_header_text_color:
type: string
nullable: true
sidebar_background_color:
type: string
nullable: true
sidebar_text_color:
type: string
nullable: true
default_link_color:
type: string
nullable: true
default_badge_color:
type: string
nullable: true
default_badge_text_color:
type: string
nullable: true
heading_font:
type: string
nullable: true
body_font:
type: string
nullable: true
registration_page_background_color:
type: string
nullable: true
registration_page_default_text_color:
type: string
nullable: true
registration_page_sidebar_background_color:
type: string
nullable: true
registration_page_sidebar_text_color:
type: string
nullable: true
registration_page_button_background_color:
type: string
nullable: true
registration_page_button_text_color:
type: string
nullable: true
registration_page_link_color:
type: string
nullable: true
registration_page_heading_font:
type: string
nullable: true
registration_page_body_font:
type: string
nullable: true
accent_color:
type: string
nullable: true
accents:
type: array
nullable: true
minItems: 3
maxItems: 5
items:
type: string
description: 3-5 hex colors used by templates for accent elements.
gradients:
type: object
nullable: true
description: Slot (hero, cta, ambient) to gradient ID from the
frontend gradient library.
additionalProperties:
type: string
corner_style:
type: string
nullable: true
enum:
- sharp
- subtle
- soft
- rounded
- null
density:
type: string
nullable: true
enum:
- compact
- standard
- comfortable
- spacious
- null
heading_font_weight:
type: string
nullable: true
body_font_weight:
type: string
nullable: true
hidden_layout_elements:
type: array
items:
type: string
enum:
- sidebar
- header
- cover
- title
- breadcrumbs
description: Layout chrome to hide on this space.
SpaceSettings:
type: object
nullable: true
description: Behavioral settings stored on the space's settings record.
Returned on detail reads; written via PATCH /spaces/{space_id}/settings.
properties:
show_start_date:
type: boolean
nullable: true
start_date:
type: string
format: date-time
nullable: true
end_date:
type: string
format: date-time
nullable: true
launch_on_date:
type: boolean
nullable: true
description: Gate for the scheduled launch. The paired launch_time
must be present whenever this is true.
launch_time:
type: string
format: date-time
nullable: true
archive_on_date:
type: boolean
nullable: true
archive_time:
type: string
format: date-time
nullable: true
readonly_on_date:
type: boolean
nullable: true
readonly_time:
type: string
format: date-time
nullable: true
new_member_notifications:
type: string
nullable: true
description: manager or none on writes; legacy rows may read everyone.
hide_member_emails:
type: boolean
nullable: true
allow_member_copy:
type: boolean
nullable: true
max_sub_space_membership:
type: integer
nullable: true
is_focus_mode:
type: boolean
nullable: true
allow_comments:
type: boolean
nullable: true
allow_completions:
type: boolean
nullable: true
show_mark_complete_button_in_header:
type: boolean
nullable: true
allow_members_to_create_tags:
type: boolean
nullable: true
list_auto_tag:
type: boolean
nullable: true
redirect_to_space:
type: string
nullable: true
description: Slug of an active space visitors are redirected to.
sidebar_default_opened:
type: boolean
nullable: true
sidebar_hide_children:
type: boolean
nullable: true
show_page_icon:
type: boolean
nullable: true
apply_to_sub_spaces:
type: boolean
nullable: true
is_cover_full_width:
type: boolean
nullable: true
space_width:
type: string
nullable: true
enum:
- wide
- narrow
- null
show_join_button:
type: boolean
nullable: true
show_registration_sidebar:
type: boolean
nullable: true
registration_button_text:
type: string
nullable: true
registration_width:
type: string
nullable: true
enum:
- wide
- narrow
- null
allow_interested_on_join:
type: boolean
nullable: true
meta_title:
type: string
nullable: true
meta_description:
type: string
nullable: true
seo_indexable:
type: boolean
nullable: true
members_map_interests_enabled:
type: boolean
nullable: true
members_map_show_ai_interests:
type: boolean
nullable: true
cobolt_indexing_excluded:
type: boolean
nullable: true
list_action_text:
type: string
nullable: true
list_template_id:
type: string
nullable: true
description: Template space slug; only meaningful when
list_child_version is template.
list_child_version:
type: string
nullable: true
description: posts, content, discussions, link, or template.
list_link_action:
type: string
nullable: true
description: subspace or linked.
list_show_author:
type: boolean
nullable: true
list_show_preview_text:
type: boolean
nullable: true
list_show_thumbnail:
type: boolean
nullable: true
list_show_comments_count:
type: boolean
nullable: true
list_show_members:
type: boolean
nullable: true
list_show_timestamp:
type: boolean
nullable: true
list_auto_thumbnail:
type: boolean
nullable: true
list_flat_view:
type: boolean
nullable: true
list_open_in_modal:
type: boolean
nullable: true
list_allow_likes:
type: boolean
nullable: true
list_filter_by:
type: string
nullable: true
list_privacy_control:
type: string
nullable: true
description: open, private, or any.
list_title_line_clamp:
type: integer
nullable: true
list_abstract_line_clamp:
type: integer
nullable: true
list_add_creator_as_role:
type: string
nullable: true
description: moderator, editor, or manager (member is rejected on writes).
list_children_capabilities:
type: array
nullable: true
items:
type: string
enum:
- full
- limited
SpaceSettingsUpdateRequest:
type: object
description: 'Partial update: only the keys present are written. Explicit
null clears nullable fields. Scheduling tier-gated to
professional/organization; completion fields and list_auto_tag likewise
when enabling.'
properties:
show_start_date:
type: boolean
start_date:
type: string
format: date-time
nullable: true
end_date:
type: string
format: date-time
nullable: true
launch_on_date:
type: boolean
description: Send launch_time in the same call when setting this true.
Turning it false clears launch_time and un-pends a pending space.
launch_time:
type: string
format: date-time
nullable: true
archive_on_date:
type: boolean
archive_time:
type: string
format: date-time
nullable: true
readonly_on_date:
type: boolean
readonly_time:
type: string
format: date-time
nullable: true
new_member_notifications:
type: string
enum:
- manager
- none
hide_member_emails:
type: boolean
allow_member_copy:
type: boolean
max_sub_space_membership:
type: integer
nullable: true
minimum: 0
is_focus_mode:
type: boolean
allow_comments:
type: boolean
allow_completions:
type: boolean
show_mark_complete_button_in_header:
type: boolean
description: When sent alone, allow_completions is set to match. When
both are sent they must agree (422 otherwise).
allow_members_to_create_tags:
type: boolean
list_auto_tag:
type: boolean
redirect_to_space:
type: string
nullable: true
description: Slug of an existing active space; null clears the redirect.
sidebar_default_opened:
type: boolean
sidebar_hide_children:
type: boolean
show_page_icon:
type: boolean
apply_to_sub_spaces:
type: boolean
is_cover_full_width:
type: boolean
space_width:
type: string
enum:
- wide
- narrow
show_join_button:
type: boolean
show_registration_sidebar:
type: boolean
registration_button_text:
type: string
nullable: true
maxLength: 100
registration_width:
type: string
enum:
- wide
- narrow
allow_interested_on_join:
type: boolean
meta_title:
type: string
nullable: true
maxLength: 200
meta_description:
type: string
nullable: true
maxLength: 500
seo_indexable:
type: boolean
members_map_interests_enabled:
type: boolean
members_map_show_ai_interests:
type: boolean
cobolt_indexing_excluded:
type: boolean
description: Turning this on purges the subtree from the AI index and
denormalizes the flag to descendants; turning it off restores
indexing for this space (descendant flags stay set until updated
themselves).
list_action_text:
type: string
nullable: true
maxLength: 100
list_template_id:
type: string
nullable: true
description: Template space slug. Requires list_child_version
template; cleared automatically when switching to a non-template
list_child_version.
list_child_version:
type: string
enum:
- posts
- content
- discussions
- link
- template
list_link_action:
type: string
enum:
- subspace
- linked
list_show_author:
type: boolean
list_show_preview_text:
type: boolean
list_show_thumbnail:
type: boolean
list_show_comments_count:
type: boolean
list_show_members:
type: boolean
list_show_timestamp:
type: boolean
list_auto_thumbnail:
type: boolean
list_flat_view:
type: boolean
list_open_in_modal:
type: boolean
list_allow_likes:
type: boolean
list_filter_by:
type: string
enum:
- custom_order
- pods.created_at DESC
- pods.created_at ASC
- pods.last_active DESC
- pods.updated_at ASC
- LOWER(pods.intention) ASC
- LOWER(pods.intention) DESC
list_privacy_control:
type: string
enum:
- open
- private
- any
list_title_line_clamp:
type: integer
nullable: true
minimum: 1
description: The web UI writes only 2 or 20 and will round-trip its
own values over API-written ones.
list_abstract_line_clamp:
type: integer
nullable: true
minimum: 1
list_add_creator_as_role:
type: string
enum:
- moderator
- editor
- manager
description: member is rejected (posts force editor; courses and
sections force manager).
list_children_capabilities:
type: array
items:
type: string
enum:
- full
- limited
Member:
type: object
required:
- id
- space_id
- user_id
- state
- role
- created_at
- updated_at
- user
properties:
id:
type: string
pattern: "^mem_"
space_id:
type: string
pattern: "^sp_"
user_id:
type: string
pattern: "^usr_"
state:
type: string
enum:
- active
- pending
role:
type: string
nullable: true
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
user:
"$ref": "#/components/schemas/User"
Contact:
type: object
required:
- id
- space_id
- user_id
- state
- first_name
- last_name
- name
- origin_space_ids
- created_at
- updated_at
properties:
id:
type: string
pattern: "^contact_"
space_id:
type: string
pattern: "^sp_"
description: Top-level CRM space that owns the contact record.
user_id:
type: string
nullable: true
pattern: "^usr_"
state:
type: string
enum:
- contact
first_name:
type: string
nullable: true
last_name:
type: string
nullable: true
name:
type: string
nullable: true
origin_space_ids:
type: array
items:
type: string
pattern: "^sp_"
email:
type: string
format: email
description: Present only with members.email:read.
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
MemberProperty:
type: object
required:
- id
- space_ids
- name
- key
- type
- sort_order
- options
- visibility
- created_at
- updated_at
properties:
id:
type: string
pattern: "^mprop_"
space_ids:
type: array
items:
type: string
pattern: "^sp_"
name:
type: string
key:
type: string
type:
type: string
enum:
- text
- select
- multi_select
- number
- date
- url
- phone
- location
sort_order:
type: integer
options:
type: object
additionalProperties: true
visibility:
type: array
items:
type: string
icon:
type: string
nullable: true
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
MemberPropertyWriteRequest:
type: object
properties:
name:
type: string
key:
type: string
type:
type: string
enum:
- text
- select
- multi_select
- number
- date
- url
- phone
- location
sort_order:
type: integer
options:
type: object
additionalProperties: true
description: For select and multi_select, use `values` with option objects containing `value` and `name`.
visibility:
type: array
items:
type: string
icon:
type: string
nullable: true
MemberPropertyResponse:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/MemberProperty"
MemberPropertyListResponse:
type: object
required:
- data
- pagination
properties:
data:
type: array
items:
"$ref": "#/components/schemas/MemberProperty"
pagination:
"$ref": "#/components/schemas/Pagination"
MemberPropertyReorderRequest:
type: object
required:
- property_ids
properties:
property_ids:
type: array
items:
type: string
pattern: "^mprop_"
MemberPropertyReorderResponse:
type: object
required:
- data
properties:
data:
type: object
required:
- space_id
- reordered
properties:
space_id:
type: string
pattern: "^sp_"
reordered:
type: boolean
enum:
- true
RemovedMemberProperty:
type: object
required:
- id
- deleted
properties:
id:
type: string
pattern: "^mprop_"
deleted:
type: boolean
enum:
- true
DeletedMemberPropertyResponse:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/RemovedMemberProperty"
MemberPropertyValue:
type: object
required:
- property_id
- value_id
- key
- name
- type
- value
- updated_at
properties:
property_id:
type: string
pattern: "^mprop_"
value_id:
type: string
nullable: true
pattern: "^mval_"
key:
type: string
name:
type: string
type:
type: string
value:
nullable: true
oneOf:
- type: string
- type: number
- type: boolean
- type: array
items: {}
- type: object
additionalProperties: true
updated_at:
type: string
nullable: true
format: date-time
MemberPropertyValueListResponse:
type: object
required:
- data
properties:
data:
type: array
items:
"$ref": "#/components/schemas/MemberPropertyValue"
MemberPropertyValuesUpdateRequest:
type: object
properties:
properties:
type: object
additionalProperties: true
description: Object keyed by member property key or `mprop_` id. Use `null` to clear a value.
values:
type: array
items:
type: object
properties:
property_id:
type: string
pattern: "^mprop_"
key:
type: string
value:
nullable: true
oneOf:
- type: string
- type: number
- type: boolean
- type: array
items: {}
- type: object
additionalProperties: true
BulkMemberPropertyValuesUpdateRequest:
type: object
required:
- items
properties:
items:
type: array
minItems: 1
maxItems: 100
items:
allOf:
- "$ref": "#/components/schemas/MemberPropertyValuesUpdateRequest"
- type: object
required:
- member_id
properties:
member_id:
type: string
pattern: "^mem_"
BulkContactPropertyValuesUpdateRequest:
type: object
required:
- items
properties:
items:
type: array
minItems: 1
maxItems: 100
items:
allOf:
- "$ref": "#/components/schemas/MemberPropertyValuesUpdateRequest"
- type: object
required:
- contact_id
properties:
contact_id:
type: string
pattern: "^contact_"
BulkPropertyValueUpdateResult:
type: object
required:
- index
- status
properties:
index:
type: integer
status:
type: integer
data:
type: array
items:
"$ref": "#/components/schemas/MemberPropertyValue"
error:
type: object
properties:
code:
type: string
message:
type: string
BulkPropertyValueUpdateResponse:
type: object
required:
- data
properties:
data:
type: array
items:
"$ref": "#/components/schemas/BulkPropertyValueUpdateResult"
SpaceProperty:
type: object
required:
- id
- space_id
- name
- key
- type
- sort_order
- options
- visibility
- created_at
- updated_at
properties:
id:
type: string
pattern: "^sprop_"
space_id:
type: string
pattern: "^sp_"
name:
type: string
key:
type: string
type:
type: string
enum:
- text
- select
- multi_select
- number
- date
- url
- phone
- location
sort_order:
type: integer
options:
type: object
additionalProperties: true
visibility:
type: array
items:
type: string
icon:
type: string
nullable: true
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
SpacePropertyWriteRequest:
type: object
properties:
name:
type: string
key:
type: string
type:
type: string
enum:
- text
- select
- multi_select
- number
- date
- url
- phone
- location
sort_order:
type: integer
options:
type: object
additionalProperties: true
description: For select and multi_select, use `values` with option objects containing `value` and `name`.
visibility:
type: array
items:
type: string
icon:
type: string
nullable: true
SpacePropertyResponse:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/SpaceProperty"
SpacePropertyListResponse:
type: object
required:
- data
- pagination
properties:
data:
type: array
items:
"$ref": "#/components/schemas/SpaceProperty"
pagination:
"$ref": "#/components/schemas/Pagination"
SpacePropertyReorderRequest:
type: object
required:
- property_ids
properties:
property_ids:
type: array
items:
type: string
pattern: "^sprop_"
SpacePropertyReorderResponse:
type: object
required:
- data
properties:
data:
type: object
required:
- space_id
- reordered
properties:
space_id:
type: string
pattern: "^sp_"
reordered:
type: boolean
enum:
- true
RemovedSpaceProperty:
type: object
required:
- id
- deleted
properties:
id:
type: string
pattern: "^sprop_"
deleted:
type: boolean
enum:
- true
DeletedSpacePropertyResponse:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/RemovedSpaceProperty"
SpacePropertyValue:
type: object
required:
- property_id
- value_id
- space_id
- definition_space_id
- key
- name
- type
- value
- updated_at
properties:
property_id:
type: string
pattern: "^sprop_"
value_id:
type: string
nullable: true
pattern: "^sval_"
space_id:
type: string
pattern: "^sp_"
definition_space_id:
type: string
pattern: "^sp_"
key:
type: string
name:
type: string
type:
type: string
value:
nullable: true
oneOf:
- type: string
- type: number
- type: boolean
- type: array
items: {}
- type: object
additionalProperties: true
updated_at:
type: string
nullable: true
format: date-time
SpacePropertyValueListResponse:
type: object
required:
- data
properties:
data:
type: array
items:
"$ref": "#/components/schemas/SpacePropertyValue"
SpacePropertyValuesUpdateRequest:
type: object
properties:
properties:
type: object
additionalProperties: true
description: Object keyed by space property key or `sprop_` id. Use `null` to clear a value.
values:
type: array
items:
type: object
properties:
property_id:
type: string
pattern: "^sprop_"
key:
type: string
value:
nullable: true
oneOf:
- type: string
- type: number
- type: boolean
- type: array
items: {}
- type: object
additionalProperties: true
User:
type: object
required:
- id
- first_name
- last_name
- name
- username
- avatar_url
properties:
id:
type: string
pattern: "^usr_"
first_name:
type: string
nullable: true
last_name:
type: string
nullable: true
name:
type: string
nullable: true
username:
type: string
nullable: true
avatar_url:
type: string
nullable: true
email:
type: string
format: email
description: Present only with members.email:read.
RichContent:
description: Rich text document payload. Sutra returns the stored structured document when available.
oneOf:
- type: object
additionalProperties: true
- type: array
items: {}
- type: string
DeletedFlag:
type: object
required:
- deleted
properties:
deleted:
type: boolean
enum:
- true
PlacementRequest:
type: object
properties:
surface:
type: string
enum:
- auto
- collection
- document
default: auto
position:
type: integer
minimum: 0
description: Zero-based position in the resolved placement surface. Do not combine with `anchor_node_uid`.
view_as:
type: string
enum:
- list
- hcard
- vcard
- button
- link
anchor_node_uid:
type: string
description: "Existing document node UID used for document-surface placement. With `insert: append` or omitted `insert`, the item is placed after the anchor. Cannot be combined with `position`."
insert:
type: string
description: Relative insertion mode when `anchor_node_uid` is provided.
enum:
- append
- before
- after
- inside
set_parent_ordering:
type: string
enum:
- custom_order
PlacementResult:
type: object
properties:
surface:
type: string
enum:
- collection
- document
position:
type: integer
nullable: true
position_effective:
type: boolean
document_node_uid:
type: string
nullable: true
ChildAttachmentResponse:
type: object
required:
- data
properties:
data:
type: object
required:
- parent_id
- child_id
- attached
- placement
properties:
parent_id:
type: string
pattern: "^sp_"
child_id:
type: string
pattern: "^sp_"
attached:
type: boolean
placement:
"$ref": "#/components/schemas/PlacementResult"
SpecialBlockTypesResponse:
type: object
required:
- data
properties:
data:
type: object
required:
- block_types
properties:
space_id:
type: string
pattern: "^sp_"
surface:
type: string
enum:
- document
- registration_page
block_types:
type: array
items:
type: object
required:
- type
- node_type
- label
properties:
type:
type: string
enum:
- info_box
- icon_text
- quote
- badge
- divider
- contact_form
node_type:
type: string
label:
type: string
description:
type: string
defaults:
type: object
allowed_values:
type: object
style_presets:
type: array
items:
type: object
member_property_bindings:
type: array
description: Present for contact_form when the request is space-scoped.
items:
type: object
SpecialBlocksResponse:
type: object
required:
- data
properties:
data:
type: object
required:
- space_id
- surface
- document
- blocks
properties:
space_id:
type: string
pattern: "^sp_"
surface:
type: string
enum:
- document
- registration_page
document:
type: object
revision:
type: string
content_digest:
type: string
blocks:
type: array
items:
"$ref": "#/components/schemas/SpecialBlock"
SpecialBlockMutationResponse:
type: object
required:
- data
properties:
data:
type: object
required:
- space_id
- surface
- document
properties:
space_id:
type: string
pattern: "^sp_"
surface:
type: string
enum:
- document
- registration_page
document:
type: object
revision:
type: string
content_digest:
type: string
block:
"$ref": "#/components/schemas/SpecialBlock"
deleted_block:
"$ref": "#/components/schemas/SpecialBlock"
warnings:
type: array
items:
type: object
repairs:
type: array
items:
type: object
SpecialBlock:
type: object
required:
- node_uid
- type
- node_type
- config
properties:
id:
type: string
description: Same value as node_uid.
node_uid:
type: string
type:
type: string
enum:
- info_box
- icon_text
- quote
- badge
- divider
- contact_form
node_type:
type: string
mutable:
type: boolean
config:
type: object
description: Stable first-class configuration for the block.
node:
type: object
description: Canonical saved Tiptap node for inspection.
SpecialBlockCreateRequest:
type: object
required:
- type
properties:
type:
type: string
enum:
- info_box
- icon_text
- quote
- badge
- divider
- contact_form
config:
type: object
description: Block-specific config. Use special_block_types to inspect defaults and allowed values.
placement:
"$ref": "#/components/schemas/DocumentPlacementRequest"
base_revision:
type: string
SpecialBlockUpdateRequest:
type: object
properties:
config:
type: object
description: Partial block-specific config. Omitted keys preserve the current block where possible.
base_revision:
type: string
TiptapDocumentResponse:
type: object
required:
- data
properties:
data:
type: object
required:
- space_id
- document
- revision
- content_digest
properties:
space_id:
type: string
pattern: "^sp_"
document:
type: object
description: "Tiptap document object, usually { type: doc, content: [...] }."
revision:
type: string
content_digest:
type: string
warnings:
type: array
description: Advisory validation warnings returned by document mutation endpoints.
items:
type: object
repairs:
type: array
description: Automatic canonicalization repairs applied by document mutation endpoints, such as UID repair, button defaults, and spacing shorthand expansion.
items:
type: object
TiptapDocumentMutationResponse:
description: Full document response by default, or a compact delta when `response_mode=compact` is requested.
oneOf:
- "$ref": "#/components/schemas/TiptapDocumentResponse"
- "$ref": "#/components/schemas/TiptapDocumentCompactMutationResponse"
TiptapDocumentCompactMutationResponse:
type: object
required:
- data
properties:
data:
type: object
required:
- space_id
- revision
- content_digest
- operation
properties:
space_id:
type: string
pattern: "^sp_"
revision:
type: string
content_digest:
type: string
pattern: "^sha256:"
previous_content_digest:
type: string
pattern: "^sha256:"
operation:
type: string
enum:
- insert
- update
- delete
- move
changed_node_uids:
type: array
items:
type: string
changed_nodes:
type: array
description: Canonical inserted or updated top-level nodes, including generated UIDs and repairs.
items:
type: object
deleted_node_uids:
type: array
items:
type: string
moved_node_uids:
type: array
items:
type: string
placement:
"$ref": "#/components/schemas/DocumentPlacementRequest"
warnings:
type: array
items:
type: object
repairs:
type: array
items:
type: object
RegistrationPageResponse:
type: object
required:
- data
properties:
data:
type: object
required:
- space_id
- enabled
- draft
- published
properties:
space_id:
type: string
pattern: "^sp_"
enabled:
type: boolean
description: Whether the space currently gates visitors through the registration page.
draft:
"$ref": "#/components/schemas/RegistrationPageDocument"
published:
"$ref": "#/components/schemas/RegistrationPageDocument"
warnings:
type: array
description: Advisory validation warnings returned by registration page mutation endpoints.
items:
type: object
repairs:
type: array
description: Automatic canonicalization repairs applied by registration page mutation endpoints.
items:
type: object
RegistrationPageDocument:
type: object
required:
- document
- revision
- content_digest
properties:
document:
type: object
description: "Tiptap document object, usually { type: doc, content: [...] }."
revision:
type: string
content_digest:
type: string
TiptapDocumentWriteRequest:
type: object
properties:
document:
type: object
description: "Tiptap document object. actionbutton nodes must include a non-empty attrs.buttonText label."
base_revision:
type: string
force:
type: boolean
TiptapNodeInsertRequest:
type: object
properties:
nodes:
type: array
description: "Tiptap node objects. actionbutton nodes must include a non-empty attrs.buttonText label."
items:
type: object
placement:
"$ref": "#/components/schemas/DocumentPlacementRequest"
base_revision:
type: string
TiptapNodeUpdateRequest:
type: object
properties:
node:
type: object
description: "Replacement Tiptap node object. actionbutton nodes must include a non-empty attrs.buttonText label."
base_revision:
type: string
DocumentPlacementRequest:
type: object
properties:
insert:
type: string
description: Relative insertion mode. `before`, `after`, and `inside` require `anchor_node_uid`; `append` places the node at the document root when no anchor is provided and after the anchor when one is provided.
enum:
- append
- before
- after
- inside
anchor_node_uid:
type: string
description: Existing document node UID used for relative placement.
MediaResponse:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/Media"
Media:
type: object
required:
- id
- space_id
- kind
- upload_status
- media_status
properties:
id:
type: string
pattern: "^media_"
media_file_id:
type: integer
description: Legacy internal ID exposed during public media ID migration.
space_id:
type: string
pattern: "^sp_"
kind:
type: string
enum:
- video
- image
- audio
- file
- embed
source_url:
type: string
nullable: true
description: Original source URL for external references or verified upload source URL when available.
upload_status:
type: string
enum:
- pending_upload
- complete
- abandoned
- failed
media_status:
type: string
enum:
- pending
- processing
- ready
- failed
playback_url:
type: string
nullable: true
thumbnail_url:
type: string
nullable: true
error_message:
type: string
nullable: true
document_node_uid:
type: string
nullable: true
object:
"$ref": "#/components/schemas/MediaStorageObject"
upload:
"$ref": "#/components/schemas/MediaUploadInstructions"
MediaStorageObject:
type: object
properties:
bucket:
type: string
key:
type: string
MediaUploadInstructions:
type: object
required:
- method
- url
- headers
- expires_at
properties:
method:
type: string
enum:
- PUT
url:
type: string
format: uri
headers:
type: object
additionalProperties:
type: string
expires_at:
type: string
format: date-time
MediaUploadPlacementRequest:
type: object
properties:
insert_node:
type: boolean
default: true
description: When false, create the media record without inserting a document node.
insert:
type: string
description: Relative insertion mode for the inserted media node. `before`, `after`, and `inside` require `anchor_node_uid`; `append` places the node at the document root when no anchor is provided and after the anchor when one is provided.
enum:
- append
- before
- after
- inside
anchor_node_uid:
type: string
description: Existing document node UID used for relative placement.
MediaUploadCreateRequest:
type: object
required:
- filename
- content_type
- size_bytes
properties:
filename:
type: string
content_type:
type: string
example: video/mp4
size_bytes:
type: integer
format: int64
minimum: 1
kind:
type: string
enum:
- video
- image
- audio
- file
default: video
placement:
"$ref": "#/components/schemas/MediaUploadPlacementRequest"
base_revision:
type: string
description: Optional document `revision` or `content_digest` to guard placeholder insertion against concurrent edits.
MediaUploadCompleteRequest:
type: object
properties:
size_bytes:
type: integer
format: int64
minimum: 1
etag:
type: string
description: Optional ETag returned by the upload PUT. Completion rejects the request when it does not match the stored S3 object's ETag.
MediaReferenceCreateRequest:
type: object
required:
- url
properties:
url:
type: string
description: Loom, YouTube, or Vimeo URL. iframe embed code is also accepted.
kind:
type: string
enum:
- embed
default: embed
placement:
"$ref": "#/components/schemas/MediaUploadPlacementRequest"
base_revision:
type: string
SpaceCreateRequest:
type: object
properties:
name:
type: string
intention:
type: string
description: Backward-compatible alias for name.
description:
type: string
nullable: true
type:
type: string
default: content
version:
type: string
description: Backward-compatible alias for type.
privacy:
type: string
default: open
privacy_level:
type: string
description: Backward-compatible alias for privacy.
pod_type:
type: string
enum:
- standard
- readonly
default: standard
parent_id:
type: string
pattern: "^sp_"
description: Optional parent space. Omit to create a top-level space for the API user.
content_scaffold:
type: string
enum:
- none
- ui_default
description: Pass none when content will be populated programmatically through document endpoints. ui_default adds starter module content meant for manual editing.
placement:
"$ref": "#/components/schemas/PlacementRequest"
SpaceUpdateRequest:
type: object
properties:
name:
type: string
minLength: 3
maxLength: 100
description:
type: string
nullable: true
description: Sanitized HTML (same safelist as the web app). Null clears it.
type:
type: string
enum:
- discussion
- content
- list
- showcase
- events
- course
- section
description: Space format. Changing it is tier-gated (professional/organization)
and reverting to content requires the space to have been a content
space before. Reads may return legacy values not writable here.
version:
type: string
description: Backward-compatible alias for type.
privacy:
type: string
enum:
- open
- private
- payment
description: Setting private is tier-gated. Transitions to or from
payment must go through PATCH /spaces/{id}/payment instead.
privacy_level:
type: string
description: Backward-compatible alias for privacy.
state:
type: string
enum:
- active
- archived
description: 'Archiving is a two-phase transition: descendants are
ghosted asynchronously, shareable links are cleared, and Stripe
subscriptions in the tree are cancelled. Unarchive restores
descendants but not cleared links, redirects, or subscriptions.'
visibility:
type: string
nullable: true
enum:
- public
- ''
description: '"public" lists the space publicly; "" (or null) unlists
it. A private space cannot be public. Changing visibility cascades
the new value to every descendant space.'
pod_type:
type: string
enum:
- standard
- readonly
size:
type: integer
nullable: true
minimum: 1
description: Member limit. Null means unlimited.
resource_editing:
type: string
enum:
- open
- closed
present_as:
type: string
enum:
- list
- grid
allow_reflections:
type: boolean
show_members:
type: boolean
block_until_registered:
type: boolean
block_until_approved:
type: boolean
allow_members_to_invite:
type: boolean
use_legacy_registration_page:
type: boolean
hangout_link:
type: string
nullable: true
format: uri
description: http(s) URL or null to clear.
abstract_text:
type: string
nullable: true
maxLength: 10000
emojicon:
type: string
nullable: true
maxLength: 64
circle_creation:
type: array
items:
type: string
enum:
- discussion
- subcircles
- resources
description: What members may create in this space. Empty array means
nothing.
url_handle:
type: string
nullable: true
minLength: 3
maxLength: 25
pattern: "^[A-Za-z0-9]+$"
description: Shareable-link handle (tier-gated to professional/organization
accounts). Null clears it.
SpaceResponse:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/Space"
DeletedSpaceResponse:
type: object
required:
- data
properties:
data:
allOf:
- "$ref": "#/components/schemas/Space"
- "$ref": "#/components/schemas/DeletedFlag"
ReorderResponse:
type: object
required:
- data
properties:
data:
type: object
required:
- reordered
properties:
id:
type: string
nullable: true
space_id:
type: string
nullable: true
pattern: "^sp_"
reordered:
type: boolean
enum:
- true
MemberCreateRequest:
type: object
anyOf:
- required:
- email
- required:
- user_id
properties:
email:
type: string
format: email
user_id:
type: string
pattern: "^usr_"
first_name:
type: string
last_name:
type: string
username:
type: string
role:
type: string
enum:
- member
- editor
- moderator
state:
type: string
enum:
- active
- pending
notify:
type: boolean
default: false
MemberUpdateRequest:
type: object
properties:
role:
type: string
enum:
- member
- editor
- moderator
email_frequency:
type: string
MemberResponse:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/Member"
RemovedMember:
type: object
required:
- id
- removed
properties:
id:
type: string
pattern: "^mem_"
removed:
type: boolean
enum:
- true
DeletedMemberResponse:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/RemovedMember"
BulkItemError:
type: object
required:
- code
- message
properties:
code:
type: string
message:
type: string
BulkMemberResult:
type: object
required:
- index
- status
properties:
index:
type: integer
status:
type: integer
data:
oneOf:
- "$ref": "#/components/schemas/Member"
- "$ref": "#/components/schemas/RemovedMember"
error:
"$ref": "#/components/schemas/BulkItemError"
BulkMemberResponse:
type: object
required:
- data
properties:
data:
type: array
items:
"$ref": "#/components/schemas/BulkMemberResult"
BulkDeletedMemberResponse:
type: object
required:
- data
properties:
data:
type: array
items:
type: object
required:
- index
- status
properties:
index:
type: integer
status:
type: integer
data:
"$ref": "#/components/schemas/RemovedMember"
error:
"$ref": "#/components/schemas/BulkItemError"
Invitation:
type: object
required:
- id
- space_id
- email
- state
- billing_type
- role
- added_by_user_id
- space_plan_id
- created_at
- updated_at
properties:
id:
type: string
pattern: "^inv_"
space_id:
type: string
pattern: "^sp_"
email:
type: string
format: email
nullable: true
description: Null unless the token has members.email:read.
state:
type: string
billing_type:
type: string
nullable: true
role:
type: string
nullable: true
added_by_user_id:
type: string
nullable: true
pattern: "^usr_"
space_plan_id:
type: string
nullable: true
pattern: "^plan_"
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
InvitationCreateRequest:
type: object
required:
- email
properties:
email:
type: string
format: email
message:
type: string
nullable: true
role:
type: string
enum:
- member
- editor
- moderator
notify:
type: boolean
default: false
add_as_subscriber:
type: boolean
default: false
billing_type:
type: string
default: standard_checkout
free_access:
type: boolean
default: false
InvitationUpdateRequest:
type: object
properties:
message:
type: string
nullable: true
invitation_state:
type: string
email_invitation:
type: boolean
add_as_subscriber:
type: boolean
free_access:
type: boolean
role:
type: string
enum:
- member
- editor
- moderator
InvitationResponse:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/Invitation"
InvitationListResponse:
type: object
required:
- data
- pagination
properties:
data:
type: array
items:
"$ref": "#/components/schemas/Invitation"
pagination:
"$ref": "#/components/schemas/Pagination"
DeletedInvitationResponse:
type: object
required:
- data
properties:
data:
allOf:
- "$ref": "#/components/schemas/Invitation"
- "$ref": "#/components/schemas/DeletedFlag"
ResentInvitationResponse:
type: object
required:
- data
properties:
data:
allOf:
- "$ref": "#/components/schemas/Invitation"
- type: object
required:
- resent
properties:
resent:
type: boolean
enum:
- true
BulkInvitationResponse:
type: object
required:
- data
properties:
data:
type: array
items:
type: object
required:
- index
- status
properties:
index:
type: integer
status:
type: integer
data:
"$ref": "#/components/schemas/Invitation"
error:
"$ref": "#/components/schemas/BulkItemError"
ContentBlock:
type: object
required:
- id
- space_id
- author
- type
- content
- raw_content
- priority
- created_at
- updated_at
properties:
id:
type: string
pattern: "^blk_"
space_id:
type: string
pattern: "^sp_"
author:
"$ref": "#/components/schemas/User"
type:
type: string
enum:
- content_block
content:
"$ref": "#/components/schemas/RichContent"
raw_content:
type: string
nullable: true
priority:
type: integer
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
ContentBlockWriteRequest:
type: object
properties:
content:
"$ref": "#/components/schemas/RichContent"
raw_content:
type: string
message_body:
type: string
priority:
type: integer
privacy:
type: string
ContentBlockResponse:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/ContentBlock"
ContentBlockListResponse:
type: object
required:
- data
- pagination
properties:
data:
type: array
items:
"$ref": "#/components/schemas/ContentBlock"
pagination:
"$ref": "#/components/schemas/Pagination"
DeletedContentBlockResponse:
type: object
required:
- data
properties:
data:
allOf:
- "$ref": "#/components/schemas/ContentBlock"
- "$ref": "#/components/schemas/DeletedFlag"
Message:
type: object
required:
- id
- space_id
- author
- type
- content
- raw_content
- created_at
- updated_at
properties:
id:
type: string
pattern: "^blk_"
space_id:
type: string
pattern: "^sp_"
author:
"$ref": "#/components/schemas/User"
type:
type: string
enum:
- discussion
- comment
- message
content:
"$ref": "#/components/schemas/RichContent"
raw_content:
type: string
nullable: true
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
MessageWriteRequest:
type: object
properties:
content:
"$ref": "#/components/schemas/RichContent"
raw_content:
type: string
message_body:
type: string
type:
type: string
enum:
- discussion
- comment
MessageResponse:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/Message"
MessageListResponse:
type: object
required:
- data
- pagination
properties:
data:
type: array
items:
"$ref": "#/components/schemas/Message"
pagination:
"$ref": "#/components/schemas/Pagination"
DeletedMessageResponse:
type: object
required:
- data
properties:
data:
allOf:
- "$ref": "#/components/schemas/Message"
- "$ref": "#/components/schemas/DeletedFlag"
Reflection:
type: object
required:
- id
- space_id
- parent_id
- author
- content
- raw_content
- created_at
- updated_at
properties:
id:
type: string
pattern: "^reply_"
space_id:
type: string
pattern: "^sp_"
parent_id:
type: string
pattern: "^blk_"
author:
"$ref": "#/components/schemas/User"
content:
"$ref": "#/components/schemas/RichContent"
raw_content:
type: string
nullable: true
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
ReflectionWriteRequest:
type: object
properties:
content:
"$ref": "#/components/schemas/RichContent"
raw_content:
type: string
ReflectionResponse:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/Reflection"
ReflectionListResponse:
type: object
required:
- data
- pagination
properties:
data:
type: array
items:
"$ref": "#/components/schemas/Reflection"
pagination:
"$ref": "#/components/schemas/Pagination"
DeletedReflectionResponse:
type: object
required:
- data
properties:
data:
allOf:
- "$ref": "#/components/schemas/Reflection"
- "$ref": "#/components/schemas/DeletedFlag"
SurveyAnswer:
type: object
required:
- id
- content
- position
- description
- payment_amount
properties:
id:
type: string
pattern: "^ans_"
content:
type: string
nullable: true
position:
type: integer
description:
type: string
nullable: true
payment_amount:
type: number
nullable: true
SurveyQuestion:
type: object
required:
- id
- content
- type
- required
- position
- answers
properties:
id:
type: string
pattern: "^ques_"
content:
type: string
nullable: true
type:
type: string
nullable: true
required:
type: boolean
position:
type: integer
answers:
type: array
items:
"$ref": "#/components/schemas/SurveyAnswer"
Survey:
type: object
required:
- id
- space_id
- title
- description
- type
- allow_anonymous
- created_at
- updated_at
properties:
id:
type: string
pattern: "^surv_"
space_id:
type: string
pattern: "^sp_"
title:
type: string
description:
type: string
nullable: true
type:
type: string
nullable: true
allow_anonymous:
type: boolean
questions:
type: array
items:
"$ref": "#/components/schemas/SurveyQuestion"
description: Included on single-survey responses and mutations.
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
SurveyWriteRequest:
type: object
properties:
title:
type: string
description:
type: string
nullable: true
type:
type: string
content:
"$ref": "#/components/schemas/RichContent"
allow_anonymous:
type: boolean
SurveyResponse:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/Survey"
SurveyListResponse:
type: object
required:
- data
- pagination
properties:
data:
type: array
items:
"$ref": "#/components/schemas/Survey"
pagination:
"$ref": "#/components/schemas/Pagination"
DeletedSurveyResponse:
type: object
required:
- data
properties:
data:
allOf:
- "$ref": "#/components/schemas/Survey"
- "$ref": "#/components/schemas/DeletedFlag"
SurveySubmissionChoice:
type: object
required:
- id
- question_id
- answer_id
- content
- member_property_value_id
- created_at
properties:
id:
type: string
pattern: "^choice_"
question_id:
type: string
nullable: true
pattern: "^ques_"
answer_id:
type: string
nullable: true
pattern: "^ans_"
content:
type: string
nullable: true
member_property_value_id:
type: string
pattern: "^mval_"
nullable: true
description: Public member property value ID when this choice wrote a member property value.
created_at:
type: string
format: date-time
nullable: true
SurveySubmission:
type: object
required:
- id
- survey_id
- user
- submitted_at
- choices
properties:
id:
type: string
survey_id:
type: string
nullable: true
pattern: "^surv_"
user:
"$ref": "#/components/schemas/User"
submitted_at:
type: string
format: date-time
nullable: true
choices:
type: array
items:
"$ref": "#/components/schemas/SurveySubmissionChoice"
SurveySubmissionResponse:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/SurveySubmission"
SurveySubmissionListResponse:
type: object
required:
- data
- pagination
properties:
data:
type: array
items:
"$ref": "#/components/schemas/SurveySubmission"
pagination:
"$ref": "#/components/schemas/Pagination"
Plan:
type: object
required:
- id
- space_id
- name
- short_description
- amount_cents
- currency
- frequency
- status
- visibility
- trial_period_days
- created_at
- updated_at
properties:
id:
type: string
pattern: "^plan_"
space_id:
type: string
pattern: "^sp_"
name:
type: string
short_description:
type: string
nullable: true
amount_cents:
type: integer
currency:
type: string
nullable: true
frequency:
type: string
nullable: true
status:
type: string
nullable: true
visibility:
type: string
nullable: true
trial_period_days:
type: integer
nullable: true
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
PlanWriteRequest:
type: object
properties:
name:
type: string
short_description:
type: string
nullable: true
long_description:
type: string
nullable: true
amount:
type: integer
description: Amount in cents.
amount_cents:
type: integer
description: Alias for amount (matches the read shape). amount wins
when both are sent.
currency:
type: string
frequency:
type: string
billing_limit_type:
type: string
billing_count:
type: integer
billing_until_date:
type: string
format: date
trial_period_days:
type: integer
pwyc_enabled:
type: boolean
pwyc_min:
type: integer
pwyc_max:
type: integer
pwyc_default:
type: integer
sort_order:
type: integer
status:
type: string
visibility:
type: string
recommended:
type: boolean
features:
type: object
additionalProperties: true
max_purchasers:
type: integer
redirect_after_purchase:
type: string
nullable: true
show_on_registration:
type: boolean
PlanResponse:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/Plan"
warnings:
type: array
items:
type: string
description: Advisory only (e.g. the space's payment gate is off, or
no active plan remains). The write succeeded.
PlanListResponse:
type: object
required:
- data
- pagination
properties:
data:
type: array
items:
"$ref": "#/components/schemas/Plan"
pagination:
"$ref": "#/components/schemas/Pagination"
DeletedPlanResponse:
type: object
required:
- data
properties:
data:
allOf:
- "$ref": "#/components/schemas/Plan"
- "$ref": "#/components/schemas/DeletedFlag"
warnings:
type: array
items:
type: string
description: Advisory only (e.g. no active plan remains behind an
enabled paywall). The write succeeded.
Enrollment:
type: object
required:
- id
- space_id
- plan_id
- user_id
- payment_id
- coupon_id
- status
- amount_paid_cents
- currency
- created_at
- updated_at
properties:
id:
type: string
pattern: "^enr_"
space_id:
type: string
pattern: "^sp_"
plan_id:
type: string
nullable: true
pattern: "^plan_"
user_id:
type: string
nullable: true
pattern: "^usr_"
payment_id:
type: string
nullable: true
pattern: "^pay_"
coupon_id:
type: string
nullable: true
pattern: "^cpn_"
status:
type: string
nullable: true
amount_paid_cents:
type: integer
nullable: true
currency:
type: string
nullable: true
email:
type: string
format: email
description: Present only with members.email:read.
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
EnrollmentResponse:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/Enrollment"
EnrollmentListResponse:
type: object
required:
- data
- pagination
properties:
data:
type: array
items:
"$ref": "#/components/schemas/Enrollment"
pagination:
"$ref": "#/components/schemas/Pagination"
Payment:
type: object
required:
- id
- space_id
- user_id
- coupon_id
- amount_cents
- refunded_amount_cents
- status
- payment_type
- frequency
- created_at
- updated_at
properties:
id:
type: string
pattern: "^pay_"
space_id:
type: string
nullable: true
pattern: "^sp_"
user_id:
type: string
nullable: true
pattern: "^usr_"
coupon_id:
type: string
nullable: true
pattern: "^cpn_"
amount_cents:
type: integer
refunded_amount_cents:
type: integer
status:
type: string
nullable: true
payment_type:
type: string
nullable: true
frequency:
type: string
nullable: true
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
PaymentResponse:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/Payment"
PaymentListResponse:
type: object
required:
- data
- pagination
properties:
data:
type: array
items:
"$ref": "#/components/schemas/Payment"
pagination:
"$ref": "#/components/schemas/Pagination"
Coupon:
type: object
required:
- id
- space_id
- code
- value
- discount_type
- frequency
- status
- expires_at
- created_at
- updated_at
properties:
id:
type: string
pattern: "^cpn_"
space_id:
type: string
nullable: true
pattern: "^sp_"
code:
type: string
value:
type: number
discount_type:
type: string
frequency:
type: string
status:
type: string
expires_at:
type: string
format: date-time
nullable: true
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
CouponWriteRequest:
type: object
required:
- code
- value
properties:
code:
type: string
value:
type: number
discount_type:
type: string
default: percent
frequency:
type: string
default: once
expire_at:
type: string
format: date-time
status:
type: string
default: active
CouponUpdateRequest:
type: object
properties:
code:
type: string
value:
type: number
frequency:
type: string
expire_at:
type: string
format: date-time
status:
type: string
CouponResponse:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/Coupon"
CouponListResponse:
type: object
required:
- data
- pagination
properties:
data:
type: array
items:
"$ref": "#/components/schemas/Coupon"
pagination:
"$ref": "#/components/schemas/Pagination"
DeletedCouponResponse:
type: object
required:
- data
properties:
data:
allOf:
- "$ref": "#/components/schemas/Coupon"
- "$ref": "#/components/schemas/DeletedFlag"
Broadcast:
type: object
required:
- id
- space_id
- author
- title
- content
- status
- scheduled_send_enabled
- scheduled_at
- sent_at
- send_count
- type
- target
- filters
- created_at
- updated_at
properties:
id:
type: string
pattern: "^bcst_"
space_id:
type: string
pattern: "^sp_"
author:
"$ref": "#/components/schemas/User"
title:
type: string
nullable: true
content:
"$ref": "#/components/schemas/RichContent"
status:
type: string
enum:
- draft
- processing
- scheduled
- sent
- error
scheduled_send_enabled:
type: boolean
scheduled_at:
type: string
format: date-time
nullable: true
sent_at:
type: string
format: date-time
nullable: true
send_count:
type: integer
nullable: true
type:
type: string
nullable: true
target:
type: array
items:
type: string
filters:
type: object
additionalProperties: true
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
BroadcastWriteRequest:
type: object
properties:
title:
type: string
raw_content:
type: string
content:
"$ref": "#/components/schemas/RichContent"
target:
type: array
items:
type: string
default:
- active
filters:
type: object
additionalProperties: true
type:
type: string
default: email
broadcast_type:
type: string
description: Backward-compatible alias for type.
BroadcastResponse:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/Broadcast"
BroadcastListResponse:
type: object
required:
- data
- pagination
properties:
data:
type: array
items:
"$ref": "#/components/schemas/Broadcast"
pagination:
"$ref": "#/components/schemas/Pagination"
DeletedBroadcastResponse:
type: object
required:
- data
properties:
data:
allOf:
- "$ref": "#/components/schemas/Broadcast"
- "$ref": "#/components/schemas/DeletedFlag"
BroadcastSendResponse:
type: object
required:
- data
- delivery_job_id
properties:
data:
"$ref": "#/components/schemas/Broadcast"
delivery_job_id:
type: string
BroadcastDeliveryStatusResponse:
type: object
required:
- data
properties:
data:
type: object
required:
- id
- status
- send_count
- error_count
- started_at
- completed_at
properties:
id:
type: string
pattern: "^bcst_"
status:
type: string
enum:
- draft
- processing
- scheduled
- sent
- error
send_count:
type: integer
error_count:
type: integer
started_at:
type: string
format: date-time
nullable: true
completed_at:
type: string
format: date-time
nullable: true
Automation:
type: object
properties:
id:
type: string
pattern: "^auto_"
space_id:
type: string
pattern: "^sp_"
name:
type: string
trigger_type:
type: string
description: Canonical trigger key (e.g. person_registered, survey_completed).
trigger_label:
type: string
description: Human-readable trigger name.
function_slug:
type: string
active:
type: boolean
description: Whether the automation is enabled (null is treated as active).
member_count:
type: integer
active_member_count:
type: integer
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
AutomationDetail:
allOf:
- "$ref": "#/components/schemas/Automation"
- type: object
properties:
steps:
type: array
items:
"$ref": "#/components/schemas/AutomationStep"
AutomationStep:
type: object
properties:
id:
type: string
pattern: "^astep_"
position:
type: integer
action_type:
type: string
description: Canonical action key (e.g. send_email, wait, add_to_existing_space, condition, goto).
action_label:
type: string
description: Human-readable action name.
description:
type: string
nullable: true
enabled:
type: boolean
description: False makes this action a no-op while preserving its configuration and graph position.
deactivatable:
type: boolean
readOnly: true
description: False for control-flow steps such as condition and goto.
params:
type: object
description: "Action params with internal ids translated to PUBLIC ids (e.g. object_id as bcst_/sp_/surv_; condition rule field_id as mprop_). A webhook step exposes url/name/fields."
edges:
type: object
description: Graph edges as public step ids (astep_) or null.
properties:
next:
type: string
nullable: true
on_yes:
type: string
nullable: true
on_no:
type: string
nullable: true
AutomationStepInput:
type: object
properties:
temp_id:
type: string
description: Caller id for a NEW step in a replace graph; referenced by edges.
id:
type: string
pattern: "^astep_"
description: Existing step id to update in place (replace graph).
action_type:
type: string
description: Canonical action key (see GET /automations/capabilities).
enabled:
type: boolean
description: Omit to preserve the current value on update; new steps default to true. Cannot be false for condition or goto.
params:
type: object
description: Action params using public ids where referenced.
next:
type: string
description: Successor step id (astep_) or temp_id, for a normal/goto step.
on_yes:
type: string
description: Yes-branch step id (astep_) or temp_id, for a condition.
on_no:
type: string
description: No-branch step id (astep_) or temp_id, for a condition.
AutomationStepCreateInput:
allOf:
- "$ref": "#/components/schemas/AutomationStepInput"
- type: object
required:
- action_type
AutomationMember:
type: object
properties:
id:
type: string
pattern: "^aenr_"
automation_id:
type: string
pattern: "^auto_"
member:
type: object
nullable: true
properties:
user:
"$ref": "#/components/schemas/User"
member_id:
type: string
pattern: "^mem_"
description: Present when the user is still a member of the automation's space.
status:
type: string
enum:
- ongoing
- completed
current_step_position:
type: integer
nullable: true
current_step_action:
type: string
nullable: true
description: Canonical action type of the current step.
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
Pagination:
type: object
required:
- limit
- next_cursor
- has_more
properties:
limit:
type: integer
next_cursor:
type: string
nullable: true
pattern: "^cur_"
has_more:
type: boolean
TiptapDesignNode:
type: object
additionalProperties: true
description: A Sutra-supported Tiptap node. See the Design API capability manifest for supported node types, marks, and attrs.
TiptapDesignNodes:
type: array
items:
"$ref": "#/components/schemas/TiptapDesignNode"
DesignCapabilitiesResponse:
type: object
required:
- data
properties:
data:
type: object
required:
- version
- document
- nodes
- marks
- allowed_values
- block_appearance
- fonts
- styles
- rules
- anti_patterns
- website
description: Structured schema and user-facing editor capability manifest. Node attribute lists come from the editor's ProseMirror schema; each node's appearance contract comes from the controls exposed in block settings.
properties:
version:
type: string
description: Manifest version. Bumped when the contract shape changes.
example: 2.0.0
document:
type: object
description: Top-level document shape and payload limits.
properties:
top_level:
type: string
max_bytes:
type: integer
max_nodes:
type: integer
nodes:
type: object
description: Map of node type to its schema attrs, uid behavior, and exact UI-backed appearance authoring contract.
additionalProperties:
type: object
properties:
attrs:
type: array
items:
type: string
uid:
type: boolean
appearance:
type: object
description: >-
Exact appearance values backed by user-facing block settings for this
node. MCP clients must use this per-node contract instead of the legacy
global styles.supported_keys union.
properties:
source:
type: string
mcp_authorable:
type: boolean
description: Whether MCP may add new appearance values for this node type.
controls:
type: object
description: UI control groups and the storage/key set written by each control.
additionalProperties:
type: object
properties:
storage:
type: string
enum: [styles, columnStyles, attrs]
keys:
type: array
items:
type: string
legacy_storage:
type: boolean
modes:
type: array
items:
type: string
custom:
type: object
description: Control-specific custom-field values, enums, and UI bounds.
additionalProperties: true
style_keys:
type: object
description: Exact UI-editable CSS keys, grouped by their style storage object.
additionalProperties:
type: array
items:
type: string
attrs:
type: array
description: Exact UI-editable appearance attrs for the node.
items:
type: string
responsive:
type: object
description: Exact UI-editable breakpoint appearance contract, when supported.
properties:
breakpoints:
type: array
items:
type: string
style_keys:
type: array
items:
type: string
attrs:
type: array
items:
type: string
conditional:
type: array
description: Additional UI-editable overrides whose when clause must match the node's base attrs.
items:
type: object
properties:
when:
type: object
properties:
attrs_equal:
type: object
additionalProperties: true
attrs_not_equal:
type: object
additionalProperties: true
attrs_present:
type: array
items:
type: string
attrs_absent:
type: array
items:
type: string
style_keys:
type: array
items:
type: string
attrs:
type: array
items:
type: string
note:
type: string
note:
type: string
marks:
type: object
description: Map of mark type to its supported attrs.
additionalProperties:
type: object
properties:
attrs:
type: array
items:
type: string
allowed_values:
type: object
description: Map of attr name to the enumerated set of valid values, so clients can pick valid values instead of guessing.
additionalProperties:
type: array
items:
type: string
block_appearance:
type: object
description: >-
Exact semantic and custom-field contracts for box-level inherited
typography, box/container hover, and BlockShell entrance animation.
Per-node appearance.controls remains the support allowlist.
properties:
box_typography:
type: object
additionalProperties: true
box_hover:
type: object
additionalProperties: true
entrance_animation:
type: object
additionalProperties: true
fonts:
type: object
description: Font families Sutra actually loads; others fall back at render time.
properties:
available:
type: array
items:
type: string
note:
type: string
styles:
type: object
description: Legacy global style-key union, per-node authoring direction, and the themed() color recipe.
properties:
supported_keys:
type: array
description: Legacy validation union; not a per-node render or user-interface guarantee.
items:
type: string
authoring_contract:
type: string
description: Directs clients to the exact per-node appearance contract.
themed_recipe:
type: string
rules:
type: object
description: Map of rule key to human-readable authoring guidance.
additionalProperties:
type: string
anti_patterns:
type: array
items:
type: string
website:
type: object
description: >-
Website-mode authoring contract for header/footer share blocks and
the navbar config. Documents the share_block style shape (CSS nested
under style.styles, plus fullWidth/flexLayout/flexGap/flexItemSizing/flexRowAlign/minHeight), the navbar
style fields and allowed values, the link object shape, and the key
rules (the header bar background lives on the site_header share
block; use the box minHeight ATTR — not min-height in styles — for
full-viewport sections).
example:
version: 2.19.0
document:
top_level: "Array of Tiptap node objects, or { default: { type: 'doc', content: [...] } }."
max_bytes: 750000
max_nodes: 2000
nodes:
actionbutton:
attrs: [actionCallback, actionCallbackTarget, actionCallbackValue, buttonAction, buttonBackgroundColor, buttonBorderColor, buttonBorderWidth, buttonShadow, buttonSize, buttonText, buttonTextColor, class, idName, isMarkComplete, linkTo, radius, radiusCustom, styles, textAlign, uid]
required_attrs: [buttonText]
uid: true
box:
attrs: [animateIn, animateInCustom, aspectRatio, blockTheme, boxHover, boxHoverCustom, boxModel, columnRadius, columnRadiusCustom, columnStyles, flexGap, flexItemSizing, flexLayout, flexMobileGap, flexMobileLayout, flexRowAlign, fullWidth, height, hidden, maxHeight, maxWidth, minHeight, minWidth, overflow, radius, radiusCustom, responsive, selfAlign, styles, uid, width]
uid: true
appearance:
source: user-facing block settings
mcp_authorable: true
controls:
spacing:
storage: styles
keys: [margin-top, margin-bottom, margin-left, margin-right, padding-top, padding-bottom, padding-left, padding-right]
text_defaults:
storage: styles
keys: [color, font-family, font-size, font-weight, line-height]
hover:
storage: attrs
keys: [boxHover, boxHoverCustom]
modes: [none, shadow, lift, custom]
animation:
storage: attrs
keys: [animateIn, animateInCustom]
modes: [none, fade, up, down, zoom, left, right, custom]
content_layout:
storage: attrs
keys: [flexLayout, flexGap, flexItemSizing, flexRowAlign]
style_keys:
styles: [margin-top, margin-bottom, margin-left, margin-right, padding-top, padding-bottom, padding-left, padding-right, border-top-width, border-top-style, border-top-color, box-shadow, background-color, background-image, align-items]
attrs: [radius, radiusCustom, flexLayout, flexGap, flexItemSizing, flexRowAlign, fullWidth, minHeight, overflow, boxHover, boxHoverCustom, animateIn, animateInCustom, hidden]
column:
attrs: [circle_id, flexGap, flexItemSizing, flexLayout, flexRowAlign, nestedRadius, position, radius, radiusCustom, size, styles, uid]
uid: true
container:
attrs: [columnRadius, columnRadiusCustom, columnStyles, flexGap, flexItemSizing, flexLayout, flexRowAlign, fullWidth, minHeight, radius, radiusCustom, styles, uid]
uid: true
heading:
attrs: [blockId, level, nestedRadius, styles, textAlign, uid]
uid: true
image:
attrs: [aspectRatio, link, markup, objectPosition, radius, radiusCustom, resizeableHeight, resizeableParentHeight, resizeableWidth, src, styles, textAlign, uid, uploader]
uid: true
paragraph:
attrs: [blockId, nestedRadius, styles, textAlign, uid]
uid: true
text:
attrs: [uid, styles]
uid: false
marks:
bold:
attrs: []
italic:
attrs: []
underline:
attrs: []
strike:
attrs: []
code:
attrs: []
link:
attrs: [href, target]
textStyle:
attrs: [color, fontSize, fontFamily, whiteSpace]
highlight:
attrs: [color]
allowed_values:
buttonSize: [S, M, L, XL]
buttonShadow: [none, subtle, strong]
radius: [no-radius, with-radius, circle-radius, custom]
actionCallbackTarget: [_current, _blank, _auto, _nothing, _section]
textAlign: [left, center, right, justify]
flexLayout: [stack, row, spread, hspread]
flexItemSizing: [equal, fit]
flexRowAlign: [left, center, right]
dividerStyle: [solid, dashed, dotted]
dividerAlign: [left, center, right]
iconStyle: [circle, square, none]
iconSide: [top, left, right]
boxHover: [none, shadow, lift, custom]
animateIn: [none, fade, up, down, zoom, left, right, custom]
block_appearance:
box_typography:
nodes: [box, container]
storage: attrs.styles
keys: [color, font-family, font-size, font-weight, line-height]
box_hover:
mode_attr: boxHover
allowed_values: [none, shadow, lift, custom]
custom_attr: boxHoverCustom
custom_fields:
lift: { type: number, min: 0, max: 16, unit: px }
scale: { type: number, min: 95, max: 110, unit: percent }
shadow: [inherit, none, subtle, medium, strong]
transition: { type: number, min: 0, max: 500, unit: ms }
entrance_animation:
mode_attr: animateIn
allowed_values: [none, fade, up, down, zoom, left, right, custom]
custom_attr: animateInCustom
custom_fields:
trigger: [load, scroll]
duration: { type: number, min: 0, max: 1200, unit: ms }
delay: { type: number, min: 0, max: 1000, unit: ms }
distance: { type: number, min: 0, max: 120, unit: px }
easing: [ease-out, ease, linear, spring]
once: boolean
fonts:
available: [Caveat, Cinzel, "Crimson Text", "DM Sans", "EB Garamond", Fraunces, Inter, "JetBrains Mono", Lato, Lora, Merriweather, Nunito, "Open Sans", Pacifico, "Permanent Marker", "Playfair Display", Poppins, Raleway, "Source Serif 4", "Space Mono"]
note: Use only these font-family values; others fall back at render time.
styles:
supported_keys: [background-color, color, border-color, border-radius, border-width, border-style, box-shadow, padding, padding-top, padding-right, padding-bottom, padding-left, margin, margin-top, margin-right, margin-bottom, margin-left, text-align, font-size, font-weight, line-height, min-height, width, max-width, gap, align-items, justify-content, background-image, background-size, background-position, border-left-color, border-left-width, border-left-style]
authoring_contract: Use nodes.<type>.appearance; only those per-node style keys and attrs are backed by user-facing editor controls.
themed_recipe: "themed(token:primary@L96,S30 ; #f5f3ff)"
rules:
grid_distribution: "Use 12-unit dist arrays such as [6,6], [8,4], or [4,4,4]."
buttons: "For an in-page actionbutton, give the target block a stable unique attrs.uid (for example 'page-top') and use { buttonAction:'section', actionCallback:'link', actionCallbackTarget:'_section', actionCallbackValue:'#jumpTo=page-top' }."
uid_stability: Preserve every existing node attrs.uid during full-document replacements so navbar, actionbutton, and inline section links do not break.
images: "Use a real public URL for image src, include alt text, and avoid data: URLs."
colors: Prefer themed() recipes for color-bearing styles when theme adaptation should apply.
text_styles: "Put per-text color/fontSize/fontFamily on a textStyle mark; keep textAlign on the node's textAlign attr and margins/padding on the node's styles."
destructive_omissions: Publish rejects missing circle nodes and response-bearing interactive nodes unless explicitly confirmed.
anti_patterns:
- Do not emit image_keywords; it is only resolved during AI build pipelines.
- Do not use raw JavaScript event attrs such as onclick.
- Do not rely on linkTo for new action buttons.
- "Do not use percentage-like grid dist values such as [50,50]."
- "Do not use position:absolute/fixed, float, or z-index layering. Sutra renders normal flow + flexbox only."
DesignCircleSummary:
type: object
properties:
slug:
type: string
id:
type: string
pattern: "^sp_"
uid:
type: string
DesignInteractiveBlockSummary:
type: object
additionalProperties: true
properties:
uid:
type: string
type:
type: string
id:
type: string
nullable: true
circle_id:
type: string
nullable: true
interactive_position:
type: integer
nullable: true
has_responses:
type: boolean
response_count:
type: integer
confirm_token:
type: string
SpaceDesignResponse:
type: object
required:
- data
properties:
data:
type: object
required:
- space_id
- view_type
- nodes
- content_digest
- circles
- interactive_blocks
- published_url
- manifest_version
properties:
space_id:
type: string
pattern: "^sp_"
view_type:
type: string
example: tiptap
nodes:
"$ref": "#/components/schemas/TiptapDesignNodes"
content_digest:
type: string
pattern: "^sha256:"
circles:
type: array
items:
"$ref": "#/components/schemas/DesignCircleSummary"
interactive_blocks:
type: array
items:
"$ref": "#/components/schemas/DesignInteractiveBlockSummary"
published_url:
type: string
format: uri
manifest_version:
type: string
DesignDiagnostic:
type: object
additionalProperties: true
properties:
code:
type: string
path:
type: string
nullable: true
message:
type: string
DesignRepair:
type: object
additionalProperties: true
properties:
code:
type: string
count:
type: integer
nullable: true
DesignDiagnostics:
type: object
required:
- valid
- errors
- warnings
- repairs
properties:
valid:
type: boolean
errors:
type: array
items:
"$ref": "#/components/schemas/DesignDiagnostic"
warnings:
type: array
items:
"$ref": "#/components/schemas/DesignDiagnostic"
repairs:
type: array
items:
"$ref": "#/components/schemas/DesignRepair"
DesignValidationRequest:
type: object
required:
- nodes
properties:
nodes:
oneOf:
- "$ref": "#/components/schemas/TiptapDesignNodes"
- type: object
additionalProperties: true
description: 'Tiptap nodes array or a wrapped `{ default: { type: "doc", content: [...] } }` document.'
base_digest:
type: string
pattern: "^sha256:"
nullable: true
DesignValidationResponse:
allOf:
- "$ref": "#/components/schemas/DesignDiagnostics"
- type: object
properties:
node_count:
type: integer
content_digest:
type: string
nullable: true
pattern: "^sha256:"
DesignDraftMutationRequest:
type: object
required:
- nodes
- base_digest
- client_draft_key
properties:
nodes:
oneOf:
- "$ref": "#/components/schemas/TiptapDesignNodes"
- type: object
additionalProperties: true
base_digest:
type: string
pattern: "^sha256:"
client_draft_key:
type: string
description: Stable caller-provided key for retries or named variants.
title:
type: string
nullable: true
note:
type: string
nullable: true
source:
type: string
nullable: true
default: mcp_local
enum:
- mcp_local
- mcp_remote
- web
- system
- api
description: "Origin of the draft. HTML/CSS porting clients and other direct Admin API callers should send `api`. Defaults to `mcp_local` when omitted."
DesignDraftPatchRequest:
type: object
required:
- draft_digest
- operations
properties:
draft_digest:
type: string
pattern: "^sha256:"
description: Current draft content digest from create/update, get draft, or the previous patch response.
operations:
type: array
minItems: 1
description: Ordered operations applied atomically before the complete draft is validated.
items:
"$ref": "#/components/schemas/DesignDraftPatchOperation"
DesignDraftPatchOperation:
oneOf:
- type: object
required:
- op
- nodes
properties:
op:
type: string
enum:
- insert
nodes:
"$ref": "#/components/schemas/TiptapDesignNodes"
placement:
"$ref": "#/components/schemas/DocumentPlacementRequest"
- type: object
required:
- op
- node_uid
- node
properties:
op:
type: string
enum:
- update
node_uid:
type: string
node:
type: object
- type: object
required:
- op
- node_uid
properties:
op:
type: string
enum:
- delete
node_uid:
type: string
- type: object
required:
- op
- node_uid
properties:
op:
type: string
enum:
- move
node_uid:
type: string
placement:
"$ref": "#/components/schemas/DocumentPlacementRequest"
DesignDraftSummary:
type: object
properties:
draft_id:
type: string
pattern: "^dsdft_"
space_id:
type: string
pattern: "^sp_"
status:
type: string
enum:
- draft
- published
- superseded
- restored
- discarded
node_count:
type: integer
base_digest:
type: string
pattern: "^sha256:"
content_digest:
type: string
pattern: "^sha256:"
preview_url:
type: string
format: uri
diagnostics:
"$ref": "#/components/schemas/DesignDiagnostics"
DesignDraftMutationResponse:
type: object
required:
- data
properties:
data:
"$ref": "#/components/schemas/DesignDraftSummary"
DesignDraftPatchResponse:
type: object
required:
- data
properties:
data:
allOf:
- "$ref": "#/components/schemas/DesignDraftSummary"
- type: object
properties:
operation_count:
type: integer
inserted_node_uids:
type: array
items:
type: string
updated_node_uids:
type: array
items:
type: string
deleted_node_uids:
type: array
items:
type: string
moved_node_uids:
type: array
items:
type: string
changed_nodes:
type: array
description: Canonical inserted and updated top-level nodes only; the complete draft is available from GET design draft.
items:
type: object
DesignDraftResponse:
type: object
required:
- data
properties:
data:
allOf:
- "$ref": "#/components/schemas/DesignDraftSummary"
- type: object
properties:
nodes:
"$ref": "#/components/schemas/TiptapDesignNodes"
content_digest:
type: string
pattern: "^sha256:"
DesignDraftPreviewLinkResponse:
type: object
required:
- data
properties:
data:
type: object
required:
- draft_id
- space_id
- preview_url
- expires_at
properties:
draft_id:
type: string
pattern: "^dsdft_"
space_id:
type: string
pattern: "^sp_"
preview_url:
type: string
format: uri
description: "Short-lived signed URL that renders the draft preview for an unauthenticated browser (no Sutra login). Carries a `pt` preview token in the URL fragment (`#pt=...`), not in the query string."
expires_at:
type: string
format: date-time
description: ISO-8601 time when the signed preview link expires (~15 minutes after it is minted).
DesignDraftPublishRequest:
type: object
properties:
confirm_destroy_circles:
type: array
items:
type: string
description: Circle slugs or public IDs explicitly confirmed for removal.
confirm_destroy_interactive_with_responses:
type: array
items:
type: string
description: Interactive confirm tokens explicitly confirmed for removal.
DesignDraftPublishResponse:
type: object
required:
- data
properties:
data:
type: object
properties:
draft_id:
type: string
pattern: "^dsdft_"
space_id:
type: string
pattern: "^sp_"
status:
type: string
example: published
content_digest:
type: string
pattern: "^sha256:"
previous_digest:
type: string
pattern: "^sha256:"
revision:
type: number
published_url:
type: string
format: uri
rollback_handle:
type: object
properties:
draft_id:
type: string
pattern: "^dsdft_"
view_backup_id:
type: integer
nullable: true
diagnostics:
"$ref": "#/components/schemas/DesignDiagnostics"
DesignDraftRestoreRequest:
type: object
properties:
force_restore:
type: boolean
default: false
current_digest:
type: string
nullable: true
pattern: "^sha256:"
DesignDraftRestoreResponse:
type: object
required:
- data
properties:
data:
type: object
properties:
draft_id:
type: string
pattern: "^dsdft_"
space_id:
type: string
pattern: "^sp_"
status:
type: string
example: restored
content_digest:
type: string
pattern: "^sha256:"
previous_digest:
type: string
pattern: "^sha256:"
undo_restore_view_backup_id:
type: integer
nullable: true
published_url:
type: string
format: uri
diagnostics:
"$ref": "#/components/schemas/DesignDiagnostics"
DesignAssetImportRequest:
type: object
required:
- space_id
- source_url
properties:
space_id:
type: string
pattern: "^sp_"
source_url:
type: string
format: uri
alt:
type: string
nullable: true
DesignAssetResponse:
type: object
required:
- data
properties:
data:
type: object
properties:
asset_id:
type: string
pattern: "^asset_"
url:
type: string
format: uri
width:
type: integer
nullable: true
height:
type: integer
nullable: true
content_type:
type: string
example: image/jpeg
alt:
type: string
nullable: true
source_url:
type: string
format: uri
ErrorResponse:
type: object
required:
- error
properties:
error:
type: object
required:
- code
- message
- request_id
properties:
code:
type: string
message:
type: string
request_id:
type: string
required_scope:
type: string
retry_after:
type: integer