Appearance
Template tags
A tag is a movable name for a published version. Render what it names by adding it as an @ suffix — report@production. Moving the tag changes what renders without changing the request. See Versions & Tags for how versions and tags fit together.
A tag is 1–64 characters of lowercase letters, digits and single hyphens. It cannot be all digits, because that would be a second spelling of @<number>, and live and latest are reserved.
Point a tag at a version
PUT
/v2/templates/{templateId}/tags/{tag}
Names a published version, so it can be identified by name rather than by number. Setting a tag the template already holds moves it to the version in the request. Sending the same version again succeeds unchanged.
Authorizations
BearerAuth
Your Papermill API key, sent as Authorization: Bearer <key>.
Type
HTTP (bearer)
or
ApiKeyHeader
Your Papermill API key. Equivalent to the bearer form.
Type
API Key (header: x-api-key)
Parameters
Path Parameters
templateId*
Type
Requiredstring
Min Length
1Max Length
128Pattern
"^(?!__.*__$)[A-Za-z0-9_-]+$"tag*
Type
Requiredstring
Min Length
1Max Length
64Request Body
application/json
JSON "version": 0
{
}
Responses
Tag set
application/json
JSON "tag": "string", "version": 0
{
}
List a template's tags
GET
/v2/templates/{templateId}/tags
Every tag the template holds and the version each one names, ordered by name. has_more is true when the template holds tags beyond the ones returned; send the last tag back as start_after to continue.
Authorizations
BearerAuth
Your Papermill API key, sent as Authorization: Bearer <key>.
Type
HTTP (bearer)
or
ApiKeyHeader
Your Papermill API key. Equivalent to the bearer form.
Type
API Key (header: x-api-key)
Parameters
Path Parameters
templateId*
Type
Requiredstring
Min Length
1Max Length
128Pattern
"^(?!__.*__$)[A-Za-z0-9_-]+$"Query Parameters
start_after
Type
string
Min Length
1Max Length
64Responses
Tags held
application/json
JSON "tags": [ { "tag": "string", "version": 0, "updated_at": "string", "updated_by": { "id": "string", "name": "string", "email": "string" } } ], "has_more": true
{
}
Read one tag
GET
/v2/templates/{templateId}/tags/{tag}
The version a tag names, and who last moved it there.
Authorizations
BearerAuth
Your Papermill API key, sent as Authorization: Bearer <key>.
Type
HTTP (bearer)
or
ApiKeyHeader
Your Papermill API key. Equivalent to the bearer form.
Type
API Key (header: x-api-key)
Parameters
Path Parameters
templateId*
Type
Requiredstring
Min Length
1Max Length
128Pattern
"^(?!__.*__$)[A-Za-z0-9_-]+$"tag*
Type
Requiredstring
Min Length
1Max Length
64Responses
The tag
application/json
JSON "tag": "string", "version": 0, "updated_at": "string", "updated_by": { "id": "string", "name": "string", "email": "string" }
{
}
List a tag's history
GET
/v2/templates/{templateId}/tags/{tag}/history
Every recorded change to a tag, newest first: which version it was pointed at, which it named before, when, and by whom. A tag is a pointer that gets overwritten, so this is where earlier moves are kept. History survives removing the tag. The most recent changes are the ones returned, and has_more is true when the tag has been moved more times than fit — there is no way to page further back, so treat it as a depth limit rather than a cursor.
Authorizations
BearerAuth
Your Papermill API key, sent as Authorization: Bearer <key>.
Type
HTTP (bearer)
or
ApiKeyHeader
Your Papermill API key. Equivalent to the bearer form.
Type
API Key (header: x-api-key)
Parameters
Path Parameters
templateId*
Type
Requiredstring
Min Length
1Max Length
128Pattern
"^(?!__.*__$)[A-Za-z0-9_-]+$"tag*
Type
Requiredstring
Min Length
1Max Length
64Responses
Recorded changes
application/json
JSON "events": [ { "action": "string", "version": 0, "previous_version": 0, "at": "string", "by": { "id": "string", "name": "string", "email": "string" } } ], "has_more": true
{
}
Remove a tag
DELETE
/v2/templates/{templateId}/tags/{tag}
Removes a tag, leaving the version it named untouched — versions are never deleted, so anything rendering by that version number keeps working. Anything rendering by the tag stops: <template>@<tag> names nothing once the tag is gone. removed is false when the template was not holding the tag.
Authorizations
BearerAuth
Your Papermill API key, sent as Authorization: Bearer <key>.
Type
HTTP (bearer)
or
ApiKeyHeader
Your Papermill API key. Equivalent to the bearer form.
Type
API Key (header: x-api-key)
Parameters
Path Parameters
templateId*
Type
Requiredstring
Min Length
1Max Length
128Pattern
"^(?!__.*__$)[A-Za-z0-9_-]+$"tag*
Type
Requiredstring
Min Length
1Max Length
64Responses
Tag removed
application/json
JSON "tag": "string", "removed": true
{
}
Example
Promote a version to production, then render through the tag. Every caller sending @production picks up the new version with no change at their end.
shell
set -e
curl -fsS -X PUT "https://api.papermill.io/v2/templates/$TEMPLATE_ID/tags/production" \
-H "Authorization: Bearer $PAPERMILL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"version": 3}'
curl -X POST "https://api.papermill.io/v2/pdf?template_id=$TEMPLATE_ID@production" \
-H "Authorization: Bearer $PAPERMILL_API_KEY" \
-H "Content-Type: application/json" \
-o report.pdf \
-d '{"customer": "Acme Co"}'python
import os
import requests
key = os.environ["PAPERMILL_API_KEY"]
template_id = os.environ["TEMPLATE_ID"]
auth = {"Authorization": f"Bearer {key}"}
requests.put(
f"https://api.papermill.io/v2/templates/{template_id}/tags/production",
headers=auth,
json={"version": 3},
).raise_for_status()
pdf = requests.post(
"https://api.papermill.io/v2/pdf",
params={"template_id": f"{template_id}@production"},
headers={**auth, "Content-Type": "application/json"},
json={"customer": "Acme Co"},
)
pdf.raise_for_status()
with open("report.pdf", "wb") as f:
f.write(pdf.content)javascript
import fs from 'node:fs/promises'
const key = process.env.PAPERMILL_API_KEY
const templateId = process.env.TEMPLATE_ID
const auth = { Authorization: `Bearer ${key}` }
const tagged = await fetch(`https://api.papermill.io/v2/templates/${templateId}/tags/production`, {
method: 'PUT',
headers: { ...auth, 'Content-Type': 'application/json' },
body: JSON.stringify({ version: 3 }),
})
if (!tagged.ok) throw new Error(`${tagged.status} ${tagged.statusText}`)
const pdf = await fetch(`https://api.papermill.io/v2/pdf?template_id=${templateId}@production`, {
method: 'POST',
headers: { ...auth, 'Content-Type': 'application/json' },
body: JSON.stringify({ customer: 'Acme Co' }),
})
if (!pdf.ok) throw new Error(`${pdf.status} ${pdf.statusText}`)
await fs.writeFile('report.pdf', Buffer.from(await pdf.arrayBuffer()))Rolling back is the same call with the previous version number.
Removing a tag
Deleting a tag leaves the version it named untouched, so anything rendering by that version number keeps working. Anything rendering by the tag stops: report@production names nothing once the tag is gone. Move a tag rather than removing it unless you mean to retire the name.
The history survives removal, so GET …/tags/{tag}/history still answers where the tag pointed and who moved it.