I’m building a workflow that turns WooCommerce orders into a PDF report. Someone picks a period in a form (daily up to yearly), n8n pulls the orders, builds an HTML report with charts, renders it to PDF and emails it. The happy path is the easy part. The edge cases are where the time goes, so here are the ones I think are worth sharing while it’s still in progress.
1. “Last 7 days” needs an exact definition
I settled on complete local days. Every period ends at the start of today in the store’s timezone, so yesterday is the last included day. Then both boundaries are converted to UTC and filtered as a half-open interval: start <= date_created_gmt < end. An order created exactly at midnight lands in one report only. Never in two, never in none.
2. Don’t rely on the API date filter alone
The after and before parameters are a good first cut, but I apply the exact interval again in a Code node afterwards. It costs nothing and removes any doubt about inclusive vs exclusive boundaries.
3. Pagination is all or nothing
per_page=100, loop on page until X-WP-TotalPages, then deduplicate by order ID, because an order can shift between pages if a new one arrives mid-run. If any page fails, the workflow stops. A report that silently misses page 2 is worse than no report at all.
4. “Paid” and “completed” are different questions
Order status tells you where the order is now. Whether a payment was recorded is a separate fact, so I use date_paid_gmt as the payment indicator and keep it independent from status. Refunds are deducted from the orders they belong to, and if refund data is incomplete, the net shows as “unknown” instead of a confident wrong number.
5. Say what the report actually is
It’s a snapshot: orders created in the period, with whatever status they have at the moment the report runs. Run it again tomorrow and a “processing” order may have become “completed”. One sentence in the PDF explaining this saves a lot of “why did the numbers change” messages.
6. Check the currency unit against a real order
In Iran, shop prices are stored in rial or toman depending on how the store was set up, and the two differ by 10x. So I’m comparing a real order in the admin with its API total before deciding anything. Guessing from the currency label is how you end up with a report that’s off by an order of magnitude.
7. Charts as inline SVG
The PDF renderer gets plain HTML with SVG charts generated in a Code node. No chart service, no external requests, and it renders the same way every time.
8. Customer data stays in the attachment
Buyer names and phone numbers only exist inside the PDF. They don’t go into the email body, error alerts or pinned data, and execution data gets pruned so nothing is kept longer than needed.
For those of you doing WooCommerce reporting in n8n: do you pull from the REST API like this, or query the database directly? And how do you handle refunds that happen after the reporting period has closed?