ZUGFeRD电子发票(基于Airtable,使用Zapier:筛选行、构建 JSON、通过电子邮件发送混合 PDF

PDF4me Create ZUGFeRD Invoice是一个Zapier操作,它将结构化发票数据转换为混合PDF/A-3电子发票。它读取Airtable中的一行数据,将 JSON 对象转换为嵌入可读 PDF 中的EN 16931 XML,将文件写回记录,并通过电子邮件发送给买方。
电子发票强制要求最初被视为文件格式问题,最终却被简化为采购问题:选择一个平台,按单付费,然后将数据迁移到该平台。这种解决方案在大规模应用时或许合理,但对于每月仅从现有数据库中开具二十张发票的团队来说却显得荒谬。另一种方案并非手动编写 XML 代码,而是将发票描述为 JSON 格式,并由其他系统生成符合规范的文件。
Airtable一行包含发票信息:卖家、买家、单个项目以及总计。将Status设置为New后,Zap 会获取该发票,检查该字段,并将 JSON 对象传递给PDF4me会生成一个PDF/A-3格式的文件,该文件既可供人阅读,也可由机器解析,并附加到发票记录中发送给买家。无需平台订阅,无需 XML 处理,数据也始终保留在数据库内。
基于原因的问答
Why describe the invoice as JSON rather than XML?因为跨行业发票的语法冗长、嵌套层级深,而且对每个代码的位置要求非常严格。JSON 对象用更少的空间表达相同的信息,键也更符合业务术语, PDF4me可以从中生成符合规范的 XML。最容易出错的部分往往是你没有维护的部分。
Why does the hybrid file matter?因为发票有两个受众。买方系统读取嵌入的 XML 并自动记账,无需任何人手动输入;应付账款人员打开同一个文件,看到一页内容。一个文档就能满足两者的需求,这就是原因。FeRD指定使用混合格式,而不是单独的 XML 格式。
Why put a Filter in front of the invoice step?因为开具发票是不可逆的操作。如果一个 Zap 程序在每条新数据行都触发,最终会在处理完一条未完成的数据行时触发,并向客户发送一封包含空白行的文档。而过滤器则将开具发票变成了一个需要明确操作的过程:用户将Status设置为New,这便构成了开具发票的指令。
Why keep the invoice data in Airtable at all?因为它通常是已在系统中跟踪的工作的副产品:项目、客户、约定的价格。为了满足文件格式要求而将其导入发票产品,意味着要永远在两个系统中维护同一个客户的信息,而格式要求实际上并没有要求你这样做。
您将获得
输入:包含发票编号、日期、包含增值税号的卖家信息块、买家信息块、一个明细项目和总计的Airtable行, Status设置为New。输出:该记录对应的ZUGFeRD PDF/A-3文件,并发送到买家的收件箱。

每张发票对应一行。这里的每一列都会成为 Zap 发送的 JSON 中的一个键。

买家看到发票,他们的会计系统看到发票中的 XML 数据。
你需要什么
- A Zapier account一个允许多步骤 Zap 的方案。Filter by Zapier已内置并计为一步。
- PDF4me API密钥. 获取您的 API 密钥.
- An Airtable base捕获的基础是
PDF4me Live Automations,其中包含一个名为ZUGFeRD Requests的表,该表包含发票抬头、包含增值税 ID 的卖家块、买家块、行项目字段、 NetTotal、 VATAmount和GrossTotal、电子邮件列、 Status字段和名为Document附件字段。 - A Gmail account已连接到Zapier。
- Your seller details including a VAT ID它们来自列,因此一个数据库可以为多个法人实体开具发票。
Zap概览
- New Record (Airtable) 在
ZUGFeRD Requests中每出现一个新行时触发。 - Filter conditions ( Filter by Zapier)仅在Status恰好为
New时继续。 - Create ZUGFeRD Invoice ( PDF4me)将 JSON 转换为混合 PDF。
- Update Record ( Airtable)会写入文件、状态以及指向该行的链接。
- Send Email ( Gmail)将电子发票发送给买方。
Zap 完整概览

与 Swiss QR Zap 的五步形状相同。只有中间的PDF4me步骤有所不同。
步骤 1:如何从新的Airtable行触发 Zap?
目前流程:尚未启动,这是触发点。
- 创建一个 Zap,然后选择Airtable > New Record。
- 选择Base
PDF4me Live Automations和TableZUGFeRD Requests。 - Zapier。Zapier 报告在Airtable中找到 1 条新记录,并且这些列在下游可用。
投票徽章显示剩余2 分钟,这是计划中的时间,而不是此步骤中的时间。
步骤 2:如何阻止 Zap 对未完成的行进行开票?
目前为止的流程: Airtable触发器。
- Filter by Zapier > Only continue if。
- 建立一条规则: 1. Status / (文本) Exactly matches /
New。 - 测试一下。
Filter conditions配置

绿色方框标明了允许记录通过的字段。对应的黄色方框标明了阻止记录通过的字段。
Tip.Exactly matches区分大小写和空格,所以new和New 如果末尾带有空格,则每行都会静默失败。 Make Status改为单选下拉列表而不是自由文本,则不会出现此问题。
步骤 3:如何将行转换为ZUGFeRD发票?
目前流程:触发器和过滤器。
- 添加PDF4me > Create ZUGFeRD Invoice。
- 设置输出选项:
- File Name:
ZUGFeRD_+ Invoice Number +.pdf - Input Format:
JSON - Output Mode:
XmlWithPdf - Zugferd Version:
2+ - Conformance Level:
EN16931 - Render Invoice On Pdf:
True - 除非您提供自己的信笺抬头,否则请将File留空。
- File Name:
- 将对象粘贴到Invoice Json Data中,并将每个Airtable字段映射到该对象:
{
"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"
}
}
TypeCode三个部分值得注意。TypeCode 380是商业发票的代码,是固定的。UnitCode C62是联合国/欧洲PaymentReference委员会UnitCode UN/ECE) 编码,表示“一个单位”,用于表示服务时Payment或单位。PaymentReference 是付款时买方提供的文本,这里就是发票号码。
Create ZUGFeRD Invoice配置

