Templates / Certificate
Certificate
Landscape A4 with a fine border, recipient in display size, two signature lines. For courses, awards and completed reviews.
1 page, A4 landscape. Rendered in 14 ms. 7 inputs, all optional.
Inputs
Everything variable comes in through sys.inputs. Missing keys fall back to sensible defaults, so an agent can send only what it knows.
| Key | Sample value |
|---|---|
course | Typst for Agents: rendering documents with Foliant |
date | 28 September 2026 |
issuer | Meridian Academy |
logo | logo.png |
recipient | Ada Lovelace |
serial | CERT-2026-0193 |
signer | Martin Karrer, Instructor |
Render it
After copying the template into your account:
curl -X POST https://api.foliant.dev/v1/render \
-H "Authorization: Bearer $FOLIANT_API_KEY" \
-H "Content-Type: application/json" \
-o certificate.pdf -d @- <<'JSON'
{ "template": "certificate.typ",
"inputs": {
"course": "Typst for Agents: rendering documents with Foliant",
"date": "28 September 2026",
"issuer": "Meridian Academy",
"logo": "logo.png",
"recipient": "Ada Lovelace",
"serial": "CERT-2026-0193",
"signer": "Martin Karrer, Instructor"
} }
JSON
Through MCP, render_document with template: "certificate.typ" and the same inputs; get_template or fetch lists the keys.
Source
template.typ, 26 lines
#let input(k, default: "") = sys.inputs.at(k, default: default)
#let logo = input("logo")
#set page(paper: "a4", flipped: true, margin: 18mm,
background: place(center + horizon, rect(width: 100% - 24mm, height: 100% - 24mm, stroke: 1.2pt + rgb("b8341c"), inset: 0pt)[#place(center + horizon, rect(width: 100% - 4mm, height: 100% - 4mm, stroke: 0.4pt + rgb("b8341c")))]))
#set text(font: "Libertinus Serif", fill: rgb("1a1917"))
#align(center)[
#v(6mm)
#if logo != "" { image(logo, width: 40mm) } else { text(size: 14pt, weight: 600)[#input("issuer")] }
#v(8mm)
#text(size: 12pt, tracking: 4pt, fill: luma(110))[CERTIFICATE OF COMPLETION]
#v(6mm)
#text(size: 12pt, fill: luma(90))[This certifies that]
#v(3mm)
#text(size: 36pt, weight: 600)[#input("recipient")]
#v(4mm)
#text(size: 12pt, fill: luma(90))[has successfully completed]
#v(2mm)
#text(size: 18pt, style: "italic")[#input("course")]
#v(12mm)
#grid(columns: (1fr, 1fr), gutter: 40mm,
[#line(length: 100%, stroke: 0.5pt) #v(2pt) #text(size: 9.5pt)[#input("signer")]],
[#line(length: 100%, stroke: 0.5pt) #v(2pt) #text(size: 9.5pt)[#input("date")]])
#v(1fr)
#text(size: 8pt, fill: luma(150))[#input("issuer") · #input("serial")]
]