Make documents from a spreadsheet
Download a form made from your template, fill it in Excel or as CSV, and upload it. One row of the doc sheet becomes one PDF. Everything is checked before anything is made — if one cell is wrong, nothing is made.
Getting the form
Open a template, choose "Make from spreadsheet", and download the Excel form or one CSV per sheet. The form is generated from the template: the number of sheets is decided by how deeply the template nests arrays. No arrays: one sheet (doc). A table over data.items: two sheets (doc and items). Two levels (a block with a table inside): three.
Row 1 is the header and is the contract — do not change it. Row 2 explains each column, row 3 is an example; both are ignored on upload. Enter data from row 4. The Excel file also carries a hidden sheet that ties it to the template.
Filling it in
Column A of every sheet is _key, the document key — for example the invoice number. It must be different for every document and is what joins the rows of one document across sheets. It is not part of the data your template sees.
A third-level sheet (a table inside a repeating block) also has _row in column B: the number of the parent row among rows with the same _key, counting from 1. Second-level sheets need only _key; their order is the file order.
An empty cell means the value is missing. If the template uses that value, generation stops and the cell is named. To make a column optional, give it a default in the template: {{ data.memo || "" }}.
Numbers: plain digits only — no thousands separators or currency symbols. "1,000" stays text and breaks arithmetic. Dates: YYYY-MM-DD. In Excel, number and date cells keep their type; in CSV a cell that reads entirely as a number becomes one.
CSV: one file per sheet, named brewmypdf_(templateId)_(formHash)_(sheet).csv. Keep that name — the Excel form carries a hidden sheet that names its template, but for CSV the file name is the only clue. Files saved by Korean Excel in EUC-KR are read as well as UTF-8.
A worked example — 120 invoices
If you read only one section, read this one. We follow an invoice from spreadsheet to PDF.
Why is it split into sheets? Because one invoice holds two different kinds of thing. Some values appear exactly once per invoice — the company, the contact, the issue date. Others repeat an unknown number of times: the line items. One invoice has two lines, the next has forty. To keep both on a single row you would need columns like item1, qty1, price1, item2, qty2 and so on, sized for the longest invoice you will ever send — hundreds of empty columns on every other row. So anything that repeats gets its own sheet, where one line is one row and there can be as many as you like.
When a template uses per-invoice values together with a table of line items, the form comes out as two sheets. One row of the doc sheet is one invoice; one row of the items sheet is one line of that invoice.
doc sheet
_key invoice_no date company contact
INV-001 INV-2026-01 2026-09-01 Acme Ltd. Kim <- invoice 1
INV-002 INV-2026-02 2026-09-01 Northwind Tanaka <- invoice 2
...
INV-120 INV-2026-120 2026-09-30 Societe SA Dupont <- invoice 120
items sheet
_key name qty price
INV-001 Consulting Sep 1 3000000 -+
INV-001 Server rental 3 120000 | 8 lines of invoice 1
INV-001 ... six more -+
INV-002 Design work 1 1500000 -+ 2 lines of invoice 2
INV-002 Revisions x2 2 80000 -+
...What ties the two sheets together is _key in column A. Every row in the items sheet whose _key is INV-001 becomes a line of that invoice. The value can be anything as long as it is unique per invoice — the invoice number is the obvious choice. It is never printed on the document; it is only a label for joining rows.
When you press the make button, this happens once per row of the doc sheet.
doc sheet, 1 row -+
+--> { invoice_no: 'INV-2026-01',
items sheet, | company: 'Acme Ltd.',
8 rows of INV-001 -+ items: [ 8 lines ] }
|
v
template + data
|
v
INV-001.pdf (2-3 pages) = 1 creditSo 120 rows in the doc sheet produce 120 PDFs. It makes no difference that the items sheet has 960 rows — those 960 are distributed across the 120 documents. The cost is 120 credits. An invoice costs one credit whether it comes out two pages or three; pages are not counted. In short, credits always equal the number of rows in the doc sheet.
Sometimes there are three sheets. That happens when a template repeats invoices inside one PDF and each of those has its own line items — a repeat inside a repeat, so: doc, invoices, lines. The third sheet then carries one extra column, _row, which says which invoice under the same _key a line belongs to, counted from 1. That is as far as nesting goes — four levels cannot be laid out as a table, so no form is produced.
What is checked
The check runs in your browser; the file is not sent to the server. It compares the form to the current template, the headers to the expected columns, the keys (empty, duplicate, orphaned), and the row limits. Then it compiles every document the same way the renderer will, and reports any value the template cannot use: empty cells, text where arithmetic needs a number, more than 100 pages.
Every finding names the sheet, row and column. If there is one finding, the make button does not appear. Fix the file and upload again.
Making and downloading
After the checks, the first document is previewed and the summary line above it gives the document count, page count and credits. The button says how many documents will be made. Documents are submitted 50 at a time as one run; the page shows done, running, queued and failed counts and a download link per finished document.
If submission stops partway (quota or queue budget), the documents already submitted are still made, the run is marked failed at that point, and you can upload again to submit the rest. A run is never silently cut short. ⚠ Credits are checked per batch of 50 — if your remaining credits are fewer than a batch, that batch builds nothing at all. With 30 credits left and 100 rows uploaded, only the first 50 are built and it stops there. To spend the last credits exactly, upload only as many rows as you have left. Once a run has finished you can take the completed documents as one ZIP — up to 500 MB in total; past that no archive is built, so use the per-document links.
Scheduled runs
Instead of uploading a table every time, register a data URL and we fetch it on schedule and build the documents. It must be an https URL that opens without a login — a Google Sheets “publish to the web” CSV link, an export URL on your own server, and so on.
A schedule is daily, weekly on a chosen weekday, or monthly on a chosen day, plus a time and a time zone. There is no cron syntax. Because the time zone is stored, a run happens at the same wall-clock time even where daylight saving applies. A day that does not exist in a month (the 31st of February, say) falls back to the last day of that month.
We open the URL and check it the moment you register it. If it does not pass, nothing is saved — so you never learn about a broken URL a month later, on the first run.
Every run goes through exactly the same checks as an upload. If anything fails, no document is built at all, the run is recorded as failed, and we email you. No credits are used. Successful runs are not emailed.
A given run happens once and only once. After three consecutive failures the schedule turns itself off and we tell you. If you edit the template it no longer matches the registered form, so delete the scheduled run and create it again.
The shortest interval is one day; there are no hourly or minute schedules. A run starts later than the time you set — usually by about a minute, and by at most six. That is the wait for the next five-minute sweep plus the delay the cloud adds in firing it. Each run builds at most 500 documents (fewer than the 1,000 you may upload by hand), each URL may return at most 10 MB within 20 seconds and through at most 3 redirects. The number of scheduled runs you can keep on equals your plan's template count. Sources that require a login or token are not supported yet.
Limits
Up to 1,000 documents per run and 10 MB per file; a ZIP holds at most 500 MB. Arrays may nest two levels deep (a block and a table, or two blocks); a template three deep cannot have a form. Each document is subject to the usual 100-page limit and to your plan quota — one document is one render, and pages are not counted. Credits are checked per batch of 50 (see above).