Templates API: List, Retrieve, Create, Update, and Delete Templates
Last updated March 23, 2026
Complete API reference for listing, retrieving, creating, updating, and deleting templates in PDFMonkey.
Most users don't need the Templates API
Authentication
All requests require a Bearer token in the Authorization header:
Authorization: Bearer YOUR_SECRET_KEY
See Authentication for how to find your API key.
The DocumentTemplate object
A DocumentTemplate is the reusable design that defines a document’s layout. It contains:
- HTML + Liquid for dynamic content
- CSS / SCSS for styling
- Test data for previewing in the Dashboard
- Settings for paper size, margins, headers, and footers
Draft vs published properties
Each template maintains two sets of properties:
- Draft properties (
body_draft,scss_style_draft,settings_draft,sample_data_draft,pdf_engine_draft_id) for content being edited in the Dashboard but not yet published. - Published properties (
body,scss_style,settings,sample_data,pdf_engine_id) used when generating documents.
When you publish a template in the Dashboard, draft values are copied to their published counterparts.
Attributes
{
"id": "8ac0d8f7-dbd3-46dd-b2d3-af036a2776d9",
"app_id": "3161c5e5-9966-4630-9b07-63f718092784",
"identifier": "My Awesome Template",
"edition_mode": "code",
"output_type": "pdf",
"body": "<p>Hello {{name}}</p>",
"body_draft": "<p>Hello, <strong>{{name}}!</strong></p>",
"scss_style": "p { color: green; }",
"scss_style_draft": "p { color: purple; }",
"sample_data": "{ \"name\": \"Peter Parker\" }",
"sample_data_draft": "{ \"name\": \"Spider-Man\" }",
"settings": {
"footer": {
"center": null,
"content": null,
"left": null,
"right": "page [page]/[topage]"
},
"header": {
"center": null,
"content": null,
"left": null,
"right": null
},
"inject_javascript": false,
"margin": {
"bottom": 0,
"left": 0,
"right": 0,
"top": 0
},
"orientation": "portrait",
"paper_format": "a4",
"paper_height": 297,
"paper_width": 210,
"transparent_background": false,
"use_emojis": false,
"use_paged": false
},
"settings_draft": { /* same structure as settings */ },
"pdf_engine_id": "5c709522-90db-4aea-b49f-15aeaa7180c7",
"pdf_engine_draft_id": "5c709522-90db-4aea-b49f-15aeaa7180c7",
"template_folder_id": null,
"ttl": 86400,
"created_at": "2050-01-02T03:04:05.678+02:00",
"updated_at": "2050-01-02T03:04:05.678+02:00",
"auth_token": "ZCsspcSZieyfdCUHYjKW1B9D8mnrz2ck",
"checksum": "kfYsx6xzMx3JkYxLd4LW6YeU5rkcuTxQ",
"preview_url": "https://preview.pdfmonkey.io/pdf/..."
}
| Attribute | Type | Description |
|---|---|---|
id | UUID | Unique identifier. |
app_id | UUID | Unique identifier of the template’s workspace. |
identifier | String | Human-readable name (1–100 characters). |
edition_mode | String | code, visual (deprecated), or builder. |
output_type | String | pdf or image. Determines the format of generated documents. |
body | String | Published HTML + Liquid content used to generate documents. |
body_draft | String | Unpublished HTML + Liquid content, not yet used for generation. |
scss_style | String | Published CSS or SCSS styles applied to the content. Does not apply to headers or footers. |
scss_style_draft | String | Unpublished CSS or SCSS styles. |
sample_data | String | Published test data. Not used for generation; serves as a rollback point for draft changes. |
sample_data_draft | String | Draft JSON data used to preview the template. Not used for generation. |
settings | Object | Published printing settings. See Settings below. |
settings_draft | Object | Unpublished printing settings. See Settings below. |
pdf_engine_id | UUID | ID of the PDF engine used when generating documents. See PDF engines below. |
pdf_engine_draft_id | UUID | ID of the PDF engine used to preview draft content. Useful to test a new engine before switching. See PDF engines below. |
template_folder_id | UUID or null | ID of a folder to group the template into. |
ttl | Number | Time-to-live in seconds. Documents generated from this template are automatically deleted after this delay. See Retention and Deletion. |
created_at | String (ISO 8601) | Timestamp when the template was created. |
updated_at | String (ISO 8601) | Timestamp when the template was last updated. |
auth_token | String | Internal. Not used. |
checksum | String | Internal. Used for preview cache invalidation. |
preview_url | String (URL) | URL to preview the template using draft properties. Embed in an <iframe> or open directly. |
Settings
The settings attribute (and its draft counterpart settings_draft) controls the layout, formatting, and behavior of generated documents.
Not all settings apply to every template configuration. The Applies to column indicates which edition modes and output types each setting is relevant to.
| Attribute | Type | Applies to | Description |
|---|---|---|---|
footer | Object | PDF (code, builder) | Configures the footer. |
footer.left / footer.center / footer.right | String | PDF (code, builder) | Content for the left, center, or right parts of the footer. Magic tokens [page] and [topage] insert the current page number and total pages. HTML + Liquid is not supported. |
footer.content | String | PDF (code, builder) | Full-width footer content. Overrides left, center, and right when set. |
header | Object | PDF (code, builder) | Configures the header. |
header.left / header.center / header.right | String | PDF (code, builder) | Content for the left, center, or right parts of the header. Magic tokens [page] and [topage] can be used. HTML + Liquid is not supported. |
header.content | String | PDF (code, builder) | Full-width header content. Overrides left, center, and right when set. |
inject_javascript | Boolean | All | When true, the document’s payload (or test data) is accessible in JavaScript via the $docPayload variable. Can impact performance with large payloads. Always enabled for builder templates. |
margin | Object | PDF (code, builder) | Sets the margins of the document. |
margin.bottom / margin.left / margin.right / margin.top | Number | PDF (code, builder) | Margin in millimeters. Defaults to 10 if set to null or omitted. |
orientation | String | PDF (code, builder) | Page orientation: portrait or landscape. |
paper_format | String | PDF (code, builder) | Paper format: a0, a1, a2, a3, a4, a5, a6, letter, or custom. |
paper_height | Number | PDF (code, builder) | Paper height in millimeters. Only used when paper_format is custom; otherwise derived from the format. |
paper_width | Number | PDF (code, builder) | Paper width in millimeters. Only used when paper_format is custom; otherwise derived from the format. |
transparent_background | Boolean | Image | When true, the generated image has a transparent background instead of white. |
use_emojis | Boolean | All | When true, enables emoji rendering (via Noto Color Emoji) in the generated document. |
use_paged | Boolean | PDF (code, builder) | Specific to PDF Engine v3. When true, the engine waits for Paged.js rendering to complete before generating the PDF. Other engines ignore this setting. |
PDF engines
PDFMonkey provides multiple PDF engines, each with different capabilities. We strongly recommend using v4, the most recent and powerful engine. See Our Engines for a detailed comparison.
To retrieve the list of available engines:
curl https://api.pdfmonkey.io/api/v1/engines \
-H "Authorization: Bearer YOUR_SECRET_KEY"
{
"pdf_engines": [
{ "id": "5c709522-90db-4aea-b49f-15aeaa7180c7", "name": "v4", "deprecated_on": null },
{ "id": "61749ef7-6aca-4edb-84ca-685adb638c34", "name": "v3", "deprecated_on": null },
{ "id": "1f8da2ab-29c4-455c-a5fb-8771e44148c3", "name": "v2", "deprecated_on": null }
],
"meta": {
"current_page": 1,
"next_page": null,
"prev_page": null,
"total_pages": 1
}
}
List templates
GET /api/v1/document_template_cards
Returns a paginated list of template cards. Template cards are lightweight objects that omit the template body, styles, and test data.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
q[workspace_id] | String (UUID) | Yes | The workspace to list templates from. Also accepts q[workspaceId], q[app_id], or q[appId]. |
q[folders] | String | No | Comma-separated list of folder IDs. Use "none" for templates not in any folder, or "all" (default) for all templates. |
page | Integer | No | Page number for pagination. |
sort | String | No | Attribute to sort by. |
Request
curl -H 'Authorization: Bearer YOUR_SECRET_KEY' \
'https://api.pdfmonkey.io/api/v1/document_template_cards?q[workspace_id]=3161c5e5-9966-4630-9b07-63f718092784'
cards = Pdfmonkey::Template.list_cards(
workspace_id: '3161c5e5-9966-4630-9b07-63f718092784'
)
cards.each { |card| puts card.identifier }
const response = await fetch(
'https://api.pdfmonkey.io/api/v1/document_template_cards?q[workspace_id]=3161c5e5-9966-4630-9b07-63f718092784',
{
headers: {
'Authorization': 'Bearer YOUR_SECRET_KEY',
},
}
);
const data = await response.json();
console.log(data.document_template_cards);
import requests
response = requests.get(
'https://api.pdfmonkey.io/api/v1/document_template_cards',
headers={
'Authorization': 'Bearer YOUR_SECRET_KEY',
},
params={
'q[workspace_id]': '3161c5e5-9966-4630-9b07-63f718092784',
},
)
data = response.json()
print(data['document_template_cards'])
<?php
$ch = curl_init('https://api.pdfmonkey.io/api/v1/document_template_cards?q[workspace_id]=3161c5e5-9966-4630-9b07-63f718092784');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer YOUR_SECRET_KEY',
],
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
print_r($data['document_template_cards']);
Response
{
"document_template_cards": [
{
"id": "8ac0d8f7-dbd3-46dd-b2d3-af036a2776d9",
"app_id": "3161c5e5-9966-4630-9b07-63f718092784",
"auth_token": "ZCsspcSZieyfdCUHYjKW1B9D8mnrz2ck",
"created_at": "2050-01-02T03:04:05.678+02:00",
"edition_mode": "code",
"identifier": "My Awesome Template",
"is_draft": true,
"output_type": "pdf",
"pdf_engine_deprecated_on": null,
"pdf_engine_name": "v4",
"template_folder_id": null,
"template_folder_identifier": null,
"updated_at": "2050-01-02T03:04:05.678+02:00"
}
],
"meta": {
"current_page": 1,
"next_page": null,
"prev_page": null,
"total_pages": 1
}
}
Template cards vs full templates
identifier, edition_mode, and is_draft, but not the template body, styles, or test data. To get the full template content, use Get a template.Get a template
GET /api/v1/document_templates/{id}
Returns the full DocumentTemplate object including body, styles, test data, and settings.
Request
curl -H 'Authorization: Bearer YOUR_SECRET_KEY' \
https://api.pdfmonkey.io/api/v1/document_templates/8ac0d8f7-dbd3-46dd-b2d3-af036a2776d9
template = Pdfmonkey::Template.fetch('8ac0d8f7-dbd3-46dd-b2d3-af036a2776d9')
puts template.identifier
puts template.body
puts template.settings
const response = await fetch(
'https://api.pdfmonkey.io/api/v1/document_templates/8ac0d8f7-dbd3-46dd-b2d3-af036a2776d9',
{
headers: {
'Authorization': 'Bearer YOUR_SECRET_KEY',
},
}
);
const data = await response.json();
console.log(data.document_template);
import requests
response = requests.get(
'https://api.pdfmonkey.io/api/v1/document_templates/8ac0d8f7-dbd3-46dd-b2d3-af036a2776d9',
headers={
'Authorization': 'Bearer YOUR_SECRET_KEY',
},
)
data = response.json()
print(data['document_template'])
<?php
$ch = curl_init('https://api.pdfmonkey.io/api/v1/document_templates/8ac0d8f7-dbd3-46dd-b2d3-af036a2776d9');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer YOUR_SECRET_KEY',
],
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
print_r($data['document_template']);
Response
Returns 200 OK with a document_template object:
{
"document_template": {
"id": "8ac0d8f7-dbd3-46dd-b2d3-af036a2776d9",
"app_id": "3161c5e5-9966-4630-9b07-63f718092784",
"identifier": "My Awesome Template",
"edition_mode": "code",
"output_type": "pdf",
"body": "<p>Hello {{name}}</p>",
"body_draft": "<p>Hello, <strong>{{name}}!</strong></p>",
"scss_style": "p { color: green; }",
"scss_style_draft": "p { color: purple; }",
"sample_data": "{ \"name\": \"Peter Parker\" }",
"sample_data_draft": "{ \"name\": \"Spider-Man\" }",
"settings": { "...": "..." },
"settings_draft": { "...": "..." },
"pdf_engine_id": "5c709522-90db-4aea-b49f-15aeaa7180c7",
"pdf_engine_draft_id": "5c709522-90db-4aea-b49f-15aeaa7180c7",
"template_folder_id": null,
"ttl": 86400,
"created_at": "2050-01-02T03:04:05.678+02:00",
"updated_at": "2050-01-02T03:04:05.678+02:00",
"auth_token": "ZCsspcSZieyfdCUHYjKW1B9D8mnrz2ck",
"checksum": "kfYsx6xzMx3JkYxLd4LW6YeU5rkcuTxQ",
"preview_url": "https://preview.pdfmonkey.io/pdf/..."
}
}
Create a template
POST /api/v1/document_templates
Creates a new template. In most cases you should create templates through the Dashboard, but the API is available for programmatic workflows.
Parameters
All parameters are nested under a document_template key.
| Name | Type | Required | Description |
|---|---|---|---|
app_id | String (UUID) | Yes | The workspace to create the template in. |
identifier | String | Yes | Human-readable name (1–100 characters). |
body | String | No | Published HTML + Liquid content. |
body_draft | String | No | Draft HTML + Liquid content. |
scss_style | String | No | Published CSS/SCSS styles. |
scss_style_draft | String | No | Draft CSS/SCSS styles. |
sample_data | String | No | Published test data (JSON string). |
sample_data_draft | String | No | Draft test data (JSON string). |
settings | Object or String | No | Published printing settings. See Settings. |
settings_draft | Object or String | No | Draft printing settings. |
pdf_engine_id | String (UUID) | No | PDF engine for generation. Defaults to the latest engine. See PDF engines. |
pdf_engine_draft_id | String (UUID) | No | PDF engine for preview. Defaults to the latest engine. |
template_folder_id | String (UUID) | No | Folder to place the template in. |
ttl | Integer | No | Time-to-live in seconds for generated documents. Allowed values depend on your plan. See Retention and Deletion. |
edition_mode | String | No | code (default) or builder. |
output_type | String | No | pdf (default) or image. See Output Format. |
Request
curl https://api.pdfmonkey.io/api/v1/document_templates \
-X POST \
-H 'Authorization: Bearer YOUR_SECRET_KEY' \
-H 'Content-Type: application/json' \
-d '{
"document_template": {
"app_id": "3161c5e5-9966-4630-9b07-63f718092784",
"identifier": "Invoice Template",
"body_draft": "<h1>Invoice #{{number}}</h1><p>Total: {{total}}</p>",
"scss_style_draft": "h1 { color: #333; }",
"sample_data_draft": "{ \"number\": \"INV-001\", \"total\": \"$123.50\" }",
"settings_draft": {
"paper_format": "a4",
"orientation": "portrait",
"margin": { "top": 20, "bottom": 20, "left": 15, "right": 15 }
}
}
}'
template = Pdfmonkey::Template.create(
workspace_id: '3161c5e5-9966-4630-9b07-63f718092784',
identifier: 'Invoice Template',
body: '<h1>Invoice #{{number}}</h1><p>Total: {{total}}</p>',
scss_style: 'h1 { color: #333; }',
sample_data: '{ "number": "INV-001", "total": "$123.50" }',
settings: {
paper_format: 'a4',
orientation: 'portrait',
margin: { top: 20, bottom: 20, left: 15, right: 15 },
},
)
puts template.id
const response = await fetch('https://api.pdfmonkey.io/api/v1/document_templates', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_SECRET_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
document_template: {
app_id: '3161c5e5-9966-4630-9b07-63f718092784',
identifier: 'Invoice Template',
body_draft: '<h1>Invoice #{{number}}</h1><p>Total: {{total}}</p>',
scss_style_draft: 'h1 { color: #333; }',
sample_data_draft: '{ "number": "INV-001", "total": "$123.50" }',
settings_draft: {
paper_format: 'a4',
orientation: 'portrait',
margin: { top: 20, bottom: 20, left: 15, right: 15 },
},
},
}),
});
const data = await response.json();
console.log(data.document_template);
import requests
response = requests.post(
'https://api.pdfmonkey.io/api/v1/document_templates',
headers={
'Authorization': 'Bearer YOUR_SECRET_KEY',
},
json={
'document_template': {
'app_id': '3161c5e5-9966-4630-9b07-63f718092784',
'identifier': 'Invoice Template',
'body_draft': '<h1>Invoice #{{number}}</h1><p>Total: {{total}}</p>',
'scss_style_draft': 'h1 { color: #333; }',
'sample_data_draft': '{ "number": "INV-001", "total": "$123.50" }',
'settings_draft': {
'paper_format': 'a4',
'orientation': 'portrait',
'margin': {'top': 20, 'bottom': 20, 'left': 15, 'right': 15},
},
},
},
)
data = response.json()
print(data['document_template'])
<?php
$ch = curl_init('https://api.pdfmonkey.io/api/v1/document_templates');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer YOUR_SECRET_KEY',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'document_template' => [
'app_id' => '3161c5e5-9966-4630-9b07-63f718092784',
'identifier' => 'Invoice Template',
'body_draft' => '<h1>Invoice #{{number}}</h1><p>Total: {{total}}</p>',
'scss_style_draft' => 'h1 { color: #333; }',
'sample_data_draft' => '{ "number": "INV-001", "total": "$123.50" }',
'settings_draft' => [
'paper_format' => 'a4',
'orientation' => 'portrait',
'margin' => ['top' => 20, 'bottom' => 20, 'left' => 15, 'right' => 15],
],
],
]),
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
print_r($data['document_template']);
Response
Returns 201 Created with the full document_template object.
Validation errors
If required fields are missing or invalid, the API returns 422 Unprocessable Entity:
{
"errors": {
"identifier": ["can't be blank"]
}
}
Update a template
PUT /api/v1/document_templates/{id}
Updates an existing template. Only the fields you include in the request body are changed.
Parameters
All parameters are nested under a document_template key. The same fields as Create a template are accepted.
Request
curl https://api.pdfmonkey.io/api/v1/document_templates/8ac0d8f7-dbd3-46dd-b2d3-af036a2776d9 \
-X PUT \
-H 'Authorization: Bearer YOUR_SECRET_KEY' \
-H 'Content-Type: application/json' \
-d '{
"document_template": {
"body_draft": "<h1>Invoice #{{number}}</h1><p>Due: {{due_date}}</p><p>Total: {{total}}</p>",
"sample_data_draft": "{ \"number\": \"INV-001\", \"due_date\": \"2050-04-01\", \"total\": \"$123.50\" }"
}
}'
template = Pdfmonkey::Template.fetch('8ac0d8f7-dbd3-46dd-b2d3-af036a2776d9')
template.update!(
body: '<h1>Invoice #{{number}}</h1><p>Due: {{due_date}}</p><p>Total: {{total}}</p>',
sample_data: '{ "number": "INV-001", "due_date": "2050-04-01", "total": "$123.50" }',
)
const response = await fetch(
'https://api.pdfmonkey.io/api/v1/document_templates/8ac0d8f7-dbd3-46dd-b2d3-af036a2776d9',
{
method: 'PUT',
headers: {
'Authorization': 'Bearer YOUR_SECRET_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
document_template: {
body_draft: '<h1>Invoice #{{number}}</h1><p>Due: {{due_date}}</p><p>Total: {{total}}</p>',
sample_data_draft: '{ "number": "INV-001", "due_date": "2050-04-01", "total": "$123.50" }',
},
}),
}
);
const data = await response.json();
console.log(data.document_template);
import requests
response = requests.put(
'https://api.pdfmonkey.io/api/v1/document_templates/8ac0d8f7-dbd3-46dd-b2d3-af036a2776d9',
headers={
'Authorization': 'Bearer YOUR_SECRET_KEY',
},
json={
'document_template': {
'body_draft': '<h1>Invoice #{{number}}</h1><p>Due: {{due_date}}</p><p>Total: {{total}}</p>',
'sample_data_draft': '{ "number": "INV-001", "due_date": "2050-04-01", "total": "$123.50" }',
},
},
)
data = response.json()
print(data['document_template'])
<?php
$ch = curl_init('https://api.pdfmonkey.io/api/v1/document_templates/8ac0d8f7-dbd3-46dd-b2d3-af036a2776d9');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer YOUR_SECRET_KEY',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'document_template' => [
'body_draft' => '<h1>Invoice #{{number}}</h1><p>Due: {{due_date}}</p><p>Total: {{total}}</p>',
'sample_data_draft' => '{ "number": "INV-001", "due_date": "2050-04-01", "total": "$123.50" }',
],
]),
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
print_r($data['document_template']);
Response
Returns 200 OK with the updated document_template object.
Delete a template
DELETE /api/v1/document_templates/{id}
Permanently deletes a template.
Request
curl https://api.pdfmonkey.io/api/v1/document_templates/8ac0d8f7-dbd3-46dd-b2d3-af036a2776d9 \
-X DELETE \
-H 'Authorization: Bearer YOUR_SECRET_KEY'
Pdfmonkey::Template.delete('8ac0d8f7-dbd3-46dd-b2d3-af036a2776d9')
const response = await fetch(
'https://api.pdfmonkey.io/api/v1/document_templates/8ac0d8f7-dbd3-46dd-b2d3-af036a2776d9',
{
method: 'DELETE',
headers: {
'Authorization': 'Bearer YOUR_SECRET_KEY',
},
}
);
console.log(response.status); // => 204
import requests
response = requests.delete(
'https://api.pdfmonkey.io/api/v1/document_templates/8ac0d8f7-dbd3-46dd-b2d3-af036a2776d9',
headers={
'Authorization': 'Bearer YOUR_SECRET_KEY',
},
)
print(response.status_code) # => 204
<?php
$ch = curl_init('https://api.pdfmonkey.io/api/v1/document_templates/8ac0d8f7-dbd3-46dd-b2d3-af036a2776d9');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer YOUR_SECRET_KEY',
],
]);
curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE); // => 204
curl_close($ch);
Response
Returns 204 No Content with an empty body.
Related pages
- Authentication – Find your API key and authenticate requests.
- Documents API – Create, list, and manage generated documents.
- Generate Documents with the API – Step-by-step guide with examples in multiple languages.
- Our Engines – Detailed comparison of PDF engine versions.
- Output Format – Choose between PDF and image output.
- Retention and Deletion – Understand TTL values and automatic document cleanup.
- Webhooks – Receive notifications when document generation completes.
Frequently asked questions
- What is a DocumentTemplate in PDFMonkey?
- A DocumentTemplate is the reusable design that defines a document's layout. It contains HTML + Liquid for dynamic content, CSS/SCSS for styling, test data for previewing, and settings for paper size, margins, headers, and footers.
- How do I list all templates with the PDFMonkey API?
- Send a GET request to /api/v1/document_template_cards with a q[workspace_id] parameter. The response returns a paginated list of lightweight template card objects.
- Can I create and update templates via the API?
- Yes. POST to /api/v1/document_templates to create a template and PUT to /api/v1/document_templates/{id} to update one. Most users design templates in the Dashboard and only use the API for document generation.