Skip to main content
The page-builder catalog is the single source of truth for the templates and section types available when building hub pages. Every Membership.io surface that composes pages — backend, hub, admin, and CLI — consumes this catalog.
GET /api/v1/page-builder/catalog returns the raw catalog JSON. The response ETag header is the catalog’s content digest — send If-None-Match: "<digest>" to get a 304 Not Modified, and cache by digest.Current catalogVersion: 0.22.1 · digest: sha256:bf03f334ebc11302490979ca4b2cf552d6cfbbb0c32c6f284f810d8f637b1ace

Node shape

Every node in a page tree is the same envelope. The renderer dispatches on kind — never on type — and reads the node’s content from a top-level value, a sibling of settings:
A section node is the same envelope plus a template from the table below and a children array. Putting a node’s content in settings.value instead of value, or omitting a section’s template, is accepted by the API and then silently dropped by the renderer; an unrecognized settings.weight (a CSS keyword such as "bold") is quietly discarded rather than applied. Every node also needs an id. See Node shape for the full contract, including the leaf-kind settings and the surface.background enum.

Templates

Node kinds

The catalog’s settingsSchema map is the authority on what each kind accepts: 33 kind:<nodeKind> entries plus the shared background, gradient, structural, surface shapes, each listing typed properties with their enums, defaults, and per-field notes, split into core and presentational buckets matching the consumer profiles below. See Node shape for the shapes that most often cause a silent render drop.

Section types

Anon-safe — whether the section type is whitelisted on the backend’s sanitized pre-auth render (login / register / payment pages for logged-out visitors). It does not affect public-hub page visibility: anonymous visitors get the full published tree of any public page; only author-set access gates prune content there.

Settings vocabulary

settingsSchema is the per-kind:<k> settings contract for the page-builder node tree. Each kind’s schema splits into two tiers: core settings that every consumer — the web hub, native apps, any future renderer — must honor to render the node correctly, and presentational settings that native apps and other constrained consumers are free to ignore. Only keys and values the mio-hub renderer actually implements are listed below; this documents what’s real, not an aspirational spec. Recipes must not restate a setting’s default value — omitting a key defers to the hub’s built-in default for that key. The mio-hub renderer is the source of truth for this vocabulary, and it is declared directly in the catalog (MIO-2685).

shared:background

Flattened TemplateSurface Background discriminated union (src/lib/page-tree/types.ts). Validation limitation: enum applies to ‘type’; all variant fields are optional and the validator cannot enforce which fields are required per ‘type’ value. ‘thumbnail’ is excluded per the honesty policy (decision 4) — declared as a TODO in hub types, implemented nowhere, used by no recipe.

shared:gradient

Paired with shared:background when type=‘gradient’ (src/lib/page-tree/types.ts Gradient, src/lib/theme/types.ts GradientType).

shared:surface

TemplateSurface (src/lib/page-tree/types.ts). Nested under a kind’s own ‘surface’ settings key (see kind:stack, kind:content-card, and the section-root template-level surface consumed via TemplateSurface). Resolved by useNodeSurface() (src/components/primitives/node-surface.tsx).

shared:structural

NOT referenced via {type:‘object’,shape:‘structural’} from a kind descriptor like the other shared shapes. This is a validator-level ADDITIVE allowlist: every node’s settings object is validated against ‘kind:<its-kind>’ UNIONED with these three keys — tab_label/slot are read generically off ANY child node’s settings by an ANCESTOR container (tabs.tsx, accordion.tsx, find-by-slot.ts), independent of the child’s own kind, and are not part of any single kind’s own *Settings TS interface; surface is read generically off ANY node’s settings by renderer.tsx’s <TemplateSurface> wrapper, gated on that node’s ‘template’ annotation naming a templates[]/pageTemplates[] entry that itself declares a ‘surface’ property (the surface-declaring template set), independent of the node’s own kind. This is an extension beyond the design spec’s literal decision-1 text (which only names shared:surface as a referenced shape); documented here because the real catalog already uses tab_label/slot on stack/text/tabs nodes and surface on section-root container nodes (see Task A1 defaults-audit notes + MIO-2685 review round 1), and excluding any of the three would make the validator reject existing recipes. MIO-2724 addendum: ‘name’/‘role’/‘salesMeta’ (REVIEW — flagged for owner confirmation, see their own descriptions) extend this additive allowlist with catalog-authoring-only narrative-arc metadata used by the page-sales recipe’s section-root nodes — distinct from any mio-hub renderer concern, and (for ‘role’) a deliberate same-name/different-vocabulary overload against kind:field.core.role, resolved safely by this validator’s kind-first-then-structural-fallback lookup order.

kind:stack

kind:row

kind:grid

kind:carousel

kind:horizontal-scroll

kind:tabs

No settings. The Tabs component reads NO settings of its own (PRIMITIVE_DEFAULTS explicitly documents this: “tabs — the component reads no settings at all”). Its per-child tab label comes from shared:structural’s tab_label on each CHILD’s own settings, not from a tabs-kind setting.

kind:container

No PRIMITIVE_DEFAULTS entry (container: {}) — the DS-intended maxWidth:‘content’ default has NO inline ’??’ fallback in container.tsx, deliberately undeclared per that file’s own comment (would change rendering the moment MIO-2358 wires cascade layer 1).

kind:content-card

kind:accordion

kind:video

kind:divider

kind:progress-ring

kind:headline

kind:text

kind:image

EXCLUDES ‘width’/‘height’ from ImageSettings — the hub interface comment states they are ‘presently no-ops’ (no longer forwarded to the rendered <img>, ui/thumbnail owns that element with no sizing passthrough), kept on the TS contract only for BE-served-data forward-compat parsing, not for authoring. Per the honesty policy, a key with no rendering effect does not enter the vocabulary.

kind:button

kind:icon

kind:field

kind:media-slot

kind:cta-slot

kind:file-player

kind:file-attachments

kind:search-bar

kind:quote

kind:banner

kind:countdown

kind:theme-toggle

No settings.

kind:plan-group

kind:plan-card

kind:plan-price

kind:doodle

kind:featured-icon

Consumer profiles

  • ios-min — templates: hero; settings: core
  • web — templates: all templates; settings: core+presentational