Line-item tax_lines duplicated once per order line count

We’re seeing the same tax_lines duplication behaviour reported here: Observing an unexpected behavior in the Shopify orders/create (and orders/updated) webhook payload related to tax_lines at the line item level
Donal explained that when the fastrr checkout app creates an order via the Admin REST API and passes tax_lines at the order level, Shopify distributes that amount proportionally across all taxable line items. We wanted to confirm the exact pattern we’re seeing and ask whether this is expected, permanent behaviour, or something that’s being fixed.

Setup: checkout via Fastrr, tax config is a flat 5% IGST (India, interstate), single component, no CGST/SGST split, no overrides — see attached tax config screenshot.

What we found: for every Fastrr-checkout order we’ve checked, each line item’s tax_lines array contains exactly as many duplicate entries as there are line items in the whole order — not tied to discounts, bundles, or promo codes.

A manually-created order on the same store (not through Fastrr) with the same number of line items has exactly one tax_lines entry per item, as expected.

Our questions

  1. Is this the same “order-level tax_lines split across line items” behaviour Donal described? Or is it a separate issue?

  2. Is this permanent behaviour for orders created this way? Or does Shopify plan to fix it upstream, the way it fixed the Subscriptions API?

  3. We suspect duplication could also hit CGST and SGST orders (India’s two-part sales tax for sales within one state), not just IGST. Here’s our plan to handle it — group tax_lines entries by title and rate together, and count each distinct title+rate combination’s rate only once, even if it repeats:

    • Two IGST entries at 5% → counted as one 5% IGST.
    • A CGST entry at 2.5% and an SGST entry at 2.5% → still added, since the titles differ (2.5% + 2.5% = 5%).
    • Two entries with the same title but different rates — for example, stacked US state, county, and city tax — still added, since the rates differ.

    Is this the right way to handle it? Or is there a case where it would give the wrong number?

We can share full order files if that helps: Shopify Order with Multiple tax_lines - Pastebin.com

Hey @Jeet - thanks for sharing the Pastebin sample. I checked the payload, and this is does look to be expected for REST-created orders using order-level tax_lines.

In your sample, each item’s three ₹10.57 entries total ₹31.71. Across the three items, that totals ₹95.13, matching current_total_tax. We document this allocation here: Order

For totals, I’d use total_tax or currentTotalTaxSet. If you do need to reconstruct the total from tax_lines, the best thing to do would be to sum every returned price. Order-level tax lines are aggregated when both rate and title match, with price representing the combined amount for that group. Just out of curiosity, would you be open to sharing what you’re using this grouping for and why the order’s total_tax field doesn’t meet that need?

I can definitely take a closer look in the logs though if you’re able to share the response x-request-id from the API Response headers of the example call. I’d also recommend replacing the current Pastebin with a redacted version since it includes customer and order details - just wanted to mention that!

Thanks for checking @Alan_G

On why total_tax alone doesn’t cover our case: we generate GST tax invoices for Indian merchants. Indian GST law requires each line item to show its own GST rate and tax amount on the invoice, not just one number for the whole order. A single cart can mix line items with different HSN/SAC codes (the product tax codes GST law requires per line). In principle, those line items can carry different GST rates too. So we can’t collapse everything into the order total — we need a correct rate and amount for each line.

Our plan to handle taxes on invoice:

  • GST rate to print on the invoice: group tax_lines entries by title and rate together, and count each distinct group’s rate once. For the case above, that gives 5%. It would still add CGST + SGST correctly (different titles), or stacked jurisdiction taxes correctly (same title, different rate), if we ever see those. As our system will calculate the tax price automatically if taxable price and tax rate are present.

    Let me know your thoughts on this.

Hey @Jeet - thanks for clarifiying.

Just confirming on our end, when an order is created through the REST Admin API with tax_lines at the order level, Shopify splits each entry proportionally across every taxable line item. Your N-per-line pattern is what you’d get if the checkout app is sending one order-level IGST entry per line item rather than a single combined one. One clarification on my earlier reply - those order-level entries aren’t merged when title and rate match, which is why you see duplicates rather than one line. You can confirm by checking the order-level tax_lines array on one of these orders; three identical IGST entries on a three-item order would be the source.

This is documented behaviour for REST-created orders. The Order resource supports tax_lines on each line_items[] entry instead of at the order level (it has to be one or the other). If Fastrr passes tax per line item, Shopify stores it exactly as given with no distribution, and you’d get the precise per-line rate and amount you need for GST invoices. I’d raise that with Fastrr directly if possible.

On the grouping approach, it’ll work for carts where every item shares the same rate, but I’d be cautious relying on it more broadly. With one item at 5% and one at 12% sent as order-level tax lines, both rates get distributed onto both line items, so your rule would read 17% on each line and the 5% item’s tax_lines would include a share of the 12% item’s tax. Nothing in the payload ties a distributed entry back to its original line, so it isn’t recoverable client-side - that’s essentially what happened in Donal’s thread with the 5% + 3% case. In the meantime, since your system already calculates tax from taxable price + rate, I’d source the per-line GST rate from your own product/HSN mapping and use Shopify’s total_tax as a reconciliation check, rather than deriving the rate from the distributed entries.

Hope this helps a bit, let me know if I can clarify anything on our end here as always :slight_smile: