Craftkitdocs

AI setup prompt

One-prompt setup — paste into any AI assistant to generate a complete integration for your stack.

AI project setup — one-prompt Craftkit integration

Copy the prompt below and paste it directly into Claude, ChatGPT, Cursor, or any AI coding assistant. The AI will ask you a few questions and then generate a complete, production-ready Craftkit integration tailored to your project.


The prompt

You are setting up a complete Craftkit document-generation integration. Craftkit (https://www.craftkit.dev) lets SaaS apps embed a template builder and/or a document form-fill widget. It also exposes a REST API for programmatic PDF rendering.

Ask me the following questions ONE AT A TIME before writing any code:

  1. Stack: What framework and language is your backend? (Next.js App Router, Express, FastAPI, Rails, Laravel, etc.)
  2. Frontend: What framework is your frontend? (React, Vue, Svelte, vanilla JS, etc.)
  3. Auth: What auth system do you use? (Clerk, NextAuth, custom JWT, session cookies, etc.) — I need to know how to protect the Craftkit proxy routes.
  4. Tenancy: Is this single-tenant (one org) or multi-tenant (many orgs, each needing isolated templates)?
  5. Use case: Which embed surfaces do you need?
    • (A) Builder only — your customers design their own templates
    • (B) Form-fill only — your users fill and generate documents from pre-built templates
    • (C) Both — customers design templates; users fill them
    • (D) API-only — your backend triggers renders programmatically (no embed)
  6. Variables: Describe your data model briefly — what fields will populate the documents? (e.g. "customer name/email, booking date/vessel, invoice total")

Once I answer all six questions, generate the following complete, working code with no placeholders:

A. Environment variables

List every env var needed with a comment explaining each one.

B. Backend proxy routes

For Next.js App Router: generate the full app/api/craftkit/ directory tree with all route files. For other frameworks: generate equivalent middleware/controllers. Always use the admin provision pattern for multi-tenant:

  • lib/credentials.tsgetOrgApiKey(orgId) caches per-org keys via POST /v1/admin/provision
  • session/route.ts — mint sessions; resolve org key; support modes: create/edit/fill/view
  • refresh/route.ts — refresh sessions; must pass orgId and use getOrgApiKey(orgId), NOT a single fixed CRAFTKIT_API_KEY (that breaks multi-tenant refresh)
  • templates/route.ts — list published templates for an org
  • renders/route.ts — list renders for an org
  • renders/[id]/download/route.ts — proxy PDF download

C. Frontend embed component

A complete, reusable React/Vue/vanilla component that:

  • Mints a session on mount (calls the backend session route)
  • Renders the Craftkit iframe using the returned iframe_url
  • Handles session.expiring by calling the refresh route with orgId
  • Handles session.expired by re-minting
  • Emits onPublished when a template is published (saves craftkitTemplateId to your DB)
  • Emits onCompleted when a form-fill document is ready
  • Shows a loading state while minting and an error state on failure

D. Variable catalog

Generate a POST /v1/embed/catalogs call (curl + equivalent code) with my data model mapped to Craftkit field types (text, number, currency, date, email, url, image, boolean, longtext). Mark fields that should be required in the form.

E. Example page

One example page/route that uses the embed component — create mode for a new template or fill mode for a document.

F. Checklist

A copy-paste checklist of everything I need to do in the Craftkit dashboard before this code will work:

  • Create account and project
  • Enable embed mode (Dashboard → Project → Embed → Overview)
  • Add allowed origins for the embed iframe
  • Note the CRAFTKIT_ADMIN_KEY from project settings
  • (if catalog) Publish the variable catalog and note its name

Key rules the AI must follow when generating code:

  • Never hardcode API keys or secrets — always use env vars
  • The refresh route MUST use getOrgApiKey(orgId), not a fixed CRAFTKIT_API_KEY
  • The templateExternalId passed to session minting must be the Craftkit UUID (from the template.published event), NOT an internal MongoDB ObjectId or integer ID
  • The iframe_url from the session response must be used verbatim — never construct the iframe URL manually (path differs between fill and builder modes)
  • Validate e.origin before acting on postMessage events
  • Always mint a fresh session for each iframe mount — never cache iframe_url

What the AI will generate

Depending on your answers, the AI generates a complete, drop-in integration:

Answer Generated output
Next.js + Clerk + multi-tenant + builder + form Full app/api/craftkit/ directory, CraftkitEmbed component, Clerk auth() guard, Zustand/React Query hooks
Express + JWT + single-tenant + API-only Middleware, render controller, webhook handler, polling utility
Next.js + NextAuth + single-tenant + form-fill Slim proxy (no provision), form-fill component, catalog

Quick reference — key decisions

Multi-tenant vs single-tenant

Single-tenant Multi-tenant
Env vars CRAFTKIT_API_KEY (one fixed key) CRAFTKIT_ADMIN_KEY (provision key)
Session mint Use CRAFTKIT_API_KEY directly Call getOrgApiKey(orgId)
Session refresh Use CRAFTKIT_API_KEY directly Call getOrgApiKey(orgId)MUST match session's org
Org isolation Shared project One Craftkit project per org, auto-provisioned

Mode cheat sheet

Mode iframe path Permissions required
create /embed/builder publish: true, saveDraft: true (defaults)
edit /embed/builder publish: true, saveDraft: true (defaults)
view /embed/builder publish: false, saveDraft: false
fill /embed/form submitForm: truemust set explicitly

Critical pitfalls

  1. Never use a MongoDB ObjectId as templateExternalId — Craftkit requires UUID format. Store the UUID from the template.published event and use that.

  2. Never cache iframe_url across page navigations — each mount needs a fresh mint.

  3. Never use a fixed CRAFTKIT_API_KEY for refresh in multi-tenant — the session's partnerId must match the key used for refresh. Use getOrgApiKey(orgId).

  4. submitForm defaults to false — fill sessions must explicitly set it to true.

  5. API keys are environment-specific — a key created in local dev does not exist in production. Always create keys in the target environment's Craftkit dashboard.