Skip to content

Integration

Formfeed for WooCommerce

WooCommerce keeps your orders: the products, the shipping, the fees, the coupons and the VAT of each rate. A webhook on Order updated and one function turn every completed order into a ZUGFeRD / Factur-X e-invoice, a PDF/A-3 with the invoice as XML inside, validated before it reaches you. No plugin is installed in the shop, and nothing is calculated again: the e-invoice states what the order says.

No plugin to install: a webhook handler and one function do it today.

Free plan with 100 units a month, no credit card

One webhook, one function

WooCommerce sends order.updated for every change of an order. The handler checks the signature, reads the completed order through the REST API, turns it into the _invoice block and renders it with a template that prints the block, such as the E-invoice example in the app; the render id it writes into the order’s meta data keeps every later update from making a second one. The recipe, with the whole function and the same in n8n, is in the documentation.

WooCommerce webhook: order.updated, completedJavaScript
const order = await shop('GET', `orders/${id}`);
if (order.meta_data.some((meta) => meta.key === 'formfeed_render')) return;

const render = await formfeed.renders.create(
  {
    template: 'e-rechnung',
    data: { _invoice: wooToInvoice(order, config) },
    post: { einvoice: {} },
    filename: `${order.number}.pdf`,
  },
  { idempotencyKey: `woocommerce-${id}` },
);
await shop('PUT', `orders/${id}`, {
  meta_data: [{ key: 'formfeed_render', value: render.id }],
});

What the function takes from the order

  • Products, shipping and fees as lines, each with the VAT it carries. A coupon stays visible as an allowance on its line, and a negative fee is a negative quantity.
  • The VAT of each rate as the order states it. Rates above 0 % are category S; a rate of 0 % and a customer WooCommerce exempts from VAT become the category you state once, because that choice is yours and your tax adviser’s.
  • The order’s total. The lines and their VAT have to come to it, and an order WooCommerce has a payment date for is stated as paid.
  • The buyer from the billing address, with the VAT ID your VAT number plugin keeps in the order’s meta data.

It refuses rather than guesses

Compound taxes, a line with two taxes, a rate of 0 % without a category and totals a cent off, which rounding tax at subtotal level can cause, make the function stop with the order’s number, instead of making an e-invoice that differs from the order. The API then checks the block against EN 16931 before anything is rendered or charged. When it refuses one, the cause is data missing in the order, most often a billing address without a country, and the refusal names every field and the rule it breaks.

Worth knowing before you build it

  • Live e-invoices need the Starter plan or higher. While you build, a test key makes valid e-invoices with the test mark, up to 20 a day on the Free plan.
  • The order number is the invoice number, unless your shop numbers its invoices separately and passes its own.
  • A refund needs a credit note, which the function does not make.
  • Formfeed makes and validates the file. Sending it to your customer and archiving it stay with you: Formfeed keeps the file only for the workspace’s retention period (30 days on Starter, a year on Pro), not for the years an invoice has to be kept.

More integrations

Start rendering today

The free plan includes 100 units a month and free test renders. Change plans when you need more.