Skip to main content
POST https://api.craftkit.dev/v1/templates
Create a template from a manifest alone. Craftkit synthesizes a layout that renders every field — scalars as labeled values, image variables as images, and loops as repeating tables — and publishes it as version 1. This is the self-serve path for loop/table + image templates (no dashboard step, no hand-written layout). Pass an explicit layout only if you want full control.

Authorization

Authorization
string
required
Bearer ck_live_… — the template is created in this key’s project.

Body

name
string
required
Display name (1–120 chars).
slug
string
Kebab-case identifier, unique in the project. Omit to derive one from name (a short suffix is added if it collides). A provided slug that already exists returns 409.
description
string
Optional, up to 280 chars.
manifest
object
required
The variable manifest the render payload binds to.
layout
object
Optional CanvasDocument contentJson override. When omitted, it is generated from the manifest.
pageConfig
object
Optional page format (format, orientation, margin, printBackground). Defaults to A4 portrait.

Response

201:
id
string
slug
string
Final slug (may differ from a derived input if it collided).
currentVersionNumber
number
Always 1 for a newly created template.
manifest
object
The stored manifest, echoed back.

Errors

StatuscodeMeaning
400invalid_jsonBody is not valid JSON.
400invalid_requestEnvelope, manifest, or pageConfig failed validation (issues included).
400invalid_loop_keyA loop key contains a dot — use a dot-free top-level key.
401unauthorizedMissing/invalid key.
409slug_conflictA provided slug already exists in this project.
cURL
curl -X POST https://api.craftkit.dev/v1/templates \
  -H "Authorization: Bearer $CRAFTKIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Charter Handover",
    "slug": "charter-handover",
    "manifest": {
      "variables": [
        { "key": "booking.code", "label": "Booking code", "dataType": "text", "required": true },
        { "key": "handover.signedBy", "label": "Signed by", "dataType": "text", "required": true },
        { "key": "handover.signatureImageUrl", "label": "Signature", "dataType": "image" }
      ],
      "loops": [
        { "key": "areas", "label": "Inspection areas", "itemFields": [
          { "key": "areaKey", "label": "Area", "dataType": "text" },
          { "key": "condition", "label": "Condition", "dataType": "text" }
        ] }
      ]
    }
  }'
201
{
  "id": "…",
  "slug": "charter-handover",
  "currentVersionNumber": 1,
  "manifest": { "variables": [ "…" ], "loops": [ "…" ] }
}
After creating, render it immediately with POST /v1/templates/:slug/render — send loop arrays at the top level (data.areas) and the image as an https URL. See Images & signatures.