POST /v1/templates/:name/versions
Versions are immutable. Publishing never edits what is already there: invoice@2 keeps rendering
exactly as it did, and anything pinned to it is unaffected.
POST https://api.galleyrender.com/v1/templates/:name/versionsGET https://api.galleyrender.com/v1/templates/:name/versionsAuthorization: Bearer glr_sk_…POST /v1/templates/:name/versions
Section titled “POST /v1/templates/:name/versions”Publishes the next version, latest_version + 1. You cannot choose the number and you cannot
skip one.
Request
Section titled “Request”| Parameter | In | Description |
|---|---|---|
name | path | The template name. A version suffix is accepted and ignored — the new version always follows the current latest. |
| Field | Type | Required | Description |
|---|---|---|---|
source | string | yes | The new HTML + Liquid source. Not a patch: send the whole document. |
engine | string | no | chromium or satori. Inherited from the previous version when omitted. |
schema | object | no | JSON Schema for data. Inherited when omitted. Send {} to publish a version that validates nothing. |
options | object | no | Default render options. Inherited when omitted. Send {} to clear them. |
expected_pages | integer | no | PDF page estimate for the pre-flight quota check. Inherited when omitted. See create. |
example | unknown | no | Example payload for this version. Inherited when omitted. Send null to clear it. |
description | string | no | Updates the template-level description. Omitted leaves the existing one alone. |
message | string | no | A changelog line for this version. |
Response
Section titled “Response”201 Created, with the template object carrying the new version. Same fields as
POST /v1/templates.
Example
Section titled “Example” Publish version 2 shell
curl -sS https://api.galleyrender.com/v1/templates/delivery-note/versions \
-H "Authorization: Bearer $GALLEY_API_KEY" \
-H 'content-type: application/json' \
-d '{
"message": "show the shipped date in the header",
"engine": "chromium",
"options": { "page_size": "A4", "margin": "18mm" },
"source": "<html><head><style>@page{size:A4;margin:18mm}body{font:14px/1.5 system-ui}</style></head><body><h1>Delivery note {{ reference }} — {{ shipped_on | date_medium }}</h1><p>{{ customer.name }}</p></body></html>",
"schema": {
"type": "object",
"required": ["reference", "customer", "shipped_on"],
"properties": {
"reference": { "type": "string", "examples": ["DN-8841"] },
"shipped_on": { "type": "string", "format": "date", "examples": ["2026-09-16"] },
"customer": { "type": "object", "required": ["name"], "properties": { "name": { "type": "string" } } }
}
}
}' Publish version 2 javascript
// Node 22+. No dependencies — `fetch` is built in.
const res = await fetch("https://api.galleyrender.com/v1/templates/delivery-note/versions", {
method: "POST",
headers: {
authorization: `Bearer ${process.env.GALLEY_API_KEY}`,
"content-type": "application/json",
},
body: JSON.stringify({
message: "show the shipped date in the header",
engine: "chromium",
options: {
page_size: "A4",
margin: "18mm"
},
source: "<html><head><style>@page{size:A4;margin:18mm}body{font:14px/1.5 system-ui}</style></head><body><h1>Delivery note {{ reference }} — {{ shipped_on | date_medium }}</h1><p>{{ customer.name }}</p></body></html>",
schema: {
type: "object",
required: [
"reference",
"customer",
"shipped_on"
],
properties: {
reference: {
type: "string",
examples: [
"DN-8841"
]
},
shipped_on: {
type: "string",
format: "date",
examples: [
"2026-09-16"
]
},
customer: {
type: "object",
required: [
"name"
],
properties: {
name: {
type: "string"
}
}
}
}
}
}),
});
const template = await res.json();
if (!res.ok) throw new Error(template.error.message);
console.log(template.ref); Publish version 2 python
# Python 3.9+. Standard library only.
import json, os, urllib.request
body = json.dumps({
"message": "show the shipped date in the header",
"engine": "chromium",
"options": {
"page_size": "A4",
"margin": "18mm"
},
"source": "<html><head><style>@page{size:A4;margin:18mm}body{font:14px/1.5 system-ui}</style></head><body><h1>Delivery note {{ reference }} — {{ shipped_on | date_medium }}</h1><p>{{ customer.name }}</p></body></html>",
"schema": {
"type": "object",
"required": [
"reference",
"customer",
"shipped_on"
],
"properties": {
"reference": {
"type": "string",
"examples": [
"DN-8841"
]
},
"shipped_on": {
"type": "string",
"format": "date",
"examples": [
"2026-09-16"
]
},
"customer": {
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "string"
}
}
}
}
}
}).encode()
req = urllib.request.Request(
"https://api.galleyrender.com/v1/templates/delivery-note/versions",
data=body,
headers={
"Authorization": f"Bearer {os.environ['GALLEY_API_KEY']}",
"Content-Type": "application/json",
},
)
template = json.load(urllib.request.urlopen(req))
print(template["ref"]) Publish version 2 — no key shell + json
# No API key. The first call mints a 50-render trial.
curl -sS https://mcp.galleyrender.com/mcp \
-H 'content-type: application/json' \
-H 'accept: application/json, text/event-stream' \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "update_template",
"arguments": {
"template": "delivery-note",
"message": "show the shipped date in the header",
"engine": "chromium",
"options": {
"page_size": "A4",
"margin": "18mm"
},
"source": "<html><head><style>@page{size:A4;margin:18mm}body{font:14px/1.5 system-ui}</style></head><body><h1>Delivery note {{ reference }} — {{ shipped_on | date_medium }}</h1><p>{{ customer.name }}</p></body></html>",
"schema": {
"type": "object",
"required": [
"reference",
"customer",
"shipped_on"
],
"properties": {
"reference": {
"type": "string",
"examples": [
"DN-8841"
]
},
"shipped_on": {
"type": "string",
"format": "date",
"examples": [
"2026-09-16"
]
},
"customer": {
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "string"
}
}
}
}
}
}
}
}' { "object": "template", "id": "tpl_6q1wv8k4m2nt", "name": "delivery-note", "description": "One-page delivery note.", "latest_version": 2, "created_at": "2026-09-16T15:02:41.119Z", "updated_at": "2026-09-16T15:02:41.240Z", "version": 2, "ref": "delivery-note@2", "engine": "chromium", "schema": { "type": "object", "required": ["reference", "customer", "shipped_on"] }, "options": { "page_size": "A4", "margin": "18mm" }, "example": null, "source": "<html><head><style>@page{size:A4;margin:18mm}…", "checksum": "4a70dd18c9b3e026…", "message": "show the shipped date in the header", "version_created_at": "2026-09-16T15:19:57.884Z"}What publishing changes
Section titled “What publishing changes”delivery-note(unpinned) now resolves to version 2. Anything rendering the bare name picks up the change on its next call.delivery-note@1is untouched and keeps rendering.- The new version has a new
checksum, so it starts with a cold cache. Renders cached against version 1 stay valid and stay free. - Existing stored files and their signed URLs are unaffected.
GET /v1/templates/:name/versions
Section titled “GET /v1/templates/:name/versions”Lists the versions of a template, newest first.
Response
Section titled “Response”200 OK, { "object": "list", "data": [...] }. These are version summaries — no schema, no
source. Fetch GET /v1/templates/name@N for those.
| Field | Type | Description |
|---|---|---|
object | string | Always template_version. |
id | string | tv_…. |
template | string | The template name. |
ref | string | name@version. |
version | number | |
engine | string | chromium or satori. |
expected_pages | integer | The version’s declared PDF page estimate. |
checksum | string | SHA-256 over engine, source, schema and options. |
message | string | null | The changelog line recorded at publish time. |
created_at | string | ISO 8601. |
curl -sS https://api.galleyrender.com/v1/templates/delivery-note/versions \ -H "Authorization: Bearer $GALLEY_API_KEY"{ "object": "list", "data": [ { "object": "template_version", "id": "tv_2m8kq4w1v7nt", "template": "delivery-note", "ref": "delivery-note@2", "version": 2, "engine": "chromium", "checksum": "4a70dd18c9b3e026…", "message": "show the shipped date in the header", "created_at": "2026-09-16T15:19:57.884Z" }, { "object": "template_version", "id": "tv_9w4mv2k8t1qp", "template": "delivery-note", "ref": "delivery-note@1", "version": 1, "engine": "chromium", "checksum": "9c41e7b0a2d8f513…", "message": "first cut", "created_at": "2026-09-16T15:02:41.240Z" } ]}There is no rollback endpoint. To go back to version 1, publish its source again as version 3 —
or simply pin delivery-note@1 where you render.
Errors
Section titled “Errors”| Type | Status | When |
|---|---|---|
not_found | 404 | No such template on this account, or it has been deleted. |
invalid_request | 400 | Body is not JSON; source missing or empty; source is not valid Liquid; engine unknown; schema is not a valid JSON Schema. |
authentication_error | 401 | Missing, unknown or revoked key. |
See also
Section titled “See also”- POST /v1/templates
- GET /v1/templates
- Caching and signed URLs — why a new version starts cold