Skip to main content

Tax & Compliance

What it is, and what it is not

It doesIt does not
Recompute what tax should have been chargedSet the tax charged at checkout
Reconcile that against what Shopify collectedOverride Shopify's tax settings
Track registrations, exemptions and rate overridesFile on your behalf without your explicit action
Produce statutory returns and accountant exportsReplace your accountant
Monitor economic-nexus thresholdsGive tax advice

The distinction matters. Changing checkout tax requires Shopify's restricted Tax Calculation API and is deliberately out of scope. What this gives you instead is the thing most stores lack entirely: an independent second opinion on whether the tax you collected was right, computed from your own registrations and rate rules rather than from Shopify's defaults.

The nine tabs

TabWhat it is for
OverviewPeriod KPIs, action centre, nexus watch and data readiness
CalculatorCompute a supply without persisting it — for checking a rule
ReconciliationThe worklist of discrepancies between computed and collected
Filing & closeThe obligation calendar, period close and statutory exports
Registrations & nexusYour tax IDs per jurisdiction, and threshold monitoring
ExemptionsExemption and reverse-charge certificates
Rates & rulesEffective-dated rate overrides and product tax classes
AuditEvery mutation, with the actor
SettingsProvider, tolerance, FX and engine configuration

Supported regimes

RegimeCoverageNotes
India GSTCGST + SGST for intra-state, IGST for inter-statePlace of supply from the buyer's state; GSTIN checksum validated
EU VAT27 member statesOSS and reverse charge; per-state standard and reduced rates
UK VATStandard, reduced, zeroImport VAT threshold on consignments at or below £135
US sales taxDestination-based, nexus-gatedState defaults offline; county, city and special-district rates come from the tax provider
CanadaGST, HST, PST and QST by provinceDestination-based
APAC GSTAustralia, Singapore, New ZealandSingle-rate GST with per-country registration thresholds

Adding a regime is a plugin, not a rewrite. Each implements the same interface — resolve the supply, determine the rate, build the tax components, apply rounding — so the rest of the engine is unchanged.

How rates are resolved

Rates come from three layers, in order:

  1. Your effective-dated overrides. A rate you enter with a start date wins for supplies on or after that date.
  2. The tax provider. For US local rates — county, city, special district — where a static table cannot be correct.
  3. Statutory defaults. Baked-in rates per regime as a fallback.

This is why a rate change is normally a dated override rather than a support ticket: your override is the top layer and takes effect from the date you set.

The provider layer is metered — a TTL cache, a daily spend cap and a circuit breaker — so a provider outage degrades to the statutory default with the result flagged as approximate, rather than failing the computation.

Computation is idempotent

Each computation is keyed by a hash over its canonical inputs plus the engine version and the rate epoch. The same order, computed twice, produces the same immutable record rather than a second row.

Two consequences worth knowing:

  • Redelivered webhooks are safe. Shopify redelivers on any non-2xx, and a redelivery cannot double-count.
  • Descriptive fields do not affect the key. Buyer name, customer ID and email are carried on the computation for reporting but deliberately excluded from the hash — enriching an order with a name must not spawn a duplicate computation.

Money is computed in decimal throughout. Component splits assign the rounding residue to the last component, so the components always sum exactly to the total, and a violated invariant fails closed rather than being written.

Multi-currency

Every headline number is normalised to a reporting currency you pick at the top of the page, and period KPIs are computed from FX-anchored columns.

Why this is not optional

You cannot sum mixed currencies. A store selling in five currencies whose dashboard adds the raw amounts produces a number that is not wrong by a percentage — it is meaningless. Every aggregate here runs against a normalised anchor, and when a rate is unavailable the row is reported as unanchored rather than silently included at the wrong scale.

When a filing period is finalised, its FX rates are snapshotted, so regenerating a return next year reproduces the same figures.

Getting data in

SourceWhen
Order webhooksLive — orders and refunds compute as they happen
Historical backfillOn demand, per period, from the Filing tab
RefundsCredit notes compute as negative amounts

A period before you installed the app is structurally empty until you backfill it. The Filing tab's Import orders for this period action fetches the period's orders and runs them through the same pipeline, skipping any already computed — so it is safe to re-run and cannot double-count.

Permissions

Tax is governed by its own permission set, all at Pro and above:

PermissionGrants
tax:read:allView dashboards, reconciliation and reports
tax:compute:runRun and re-run computations, backfill periods
tax:reconcile:resolve / :assign / :approve / :suppressThe reconciliation workflow
tax:rates:manageRate tables and product tax classes
tax:registration:manageRegistrations
tax:exemption:manageExemption and reverse-charge certificates
tax:report:generate / :finalizeGenerate exports; close a period
tax:filing:manage / :reviewRecord filings and payments; accountant review
tax:filing:submit / :approve / :signDirect e-filing — maker, checker and signatory
tax:settings:manageEngine configuration

Several actions enforce separation of duties on identity, not merely on permission: the person who finalises a period cannot be the person who prepared it, and the person who approves a filing cannot be the one who staged it. Holding both permissions is not a way around it.

Plan tiers

CapabilityFreeStarterProAgencyEnterprise
Everything in Tax & Compliance

The whole engine sits at Pro. Individual capabilities are then governed by the permission set above, so a Pro store can give its bookkeeper reconciliation access without giving them the ability to close a period.

Best practices

  • Enter your registrations first. The engine cannot tell you what you owe in a jurisdiction it does not know you are registered in — supplies there resolve as unregistered.
  • Set the reporting currency once and leave it. Comparing periods across different reporting currencies defeats the point.
  • Backfill the periods you still need to file before generating a return.
  • Fix the cause, not the row. A cluster of "not charged" verdicts is usually one unmapped product tax class.
  • Treat every figure as a draft until your accountant has seen it. This is a reporting aid; the filer of record is you.

See also