Create a template
curl --request POST \
--url https://api.pdfbase.dev/v1/templates \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"html": "<string>",
"css": "<string>",
"schema": {},
"defaults": {},
"sample_data": {},
"description": "<string>"
}
'import requests
url = "https://api.pdfbase.dev/v1/templates"
payload = {
"name": "<string>",
"html": "<string>",
"css": "<string>",
"schema": {},
"defaults": {},
"sample_data": {},
"description": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
html: '<string>',
css: '<string>',
schema: {},
defaults: {},
sample_data: {},
description: '<string>'
})
};
fetch('https://api.pdfbase.dev/v1/templates', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.pdfbase.dev/v1/templates",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'html' => '<string>',
'css' => '<string>',
'schema' => [
],
'defaults' => [
],
'sample_data' => [
],
'description' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.pdfbase.dev/v1/templates"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"html\": \"<string>\",\n \"css\": \"<string>\",\n \"schema\": {},\n \"defaults\": {},\n \"sample_data\": {},\n \"description\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.pdfbase.dev/v1/templates")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"html\": \"<string>\",\n \"css\": \"<string>\",\n \"schema\": {},\n \"defaults\": {},\n \"sample_data\": {},\n \"description\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.pdfbase.dev/v1/templates")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"html\": \"<string>\",\n \"css\": \"<string>\",\n \"schema\": {},\n \"defaults\": {},\n \"sample_data\": {},\n \"description\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"version": 123
}Templates
Create a template
Store a reusable HTML template with a data schema for repeated rendering.
POST
/
v1
/
templates
Create a template
curl --request POST \
--url https://api.pdfbase.dev/v1/templates \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"html": "<string>",
"css": "<string>",
"schema": {},
"defaults": {},
"sample_data": {},
"description": "<string>"
}
'import requests
url = "https://api.pdfbase.dev/v1/templates"
payload = {
"name": "<string>",
"html": "<string>",
"css": "<string>",
"schema": {},
"defaults": {},
"sample_data": {},
"description": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
html: '<string>',
css: '<string>',
schema: {},
defaults: {},
sample_data: {},
description: '<string>'
})
};
fetch('https://api.pdfbase.dev/v1/templates', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.pdfbase.dev/v1/templates",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'html' => '<string>',
'css' => '<string>',
'schema' => [
],
'defaults' => [
],
'sample_data' => [
],
'description' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.pdfbase.dev/v1/templates"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"html\": \"<string>\",\n \"css\": \"<string>\",\n \"schema\": {},\n \"defaults\": {},\n \"sample_data\": {},\n \"description\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.pdfbase.dev/v1/templates")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"html\": \"<string>\",\n \"css\": \"<string>\",\n \"schema\": {},\n \"defaults\": {},\n \"sample_data\": {},\n \"description\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.pdfbase.dev/v1/templates")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"html\": \"<string>\",\n \"css\": \"<string>\",\n \"schema\": {},\n \"defaults\": {},\n \"sample_data\": {},\n \"description\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"version": 123
}Phase
Phase 1 (Launch)Request
string
required
Human-readable name for the template. Must be unique within your account. Used as the identifier in CLI commands (
pdfbase templates push).string
required
HTML content with Handlebars placeholders for dynamic data. Supports
{{variable}}, {{#each items}}, {{#if condition}}, and all standard Handlebars helpers.string
CSS stylesheet applied to the template. Kept separate from HTML for cleaner template management.
object
required
JSON Schema defining the expected data shape. PDFBase validates render requests against this schema and returns
422 on mismatch.Supported types: string, number, boolean, date, array, object.object
Default rendering options applied every time this template is rendered. Can be overridden per-render.
format(string) — Page sizemargin(string | object) — Marginslandscape(boolean) — Orientationheader(object) — Header HTMLfooter(object) — Footer HTMLcompress(string) — Compression level
object
Example data that satisfies the schema. Used by the CLI’s
preview command and the dashboard’s template preview.string
Optional description shown in the dashboard and CLI listings.
Response
{
"id": "tpl_abc123",
"object": "template",
"name": "invoice",
"description": "Standard customer invoice",
"schema": {
"number": "string",
"customer": "string",
"items": "array",
"due_date": "date",
"total": "string"
},
"defaults": {
"format": "a4",
"margin": "20mm",
"compress": "medium"
},
"version": 1,
"created_at": "2026-05-19T10:00:00Z",
"updated_at": "2026-05-19T10:00:00Z"
}
integer
Auto-incrementing version number. Starts at 1, increments on every
PATCH update. Useful for tracking which version of a template generated a specific PDF.Example
curl -X POST https://api.pdfbase.dev/v1/templates \
-H "Authorization: Bearer pk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"name": "invoice",
"description": "Standard customer invoice",
"html": "<!DOCTYPE html><html><head><style>body { font-family: Inter, sans-serif; } table { width: 100%; border-collapse: collapse; } th, td { padding: 8px; text-align: left; border-bottom: 1px solid #eee; }</style></head><body><h1>Invoice #{{number}}</h1><p>Bill to: {{customer}}</p><table><thead><tr><th>Item</th><th>Qty</th><th>Price</th></tr></thead><tbody>{{#each items}}<tr><td>{{this.name}}</td><td>{{this.qty}}</td><td>{{this.price}}</td></tr>{{/each}}</tbody></table><p><strong>Total: {{total}}</strong></p><p>Due: {{due_date}}</p></body></html>",
"schema": {
"number": "string",
"customer": "string",
"items": "array",
"due_date": "date",
"total": "string"
},
"defaults": {
"format": "a4",
"margin": "20mm",
"compress": "medium"
},
"sample_data": {
"number": "INV-001",
"customer": "Acme Corp",
"items": [
{ "name": "Widget", "qty": 10, "price": "$50.00" },
{ "name": "Gadget", "qty": 5, "price": "$75.00" }
],
"due_date": "2026-06-19",
"total": "$875.00"
}
}'