Skip to content

Template slugs

A slug is a name you give a template — quarterly-report rather than the id it was created with. It works anywhere you render or read a template by template_id, including in front of an @ suffix: quarterly-report@3 and quarterly-report@production both render what the id form would. The one place it is not accepted is the template_id below, which assigns a name and so needs the id itself.

A slug is unique within your workspace, and a template holds at most one. Assigning a second releases the first, so a template's name can be changed without ever naming two things at once.

A slug is 3–64 characters of lowercase letters, digits and single hyphens. It cannot begin with papermill-, which is reserved for public templates, and it cannot have the shape of a template id — twenty lowercase letters and digits, which is what an id looks like. The last two rules are Papermill's own, and breaking one is rejected with message Invalid slug '<slug>': <the rule it broke> carrying ERR_SLUG_INVALID. A name that breaks the length or character rules is rejected as a malformed request, naming the field and the rule but carrying no code.

Assign a slug to a template

POST
/v2/slugs

Gives a template a human-readable name that can be used in place of its id. A slug is unique within your workspace, and a template holds at most one: assigning a second one releases the first. Re-assigning a slug the template already holds 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)

Request Body

application/json
JSON
{
  
"slug": "string",
  
"template_id": "string"
}

Responses

Slug assigned

application/json
JSON
{
  
"slug": "string",
  
"template_id": "string"
}

Playground

Authorization
Body

Samples

List assigned slugs

GET
/v2/slugs

Every slug assigned in your workspace, with the template each one names. A workspace holds at most one slug per template, so the listing is capped at 1000 and there is no cursor: a workspace with more templates than that would need one added before the listing could be read as complete.

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)

Responses

Assigned slugs

application/json
JSON
{
  
"slugs": [
  
  
{
  
  
  
"slug": "string",
  
  
  
"template_id": "string"
  
  
}
  
]
}

Playground

Authorization

Samples

Check whether a slug is available

GET
/v2/slugs/{slug}

Reports whether a slug is free to assign in your workspace, and which template it names when it is already taken. A slug that breaks the naming rules is reported as invalid rather than as available.

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

slug*
Type
string
Required
Min Length
3
Max Length
64
Pattern
"^[a-z0-9]+(?:-[a-z0-9]+)*$"

Responses

Slug status

application/json
JSON
{
  
"slug": "string",
  
"available": true,
  
"template_id": "string"
}

Playground

Authorization
Variables
Key
Value

Samples

Release a slug

DELETE
/v2/slugs/{slug}

Releases a slug so it can be assigned again. A slug can be released even when the template it named is no longer available.

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

slug*
Type
string
Required
Min Length
3
Max Length
64
Pattern
"^[a-z0-9]+(?:-[a-z0-9]+)*$"

Responses

Slug released

Playground

Authorization
Variables
Key
Value

Samples

Example

Name a template, then render through the name. Nothing else about the request changes — the slug simply takes the place of the id.

shell
set -e
curl -fsS -X POST "https://api.papermill.io/v2/slugs" \
  -H "Authorization: Bearer $PAPERMILL_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"slug\": \"quarterly-report\", \"template_id\": \"$TEMPLATE_ID\"}"

curl -X POST "https://api.papermill.io/v2/pdf?template_id=quarterly-report" \
  -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.post(
    "https://api.papermill.io/v2/slugs",
    headers=auth,
    json={"slug": "quarterly-report", "template_id": template_id},
).raise_for_status()

pdf = requests.post(
    "https://api.papermill.io/v2/pdf",
    params={"template_id": "quarterly-report"},
    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 assigned = await fetch('https://api.papermill.io/v2/slugs', {
  method: 'POST',
  headers: { ...auth, 'Content-Type': 'application/json' },
  body: JSON.stringify({ slug: 'quarterly-report', template_id: templateId }),
})
if (!assigned.ok) throw new Error(`${assigned.status} ${assigned.statusText}`)

const pdf = await fetch('https://api.papermill.io/v2/pdf?template_id=quarterly-report', {
  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()))

Assigning a slug the template already holds succeeds and changes nothing, so this is safe to repeat from a setup script. When another template holds it, Papermill rejects the request with message Slug '<slug>' is already in use — names are taken, never stolen, so pointing one at a different template means releasing it first.

Checking a name before you take it

GET …/slugs/{slug} answers whether a name is free, and names the template holding it when it is not. A name that breaks the rules is reported as invalid rather than as available, so a setup script can tell "nobody has this yet" apart from "nobody can ever have this".

Releasing a slug

Releasing frees the name for reuse and leaves the template untouched — it keeps rendering under its id, and under any version or tag. Anything rendering by the slug stops, so release a name only when you mean to retire it. When the name is not assigned, Papermill rejects the request with message Slug '<slug>' is not assigned carrying ERR_SLUG_NOT_ASSIGNED.

A slug can be released even when the template it named is gone, so a name is never stranded by the template outliving its usefulness.