每个值都是一个Airtable标记。请注意VAT Amount为 190.95, Gross Total 1195.95,尽管表格中显示为 191 和 1196。
每个设置决定什么
| 场地 | 这里的价值 | 它控制着什么 |
|---|---|---|
| Input Format | JSON | 请提供结构化对象,而不是现成的 XML 或 CSV 行。 |
| Output Mode | XmlWithPdf | 返回一个混合文件。XmlOnly 仅返回发票 XML 文件XmlOnly |
| Zugferd Version | 2+ | 2.x 代产品符合EN 16931标准,而旧版 1.0 产品则不符合。 |
| Conformance Level | EN16931 | 发票声称符合的规范,以及因此 JSON 必须提供的键。 |
| Render Invoice On Pdf | True | 根据相同的数据绘制一个可读页面。如果没有提供文件,这就是赋予文件人类感知能力的部分。 |
| 文件 | 空的 | 带有您信头的基础 PDF 文件将放在哪里? |
Do not trust the grid for decimals.由于数字字段的精度设置, Airtable显示VATAmount 191, GrossTotal 1196,但实际的标记值分别为190.95和1195.95,这才是发票上显示的数值。在任何人尝试将列与已开具的单据进行核对之前,请提高精度设置。
步骤 4:如何将发票重新写入记录?
目前流程:所有步骤都已完成PDF4me步骤。
- 添加Airtable > Update Record。
- 配置:
- 根据
PDF4me Live Automations, 桌子ZUGFeRD Requests - Record:触发器中的ID
- Append attachments:
False - Document:步骤 3 中的File Url
- Status:
Generated
- 根据
- 其他字段留空,以免内容被覆盖。
Update Record配置

最上面的警告信息最值得一读。它下面的内容故意留空。
"Possible Zap loop detected" is a real warning, not noise.此步骤会将数据写入 Zap 触发的表,因此其自身的更新可能会再次唤醒 Zap。但此处不会,因为更新会将Status设置为Generated,而步骤 2 中的筛选器仅允许New通过。筛选器和此更新是同一机制;更改其中任何一个都需要重新检查。
第五步:如何向买家发送电子发票?
目前流程:所有操作均已完成记录更新。
- 添加Gmail > Send Email。
- 配置:
- To:触发器中的Email列
- Subject:
Your e-invoice及Invoice Number - Body type:
Html - Body:简短的问候语,包括买方姓名、发票号码和总金额。
- Attachments:步骤 3 中的File Url
Send Email配置

