Quickstart
This guide takes you from a new account to a PDF on disk. You need a Doquill account and about five minutes.
-
Create an API key.
In the app, open Developers → API keys and click Create Key. Give it a name, and under Permissions select at least
render. Copy the key when it’s shown: you won’t see it again.Keep the key on your server. Anyone holding it can render with your workspace’s quota.
-
Publish a template.
Open Templates → Browse. In a new workspace the premade templates are listed right there; otherwise click Create from template. Pick Invoice. It is copied into your workspace and opens in the editor.
Click Publish. Renders only use published versions, so this step is required even if you don’t change anything.
-
Copy the template ID.
The ID is the last part of the editor’s URL:
https://app.doquill.com/templates/<template-id>.You can also list templates with your key:
GET https://api.doquill.com/v1/templates. -
Write the request body.
A render request names the template and passes the data it fills in. Save this as
request.json, replacing<template-id>. The data is the Invoice template’s sample data; other premade templates show theirs in the editor’s Sample Data panel.request.json {"template_id": "<template-id>","data": {"number": "INV-1042","issued_at": "2026-01-05","due_at": "2026-02-04","company": {"name": "Northwind Studio","address": "8 Speicherstraße\n20457 Hamburg, Germany","iban": "DE89370400440532013000","bic": "COBADEFFXXX"},"customer": { "name": "Acme Corp", "address": "12 Rue de Rivoli\n75004 Paris, France" },"items": [{ "description": "Brand identity design", "quantity": 1, "unit_price": 4800 },{ "description": "Landing page (design + build)", "quantity": 1, "unit_price": 3200 },{ "description": "Design retainer", "quantity": 6, "unit_price": 250 }],"subtotal": 9500,"tax_rate": 0.1,"tax": 950,"total": 10450}} -
Render the PDF.
POST /v1/renderwith your key as a bearer token. The response body is the PDF.curl https://api.doquill.com/v1/render \-H "Authorization: Bearer $DOQUILL_API_KEY" \-H "Content-Type: application/json" \-d @request.json \--fail-with-body \-o invoice.pdfimport { readFile, writeFile } from "node:fs/promises";const response = await fetch("https://api.doquill.com/v1/render", {method: "POST",headers: {Authorization: `Bearer ${process.env.DOQUILL_API_KEY}`,"Content-Type": "application/json",},body: await readFile("request.json"),});if (!response.ok) {throw new Error(`Render failed: ${await response.text()}`);}await writeFile("invoice.pdf", Buffer.from(await response.arrayBuffer()));import osimport requestswith open("request.json", "rb") as f:body = f.read()response = requests.post("https://api.doquill.com/v1/render",headers={"Authorization": f"Bearer {os.environ['DOQUILL_API_KEY']}","Content-Type": "application/json",},data=body,timeout=60,)if not response.ok:raise RuntimeError(f"Render failed: {response.text}")with open("invoice.pdf", "wb") as f:f.write(response.content)package mainimport ("bytes""fmt""io""net/http""os")func main() {body, err := os.ReadFile("request.json")if err != nil {panic(err)}req, err := http.NewRequest(http.MethodPost, "https://api.doquill.com/v1/render", bytes.NewReader(body))if err != nil {panic(err)}req.Header.Set("Authorization", "Bearer "+os.Getenv("DOQUILL_API_KEY"))req.Header.Set("Content-Type", "application/json")resp, err := http.DefaultClient.Do(req)if err != nil {panic(err)}defer resp.Body.Close()if resp.StatusCode != http.StatusOK {msg, _ := io.ReadAll(resp.Body)panic(fmt.Sprintf("render failed: %s", msg))}pdf, err := io.ReadAll(resp.Body)if err != nil {panic(err)}if err := os.WriteFile("invoice.pdf", pdf, 0o644); err != nil {panic(err)}} -
Open
invoice.pdf.
Next steps
Section titled “Next steps”- Change the template: Template structure and Template syntax.
- Validate your data: Data & JSON Schema.
- Render in the background and get notified: Sync vs async rendering and Webhooks.