Design API
The Design API lets API clients read, validate, draft, publish, and restore
Sutra-rendered page designs for a space's Tiptap view.
Endpoints
GET /design/capabilities returns the generated schema and editor capability
manifest. For every node, nodes.<type>.appearance is the exact appearance
contract backed by user-facing block settings: style_keys gives the keys
allowed in each style storage object, attrs gives UI-editable appearance
attrs, controls groups them by editor control, and responsive lists the
supported breakpoint overrides. Responsive style_keys/attrs are
unconditional; entries under conditional apply only when their when
clause matches the node's base attrs. MCP clients must author appearance only
from that per-node contract and only when mcp_authorable is true. The top-level
styles.supported_keys list is retained as a legacy validation union and is
not an authoring guarantee. The response also includes a website section
documenting website-mode header/footer (share-block) and navbar style shapes,
allowed values, and the link object — see the Website Mode section of the
overview for how to author them.
Content layout attrs include flexLayout, flexGap, flexItemSizing
(equal or fit), and flexRowAlign (left, center, right) for
row-style layouts such as side-by-side badge pills. The top-level
block_appearance section documents box-level inherited typography, box hover,
and entrance animation. Support is still per-node: use a value only when the
target node's appearance.controls lists text_defaults, hover, or
animation. allowed_values.boxHover and allowed_values.animateIn publish
the modes; the block_appearance custom-field contracts publish their shapes
and editor bounds.
GET /spaces/{space_id}/design returns current nodes, digest, circle
summaries, interactive-block summaries, and the published URL.
POST /spaces/{space_id}/design/validate validates proposed nodes and
returns diagnostics (errors, warnings, repairs). Warnings are advisory — for
example, setting min-height in a box/container/grid styles object (the
renderer clears it; set the node's minHeight attr instead, which accepts
vh/calc for full-viewport sections).
POST /spaces/{space_id}/design_drafts creates or updates the caller's
open draft for a client_draft_key.
GET /spaces/{space_id}/design_drafts/{draft_id} returns the draft content
for authorized preview clients.
PATCH /spaces/{space_id}/design_drafts/{draft_id} fully replaces a draft's
node document while preserving its identity.
PATCH /spaces/{space_id}/design_drafts/{draft_id}/nodes atomically applies
UID-based insert, update, delete, and move operations without resending the
complete draft. It requires the current draft content_digest as
draft_digest and returns a compact delta plus the next digest.
POST /spaces/{space_id}/design_drafts/{draft_id}/publish publishes a
draft if its base_digest is still current.
POST /spaces/{space_id}/design_drafts/{draft_id}/restore restores the
pre-publish backup created by a draft publish.
POST /spaces/{space_id}/design_drafts/{draft_id}/preview_link (or the bare
POST /design_drafts/{draft_id}/preview_link) mints a short-lived, signed,
read-only preview link for the draft. Requires design:read.
POST /design/assets/import fetches, validates, and re-hosts an external
image URL for use in design JSON.
Use base_digest from GET /spaces/{space_id}/design when creating or
updating drafts. If live content changes before publish, the API returns
409 conflict with the current digest so the client can re-read and rebase.
Draft mutation responses also return the draft content_digest. Pass it as
draft_digest to the next node patch; if another caller changed the same
draft, the patch returns 409 conflict with current_draft_digest rather
than silently overwriting that work. Each patch validates the complete
recomposed draft and applies all operations atomically.
Publishing rejects destructive omissions of circle nodes or response-bearing
interactive nodes unless the caller includes the confirmation values returned
in the conflict response.
Draft create/update responses include a preview_url on the canonical Sutra
application route, /space/{slug}/preview/{draft_id}. Preview URLs deliberately
do not use the space's published or branded host: those hosts route public
website paths and cannot infer the internal space slug from /preview/{draft_id}.
The bare URL uses the logged-in web session and only returns draft content to
users who can already edit the space. Opened without that session it simply
redirects to the app root, which reads as "the draft rendered blank" — so the
same responses also carry preview_link_endpoint, naming the call that mints
the shareable link described below.
To share a preview with someone who is not logged in, call
POST /design_drafts/{draft_id}/preview_link (or the space-scoped
POST /spaces/{space_id}/design_drafts/{draft_id}/preview_link). It returns a
preview_url carrying a short-lived (~15 minute), signed pt token, plus an
expires_at timestamp. The token grants read-only preview of that one draft
and renders for an unauthenticated browser — no Sutra login is required and
no Admin API token is exposed in the browser. Requires the design:read scope.
Asset import only accepts public http/https image URLs, blocks private
network targets, enforces byte and image dimension caps, sanitizes SVG, and
stores the result on Sutra-controlled S3/CDN infrastructure.