Skip to main content
POST https://api.craftkit.dev/v1/projects/{id}/templates/copy
Duplicate a template — its published layout/design, variable manifest, and everything needed to derive its jsonSchema — from a source project into this (target) project, published as version 1. This is the cross-project path the rest of the public API doesn’t cover: GET /v1/templates/:slug never returns a layout, and POST /v1/templates only accepts a manifest — so without this endpoint, copying a template between projects reproduces its 50+ variables but drops the Canvas design entirely. The copy renders byte-for-byte identically to the source: contentJson, compiledHtml, variablesManifest, and pageConfig are carried over verbatim, not regenerated.
Both the source and target project must be owned by the same authenticated account. This is a cross-project copy, not a cross-account one — an account key can only ever pull a template from a project it also owns. See Account-key auth.

Authorization

Authorization
string
required
Bearer ck_acct_… — must own both the target project (the path id) and the source project.

Path

id
string
required
The target project id (UUID) to copy into.

Body

sourceProjectId
string
UUID of the source project. Provide this or sourceProjectSlug (not both required — either is enough to resolve the project).
sourceProjectSlug
string
Slug of the source project, scoped to the authenticated account. Alternative to sourceProjectId.
sourceTemplateId
string
UUID of the template to copy, scoped to the source project. Provide this or sourceTemplateSlug.
sourceTemplateSlug
string
Slug of the template to copy, scoped to the source project. Alternative to sourceTemplateId.
name
string
Display name for the copy (1–120 chars). Omit to keep the source template’s name and slug unchanged. When provided, the target slug is derived from name instead.

Response

201 when a new template was created, 200 when an idempotent replay returned an existing one (see Idempotency below) — the body shape is identical either way:
id
string
UUID of the copy (or the pre-existing template, on a replay).
projectId
string
Echoes the path id — the target project.
slug
string
The copy’s slug (the source’s slug, unless name was given).
name
string
currentVersionNumber
number
Always 1 for a freshly created copy.
sourceProjectId
string
sourceTemplateId
string
sourceVersionNumber
number
The source’s version number that was copied (e.g. 6).
alreadyExisted
boolean
true when a non-deleted template already occupied the target slug and was returned instead of creating a duplicate (see Idempotency).

Idempotency

If the target project already has a non-deleted template at the resolved slug, this endpoint returns that template (200, alreadyExisted: true) instead of erroring or creating a duplicate — so retrying the same copy call (e.g. after a network timeout, or as part of a re-run onboarding flow) is always safe. If you need strict conflict detection instead, pass a name you know is unused in the target project — a genuine collision then falls through to the copy logic and is resolved the same way.

Errors

cURL
201
After copying, fetch GET /v1/templates/:slug in the target project with a ck_live_… key (mint one with POST /v1/projects/:id/keys) to confirm the manifest and jsonSchema match the source, then render it exactly as you would any other template with POST /v1/templates/:slug/render.