---
title: "Create template"
method: POST
path: "/v2/organizations/{organizationId}/templates"
tags: ["Templates"]
---

# Create template

`POST /v2/organizations/{organizationId}/templates`

## Request

- Base URL: `https://api.pdfs.build`
- URL: `https://api.pdfs.build/v2/organizations/{organizationId}/templates`
- Auth: HTTP bearer

Creates a draft template owned by the user that minted the API key. Drafts are not renderable until published. The source is normalized through the same pipeline the app uses and should define a top-level `#let render(...)` entry function whose named parameters match the schema fields.

External ids are case-sensitive and stay reserved after a template is deleted.

## Request body

- CreateTemplateRequest
  - `externalId` string, required: Organization-scoped template id you control. 1–128 ASCII letters, digits, `.`, `_`, `~` or `-`; `.` and `..` are reserved. Case-sensitive.
  - `name` string, required: Display name.
  - `description` string
  - `code` string, required: Template source. Must define a top-level `#let render(...)` entry function. (`typstCode` is accepted as a legacy alias.)
  - `schema` object: JSON Schema describing the render `data` payload.
  - `sampleData` object: Example data that satisfies `schema`.
  - `pageSettings` object: Page size, margins and other layout settings.
  - `schemaLocked` boolean: Freeze the data contract at creation. Cannot be changed later. Rejected if `sampleData` contains fields the schema does not declare.
  - `scopePath` string: Tenant scope for delegated agent access: zero or more segments, each 1–128 chars from the external-id charset and each ending in `/`, e.g. `acct_9f3/entity_dubai/`. Empty means unscoped — invisible to every delegated grant.

## Response `201`

The created draft, including both the generated `internalId` and your `externalId`.

- Template
  - `internalId` string, required: Generated, immutable. What v1 URLs and the embedded SDK address.
  - `externalId` string, required: Organization-scoped template id you control. 1–128 ASCII letters, digits, `.`, `_`, `~` or `-`; `.` and `..` are reserved. Case-sensitive.
  - `name` string, required
  - `description` string, nullable
  - `status` 'draft' | 'published', required
  - `scopePath` string, required: Tenant scope for delegated agent access: zero or more segments, each 1–128 chars from the external-id charset and each ending in `/`, e.g. `acct_9f3/entity_dubai/`. Empty means unscoped — invisible to every delegated grant.
  - `createdAt` string, required: UTC, ISO 8601 without a timezone suffix.
  - `updatedAt` string, required: UTC, ISO 8601 without a timezone suffix.
  - `schema` object, nullable: JSON Schema of the render `data` payload.
  - `schemaLocked` boolean, required: When true the data contract is frozen: embedded editing can restyle the document but cannot add, remove or retype a field.
  - `sampleData` object, nullable: Example data satisfying `schema`.
  - `baseTemplateId` string, nullable: Internal id of the base template this one layers on, if any.
  - `version` integer, nullable: Present when `version` was given: the frozen version `schema` and `sampleData` come from, or null for the working copy.
  - `channel` string, nullable: Present when `version` was given: the channel the selector resolved through, if any.

## Other responses

- `400`: `invalid_external_id`, `invalid_scope_path`, a missing `name` or `code`, or `schemaLocked` set while `sampleData` contains fields the schema does not declare.
- `401`: Missing, invalid or expired API key.
- `403`: `organization_scope_mismatch`, or `scope_path_admin_required` when `scopePath` is set with a key that does not belong to an organization owner or admin.
- `409`: `external_id_conflict` — the external id is already reserved in this organization.

---

[API](https://skmtc.dev/pdfs/apis/pdfs-build-api.md) · [All operations](https://skmtc.dev/pdfs/apis/pdfs-build-api/llms.txt) · [OpenAPI document](https://skmtc.dev/pdfs/apis/pdfs-build-api/revisions/1c7340b9521d?raw)
