ZUGFeRD E-Invoice from Airtable in Zapier: Filter the Rows, Build the JSON, Email the Hybrid PDF

PDF4me Create ZUGFeRD Invoice is a Zapier action that converts structured invoice data into a hybrid PDF/A-3 e-invoice. Reading one Airtable row, it turns a JSON object into EN 16931 XML embedded in a readable PDF, writes the file back onto the record, and emails it to the buyer.
E-invoicing mandates arrive as a file format problem and get answered as a procurement problem: pick a platform, pay per document, migrate your data into it. That answer is reasonable at scale and absurd for a team issuing twenty invoices a month out of a database they already run. The alternative is not writing XML by hand. It is describing the invoice as JSON and letting something else produce the conformant file.
An Airtable row holds the invoice: seller, buyer, one line item, the totals. Set Status to New and the Zap picks it up, checks that one field, and hands PDF4me a JSON object. Back comes a PDF/A-3 that a person can read and a machine can parse, attached to the record and sent to the buyer. No platform subscription, no XML, and the data never leaves the base.
Why-Based Q&A
Why describe the invoice as JSON rather than XML? Because Cross Industry Invoice syntax is long, deeply nested and strict about where each code sits. The JSON object says the same thing in a fraction of the space with keys that read like business terms, and PDF4me produces the conformant XML from it. The part that is easy to get wrong is the part you do not maintain.
Why does the hybrid file matter? Because an invoice has two audiences. The buyer's system reads the embedded XML and books it without anyone keying anything; the person in accounts payable opens the same file and sees a page. One artefact satisfies both, which is why FeRD specified a hybrid rather than XML alone.
Why put a Filter in front of the invoice step? Because issuing an invoice is not a reversible action. A Zap that fires on every new row will eventually fire on a half-finished one and email a customer a document with a blank line item. The filter makes issuing a deliberate act: a person sets Status to New and that is the instruction.
Why keep the invoice data in Airtable at all? Because it is usually a by-product of work already tracked there: the project, the client, the agreed rate. Moving it into an invoicing product to satisfy a file format means maintaining the same customer in two systems forever, and the format requirement does not actually ask you to do that.
What You'll Get
Input: an Airtable row with the invoice number, the dates, a seller block with a VAT ID, a buyer block, one line item and the totals, with Status set to New. Output: a ZUGFeRD PDF/A-3 on that record and in the buyer's inbox.

One row per invoice. Every column here becomes a key in the JSON the Zap sends.

The buyer sees an invoice. Their accounting system sees the XML inside it.
What You Need
- A Zapier account on a plan that allows multi-step Zaps. Filter by Zapier is built in and counts as a step.
- PDF4me API key. Get your API key.
- An Airtable base. The captured base is
PDF4me Live Automationswith a table namedZUGFeRD Requests, carrying the invoice header, the seller block including a VAT ID, the buyer block, the line item fields, NetTotal, VATAmount and GrossTotal, an Email column, a Status field and an attachment field calledDocument. - A Gmail account connected to Zapier.
- Your seller details including a VAT ID. They come from columns, so one base can invoice for several legal entities.
The Zap at a Glance
- New Record (Airtable) fires on every new row in
ZUGFeRD Requests. - Filter conditions (Filter by Zapier) continues only when Status is exactly
New. - Create ZUGFeRD Invoice (PDF4me) converts the JSON into a hybrid PDF.
- Update Record (Airtable) writes the file, the status and a link back to the row.
- Send Email (Gmail) delivers the e-invoice to the buyer.
Complete Zap overview

The same five-step shape as the Swiss QR Zap. Only the PDF4me step in the middle differs.
Step 1: How do you trigger a Zap from a new Airtable row?
Flow so far: nothing yet, this is the trigger.
- Create a Zap and pick Airtable > New Record.
- Choose the Base
PDF4me Live Automationsand the TableZUGFeRD Requests. - Test. Zapier reports Found 1 new Record in Airtable and the columns become available downstream.
The polling badge reads 2 min, which comes from the plan rather than this step.
Step 2: How do you stop the Zap invoicing a half-finished row?
Flow so far: the Airtable trigger.
- Add Filter by Zapier > Only continue if....
- Build one rule: 1. Status / (Text) Exactly matches /
New. - Test it.
Filter conditions configuration

