REST API
Templates API
Full reference for Doclift's Templates API: list, view, create, update, delete, publish and unpublish.
The template object
- id: unique identifier
- title, description: required strings
- category:
custom,fillable_form, orworkflow. Onlycustomtemplates can be created or edited through this API. See Writes only reach custom templates - orientation:
portraitorlandscape - published: whether the template can be used to generate documents
- content: the HTML body (
customtemplates only) - margin_top, margin_bottom, margin_left, margin_right: integers, in millimeters, minimum
5 - variables: see the Variables API
- created_at, updated_at: ISO-8601
Writes only reach custom templates
Every mutating action on this resource (create, update, delete,
publish, unpublish, and every action under /variables) resolves the
template through a scope restricted to category: "custom". create also
hard-codes category to "custom" server-side, whatever value the body
carries: the classic API cannot bring a fillable_form or a workflow
template into existence.
A fillable_form or workflow id answers 404 on write
Calling update, delete, publish, unpublish, or any /variables
endpoint with the id of a fillable_form or workflow template returns the
same 404 {"error": "Template not found"} as an id that does not exist at
all. There is no way to tell the two apart from the response. See
Fillable forms for that family, and note that
workflow templates have their own dedicated authoring surface.
Reads are not restricted the same way: GET /api/v1/templates and
GET /api/v1/templates/:id list and show templates of all three categories
once published.
List templates
curl https://app.doclift.io/api/v1/templates \
--header "X-Api-Key: <your-api-key>"
[
{
"id": 100011,
"title": "Invoice",
"description": "Monthly invoice template"
},
{
"id": 100012,
"title": "Subscription form",
"description": "Uploaded PDF form"
}
]
Returns your organization's published, non-archived templates (every
member's, not only the calling key's own) of all three categories, in a
bare array, id/title/description only. content is never present in
this shape.
| Parameter | Where | Notes |
|---|---|---|
| page | query | optional, default 1 |
Paginated at 30 per page. See Pagination.
A page past the last one answers 200 with an empty array.
| Status | Body | When |
|---|---|---|
| 200 | array | always, including an empty account or an out-of-range page |
| 403 | {"error": "..."} | missing, unknown, or disabled API key |
Show a template
curl https://app.doclift.io/api/v1/templates/100011 \
--header "X-Api-Key: <your-api-key>"
{
"id": 100011,
"title": "Invoice",
"description": "Monthly invoice template",
"content": "<h1>Invoice</h1><p><variable>client_name</variable></p>",
"created_at": "2024-01-15T10:30:00+01:00",
"updated_at": "2024-01-15T10:30:00+01:00",
"variables": [
{
"title": "client_name",
"description": "Name of the client",
"field_type": "text",
"allowed_values": []
}
]
}
variables here carries only title, description, field_type, and
allowed_values: no id, no seed_value. Works identically for
fillable_form and workflow templates once published: the field shape is
the same, content included (empty for a fillable_form, since its layout
comes from the uploaded PDF).
| Status | Body | When |
|---|---|---|
| 200 | template | published, not archived, in your organization |
| 404 | {"error": "Template not found"} | unpublished, archived, or another organization's template |
| 403 | {"error": "..."} | missing, unknown, or disabled API key |
Create a template
Always creates a custom template. Any category sent in the body is
ignored.
curl https://app.doclift.io/api/v1/templates \
--request POST \
--header "X-Api-Key: <your-api-key>" \
--header "Content-Type: application/json" \
--data '{
"template": {
"title": "Invoice",
"description": "A template for invoices",
"orientation": "portrait",
"content": "<h1>Invoice</h1><p><variable>client_name</variable></p>",
"margin_top": 10,
"margin_bottom": 10,
"margin_left": 15,
"margin_right": 15,
"variables_attributes": [
{
"title": "client_name",
"description": "Name of the client",
"field_type": "text",
"seed_value": "John Doe"
}
]
}
}'
{
"id": 100013,
"title": "Invoice",
"description": "A template for invoices",
"content": "<h1>Invoice</h1><p><variable>client_name</variable></p>",
"category": "custom",
"orientation": "portrait",
"published": false,
"margin_top": 10,
"margin_bottom": 10,
"margin_left": 15,
"margin_right": 15,
"created_at": "2024-01-15T10:30:00+01:00",
"updated_at": "2024-01-15T10:30:00+01:00",
"variables": [
{
"id": 200003,
"title": "client_name",
"description": "Name of the client",
"seed_value": "John Doe",
"field_type": "text",
"allowed_values": []
}
]
}
| Field | Type | Required | Notes |
|---|---|---|---|
| title | string | yes | |
| description | string | yes | |
| content | string | no | HTML body |
| orientation | string | no | portrait or landscape, default portrait |
| margin_top | integer | no | >= 5, default 10 |
| variables_attributes | array | no | see Variables API |
This is the one response that exposes seed_value together with id
The create/update/publish/unpublish responses render every variable with
id, title, description, seed_value, field_type, and
allowed_values. No other endpoint returns id and seed_value on the
same variable object.
| Status | Body | When |
|---|---|---|
| 201 | template, detail view | success |
| 422 | {"errors": ["..."]} | validation failure (e.g. blank title) |
| 403 | {"error": "..."} | missing, unknown, or disabled API key |
Update a template
category is not accepted here. It cannot be changed after creation, not
even between two writes on the same custom template.
curl https://app.doclift.io/api/v1/templates/100013 \
--request PATCH \
--header "X-Api-Key: <your-api-key>" \
--header "Content-Type: application/json" \
--data '{
"template": {
"title": "Updated invoice",
"variables_attributes": [
{ "id": 200003, "_destroy": true },
{ "title": "invoice_number", "field_type": "text" }
]
}
}'
{
"id": 100013,
"title": "Updated invoice",
"description": "A template for invoices",
"content": "<h1>Invoice</h1><p><variable>client_name</variable></p>",
"category": "custom",
"orientation": "portrait",
"published": false,
"margin_top": 10,
"margin_bottom": 10,
"margin_left": 15,
"margin_right": 15,
"created_at": "2024-01-15T10:30:00+01:00",
"updated_at": "2024-01-15T11:02:00+01:00",
"variables": [
{
"id": 200004,
"title": "invoice_number",
"description": null,
"seed_value": null,
"field_type": "text",
"allowed_values": []
}
]
}
Same body fields as create (minus category). Inside variables_attributes:
a hash with no id creates a variable, {"id": ..., "_destroy": true}
deletes the matching one, any other hash with an id updates it.
| Status | Body | When |
|---|---|---|
| 200 | template, detail view | success |
| 422 | {"errors": ["..."]} | validation failure |
| 404 | {"error": "Template not found"} | not custom, archived, or another organization's |
| 403 | {"error": "..."} | missing, unknown, or disabled API key |
Delete a template
curl https://app.doclift.io/api/v1/templates/100013 \
--request DELETE \
--header "X-Api-Key: <your-api-key>"
204 No Content. This archives the template rather than erasing it: it stops
appearing in the list and can no longer be generated from. There is no hard
delete through the API.
| Status | Body | When |
|---|---|---|
| 204 | none | success |
| 404 | {"error": "Template not found"} | not custom, already archived, or another organization's |
| 403 | {"error": "..."} | missing, unknown, or disabled API key |
Publish / unpublish a template
curl https://app.doclift.io/api/v1/templates/100013/publish \
--request PUT \
--header "X-Api-Key: <your-api-key>"
Both return 200 OK with the same detail view as create/update, reflecting
the new published value. Both are idempotent: publishing an
already-published template (or unpublishing an already-unpublished one)
still answers 200, never an error.
| Status | Body | When |
|---|---|---|
| 200 | template, detail view | success, including a no-op call |
| 404 | {"error": "Template not found"} | not custom, archived, or another organization's |
| 403 | {"error": "..."} | missing, unknown, or disabled API key |