Variable catalog
Inject your data model so partner end-users see the right fields.
04 — Variable Catalog
The variable catalog is the innovation that lets partners inject their data model into the embedded builder without sharing schemas.
The catalog is also consumed by the form-fill embed (
/embed/form) to drive auto-form generation: eachCatalogFieldbecomes one input, field labels and namespaces become section headings, andpreviewDatadoubles as the input's placeholder so the end-user sees the expected shape. When no catalog is attached to a session, the form embed falls back to the published version'svariableManifest. See 12-form-route.md §6.
What a catalog is
A typed, namespaced directory of variables that the partner makes available to their tenants in the embed builder.
{
"name": "partner-default",
"version": 3,
"allow_custom": false,
"namespaces": [
{
"key": "customer",
"label": "Customer",
"icon": "user",
"fields": [
{ "key": "customer.name", "label": "Customer name", "dataType": "text" },
{ "key": "customer.email", "label": "Customer email", "dataType": "email" }
]
},
{
"key": "order",
"label": "Order",
"icon": "package",
"fields": [
{ "key": "order.id", "label": "Order ID", "dataType": "text" },
{ "key": "order.placed_at", "label": "Placed", "dataType": "date", "format": "date:DD/MM/YYYY" },
{ "key": "order.total", "label": "Total", "dataType": "currency", "format": "currency:EUR" }
]
}
],
"loops": [
{
"key": "order.items",
"label": "Items",
"item_fields": [
{ "key": "name", "label": "Product name", "dataType": "text" },
{ "key": "qty", "label": "Quantity", "dataType": "number" },
{ "key": "price","label": "Unit price", "dataType": "currency" }
]
}
]
}How catalogs flow
1. Partner defines a catalog in their admin (or builds it dynamically)
2. Partner POSTs catalog inline OR by name when minting a session
3. Craftkit stores the catalog under cat_… and references it in JWT
4. Embed page fetches catalog at load
5. Variable picker UI renders the catalog as a tree
6. User clicks/drags a field → variable node inserted with attrs from catalog
7. The chip's appearance includes the namespace breadcrumbInline vs Named catalogs
Inline (smaller catalogs, dynamic)
POST /v1/embed/sessions
{
"tenant": {...},
"actor": {...},
"variable_catalog": { ... full inline ... }
}Use when:
- Catalog varies per tenant (e.g., custom fields)
- Catalog is small (<50 fields)
- Catalog is computed dynamically per session
Named (large catalogs, stable)
POST /v1/embed/sessions
{
"tenant": {...},
"actor": {...},
"catalog_ref": "partner-default-v3"
}Use when:
- Catalog is stable across all tenants (or all in a tier)
- Catalog is large (>50 fields)
- Partner manages catalogs through admin UI
Catalog evolution
Catalogs are versioned, never mutated in place. Every change creates a new version (v1, v2, v3, …).
When the catalog changes, three scenarios:
| Scenario | Behavior |
|---|---|
| Field added | Templates keep working; new field appears in picker on next session |
| Field renamed (label changed, key stable) | Existing chips re-render with new label automatically |
| Field removed (key gone) | Chips for missing keys render as [? customer.legacy_field] with a warning style; preview shows (missing); publishing is blocked until resolved |
| Field key changed | Treated as remove + add. UI shows a one-click "Remap to new field" suggestion if labels match closely |
The remap UX is critical for long-term data model evolution and is what separates a polished embed integration from a brittle one.
The catalog-aware variable picker
The picker has three layouts, all over the same data:
Layout A: Popover (toolbar trigger)
Popover with search + tree. Recently-used at top. Each row shows type glyph,
label (middle), key (monospace, faded, right). Required fields show ●.
Layout B: Always-visible left rail (premium UX)
The killer move for embed mode. Catalog tree always visible on the left.
Drag-to-insert + click-to-insert. Inside a loop, rail context-switches to
that loop's item_fields.
Layout C: Slash menu (inline)
User types / → inline menu with both variables and formatting commands.
Notion-style.
Field type catalog
Every field has a dataType. Supported types:
Format strings (format: "currency:EUR", format: "date:DD/MM/YYYY") are
optional helpers applied at render time.
Catalog namespacing convention
- Top-level keys are namespaces:
customer,order,booking - Dot-paths reference fields:
customer.name,order.total - Loops use the same dot-path pattern:
order.items - Inside a loop, item fields are unprefixed:
name,qty,price - Compiled Handlebars:
{{customer.name}},{{#each order.items}}{{name}}{{/each}}
Last revised: 2026-05-02