skills/payments-checkout/tax-calculation/SKILL.md
Calculate accurate sales tax and VAT at checkout using TaxJar or Avalara, with nexus management for multi-state and international compliance
npx skillsauth add finsilabs/awesome-ecommerce-skills tax-calculationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Accurate tax calculation at checkout is a legal requirement, not an optimization. In the United States, there are over 13,000 taxing jurisdictions. EU VAT rules require charging the customer's local VAT rate. Getting it wrong leads to under-collection (a liability you must cover) or over-collection (refunds and customer complaints). All major platforms have built-in tax calculation or direct integrations with TaxJar and Avalara that handle this correctly without custom code.
You only need to collect tax in jurisdictions where you have nexus (a tax obligation).
US Sales Tax nexus:
EU VAT:
Option A: Shopify's built-in tax (recommended for US stores)
Option B: Stripe Tax (via Shopify + Stripe)
Shopify's built-in tax covers US well. For international VAT compliance, install Stripe Tax via a Shopify app integration.
Option C: TaxJar or Avalara (for complex multi-jurisdiction requirements)
Option A: WooCommerce built-in tax
Option B: TaxJar (recommended for US compliance)
Option C: Avalara AvaTax
EU VAT on BigCommerce: Enable VAT by country under Store Setup → Tax → VAT for EU VAT compliance. For full OSS compliance, use Avalara's EU VAT module.
Use Stripe Tax (simplest) or the TaxJar/Avalara API directly:
Option A: Stripe Tax (recommended for Stripe-based stores)
// Enable Stripe Tax on the PaymentIntent — Stripe calculates and collects tax automatically
const paymentIntent = await stripe.paymentIntents.create({
amount: orderSubtotalCents, // Subtotal only — Stripe adds tax
currency: 'usd',
automatic_payment_methods: { enabled: true },
// Stripe Tax configuration
// See: https://stripe.com/docs/tax/integration
});
// Or use Stripe Checkout with automatic_tax enabled:
const session = await stripe.checkout.sessions.create({
line_items: lineItems,
mode: 'payment',
automatic_tax: { enabled: true }, // Stripe Tax handles calculation
customer_details: { address: { country: customerCountry }, address_source: 'shipping' },
success_url: `${domain}/success`,
cancel_url: `${domain}/cart`,
});
Configure Stripe Tax under Stripe Dashboard → Tax → Configure — set your tax registration numbers and the tax behaviors for each product category.
Option B: TaxJar API
const Taxjar = require('taxjar');
const taxjar = new Taxjar({ apiKey: process.env.TAXJAR_API_KEY });
async function calculateTaxForOrder({ fromAddress, toAddress, lineItems, shippingCost }) {
const response = await taxjar.taxForOrder({
from_country: fromAddress.country,
from_zip: fromAddress.zip,
from_state: fromAddress.state,
to_country: toAddress.country,
to_zip: toAddress.zip,
to_state: toAddress.state,
to_city: toAddress.city,
amount: lineItems.reduce((sum, i) => sum + i.unit_price * i.quantity, 0),
shipping: shippingCost,
line_items: lineItems.map(item => ({
id: item.id,
quantity: item.quantity,
unit_price: item.unit_price,
product_tax_code: item.tax_code ?? null, // e.g., '20010' for general goods
})),
});
return {
totalTax: response.tax.amount_to_collect,
taxRate: response.tax.rate,
hasNexus: response.tax.has_nexus, // false = no tax to collect
breakdown: response.tax.breakdown,
};
}
// After order is confirmed, commit the transaction for filing reports
async function commitTaxTransaction(order) {
await taxjar.createOrder({
transaction_id: order.id,
transaction_date: new Date().toISOString().split('T')[0],
from_country: WAREHOUSE_ADDRESS.country,
from_zip: WAREHOUSE_ADDRESS.zip,
from_state: WAREHOUSE_ADDRESS.state,
to_country: order.shippingAddress.country,
to_zip: order.shippingAddress.zip,
to_state: order.shippingAddress.state,
amount: order.subtotal,
shipping: order.shippingCost,
sales_tax: order.taxAmount,
line_items: order.lineItems.map(item => ({
id: item.id,
quantity: item.quantity,
unit_price: item.price,
sales_tax: item.taxAmount,
})),
});
}
EU VAT reverse charge (B2B cross-border within EU):
For EU B2B transactions, validate the buyer's VAT number via the EU VIES service before applying zero-rate:
async function validateEUVATNumber(vatNumber) {
const countryCode = vatNumber.slice(0, 2);
const number = vatNumber.slice(2);
const res = await fetch(
`https://ec.europa.eu/taxation_customs/vies/rest-api/ms/${countryCode}/vat/${number}`
);
const data = await res.json();
return data.isValid === true;
}
Tax calculation services require you to "commit" each transaction after payment is confirmed — this records it in your filing reports. TaxJar and Avalara apps for Shopify/WooCommerce do this automatically. For custom integrations, call the create/commit API after the order is confirmed (not before payment).
| Problem | Solution | |---------|----------| | Tax calculated but not committed to the filing API | Ensure your platform integration (TaxJar plugin, Avalara plugin) is configured to auto-commit on order completion; verify in the provider's transaction dashboard | | EU VAT charged on B2B cross-border sales | Validate VAT numbers via VIES before applying reverse charge; if validation fails, charge VAT as B2C | | Tax API adds 500ms to checkout | TaxJar and Avalara both have caching built into their Shopify/WooCommerce plugins; for custom builds, cache estimates by destination zip code and cart total for 1 hour | | Shopify charging wrong tax rate for a state | Verify your nexus state list in Settings → Taxes is correct and up to date; check for product-level tax overrides that may be incorrectly configured | | WooCommerce showing "0 tax" after TaxJar install | Verify TaxJar API key is correct; check the plugin's status page for API errors; confirm your warehouse address and nexus states are configured in the TaxJar dashboard |
tools
Let shoppers save products to a wishlist, share it with friends, and get notified when saved items come back in stock or drop in price
development
Build a themeable storefront with design tokens and CSS custom properties that supports white-labeling, multi-brand variants, and dark mode
development
Speed up product discovery with instant search suggestions, fuzzy typo matching, and category-aware results powered by Algolia or Elasticsearch
development
Build a mobile-first storefront with thumb-friendly navigation, sticky add-to-cart buttons, and touch-optimized components for high mobile conversion