Render a report by name
The Reports API is the simplest way to get a document: send a template’s name and your data, and the response is the finished PDF or XLSX file. To render one specific template version or your own HTML, use the Renders API.
Before you start
Section titled “Before you start”- An API key with
render:create,render:readandtemplate:read. - A published template, such as one called
Invoice; see Build a template. - curl or a client library, set up as in the quickstart.
1. Render a template by name
Section titled “1. Render a template by name”Send the template’s name and your data. The response is the file:
curl "$PDF_URL/v1/reports/render" \ -H "x-api-key: $API_KEY" \ -H "content-type: application/json" \ --fail-with-body -o invoice.pdf \ -d '{ "format": "pdf", "template": { "name": "Invoice" }, "data": { "invoice": { "number": "INV-2041" }, "customer": { "name": "Marta Tamm" } } }'using 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("Invoice"), Data = new { invoice = new { number = "INV-2041" }, customer = new { name = "Marta Tamm" }, },});
await File.WriteAllBytesAsync("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("Invoice"), data: { invoice: { number: "INV-2041" }, customer: { name: "Marta Tamm" } },});
await writeFile("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("Invoice"), data: { invoice: { number: "INV-2041" }, customer: { name: "Marta Tamm" } },});
await writeFile("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("Invoice"), data={"invoice": {"number": "INV-2041"}, "customer": {"name": "Marta Tamm"}}, ))
Path("invoice.pdf").write_bytes(pdf)data holds the fields your template uses. The template’s current published version is always
used, so clicking Publish in Studio changes your next document without a code change.
How the template is chosen
Section titled “How the template is chosen”template takes exactly one of these:
template |
Matches |
|---|---|
{ "name": "Invoice" } |
Templates with that name, ignoring case. |
{ "id": "..." } |
The template with that ID. |
{ "shortid": "..." } |
Templates with that shortid. Only imported templates have one. |
- Only templates that render the requested
formatcount. If several match, a published one wins, then the most recently updated. - Two templates in different folders can share a name; a request by that name then gets the one
edited last. Give templates distinct names, or render by
id. - No match, or a match that was never published, answers
404 NOT_FOUND.
Choose the language
Section titled “Choose the language”locale is a language tag such as de-CH. It picks the template’s translation file, a
spreadsheet’s number and date formats, and the language recorded in the PDF. Without it,
en-US is used, not the locale in the template’s page.json. See
Translations.
2. Check the response
Section titled “2. Check the response”Success is 200 with the file as the body: application/pdf, the image’s type for an
image, or application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
for XLSX. Any other status
returns a JSON error whose message says what to fix (curl’s --fail-with-body saves it in
place of the file; the clients throw it). The error format is in the
HTTP API.
| Status | Code | When | What to do |
|---|---|---|---|
| 400 | BAD_REQUEST |
A field is wrong or unknown, or pdf or test is sent with "format": "xlsx". |
Fix the request as message says. |
| 404 | NOT_FOUND |
No published template with that name, ID or shortid renders this format. | Check the name, the format, and that the template is published. |
| 422 | RENDER_FAILED |
The PDF render failed or was cancelled. error.renderId names it. |
Read the render to see why. Do not retry unchanged. |
| 429 | RATE_LIMITED |
The workspace is at its render allowances, or is preparing too many reports at once. | Send it again later, after Retry-After when it is sent. |
| 504 | RENDER_TIMEOUT |
The PDF was still rendering when the Reports API wait ran out. error.renderId names it. |
Follow it with GET /v1/renders/{renderId}; do not start another. |
Keep your HTTP client’s timeout above the Reports API wait. The clients’ defaults already are.
A PDF is an ordinary render: it counts against your render allowances, appears in the render list and sends webhooks. An XLSX file creates no render and sends no webhooks, but is still refused while the workspace is at its allowances.
Add "test": true (Test = true in .NET, test=True in Python) for a free test PDF with a
diagonal “TEST” watermark on every page. It doesn’t count against your render allowances; see
test renders. PDF and images only.
To retry a PDF request safely, send an Idempotency-Key header (idempotencyKey in the .NET
and TypeScript clients, idempotency_key in Python). A repeat with the same key returns the
first render instead of making a second one; see
idempotency keys. It has no effect on XLSX.
Change page settings for one request
Section titled “Change page settings for one request”pdf overrides the template’s page and PDF settings for this request only. Leave a field out
to keep the template’s value.
curl "$PDF_URL/v1/reports/render" \ -H "x-api-key: $API_KEY" \ -H "content-type: application/json" \ --fail-with-body -o invoice.pdf \ -d '{ "format": "pdf", "template": { "name": "Invoice" }, "data": { "invoice": { "number": "INV-2041" } }, "pdf": { "orientation": "landscape", "margins": { "topMm": 10, "bottomMm": 10 } } }'using 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("Invoice"), Data = new { invoice = new { number = "INV-2041" } }, Pdf = new ReportPdfOptions { Orientation = Orientation.Landscape, Margins = new Margins { TopMm = 10, BottomMm = 10 }, },});
await File.WriteAllBytesAsync("invoice.pdf", pdf);import { writeFile } from "node:fs/promises";import { Orientation, 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("Invoice"), data: { invoice: { number: "INV-2041" } }, pdf: { orientation: Orientation.Landscape, margins: { topMm: 10, bottomMm: 10 } },});
await writeFile("invoice.pdf", pdf);import { writeFile } from "node:fs/promises";import { Orientation, 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("Invoice"), data: { invoice: { number: "INV-2041" } }, pdf: { orientation: Orientation.Landscape, margins: { topMm: 10, bottomMm: 10 } },});
await writeFile("invoice.pdf", pdf);import osfrom pathlib import Path
from typefold import ( Margins, Orientation, TypefoldClient, RenderReportRequest, ReportPdfOptions, TemplateRef,)
client = TypefoldClient(os.environ["PDF_URL"], os.environ["API_KEY"])
pdf = client.render_report( RenderReportRequest( template=TemplateRef.by_name("Invoice"), data={"invoice": {"number": "INV-2041"}}, pdf=ReportPdfOptions( orientation=Orientation.LANDSCAPE, margins=Margins(top_mm=10, bottom_mm=10), ), ))
Path("invoice.pdf").write_bytes(pdf)What pdf can change:
- Paper:
pageSize(A3,A4,A5,Letter,Legalor a size in millimetres),orientation,margins(sides you leave out keep their value) andpreferCssPageSize. See Build a template. - Pages:
pageRangeskeeps only some pages, such as1-5, 8, 11-; page numbers still count the whole document.operationsreplaces the template’s pages from other templates and PDF files, and[]adds none; see Combine templates. - See-through content:
opaqueFillsdraws CSS opacity and translucent colours at full strength. - Watermark:
watermarkdraws text such asDRAFTacross every page; see Add a watermark. - PDF standards and security:
metadata,pdfa,pdfua,attachments,encryptionandsignature.metadata,encryptionandsignatureapply over the template’s values one field at a time. See PDF standards and security.
Values in pdf are used as written: only the template’s own values fill {{path}}
placeholders. Every field and its limits are in the API reference.
Add a watermark
Section titled “Add a watermark”pdf.watermark draws text such as DRAFT, COPY or PAID across every page, in front of the
content. Only text is required.
curl "$PDF_URL/v1/reports/render" \ -H "x-api-key: $API_KEY" \ -H "content-type: application/json" \ --fail-with-body -o invoice.pdf \ -d '{ "format": "pdf", "template": { "name": "Invoice" }, "data": { "invoice": { "number": "INV-2041" } }, "pdf": { "watermark": { "text": "COPY" } } }'using 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("Invoice"), Data = new { invoice = new { number = "INV-2041" } }, Pdf = new ReportPdfOptions { Watermark = new PdfWatermark { Text = "COPY" } },});
await File.WriteAllBytesAsync("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("Invoice"), data: { invoice: { number: "INV-2041" } }, pdf: { watermark: { text: "COPY" } },});
await writeFile("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("Invoice"), data: { invoice: { number: "INV-2041" } }, pdf: { watermark: { text: "COPY" } },});
await writeFile("invoice.pdf", pdf);import osfrom pathlib import Path
from typefold import ( PdfWatermark, RenderReportRequest, ReportPdfOptions, TemplateRef, TypefoldClient,)
client = TypefoldClient(os.environ["PDF_URL"], os.environ["API_KEY"])
pdf = client.render_report( RenderReportRequest( template=TemplateRef.by_name("Invoice"), data={"invoice": {"number": "INV-2041"}}, pdf=ReportPdfOptions(watermark=PdfWatermark(text="COPY")), ))
Path("invoice.pdf").write_bytes(pdf)Its colour, opacity, angle and size can be changed too; the fields and their defaults are under
Watermarks. Like every pdf option, it is for PDFs and images
only: an Excel request with pdf answers 400 BAD_REQUEST.
Render an image
Section titled “Render an image”Set "format" to "png", "jpeg" or "webp" to get one page of a PDF template as an image.
image picks the page and the width:
curl "$PDF_URL/v1/reports/render" \ -H "x-api-key: $API_KEY" \ -H "content-type: application/json" \ --fail-with-body -o invoice.png \ -d '{ "format": "png", "template": { "name": "Invoice" }, "data": { "invoice": { "number": "INV-2041" } }, "image": { "page": 1, "width": 400 } }'using Typefold.Client;
var client = new TypefoldClient( new Uri(Environment.GetEnvironmentVariable("PDF_URL")!), Environment.GetEnvironmentVariable("API_KEY")!);
byte[] png = await client.RenderReportAsync(new RenderReportRequest{ Format = RenderFormat.Png, Template = TemplateRef.ByName("Invoice"), Data = new { invoice = new { number = "INV-2041" } }, Image = new ImageOptions { Page = 1, Width = 400 },});
await File.WriteAllBytesAsync("invoice.png", png);import { writeFile } from "node:fs/promises";import { RenderFormat, TypefoldClient, TemplateRef } from "@typefold/client";
const client = new TypefoldClient({ baseUrl: process.env.PDF_URL!, apiKey: process.env.API_KEY!,});
const png = await client.renderReport({ format: RenderFormat.Png, template: TemplateRef.byName("Invoice"), data: { invoice: { number: "INV-2041" } }, image: { page: 1, width: 400 },});
await writeFile("invoice.png", png);import { writeFile } from "node:fs/promises";import { RenderFormat, TypefoldClient, TemplateRef } from "@typefold/client";
const client = new TypefoldClient({ baseUrl: process.env.PDF_URL, apiKey: process.env.API_KEY,});
const png = await client.renderReport({ format: RenderFormat.Png, template: TemplateRef.byName("Invoice"), data: { invoice: { number: "INV-2041" } }, image: { page: 1, width: 400 },});
await writeFile("invoice.png", png);import osfrom pathlib import Path
from typefold import ImageOptions, RenderFormat, RenderReportRequest, TemplateRef, TypefoldClient
client = TypefoldClient(os.environ["PDF_URL"], os.environ["API_KEY"])
png = client.render_report( RenderReportRequest( template=TemplateRef.by_name("Invoice"), data={"invoice": {"number": "INV-2041"}}, format=RenderFormat.PNG, image=ImageOptions(page=1, width=400), ))
Path("invoice.png").write_bytes(png)The response is the image, as image/png, image/jpeg or image/webp. The image fields, the
size of a social card and the limits are under
Render an image. pdf options, such as a watermark, and
test work as for a PDF; encryption, signature, attachments, pdfa and pdfua answer
400 BAD_REQUEST. An image is an ordinary render and counts as one document.
Get an Excel file
Section titled “Get an Excel file”Set "format": "xlsx" (ReportFormat.Xlsx in the .NET and TypeScript clients,
ReportFormat.XLSX in Python). The response is the .xlsx file. Which templates render which
format:
| Template | Renders |
|---|---|
Spreadsheet template (sheets.json) |
XLSX or PDF |
Workbook template (uses an .xlsx workspace file) |
XLSX only |
| HTML or component template | PDF only |
A template that renders PDF also renders images. Asking for a format the
template does not render answers 404 NOT_FOUND. pdf options and
test are for PDFs and images only.
Find your reports
Section titled “Find your reports”GET /v1/reports lists every template in the workspace, sorted by name, with the formats it
renders.
curl "$PDF_URL/v1/reports" -H "x-api-key: $API_KEY" --fail-with-bodyusing Typefold.Client;
var client = new TypefoldClient( new Uri(Environment.GetEnvironmentVariable("PDF_URL")!), Environment.GetEnvironmentVariable("API_KEY")!);
foreach (var report in await client.ListReportsAsync()){ Console.WriteLine($"{report.Name}: {string.Join(", ", report.Formats)}");}import { TypefoldClient } from "@typefold/client";
const client = new TypefoldClient({ baseUrl: process.env.PDF_URL!, apiKey: process.env.API_KEY!,});
for (const report of await client.listReports()) { console.log(`${report.name}: ${report.formats.join(", ")}`);}import { TypefoldClient } from "@typefold/client";
const client = new TypefoldClient({ baseUrl: process.env.PDF_URL, apiKey: process.env.API_KEY,});
for (const report of await client.listReports()) { console.log(`${report.name}: ${report.formats.join(", ")}`);}import os
from typefold import TypefoldClient
client = TypefoldClient(os.environ["PDF_URL"], os.environ["API_KEY"])
for report in client.list_reports(): print(f"{report.name}: {', '.join(report.formats)}"){ "items": [ { "id": "0f5b7c1e-6a43-4f7e-9d1b-1c2a3b4c5d6e", "name": "Invoice", "formats": ["pdf"], "published": true, "folderPath": "Invoices" } ]}Use id or name in template. published says whether the template has a published version;
only published templates render. formats comes from the published version, or from the draft
if it was never published. Imported templates also have a shortid.
Get the data schema
Section titled “Get the data schema”GET /v1/reports/data-schema returns the data a published template expects, as
JSON Schema, so you can generate types or check your data. Pass
format and one of name, id or shortid; the template is
chosen the same way as for a render.
curl -G "$PDF_URL/v1/reports/data-schema" \ -H "x-api-key: $API_KEY" \ --fail-with-body \ --data-urlencode "format=pdf" \ --data-urlencode "name=Invoice"using Typefold.Client;
var client = new TypefoldClient( new Uri(Environment.GetEnvironmentVariable("PDF_URL")!), Environment.GetEnvironmentVariable("API_KEY")!);
var schema = await client.GetReportDataSchemaAsync(ReportFormat.Pdf, TemplateRef.ByName("Invoice"));
Console.WriteLine(schema);import { TypefoldClient, ReportFormat, TemplateRef } from "@typefold/client";
const client = new TypefoldClient({ baseUrl: process.env.PDF_URL!, apiKey: process.env.API_KEY!,});
const schema = await client.getReportDataSchema(ReportFormat.Pdf, TemplateRef.byName("Invoice"));
console.log(JSON.stringify(schema, null, 2));import { TypefoldClient, ReportFormat, TemplateRef } from "@typefold/client";
const client = new TypefoldClient({ baseUrl: process.env.PDF_URL, apiKey: process.env.API_KEY,});
const schema = await client.getReportDataSchema(ReportFormat.Pdf, TemplateRef.byName("Invoice"));
console.log(JSON.stringify(schema, null, 2));import jsonimport os
from typefold import TypefoldClient, ReportFormat, TemplateRef
client = TypefoldClient(os.environ["PDF_URL"], os.environ["API_KEY"])
schema = client.get_report_data_schema(ReportFormat.PDF, TemplateRef.by_name("Invoice"))
print(json.dumps(schema, indent=2))How the schema is built:
- Spreadsheet templates: from the sections and columns. Each section’s data is a required array; each column is an optional value typed by its format.
- Other templates: from the sample data published with the version. A property is
requiredonly when every sample object has it. Without sample data the schema is{}.
Renders are not checked against the schema, and values a template script adds do not appear in it.
Make many reports
Section titled “Make many reports”Send one request per document; they can run in parallel. A request answered with
429 RATE_LIMITED can be sent again later, and the clients do this for you (3 times by
default).
The Reports API has no batches. To create many PDFs with one request, use a batch in the Renders API. Each batch item names a template version or sends its own document, not a template name.
Next steps
Section titled “Next steps”- Build a template: paper, headers, footers, page numbers and page breaks.
- Spreadsheet templates: Excel output.
- API reference: every Reports API field and its limits.