Quickstart
Create an API key, render a PDF from a line of HTML, then render a template by its name.
Before you start
Section titled “Before you start”You need two things:
- A Studio sign-in as a workspace owner or admin. Studio is on the hosted service or on an installation your company runs. Only owners and admins can create API keys; if you are a member, ask one for a key with the permissions in step 1.
- curl or a client library. The curl examples are for bash or zsh. To use the .NET, TypeScript and JavaScript or Python client instead, install it as its page shows and pick its tab.
Save the address you open Studio at in PDF_URL. The API answers at the same address:
export PDF_URL='https://pdf.example.com'1. Create an API key
Section titled “1. Create an API key”- Sign in to Studio and open your workspace.
- Go to Manage → API keys and select Create API key.
- Enter a Key name, such as
Quickstart. Under Permissions, keeprender:createandrender:readticked and also ticktemplate:read. - Select Create API key and copy the secret. It is shown only once.
Keep the secret in an environment variable for the next steps:
export API_KEY='paste-the-secret-here'What each permission allows is listed in API keys, scopes and roles.
2. Render some HTML
Section titled “2. Render some HTML”Send a line of HTML with A4 paper size and 15 mm margins, and save the PDF as invoice.pdf:
waitMs asks the API to wait up to 10 seconds for the PDF:
curl $PDF_URL/v1/renders \ -H "x-api-key: $API_KEY" \ -H "content-type: application/json" \ -d '{ "document": { "kind": "html", "html": "<h1>Invoice 42</h1><p>Thank you for your order.</p>" }, "settings": { "pageSize": { "widthMm": 210, "heightMm": 297 }, "margins": { "topMm": 15, "rightMm": 15, "bottomMm": 15, "leftMm": 15 } }, "waitMs": 10000 }'The response is the render. When its state is succeeded, download the PDF from
result.downloadUrl, which works without the API key for five minutes. If it is still queued
or processing, see get the finished file.
curl -o invoice.pdf "PASTE-THE-downloadUrl-HERE"using Typefold.Client;
var client = new TypefoldClient( new Uri(Environment.GetEnvironmentVariable("PDF_URL")!), Environment.GetEnvironmentVariable("API_KEY")!);
byte[] pdf = await client.RenderAsync(new DirectRenderRequest{ Document = new HtmlDocument { Html = "<h1>Invoice 42</h1><p>Thank you for your order.</p>" }, Settings = new RenderSettings { PageSize = PageSize.A4, Margins = new Margins { TopMm = 15, RightMm = 15, BottomMm = 15, LeftMm = 15 }, },});
await File.WriteAllBytesAsync("invoice.pdf", pdf);import { writeFile } from "node:fs/promises";import { PageSize, TypefoldClient } from "@typefold/client";
const client = new TypefoldClient({ baseUrl: process.env.PDF_URL!, apiKey: process.env.API_KEY!,});
const pdf = await client.render({ document: { html: "<h1>Invoice 42</h1><p>Thank you for your order.</p>" }, settings: { pageSize: PageSize.A4, margins: { topMm: 15, rightMm: 15, bottomMm: 15, leftMm: 15 }, },});
await writeFile("invoice.pdf", pdf);import { writeFile } from "node:fs/promises";import { PageSize, TypefoldClient } from "@typefold/client";
const client = new TypefoldClient({ baseUrl: process.env.PDF_URL, apiKey: process.env.API_KEY,});
const pdf = await client.render({ document: { html: "<h1>Invoice 42</h1><p>Thank you for your order.</p>" }, settings: { pageSize: PageSize.A4, margins: { topMm: 15, rightMm: 15, bottomMm: 15, leftMm: 15 }, },});
await writeFile("invoice.pdf", pdf);import osfrom pathlib import Path
from typefold import ( DirectRenderRequest, HtmlDocument, Margins, PageSize, TypefoldClient, RenderSettings,)
client = TypefoldClient(os.environ["PDF_URL"], os.environ["API_KEY"])
pdf = client.render( DirectRenderRequest( document=HtmlDocument(html="<h1>Invoice 42</h1><p>Thank you for your order.</p>"), settings=RenderSettings( page_size=PageSize.A4, margins=Margins(top_mm=15, right_mm=15, bottom_mm=15, left_mm=15), ), ))
Path("invoice.pdf").write_bytes(pdf)Open invoice.pdf: you should see a one-page A4 document with the heading “Invoice 42”.
3. Render a template by name
Section titled “3. Render a template by name”Most applications keep the layout in a template, a reusable document stored in Studio, and send only data. First create and publish the template:
-
In the sidebar, open Workspace → Editor. The editor opens in a new browser tab. Click +, then New entity → Template.
-
Enter the Template name
Quickstart invoice, leave Start with on Blank template and click Create template. The editor opens the template’stemplate.html. -
Replace its contents with:
<h1>Invoice {{number}}</h1><p>Bill to {{customer}}</p><table>{{#each lines}}<tr><td>{{item}}</td><td>{{amount}}</td></tr>{{/each}}</table>The placeholders use Handlebars syntax.
-
Click Save, then Publish. Publishing makes the template available to the API.
Now render it by name with the Reports API. It returns the PDF itself, saved here as
quickstart-invoice.pdf:
curl $PDF_URL/v1/reports/render \ -H "x-api-key: $API_KEY" \ -H "content-type: application/json" \ -d '{ "format": "pdf", "template": { "name": "Quickstart invoice" }, "data": { "number": "2026-0042", "customer": "Acme Ltd", "lines": [ { "item": "Consulting", "amount": "1,200.00" }, { "item": "Travel", "amount": "180.00" } ] } }' \ -o quickstart-invoice.pdfusing Typefold.Client;
var client = new TypefoldClient( new Uri(Environment.GetEnvironmentVariable("PDF_URL")!), Environment.GetEnvironmentVariable("API_KEY")!);
byte[] pdf = await client.RenderReportAsync(new RenderReportRequest{ Template = TemplateRef.ByName("Quickstart invoice"), Data = new { number = "2026-0042", customer = "Acme Ltd", lines = new[] { new { item = "Consulting", amount = "1,200.00" }, new { item = "Travel", amount = "180.00" }, }, },});
await File.WriteAllBytesAsync("quickstart-invoice.pdf", pdf);import { writeFile } from "node:fs/promises";import { TypefoldClient, TemplateRef } from "@typefold/client";
const client = new TypefoldClient({ baseUrl: process.env.PDF_URL!, apiKey: process.env.API_KEY!,});
const pdf = await client.renderReport({ template: TemplateRef.byName("Quickstart invoice"), data: { number: "2026-0042", customer: "Acme Ltd", lines: [ { item: "Consulting", amount: "1,200.00" }, { item: "Travel", amount: "180.00" }, ], },});
await writeFile("quickstart-invoice.pdf", pdf);import { writeFile } from "node:fs/promises";import { TypefoldClient, TemplateRef } from "@typefold/client";
const client = new TypefoldClient({ baseUrl: process.env.PDF_URL, apiKey: process.env.API_KEY,});
const pdf = await client.renderReport({ template: TemplateRef.byName("Quickstart invoice"), data: { number: "2026-0042", customer: "Acme Ltd", lines: [ { item: "Consulting", amount: "1,200.00" }, { item: "Travel", amount: "180.00" }, ], },});
await writeFile("quickstart-invoice.pdf", pdf);import osfrom pathlib import Path
from typefold import TypefoldClient, RenderReportRequest, TemplateRef
client = TypefoldClient(os.environ["PDF_URL"], os.environ["API_KEY"])
pdf = client.render_report( RenderReportRequest( template=TemplateRef.by_name("Quickstart invoice"), data={ "number": "2026-0042", "customer": "Acme Ltd", "lines": [ {"item": "Consulting", "amount": "1,200.00"}, {"item": "Travel", "amount": "180.00"}, ], }, ))
Path("quickstart-invoice.pdf").write_bytes(pdf)Open quickstart-invoice.pdf. You should see “Invoice 2026-0042”, “Bill to Acme Ltd” and a
two-row table.
Next steps
Section titled “Next steps”- How it works: workspaces, API keys, templates and renders.
- Build your first template: sample data and live preview in Studio.
- Reports API and Renders API: the two ways to render from your app, and when to use each.