← 文档 / 指南
使用 Peppol 发送和接收发票
将您公司自己的 Peppol 接入点(Recommand、Storecove 或 e-invoice.be)连接到 Nordlet,通过 Peppol 发送发票和贷记单,跟踪其交付状态,并将接收到的电子发票转为采购发票。
Peppol 是企业与公共机构之间交换结构化电子发票的欧洲网络。每张发票都从发送方的接入点传输到接收方的接入点。Nordlet 负责构建 Peppol BIS Billing 3.0 发票和贷记单,并通过您公司自己的接入点账户进行发送和接收。
Peppol 规定了接入点之间如何交换文档,但并未规定您的软件如何与您自己的接入点通信,因为每个提供商都有自己的 API。Nordlet 支持以下提供商:
| 提供商 | 发送 | 交付状态 | 接收 |
|---|---|---|---|
| Recommand | 支持 | 通过 webhook 和按需查询 | 支持 |
| Storecove | 支持 | 仅通过 webhook | 支持 |
| e-invoice.be | 支持 | 通过 webhook 和按需查询 | 支持 |
如果没有接入点,Nordlet 仍然会为您开具的每张发票和贷记单构建 Peppol 文件,供您下载并通过其他方式传递,但它不会发送或接收任何内容。
前提条件
- 在上述某个提供商处拥有账户,并且您的公司已通过该提供商在 Peppol 注册。每个提供商的服务均按其价目表收费。
- 在 Nordlet 中填写公司的增值税号(VAT number)、注册号或 Peppol ID(路径:账户 [Account] -> 公司 [Companies] -> Peppol ID)。您向其发送发票的每个客户也需要在其合作伙伴卡片中填写其中一项信息。
连接您的接入点
打开 账户 (Account) -> 合规性 (Compliance) -> 欧盟 (EU) -> Peppol 接入点 (Peppol access point),在 提供商 (Provider) 中选择您的提供商,按照下文所述填写该提供商的字段并保存。除非您的提供商为您提供了不同的地址,否则请将 API 基础 URL (API base URL) 保持为空。保存后,页面将显示您公司的 Webhook URL:https://api.nordlet.com/v1/peppol/webhooks/{provider}/{companyId},其中 {provider} 为 recommand、storecove 或 e-invoice-be,{companyId} 为您的公司 ID。每个 Nordlet 公司都有其专属的 webhook URL。
Nordlet 仅在能够验证调用方知晓您的 webhook 密钥时才接受 webhook 调用,因此来自非您接入点账户的调用将被拒绝。Nordlet 仅在调用您的接入点时连接公共互联网地址。
Recommand
- 在 Recommand 中打开您的公司,将公司的 公司 ID (company ID) 复制到 接入点账户 ID (Account ID at the access point) 中。
- 在 Recommand 中创建一个 API 密钥 (API key),并将该密钥及其密钥串复制到 API 密钥 (API key) 和 API 密钥串 (API secret) 中。
- 编造一段只有您和 Recommand 知晓的较长的随机文本,并将其输入到 Webhook 密钥 (Webhook secret) 中,然后保存。
- 在 Recommand 中为您的公司创建一个 webhook,URL 填写 Nordlet 显示的 Webhook URL,并使用相同的 webhook 密钥。
Recommand 会使用该密钥对每个 webhook 调用进行签名。
Storecove
- 在 Storecove 中为您的公司创建一个 法律实体 (legal entity),设置为既可发送也可接收,并将其 ID 复制到 接入点账户 ID (Account ID at the access point) 中。
- 在 Storecove 的 API 密钥 (API Keys) 下创建一个 API 密钥,并将其复制到 API 密钥 (API key) 中。将 API 密钥串 (API secret) 保持为空。
- 编造一段较长的随机文本,并将其输入到 Webhook 密钥 (Webhook secret) 中,然后保存。
- 在 Storecove 中设置一个推送 webhook,URL 填写 Nordlet 显示的 Webhook URL,并使用 HTTP Basic 认证进行保护:用户名任意,密码即为 webhook密钥。
Storecove 没有用于查询已发送文档状态的接口,因此对于 Storecove,交付状态仅来自其 webhook,且发票页面上没有 检查 Peppol 状态 (Check Peppol status) 按钮。Storecove 沙盒账户在 Peppol 测试网络上发送;生产环境 API 密钥需从 Storecove 客服获取。
e-invoice.be
- 在 e-invoice.be 应用的 API 设置 (API Settings) 下,将您公司的 API 密钥 (API key) 复制到 API 密钥 (API key) 中。将 接入点账户 ID (Account ID at the access point) 和 API 密钥串 (API secret) 保持为空并保存。
- 使用 e-invoice.be API (
POST https://api.e-invoice.be/api/webhooks/) 创建一个 webhook,URL 填写 Nordlet 显示的 Webhook URL,事件选择document.received、document.sent和document.sent.failed。 - 将 API 为新 webhook 返回的
secret复制到 Nordlet 的 Webhook 密钥 (Webhook secret) 中并再次保存。
e-invoice.be 会使用该密钥对每个 webhook 调用进行签名。e-invoice.be 的沙盒公司会通过电子邮件发送本应通过 Peppol 发送的文档。
发送发票
- 开具发票或贷记单。
- 检查客户的合作伙伴卡片中是否已填写 Peppol ID、增值税号或注册号。
- 在发票页面的 交付 (Delivery) 部分,点击 通过 Peppol 发送 (Send via Peppol) 并确认。“交付”部分显示在尚未付款的已开具发票上,且该按钮仅在接入点已连接时才会显示。
Nordlet 构建 Peppol 文件并将其交由您的接入点处理。随后,发票页面将显示 Peppol 交付 (Peppol delivery) 部分:
| 状态 | 含义 |
|---|---|
| pending | 已交由接入点处理,客户的接入点尚未确认 |
| delivered | 客户的接入点已确认收到发票 |
| rejected | 客户拒绝接收发票,原因显示在状态下方 |
| failed | 发票无法送达;当接入点提供原因时,原因会显示在状态下方 |
当接入点通过其 webhook 报告状态变更时,状态会自动更新。检查 Peppol状态 (Check Peppol status) 会立即向 Recommand 或 e-invoice.be 查询当前状态;对于 e-invoice.be,它还会读取客户的发票响应,如果遭到拒绝(响应代码为 RE),则显示为拒绝。纠正原因后,可以重新发送被拒绝或失败的发票。当接入点直接拒绝发票(例如因为客户未在 Peppol 注册)时,Nordlet 会显示原因,并且发票保持未发送状态。
发票页面顶部的 Peppol XML 按钮用于下载相同的 Peppol 文件而不进行发送。
根据 Peppol 规则的要求,欧盟境内交易(intra-EU supply)将开票日期作为交付日期,并将客户的国家作为交付国家。
接收发票
当接入点通过其 webhook 报告收到文档时,Nordlet 会从接入点下载 Peppol 文件。您公司收到的发票和贷记单将显示在 采购 (Purchases) -> 文档捕获 (Document capture) 中,并标记为通过发送方的 Peppol ID 从 Peppol 接收。Nordlet 会自行读取 Peppol 文件,因此接收过程不会消耗文档识别额度。
- 打开收到的文档。
- 检查供应商、日期和明细行;从您的合作伙伴中选择供应商或新建供应商。
- 点击 保存草稿 (Save draft)。Nordlet 会创建采购发票草稿(若收到的是贷记单,则创建采购贷记单草稿),并附带原始的 Peppol 文件。您可以像处理任何其他采购发票一样对其进行入账。
Nordlet 采购发票明细行不能为负数。针对整张文档的折扣、费用以及负数明细行,会按相同的税率分摊到各个明细行中。如果某个金额无法由其税率对应的明细行承载(例如退货商品的税率在发票的其他明细行中不存在),则会显示在第二个表格中:对于收到的发票,显示为 贷记单明细行 (Credit note lines);对于收到的贷记单,显示为 发票明细行 (Invoice lines)。这些明细行将作为同一供应商的第二个文档保存:一张针对新发票的采购贷记单(编号为 "<文档编号>-CR"),或是一张编号为 "<文档编号>-INV" 的采购发票。这两份文档组合在一起,其总额等于所接收文档的总额。
检查客户是否在 Peppol 上注册
通过带有 partnerId 或 participantId(格式为 "POST /v1/peppol/participants/lookup 请求,可以向 Peppol 网络查询接收方是否已注册以及其接受哪些文档。此功能在没有接入点的情况下也可以运行。
通过 API 执行相同操作
| 任务 | 调用 |
|---|---|
| 连接接入点 | POST /v1/declarations/configs/update,参数包含 system: "peppol" 以及包含 provider(recommand、storecove 或 e-invoice-be)、accountId、apiKey、apiSecret、webhookSecret 和可选的 apiBaseUrl 的 config 对象 |
| 接收接入点的 webhook | 由接入点调用的 POST /v1/peppol/webhooks/{provider}/{companyId} |
| 下载 Peppol 文件 | POST /v1/sales/invoices/peppol-xml |
| 发送 | POST /v1/sales/invoices/peppol-send(无接入点时返回 422) |
| 读取交付状态 | POST /v1/sales/invoices/peppol-status(Storecove 调用返回 422);发票包含 peppolMessageId、peppolStatus、peppolDetail、peppolSentAt、peppolCheckedAt 字段 |
| 查找接收到的文档 | POST /v1/capture/documents/list;接收到的文档包含 provider: "peppol" 和 senderId |
| 将文档转为采购发票 | POST /v1/capture/documents/confirm,包含用于第二个文档的 oppositeLines 参数 |
Webhook 事件:sale_invoice.peppol_sent、sale_invoice.peppol_delivered、sale_invoice.peppol_rejected、sale_invoice.peppol_failed 和 document_capture.peppol_received。有关错误处理、幂等性和 webhook 的详细信息,请参阅API 约定。