Documentation
API reference
Create template IDs, publish immutable versions, and render PDFs.
Set a base URL and admin token for the examples:
base=http://127.0.0.1:8080
admin_token='replace-with-your-admin-token'
Create a template ID
curl --fail-with-body -X POST "$base/v1/admin/templates" \
-H 'content-type: application/json' \
-H "x-admin-token: $admin_token" \
--data '{"id":"invoice"}'
IDs and versions start with an alphanumeric character. They can contain letters, numbers, periods, underscores, and hyphens.
Publish a version
A publish request carries everything the version needs to render, so a render never depends on host files.
| Field | Required | Contents |
|---|---|---|
schema |
yes | JSON Schema that every render request’s data is checked against |
source |
yes | Base64 Typst files by name. Must contain main.typ |
fonts |
yes | Base64 font files by name. At least one must be decodable |
static_assets |
no | Base64 files shipped with the version, read as ../static/name |
request_assets |
no | Allowlist of asset names a render request may supply |
Inside Typst, request data is sys.inputs.at("data") and request asset paths are
sys.inputs.at("assets"). This example publishes the invoice template shipped in the
repository, which uses both.
main=$(base64 < templates/invoice-v1.typ | tr -d '\n')
font=$(base64 < assets/fonts/NotoSans-Regular.ttf | tr -d '\n')
jq -n --arg main "$main" --arg font "$font" '
{
schema: {
type: "object",
additionalProperties: false,
required: ["number", "customer", "amount"],
properties: {
number: {type: "string"},
customer: {type: "string"},
amount: {type: "string"}
}
},
source: {"main.typ": $main},
fonts: {"NotoSans-Regular.ttf": $font},
request_assets: ["logo.png"]
}
' > invoice-v1.json
curl --fail-with-body -X POST "$base/v1/admin/templates/invoice/versions/v1" \
-H 'content-type: application/json' \
-H "x-admin-token: $admin_token" \
--data-binary @invoice-v1.json
Published versions cannot change or be deleted. Publishing over an existing version
returns 409; publish a new version name instead.
Render a PDF
Request assets are sent base64 under the names declared in request_assets. Any other
name is rejected with 400, so a caller cannot introduce arbitrary Typst file names.
jq -n --arg logo "$(base64 < assets/testdata/logo.png | tr -d '\n')" '
{
data: {number: "INV-001", customer: "Ada Lovelace", amount: "1,240.00"},
assets: {"logo.png": $logo}
}
' > invoice-render.json
curl --fail-with-body -X POST "$base/v1/templates/invoice/versions/v1/render" \
-H 'content-type: application/json' \
--data-binary @invoice-render.json \
--output invoice.pdf
The default response is application/pdf. assets may be omitted entirely for a
template that declares no request assets. To persist a result instead of returning
bytes, enable ALLOW_PERSISTED_RESULTS and send {"output":{"persist":true}}; the
response is then a JSON storage key and SHA-256 checksum.
Status codes
| Code | Meaning |
|---|---|
400 |
Invalid input or undeclared request asset |
401 |
Missing or invalid admin token |
404 |
Unknown published template version |
409 |
Existing version or absent template ID |
413 |
Request or object exceeds a limit |
422 |
JSON Schema validation or Typst compilation failed |
502 |
PostgreSQL or object storage is unavailable or invalid |
504 |
Rendering exceeded its deadline |