The green box names the field that let the record through. The equivalent yellow box names the one that stopped it.
Tip. Exactly matches is case and whitespace sensitive, so new and New with a trailing space both fail silently on every row. Make Status a single select rather than free text and the problem cannot occur.
Step 3: How do you turn the row into a ZUGFeRD invoice?
Flow so far: the trigger and the filter.
- Add PDF4me > Create ZUGFeRD Invoice.
- Set the output options:
- File Name:
ZUGFeRD_plus the Invoice Number plus.pdf - Input Format:
JSON - Output Mode:
XmlWithPdf - Zugferd Version:
2+ - Conformance Level:
EN16931 - Render Invoice On Pdf:
True - Leave File empty unless you are supplying your own letterhead page
- File Name:
- Paste the object into Invoice Json Data and map each Airtable field into it:
{
"InvoiceId": "{{Invoice Number}}",
"TypeCode": "380",
"InvoiceType": "RECHNUNG",
"IssueDate": "{{Invoice Date}}T00:00:00",
"DeliveryDate": "{{Invoice Date}}T00:00:00",
"IsTest": false,
"Seller": {
"Name": "{{Seller Name}}",
"VatId": "{{Seller VATID}}",
"Address": {
"Street": "{{Seller Street}}",
"PostalCode": "{{Seller Postal Code}}",
"City": "{{Seller City}}",
"Country": "{{Seller Country}}"
}
},
"Buyer": {
"Name": "{{Buyer Name}}",
"Address": {
"Street": "{{Buyer Street}}",
"PostalCode": "{{Buyer Postal Code}}",
"City": "{{Buyer City}}",
"Country": "{{Buyer Country}}"
}
},
"LineItems": [
{
"ProductName": "{{Item Description}}",
"Quantity": {{Quantity}},
"UnitCode": "C62",
"UnitPrice": {{Unit Price}},
"LineTotal": {{Net Total}}
}
],
"Totals": {
"Currency": "{{Currency}}",
"LineTotal": {{Net Total}},
"TaxBasisTotal": {{Net Total}},
"TaxPercent": {{VAT Rate}},
"TaxTotal": {{VAT Amount}},
"GrandTotal": {{Gross Total}},
"ChargeTotal": 0,
"AllowanceTotal": 0
},
"Payment": {
"Currency": "{{Currency}}",
"PaymentReference": "{{Invoice Number}}",
"DueDate": "{{Due Date}}T00:00:00"
}
}
Three parts are worth pausing on. TypeCode 380 is the code for a commercial invoice and is fixed. UnitCode C62 is the UN/ECE code for "one of something", which is what you want for hours or units of service. And PaymentReference in the Payment block is the text the buyer quotes when paying, which here is just the invoice number.
Create ZUGFeRD Invoice configuration

Every value is an Airtable token. Note VAT Amount 190.95 and Gross Total 1195.95, even though the grid displays them as 191 and 1196.
What each setting decides
| Field | Value here | What it controls |
|---|---|---|
| Input Format | JSON | That you supply a structured object rather than ready-made XML or a CSV row |
| Output Mode | XmlWithPdf | Return one hybrid file. XmlOnly returns the invoice XML alone |
| Zugferd Version | 2+ | The 2.x generation, which is the one aligned with EN 16931. The legacy 1.0 is not |
| Conformance Level | EN16931 | The profile the invoice claims to meet, and therefore which keys the JSON must supply |
| Render Invoice On Pdf | True | Draw a readable page from the same data. With no File supplied, this is what gives the file its human half |
| File | empty | Where a base PDF with your letterhead would go |
Do not trust the grid for decimals. Airtable shows VATAmount 191 and GrossTotal 1196 because of the number field's precision setting, but the tokens carry 190.95 and 1195.95, and that is what reaches the invoice. Widen the precision before anyone tries to reconcile a column against an issued document.
Step 4: How do you write the invoice back to the record?
Flow so far: everything through the PDF4me step.
- Add Airtable > Update Record.
- Configure:
- Base
PDF4me Live Automations, TableZUGFeRD Requests - Record: the ID from the trigger
- Append attachments:
False - Document: the File Url from step 3
- Status:
Generated
- Base
- Leave every other field empty so nothing is overwritten.
Update Record configuration

The warning at the top is the one worth reading. Everything below it is empty on purpose.
"Possible Zap loop detected" is a real warning, not noise. This step writes to the table the Zap triggers on, so its own update could wake the Zap again. It does not here, because the update sets Status to Generated and the filter in step 2 only passes New. The filter and this update are one mechanism; change either and re-check both.
Step 5: How do you send the e-invoice to the buyer?
Flow so far: everything through the record update.
- Add Gmail > Send Email.
- Configure:
- To: the Email column from the trigger
- Subject:
Your e-invoiceplus the Invoice Number - Body type:
Html - Body: a short greeting naming the buyer, the invoice number and the total
- Attachments: the File Url from step 3
Send Email configuration

