Skip to content

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/versions
GET https://api.galleyrender.com/v1/templates/:name/versions
Authorization: Bearer glr_sk_…

Publishes the next version, latest_version + 1. You cannot choose the number and you cannot skip one.

ParameterInDescription
namepathThe template name. A version suffix is accepted and ignored — the new version always follows the current latest.
FieldTypeRequiredDescription
sourcestringyesThe new HTML + Liquid source. Not a patch: send the whole document.
enginestringnochromium or satori. Inherited from the previous version when omitted.
schemaobjectnoJSON Schema for data. Inherited when omitted. Send {} to publish a version that validates nothing.
optionsobjectnoDefault render options. Inherited when omitted. Send {} to clear them.
expected_pagesintegernoPDF page estimate for the pre-flight quota check. Inherited when omitted. See create.
exampleunknownnoExample payload for this version. Inherited when omitted. Send null to clear it.
descriptionstringnoUpdates the template-level description. Omitted leaves the existing one alone.
messagestringnoA changelog line for this version.

201 Created, with the template object carrying the new version. Same fields as POST /v1/templates.

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"
                }
              }
            }
          }
        }
      }
    }
  }'
201 Created (source abbreviated)
{
"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"
}
  • delivery-note (unpinned) now resolves to version 2. Anything rendering the bare name picks up the change on its next call.
  • delivery-note@1 is 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.

Lists the versions of a template, newest first.

200 OK, { "object": "list", "data": [...] }. These are version summaries — no schema, no source. Fetch GET /v1/templates/name@N for those.

FieldTypeDescription
objectstringAlways template_version.
idstringtv_….
templatestringThe template name.
refstringname@version.
versionnumber
enginestringchromium or satori.
expected_pagesintegerThe version’s declared PDF page estimate.
checksumstringSHA-256 over engine, source, schema and options.
messagestring | nullThe changelog line recorded at publish time.
created_atstringISO 8601.
List versions
curl -sS https://api.galleyrender.com/v1/templates/delivery-note/versions \
-H "Authorization: Bearer $GALLEY_API_KEY"
200 OK
{
"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.

TypeStatusWhen
not_found404No such template on this account, or it has been deleted.
invalid_request400Body is not JSON; source missing or empty; source is not valid Liquid; engine unknown; schema is not a valid JSON Schema.
authentication_error401Missing, unknown or revoked key.