Payslip
Produce every employee payslip in one call and ship it password-protected, because it is personal data. You learn batches, passwords and permissions, and a bar chart of the monthly trend.
このレシピで身につくこと
エディタで作る
- Design one payslip as it should look. A batch calls this one template once per person, so the template itself must not contain the list of people.
- Make earnings and deductions two repeating tables, bound to data.earnings and data.deductions.
- Compute the net amount rather than accepting it: {{ format(sum(data.earnings, "amount") - sum(data.deductions, "amount"), "number", "0,0", "en-US") }} can never disagree with the two tables.
- Add a chart and set it to bar. Point it at data.trend, with {{ item.month }} as the label expression and {{ item.net }} as the value expression.
- A chart uses the same shape as a table — one array and two column definitions. That is deliberate, so there is no new concept to learn.
- Save and note the template_id. Each batch item carries a template_id and that person data.
スキーマと API で作る
- Post an items array to POST /v1/batch — up to 50 — each with its own template or template_id and its own data.
- Set merge to true and you get one merged file back. That path is capped at 20 and is the only one that waits and answers with a download URL.
- A merged file keeps each document header and footer and does not renumber pages — it is several documents in one file, not one document.
- Quota is checked once for the whole batch before queueing. If there is not enough it is rejected whole — a half-processed batch is awkward to refund and awkward to retry.
- password sets the open password and owner_password the permissions password. Making them the same renders the permissions below meaningless.
- permissions turns off print, copy, modify, annotate and fill individually. We never block text extraction for assistive software.
出来上がったドキュメント
下の JSON は、2 つの道筋が生むドキュメントそのものです。テストがこれを検証し、警告なしでレンダリングされることも確認しているので、そのまま貼り付けてお使いいただけます。
{
"v": 1,
"unit": "px",
"page": {
"size": "a4",
"orientation": "portrait",
"margin": {
"t": 48,
"r": 48,
"b": 56,
"l": 48
},
"header": "{{ data.company }} payslip",
"footer": "{{ data.period }} · [[page]] / [[pages]]"
},
"fonts": [],
"styles": [
{
"id": "s_h1",
"fontFamily": "Liberation Sans",
"fontSize": 20,
"fontWeight": 700,
"italic": false,
"color": "#111111",
"bg": "transparent",
"align": "left",
"valign": "top",
"lineHeight": 1.5,
"border": "none",
"radius": 0,
"opacity": 1
},
{
"id": "s_l",
"fontFamily": "Liberation Sans",
"fontSize": 12,
"fontWeight": 400,
"italic": false,
"color": "#333333",
"bg": "transparent",
"align": "left",
"valign": "top",
"lineHeight": 1.5,
"border": "none",
"radius": 0,
"opacity": 1
},
{
"id": "s_tbl",
"fontFamily": "Liberation Sans",
"fontSize": 11,
"fontWeight": 400,
"italic": false,
"color": "#111111",
"bg": "transparent",
"align": "left",
"valign": "middle",
"lineHeight": 1.5,
"border": "none",
"radius": 0,
"opacity": 1
},
{
"id": "s_net",
"fontFamily": "Liberation Sans",
"fontSize": 18,
"fontWeight": 700,
"italic": false,
"color": "#111111",
"bg": "transparent",
"align": "right",
"valign": "top",
"lineHeight": 1.5,
"border": "none",
"radius": 0,
"opacity": 1
}
],
"nodes": [
{
"id": "n_title",
"parent": "",
"order": 0,
"type": "label",
"x": 0,
"y": 0,
"w": 400,
"h": 26,
"show": "",
"styleId": "s_h1",
"props": {
"text": "{{ data.employee.name }}",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Name"
},
{
"id": "n_meta",
"parent": "",
"order": 1,
"type": "label",
"x": 0,
"y": 30,
"w": 400,
"h": 18,
"show": "",
"styleId": "s_l",
"props": {
"text": "{{ data.employee.dept }} · ID {{ data.employee.no }} · {{ data.period }}",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Department"
},
{
"id": "n_earn",
"parent": "",
"order": 2,
"type": "table",
"x": 0,
"y": 76,
"w": 340,
"h": 150,
"show": "",
"styleId": "s_tbl",
"props": {
"text": "",
"src": "",
"fit": "",
"thickness": 1,
"stroke": "#c9ced6",
"fill": "#eef4ff",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 5,
"padX": 8,
"align": "",
"valign": "middle",
"wrap": "",
"bind": "data.earnings",
"headerHeight": 26,
"rowHeight": 22,
"max": 30,
"columns": [
{
"header": "Earnings",
"cell": "{{ item.name }}",
"width": 200,
"align": "left"
},
{
"header": "Amount",
"cell": "{{ format(item.amount, \"number\", \"0,0\", \"en-US\") }}",
"width": 140,
"align": "right"
}
],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Earnings"
},
{
"id": "n_ded",
"parent": "",
"order": 3,
"type": "table",
"x": 357,
"y": 76,
"w": 340,
"h": 150,
"show": "",
"styleId": "s_tbl",
"props": {
"text": "",
"src": "",
"fit": "",
"thickness": 1,
"stroke": "#c9ced6",
"fill": "#fff1f0",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 5,
"padX": 8,
"align": "",
"valign": "middle",
"wrap": "",
"bind": "data.deductions",
"headerHeight": 26,
"rowHeight": 22,
"max": 30,
"columns": [
{
"header": "Deductions",
"cell": "{{ item.name }}",
"width": 200,
"align": "left"
},
{
"header": "Amount",
"cell": "{{ format(item.amount, \"number\", \"0,0\", \"en-US\") }}",
"width": 140,
"align": "right"
}
],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Deductions"
},
{
"id": "n_net",
"parent": "",
"order": 4,
"type": "label",
"x": 0,
"y": 244,
"w": 697,
"h": 26,
"show": "",
"styleId": "s_net",
"props": {
"text": "Net pay {{ format(sum(data.earnings, \"amount\") - sum(data.deductions, \"amount\"), \"number\", \"0,0\", \"en-US\") }}",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Net pay"
},
{
"id": "n_trend_l",
"parent": "",
"order": 5,
"type": "label",
"x": 0,
"y": 296,
"w": 697,
"h": 18,
"show": "",
"styleId": "s_l",
"props": {
"text": "Recent net pay",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Trend heading"
},
{
"id": "n_trend",
"parent": "",
"order": 6,
"type": "chart",
"x": 0,
"y": 320,
"w": 697,
"h": 200,
"show": "",
"styleId": "s_l",
"props": {
"text": "",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "data.trend",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [
{
"header": "Month",
"cell": "{{ item.month }}",
"width": 0,
"align": "left"
},
{
"header": "Net",
"cell": "{{ item.net }}",
"width": 0,
"align": "right"
}
],
"rows": 0,
"cells": [],
"chartKind": "bar",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Trend chart"
}
]
}リクエストの本文です。上のドキュメントを template に、下のデータを data に入れてください。
{
"template": "(the document above)",
"data": {
"company": "brewmypdf",
"period": "2026-08",
"employee": {
"name": "Do-hyun Kim",
"dept": "Engineering",
"no": "E-2041"
},
"earnings": [
{
"name": "Base salary",
"amount": 4200
},
{
"name": "Role allowance",
"amount": 300
},
{
"name": "Meal allowance",
"amount": 200
}
],
"deductions": [
{
"name": "Pension",
"amount": 189
},
{
"name": "Health insurance",
"amount": 148
},
{
"name": "Income tax",
"amount": 262
}
],
"trend": [
{
"month": "May",
"net": 4050
},
{
"month": "Jun",
"net": 4090
},
{
"month": "Jul",
"net": 4010
},
{
"month": "Aug",
"net": 4101
}
]
},
"password": "{{employee date of birth, 6 digits}}",
"owner_password": "{{your owner password}}",
"permissions": {
"print": true,
"copy": false,
"modify": false,
"annotate": false,
"fill": false
}
}