Skip to main content
A project template is a saved blueprint you stamp onto new projects. Its one meaningful field is the bundle: a single JSON object holding pure, portable configuration. When you apply a template, Sapt replays that bundle into a freshly-created sub-project. This page documents what’s inside the bundle. For the end-to-end onboarding flow (apply → connect integrations → invite), see Building a client onboarding funnel.
Why the reference shows bundle as an open object. The bundle is a deeply-nested structure (it embeds workflow conditions, CRM column defs, onboarding flows, and more), so the auto-generated Reference renders it as free-form JSON rather than a fixed schema. This page is the schema — treat it as the source of truth for the bundle’s shape.

What the bundle is — and isn’t

The bundle is structural config only. It carries no project-local UUIDs: roles are keyed by name, and the sidebar’s per-role overlay references those same names. Apply remaps each name to the freshly-created role’s id. Anything tenant-specific that would dangle in a fresh project is nulled during capture and reported back to you in warnings.

Core sections

These five are always present on a bundle and are applied in this fixed order — later steps may reference earlier ones (workflows and object types reference spine and bundle slugs):
Apply is best-effort: a failure mid-bundle is recorded and swallowed, leaving whatever earlier steps already committed. Always check the apply report’s failures[] — it never throws away the whole call for one bad entity.

Extended sections

All optional. Each reuses the canonical schema from its owning module, so the bundle shape can’t drift from the live product:

Variables (custom values)

A bundle can declare variables — the “custom values” pattern. Embed {{name}} placeholders anywhere in the bundle’s strings; at apply time they’re substituted with the client’s values.
At apply you pass variableValues (a name → value map). Anything you omit comes back in the report’s missingVariables[] and is left as a literal {{placeholder}} to fill in later.

The lifecycle

You can author a bundle by hand, or snapshot a live project to capture one automatically. Either way it ends up as a template you can apply (to a new sub-project) or load (into an existing one).

Snapshotting a live project

POST /projects/{projectId}/snapshot captures the project’s configuration into a reusable template. Omit include to capture everything; set keys to true to restrict capture to those subsystems.
The include allowlist accepts: roles, sidebar, workflows, objectTypes, objectRelations, crmConfig, spineFields, contentTypes, starterContent, branding, projectContext, agents. Live CMS content items are cloned only when starterContent is included. The response returns the new template plus warnings[] — the tenant-specific values that were scrubbed.
You can also tokenize on capture: pass tokenize (a list of { find, var } replacements) alongside variables to turn literal values in the captured bundle into {{var}} placeholders — so a snapshot of one client becomes a parameterized template for the next.

Apply vs. load

Both replay a bundle, but they differ in target and conflict behavior:

The apply report

Apply and load both return a report of what landed: