Craftkitdocs

POST /v1/embed/catalogs

Publish a named variable catalog version via API.

Publish a new version of a named variable catalog. Each call creates the next version number and marks it as current — the previous version is archived but never deleted.

POST /v1/embed/catalogs

Quick Start

curl

curl -X POST https://api.craftkit.dev/v1/embed/catalogs \
  -H "Authorization: Bearer $CRAFTKIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-catalog",
    "catalog": {
      "allowCustom": false,
      "namespaces": [
        {
          "key": "customer",
          "label": "Customer",
          "fields": [
            { "key": "customer.name",  "label": "Customer name",  "dataType": "text",   "previewData": "Acme Corp" },
            { "key": "customer.email", "label": "Customer email", "dataType": "email",  "previewData": "hello@acme.com" }
          ]
        }
      ],
      "loops": []
    }
  }'

Node.js

const res = await fetch('https://api.craftkit.dev/v1/embed/catalogs', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CRAFTKIT_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    name: 'my-catalog',
    catalog: {
      allowCustom: false,
      namespaces: [
        {
          key: 'customer',
          label: 'Customer',
          fields: [
            { key: 'customer.name',  label: 'Customer name',  dataType: 'text',  previewData: 'Acme Corp' },
            { key: 'customer.email', label: 'Customer email', dataType: 'email', previewData: 'hello@acme.com' },
          ],
        },
      ],
      loops: [],
    },
  }),
});

const { id, name, version } = await res.json();
// { id: "0193c2c3-1a2b-7c3d-8e4f-aabbccddeeff", name: "my-catalog", version: 1 }

Python

import os, requests

res = requests.post(
    "https://api.craftkit.dev/v1/embed/catalogs",
    headers={"Authorization": f"Bearer {os.environ['CRAFTKIT_API_KEY']}"},
    json={
        "name": "my-catalog",
        "catalog": {
            "allowCustom": False,
            "namespaces": [
                {
                    "key": "customer",
                    "label": "Customer",
                    "fields": [
                        {"key": "customer.name",  "label": "Customer name",  "dataType": "text",  "previewData": "Acme Corp"},
                        {"key": "customer.email", "label": "Customer email", "dataType": "email", "previewData": "hello@acme.com"},
                    ],
                }
            ],
            "loops": [],
        },
    },
)
result = res.json()
# {"id": "0193c2c3-1a2b-7c3d-8e4f-aabbccddeeff", "name": "my-catalog", "version": 1}

Request body

{
  "name": "my-catalog",
  "catalog": {
    "allowCustom": false,
    "namespaces": [ ... ],
    "loops": [ ... ]
  }
}
Field Type Required Description
name string Yes Catalog name. Lowercase letters, numbers, and hyphens. Reusing an existing name creates the next version.
catalog object Yes The full catalog payload — see schema below.

Catalog schema

{
  "allowCustom": false,
  "namespaces": [
    {
      "key": "customer",
      "label": "Customer",
      "icon": "user",
      "fields": [
        {
          "key": "customer.name",
          "label": "Customer name",
          "dataType": "text",
          "previewData": "Acme Corp",
          "description": "The company or individual name",
          "format": "optional format string"
        }
      ]
    }
  ],
  "loops": [
    {
      "key": "order.items",
      "label": "Order items",
      "itemFields": [
        { "key": "name",  "label": "Product",    "dataType": "text",     "previewData": "Widget A" },
        { "key": "qty",   "label": "Quantity",   "dataType": "number",   "previewData": 2 },
        { "key": "price", "label": "Unit price", "dataType": "currency", "previewData": 49.99 }
      ],
      "previewData": [
        { "name": "Widget A", "qty": 2, "price": 49.99 },
        { "name": "Widget B", "qty": 1, "price": 99.00 }
      ]
    }
  ]
}

namespaces[].fields object

Field Type Required Description
key string Yes Dot-path key used in templates: customer.name. Pattern: ^[a-zA-Z_][a-zA-Z0-9_.]*$.
label string Yes Display name in the variable picker.
dataType string Yes One of text, longtext, number, currency, date, datetime, boolean, image, url, email, select.
options { value, label }[] — Fixed choices for a select field — value is stored/validated, label is display text. Required (non-empty, unique values) when dataType is select; ignored otherwise. A value outside the options is rejected with invalid_input_data when the resolved template renders.
previewData scalar — Dummy value shown in the live preview. Doubles as input placeholder in form-fill embeds.
format string — Formatting hint: currency:EUR, date:DD/MM/YYYY.
description string — Helper text shown beneath the field in the variable picker.

loops object

Field Type Required Description
key string Yes Loop key: order.items. Compiles to {{#each order.items}}...{{/each}}.
label string Yes Display name in the picker.
itemFields array Yes Fields available inside the loop body. Same shape as namespace fields.
previewData array — Dummy rows for the live preview (max 10).

Response

201 Created

{
  "id": "0193c2c3-1a2b-7c3d-8e4f-aabbccddeeff",
  "name": "my-catalog",
  "version": 1
}
Field Type Description
id string Catalog row UUID. To pin a session to a specific version, pass catalogRef: { name, version } (catalogs are referenced by name + version, not by id).
name string The catalog name you passed.
version number Monotonically increasing version number within this name.

Versioning

Calling POST /v1/embed/catalogs with the same name creates the next version:

v1 → archived
v2 → archived
v3 → current ← sessions referencing this name get v3

Sessions minted with catalogRef: { name: "my-catalog" } always resolve to the current version. To pin a session to a specific version, pass catalogRef: { name: "my-catalog", version: 2 }.

Referencing the catalog in a session

After publishing, reference the catalog by name when minting a session:

{
  "tenant": { "externalId": "org_123", "displayName": "Acme Corp" },
  "actor":  { "externalId": "usr_456", "displayName": "Jane Smith" },
  "catalogRef": { "name": "my-catalog" }
}

Or inline a one-off catalog without publishing it first:

{
  "tenant": { ... },
  "actor":  { ... },
  "variableCatalog": { "allowCustom": false, "namespaces": [...], "loops": [] }
}

See Session API (mint & refresh) for the full session mint reference.

Errors

Status Code Meaning
401 missing_authorization No Authorization header.
401 invalid_credentials API key not found, revoked, or embed not enabled.
400 invalid_json Request body is not valid JSON.
422 invalid_request Body or catalog failed validation — check issues array for field-level details.
500 internal_error Auth check or catalog persistence threw server-side. Retry; contact support if it persists.

Last revised: 2026-05-12