South Dakota v. Wayfair (2018) eliminated the physical presence requirement for sales tax nexus, meaning any US online seller that crosses state economic thresholds ($100K or 200 transactions annually in most states) must collect and remit destination-state tax. A tax lookup table with only 2 entries (CA and NY) while serving 15 states means the store collects nothing from 13 states where it may already be liable. The Streamlined Sales Tax Agreement creates uniform filing in 24 member states; the EU VAT Directive 2006/112/EC imposes separate VAT registration requirements. Fewer than 3 configured jurisdictions in a multi-state store is not a cosmetic gap — it is unreported tax liability.
Low severity in the audit context because manual remediation is required anyway, but the real-world tax liability exposure scales directly with the number of states served and the sales volume.
Expand the tax configuration in lib/tax.ts to cover at least all states where the business has economic nexus, or delegate entirely to a tax service API:
// lib/tax.ts
// Option 1: TaxJar handles nexus, Wayfair rules, and VAT automatically
const taxJarClient = new TaxJar({ apiKey: process.env.TAXJAR_API_KEY })
async function getTaxRate(address: Address): Promise<number> {
const result = await taxJarClient.rates.get(address.zip, {
state: address.state, country: address.country
})
return result.combined_rate
}
// Option 2: Local table — must include all nexus states
// Origin-based (sell from IL): use origin state rate
// Destination-based (most US states): use buyer's state rate
// Document which approach applies:
const TAX_BASIS: 'origin' | 'destination' = 'destination'
Add a code comment documenting the origin-vs-destination basis and the date the jurisdiction list was last reviewed.
ID: ecommerce-shipping-tax.regional-compliance.regional-tax-rules
Severity: low
What to look for: Count the number of distinct tax jurisdictions configured in the tax logic. Classify whether the tax system uses: (1) origin-based taxation, (2) destination-based taxation, or (3) a tax service API that handles jurisdiction rules. List which states or countries have explicit tax configurations.
Pass criteria: The tax system explicitly handles at least 3 distinct jurisdictions with different tax rates, or delegates jurisdiction logic to a tax service API (TaxJar, Avalara, Stripe Tax). Origin-based vs. destination-based taxation is documented in a code comment or config.
Fail criteria: Tax logic has fewer than 3 distinct jurisdiction configurations while the business claims to serve multiple states/countries, or no origin/destination tax distinction exists.
Skip (N/A) when: The business operates in a single jurisdiction, or tax rules are fully managed by an external service (TaxJar, Avalara) with no in-house override logic.
Detail on fail: "Tax lookup table has 2 jurisdictions (CA: 7.25%, NY: 8%). Business serves 15 states — 13 states have no configured rate." or "No origin-based vs. destination-based distinction. All states use destination-based without documentation."
Remediation: Implement regional tax rules in lib/tax.ts:
const ORIGIN_BASED_STATES = ['NY', 'IL', 'PA'] // states using origin-based
function getTaxRate(address: Address, businessOrigin: Address): number {
if (address.country !== 'US') {
return getVATRate(address) // EU/international
}
if (ORIGIN_BASED_STATES.includes(businessOrigin.state)) {
return getTaxRateByState(businessOrigin.state)
} else {
return getTaxRateByState(address.state) // destination-based
}
}