The attachment is the same File Url that step 4 wrote to Airtable, so the record and the email always carry the same file.
Run the Zap and Verify
- Publish the Zap.
- Add a row to
ZUGFeRD Requestswith a seller, a buyer, one line item, both dates and StatusNew. - Wait for the poll. All five steps should be green.
- Open the row:
Documentshould hold a PDF named after the invoice number, andStatusshould readGenerated. - Open the attachment. You should see a readable invoice page, and a ZUGFeRD validator should find EN 16931 XML inside the same file.
- Add a row with Status
Generatedand confirm the Zap stops at step 2.
In the captured run, version 1 completed successfully on Oct 24 2026 at 12:09:01 am, producing ZUGFeRD_RE-2026-0011.pdf for an invoice from Muster GmbH in Berlin to Test Kunde AG in Muenchen, ten units of Consulting at 100.50, totalling 1195.95 EUR.
What did you actually build? Compliant e-invoicing out of a database you already run, for the cost of five Zap steps. The buyer's system gets structured data, your record keeps the artefact it produced, and one Status field decides what goes out.
Common Variations You Can Add Without Rebuilding
How this compares to the other ways of issuing an e-invoice
Each row describes the alternative. The last row is this Zap.
| Comparison | Who runs it | Where the data comes from | What you maintain |
|---|---|---|---|
| E-invoicing platform vs this Zap | Finance, through a portal | Uploads or an integration | A per-document contract and a connection to it |
| ERP module vs this Zap | Finance, inside the ERP | The ERP's own ledger | Licences, and a migration to get your data in |
| Developer library vs this Zap | A developer, inside an application | Your database, through code | The code, the schema updates and the releases |
| This Zap | Anyone who can edit a Zap | The Airtable base the team already keeps | Five steps and one JSON object |
We also built the identical flow in Make. The differences are small but real: Make filters inside the trigger for free where Zapier spends a step, Make needs parseNumber around every money value where Zapier maps them straight through, and Make uploads the file as bytes where Zapier hands Airtable a URL.
Common questions
What is e-invoicing?
E-invoicing means issuing an invoice as structured data a machine can read, rather than as a picture of a page. The buyer's accounting system parses it and books it without anyone retyping, which is the point: the saving is on the receiving side, not yours.
A growing number of jurisdictions now require it for business and public-sector trade. The European standard EN 16931 defines the core set of fields, and formats like ZUGFeRD implement it.
What is electronic invoicing?
The same thing. "Electronic invoicing" tends to be the term in legislation and "e-invoicing" the term in product marketing, and both mean structured, machine-readable invoice data rather than a PDF attached to an email.
Worth being clear about what does not count: a scanned paper invoice is not electronic invoicing, and neither is an ordinary PDF. Without embedded structured data the receiver still has to read it.
Can Airtable create invoices?
Not compliant ones. Airtable holds the data and can lay it out in an interface or a printable view, but it cannot produce a PDF/A-3 carrying conformant EN 16931 XML, which is what a mandate asks for.
The split this Zap uses is the practical one: Airtable is the record, PDF4me produces the artefact, and the artefact comes back to the record as an attachment.
How does accounts payable automation work?
Three parts: intake, extraction and posting. Intake gets documents into one place, extraction turns them into fields, posting writes those fields into the ledger with an approval gate in front of it.
Hybrid e-invoices remove the middle part. When the XML is already inside the file, extraction is parsing rather than recognition, and that is why mandates keep pushing towards it. This Zap is the sending half of that arrangement.
Troubleshooting
Open the step's input in the Zap run and read it as JSON. An empty Airtable column leaves a key empty, and a money value that ended up quoted arrives as text where a number is expected. Both produce an object that looks fine and still fails conversion.
Conformance Level decides which fields the profile requires. Claiming EN16931 while the JSON omits keys that profile expects fails validation even though the file opens normally. Supply the missing keys or drop to a lower profile.
Step 4 is not setting Status, or it is setting a value the filter still passes. That is also the loop Zapier warns about on step 4: the Zap re-processing its own output. Check the filter and the update together.
Check Output Mode is XmlWithPdf and that steps 4 and 5 both take the File Url from step 3. Attaching anything else sends a page that looks right and carries nothing their software can read.
Next Steps
A mandate looks like a format problem and is really a data problem. If the invoice already exists as rows, most of the work is done.