附件是步骤 4 写入Airtable File Url,因此记录和电子邮件始终包含同一个文件。
运行 Zap 并验证
- Publish Zap。
- 向
ZUGFeRD Requests中添加一行,其中包含卖家、买家、一个项目、两个日期和StatusNew。 - 等待投票结果。所有五个步骤都应该显示绿色。
- 打开该行:
Document应包含一个以发票编号命名的 PDF 文件,Status应显示Generated。 - 打开附件。您应该可以看到一个可读的发票页面,并且ZUGFeRD验证器应该在同一个文件中找到EN 16931 XML 代码。
- 添加一行Status
Generated,并确认 Zap 在步骤 2 停止。
在捕获的运行中,版本 1 于 2026 年 10 月 24 日凌晨 12:09:01 成功完成,生成了ZUGFeRD_RE-2026-0011.pdf这是一张从Berlin Muster GmbH开给Muenchen Test Kunde AG发票,包含 10 个单位的Consulting,每个单位 100.50,总计 1195.95 欧元。
What did you actually build?只需五个 Zap 步骤,即可从您现有的数据库中生成合规的电子发票。买方系统将获得结构化数据,您的记录将保留生成的文档,而一个Status字段即可决定哪些内容需要发送。
无需重建即可添加的常见变体
与其他开具电子发票的方式相比,这种方式有何不同?
每一行都描述了一种替代方案。最后一行就是这个 Zap。
| 比较 | 谁在运营它 | 数据来源 | 你所维护的 |
|---|---|---|---|
| 电子发票平台 vs 这个 Zap | 通过门户网站进行金融交易 | 上传或集成 | 按文件签订合同及其关联 |
| ERP模块与此Zap | ERP系统中的财务部分 | ERP自身的账簿 | 许可证,以及将您的数据迁移到新系统 |
| 开发者库 vs 此 Zap | 应用程序内部的开发人员 | 通过代码实现您的数据库 | 代码、架构更新和版本发布 |
| 这个 Zap | 任何能够编辑 Zap 的人 | 团队已经维护的Airtable数据库 | 五个步骤和一个 JSON 对象 |
我们还建造了the identical flow in Make. 差异虽小但却真实存在: Make在触发器内免费使用过滤器,而Zapier则需要额外步骤; Make需要在每个货币值周围parseNumber,而Zapier直接映射; Make将文件作为字节上传,而Zapier则向Airtable提供 URL。
常见问题
什么是电子发票?
电子发票是指以机器可读取的结构化数据形式开具发票,而不是以纸质图片的形式。买方的会计系统会自动解析并记账,无需人工重新输入,这正是关键所在:节省成本的是收款方,而不是您。
越来越多的司法管辖区现在要求商业和公共部门贸易必须使用这种凭证。European standard EN 16931定义了核心字段集, ZUGFeRD等格式实现了它。
什么是电子发票?
意思相同。“电子发票”通常是法律术语,而“电子发票”是产品营销术语,两者都指的是结构化的、机器可读的发票数据,而不是作为电子邮件附件发送的PDF文件。
需要明确哪些形式不算数:扫描的纸质发票不属于电子发票,普通的PDF文件也不行。如果没有嵌入结构化数据,接收方仍然需要阅读才能理解。
Airtable可以创建发票吗?
不符合规范。Airtable 可以Airtable数据,也可以在界面或可打印视图中显示数据,但它无法生成符合EN 16931 XML 标准的PDF/A-3文件,而这正是规范要求的。
此 Zap 使用的拆分方式很实用: Airtable是记录, PDF4me生成工件,工件作为附件返回到记录中。
应付账款自动化是如何运作的?
分为三个部分:接收、提取和过账。接收将文档集中到一个地方,提取将其转换为字段,过账将这些字段写入账本,并经过审批流程。
混合式电子发票省去了中间环节。当 XML 数据已存在于文件中时,提取过程就变成了解析而非识别,这也是为什么相关法规不断推动采用这种模式的原因。这个 Zap 应用正是这种混合模式的发送部分。
故障排除
在 Zap 运行中打开步骤的输入并将其读取为 JSON。如果Airtable列为空,则对应的键也会为空;此外,原本应该为数字的金额值会被转换为文本。这两种情况都会生成看起来没问题的对象,但转换仍然失败。
Conformance Level决定了配置文件所需的字段。如果 JSON 文件缺少EN16931配置文件所需的键,即使文件可以正常打开,验证也会失败。请补充缺失的键,或者降低配置文件的级别。
步骤 4 没有设置Status,或者设置的值仍然会被过滤器接受。这也是Zapier在步骤 4 中发出警告的原因:Zap 重新处理了自己的输出。请同时检查过滤器和更新操作。
检查Output ModeXmlWithPdf步骤 4 和 5 都采用了步骤 3 中的File Url。附加其他任何内容都会发送一个看起来正常的页面,但其中没有任何内容是他们的软件可以读取的。
后续步骤
授权书看起来像是格式问题,但实际上是数据问题。如果发票数据已经以行的形式存在,那么大部分工作就完成了。