
Payslip
Employer and employee identity, earnings and deductions tables, net pay in words, and year-to-date columns.
Hard part Earnings and deductions totals, net pay, and the amount in words.
template_id 9f7b8380-710e-433a-a4c9-4ecafc986d35
Pay cycle closes → a payslip per employee
Trigger → artefact
The payroll run closesa payslip PDF per employee, each with its own numbers
Payroll is the burst case. Nothing happens for a month and then a thousand documents are owed inside an hour, each different, each with an employee who will read it carefully.
We measured it rather than estimated it: 1,000 payslips submitted in 45.6 seconds, the last one finished at 423.6 seconds, no failures — about 142 documents a minute. When we are at capacity we refuse with a Retry-After header instead of timing out.
Built with the HTML API. Need a designed image or certificate instead? Use the Canvas API — same data, same free year.

What ships in this category

Employer and employee identity, earnings and deductions tables, net pay in words, and year-to-date columns.
Hard part Earnings and deductions totals, net pay, and the amount in words.
template_id 9f7b8380-710e-433a-a4c9-4ecafc986d35

The letter an employee asks HR for when a bank, a landlord or a visa office wants proof: role, joining date, pay components, gross and net.
Hard part Gross and net per period from the components, and the yearly gross when the caller does not send one.
template_id 1c0ace95-a57a-40ce-a3a2-2b035b07d5ee
The whole integration
# once per employee, when the run closes
curl https://api.pixldocs.com/v1/render \
-H "Authorization: Bearer $PIXLDOCS_KEY" \
-H "Content-Type: application/json" \
-d '{
"template_id": "9f7b8380-710e-433a-a4c9-4ecafc986d35",
"format": "pdf",
"data": {
"employee_name": "A. Fischer",
"pay_period": "July 2026",
"pay_date": "2026-07-31",
"earnings": [
{ "component": "Basic", "current": 60000, "ytd": 240000 }
]
}
}' --output payslip.pdfRun against the API before publishing: 200, application/pdf. For pay day, submit up to 100 at a time to /v1/renders/batch and poll the ids.
The contract
These templates take named keys — no positional arguments, no layout to describe. Send a row array and the pagination follows it.
9f7b8380-710e-433a-a4c9-4ecafc986d35Fields · 28
Rows · earnings[]
component · current · ytd
Send as many as you have. Pagination, running totals and the carried-forward header are the renderer's problem, not yours.
Rows · deductions[]
component · current · ytd
Send as many as you have. Pagination, running totals and the carried-forward header are the renderer's problem, not yours.
Rows · employer_contributions[]
component · current · ytd
Send as many as you have. Pagination, running totals and the carried-forward header are the renderer's problem, not yours.
1c0ace95-a57a-40ce-a3a2-2b035b07d5eeFields · 27
Rows · components[]
description · kind · amount
Send as many as you have. Pagination, running totals and the carried-forward header are the renderer's problem, not yours.
Nothing. Each render is independent and carries its own id. A row missing a required field returns 400 with the field named, and no credit is used for it.
At the throughput we measured that is roughly 75 minutes — but we have measured 1,000, not 10,000, so treat it as arithmetic rather than a promise.
Free to start · No credit card required