Skip to content

Tax Providers

A family of apps that calculate transaction tax on Hantera orders using an external tax engine, and — where the provider supports it — record the resulting documents for filing and audit.

Tax providers plug into the order pipeline rather than replacing it. Hantera's native tax behaviour (a taxFactor percentage per order line and delivery) keeps working for everything a tax app doesn't cover: destinations outside its enabled countries, channels it isn't enabled for, and any period where the app is switched off.

Available tax apps

  • Avalara AvaTax — US sales tax and Canadian GST/HST/PST/QST via Avalara's AvaTax service. Calculates tax on carts and orders, records SalesInvoice and ReturnInvoice documents from Hantera invoices, voids them on cancellation, and ships portal tooling for tax-code lookup, entity/use codes, and address validation.

How a tax app participates in an order

Every tax app in this family follows the same three conventions. They are deliberately vendor-neutral — nothing in Hantera core or in the Commerce app knows about a specific tax provider.

1. Absolute tax amounts, not rates

A tax app writes the exact amounts the tax engine returned:

  • setOrderLineTax { orderLineId, salesTax } per order line
  • setShippingTax { deliveryId, tax } per delivery

These are absolute currency amounts. Setting salesTax clears any taxFactor on the line, so the engine's figure is what appears on invoices — the app never re-derives tax from a percentage.

This matters for jurisdictions where tax isn't a clean percentage of the line: US sales tax combines state, county, city and special-district rates, and rounding is per jurisdiction.

2. The taxChecksum order field

External tax engines charge per call and rate-limit aggressively, so a tax app must not call out on every order render.

The convention is a single order dynamic field:

FieldTypeMeaning
taxChecksumtextAn opaque digest of the tax-relevant inputs as they stood when tax was last calculated.

On each order calculation the app recomputes the digest from the current inputs (lines, quantities, amounts, tax codes, addresses, customer, origin) and compares:

  • Same — the tax already on the order is up to date. No call.
  • Different — something tax-relevant changed. One call, then store the new digest.

Only the tax app computes or interprets the value. Everything else treats it as opaque and simply copies it along.

3. Cart tax persistence (Commerce)

The Commerce app stores calculated tax on the cart and replays it into every render, so a storefront can render a cart repeatedly for free:

  1. Commerce persists taxData on the cart — per-item tax, shipping tax, and the taxChecksum.
  2. Cart-to-order replays it onto the new order's lines and deliveries, along with the checksum.
  3. The tax app recomputes the checksum, finds it unchanged, and makes no call.
  4. When something tax-relevant does change, the app recalculates and Commerce writes the fresh values back onto the cart.

The net effect is one call per tax-relevant mutation and zero per render. See Cart Dynamic Fields for the stored shape.

Without Commerce

The checksum gate works on its own — it's a property of the tax app and the order, not of Commerce. Without the cart persistence layer you simply lose the free-render optimisation.

Failure behaviour

Tax apps in this family never block an order. If the tax engine is unreachable or rejects a request:

  • The order keeps whatever tax it already had (or falls back to native taxFactor behaviour).
  • The order is tagged so operators can find affected orders.
  • The provider's exact error code and message are written to the order timeline.
  • The checksum is not updated, so the next mutation retries.

An order that can't be taxed is still an order. Reconciling it is an operations problem, not a reason to fail a customer's checkout.

© 2026 Hantera AB. All rights reserved.