Overview
Icon for Avalara

Avalara

Handle taxes using the Avalara API (community integration)

Medusa Avalara Plugin

A Medusa plugin for integrating Avalara AvaTax as a tax provider, enabling automated tax calculations and compliance for your e-commerce store. Created and maintained by u11d.

πŸ“‹ Table of Contents

✨ Features

  • Real-time Tax Calculations: Automatically calculate accurate taxes during checkout using Avalara's AvaTax API
  • Order Transaction Management: Create AvaTax transactions when orders are placed for proper tax recording
  • Transaction Lifecycle Tracking:
    • Commit transactions when orders are completed/fulfilled
    • Void transactions when orders are canceled
  • Flexible Configuration: Support for custom shipping addresses and tax codes
  • Address Validation: Validate and standardize shipping addresses using Avalara's address validation service

πŸš€ Quick Start

1. Installation

# npm
npm install @u11d/medusa-avalara
# yarn
yarn add @u11d/medusa-avalara

2. Basic Medusa Config

Add the plugin to your Medusa config file (Copy to clipboardmedusa-config.ts) using the Copy to clipboardwithAvalaraPlugin helper:

import { defineConfig } from "@medusajs/framework/utils";
import { withAvalaraPlugin, AvalaraPluginOptions } from "@u11d/medusa-avalara";
const avalaraPluginOptions: AvalaraPluginOptions = {
client: {
accountId: "YOUR_ACCOUNT_ID",
licenseKey: "YOUR_LICENSE_KEY",
environment: "sandbox",
companyCode: "DEFAULT",
},
shipFromAddress: {
line1: "512 S Mangum St Ste 100",
city: "Durham",
region: "NC",
country: "US",
postalCode: "27701-3973",
},
taxCodes: {
shipping: "FR020100",
default: "PC040100", // Clothing and related products (business-to-customer)-general
Important Notes:

  • The Copy to clipboardwithAvalaraPlugin wrapper handles plugin modules registration and dependency injection automatically. See Manual Module Registration section if you need to understand what the helper does or configure modules manually
  • You can use environment variables instead of hardcoding options, especially important for credentials like Copy to clipboardaccountId and Copy to clipboardlicenseKey
  • The example above will use Copy to clipboardPC040100 for each product. See Advanced Usage for assigning specific tax codes to individual products
  • The Copy to clipboardshipFromAddress should reflect your Avalara configuration - ensure it matches the address configured in your Avalara account for accurate tax calculations
  • The plugin fully supports tax-inclusive pricing and automatically respects the region's tax-inclusive preferences

3. Run Database Migration

After configuring your Medusa setup, run the database migration to create the required tables:

npx medusa db:migrate

4. Enable AvaTax Provider

After starting your Medusa server:

  1. Go to your admin panel (locally available at Copy to clipboardhttp://localhost:9000/app by default)
  2. Navigate to Settings > Tax Regions
  3. Select a tax region and edit it
  4. Select Avalara as your tax provider
  5. Save the configuration

πŸ“‹ Configuration Options

Client Options (Copy to clipboardclient)

Option Type Required Default Description Copy to clipboardaccountId Copy to clipboardstring βœ… - Your Avalara account ID Copy to clipboardlicenseKey Copy to clipboardstring βœ… - Your Avalara license key Copy to clipboardenvironment Copy to clipboard"sandbox" | "production" βœ… - AvaTax environment Copy to clipboardcompanyCode Copy to clipboardstring βœ… - Your company code in AvaTax Copy to clipboarddocumentRecordingEnabled Copy to clipboardboolean ❌ Copy to clipboardtrue Controls whether documents should be recorded in AvaTax. If set to Copy to clipboardfalse transactions (sales invoices) are not created Copy to clipboardappName Copy to clipboardstring ❌ - Custom app name Copy to clipboardappVersion Copy to clipboardstring ❌ - Custom app version Copy to clipboardmachineName Copy to clipboardstring ❌ - Machine identifier

Ship From Address (Copy to clipboardshipFromAddress)

Option Type Required Description Copy to clipboardline1 Copy to clipboardstring βœ… Street address line 1 Copy to clipboardline2 Copy to clipboardstring ❌ Street address line 2 Copy to clipboardcity Copy to clipboardstring βœ… City name Copy to clipboardregion Copy to clipboardstring ⚠️ (required for US) State/province code Copy to clipboardcountry Copy to clipboardstring βœ… ISO 2-letter country code Copy to clipboardpostalCode Copy to clipboardstring βœ… Postal/ZIP code

Tax Codes (Copy to clipboardtaxCodes)

Option Type Required Default Description Copy to clipboarddefault Copy to clipboardstring ❌ Copy to clipboard"P0000000" Default tax code for products Copy to clipboardshipping Copy to clipboardstring ❌ Copy to clipboard"FR020100" Tax code for shipping

🎯 Advanced Usage

Using Different Tax Codes for Products

In most e-commerce scenarios, different products require different tax codes based on their category, material, or intended use. The plugin uses the Copy to clipboardavalara_product table to determine which specific Avalara tax code should be applied to each product during tax calculations. You can manage these product-specific tax codes either by updating the database table directly or by using the provided admin API endpoint.

You can find the complete list of available Avalara tax codes at: https://taxcode.avatax.avalara.com/

By default, all products will use the Copy to clipboardtaxCodes.default value. To assign specific Avalara tax codes to individual products, you'll need to authenticate and make a Copy to clipboardPUT request to Copy to clipboard/admin/avalara-products.

Step 1: Get Authentication Token

First, authenticate to get a Bearer token:

curl -X POST http://localhost:9000/auth/user/emailpass \
-H "Content-Type: application/json" \
-d '{
"email": "your_admin_email@example.com",
"password": "your_admin_password"
}'

This will return a response containing a Copy to clipboardtoken field. Copy the token value.

Step 2: Update Product Tax Codes

Use the token to update product tax codes:

curl -X PUT http://localhost:9000/admin/avalara-products \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
-d '{
"avalara_products": [
{
"product_id": "prod_123",
"tax_code": "PC040100"
},
{
"product_id": "prod_456",
"tax_code": "PS081000"
}
]
}'

Address Validation

The plugin provides a Copy to clipboardPOST /store/avalara-address endpoint that serves as a proxy to Avalara's ResolveAddressPost API. Address validation is critical for accurate tax calculations, as Avalara requires correctly formatted and validated addresses to determine proper tax rates and jurisdictions.

Request Body:

{
"line1": "512 S Mangum St Ste 100",
"city": "Durham",
"region": "NC",
"postalCode": "27701",
"country": "US"
}

Notes:

Manual Module Registration

If you prefer to configure modules manually without using the Copy to clipboardwithAvalaraPlugin wrapper, you can register each module individually:

import { defineConfig, Modules } from "@medusajs/framework/utils";
import { AvalaraPluginOptions } from "@u11d/medusa-avalara";
const options: AvalaraPluginOptions = {
// your options here
};
module.exports = defineConfig({
plugins: ["@u11d/medusa-avalara"],
modules: [
{
resolve: "@u11d/medusa-avalara/modules/avalara-product",
dependencies: [Modules.CACHE],
},
{
resolve: "@u11d/medusa-avalara/modules/avatax-factory",
options,
dependencies: [Modules.CACHE],
},
{
Note: Manual registration requires careful attention to module dependencies and isolation. The Copy to clipboardwithAvalaraPlugin wrapper is recommended as it handles these complexities automatically.

βš™οΈ How the plugin works?

The Medusa Avalara plugin integrates with Avalara's AvaTax service through a modular architecture:

Core Components

modules/avalara-product

  • Manages product-specific tax codes through the Copy to clipboardAvalaraProduct model and database migration
  • Used by the Copy to clipboard/admin/avalara-products API endpoint
  • Saves mapping of Copy to clipboardproduct_id β†’ Copy to clipboardavalara_tax_code in cache for fast retrieval by the AvaTax provider

modules/avatax-factory

  • Provides AvaTax client configured with plugin options
  • Validates plugin options and credentials
  • Validates communication with Avalara to ensure credentials are correct (validation happens in loader)

providers/avatax

  • Tax calculation provider implementation (separate from Copy to clipboardavatax-factory due to Medusa's module isolation requirements)
  • Skips tax calculation if shipping address is not provided
  • Retrieves Copy to clipboardavalara_tax_code from cache; uses default tax code or throws error if not found
  • Makes API calls to AvaTax to create Copy to clipboardSalesOrder entities (temporary entities for dynamic cart tax calculations)
  • The Copy to clipboardgetTaxLines method handles tax rate calculations using the AvaTax API

Order Lifecycle Integration

Subscribers and Workflows:

  • orderPlacedHandler: Creates Sales Invoices (permanent entities representing finalized transactions in Avalara)
  • orderCanceledHandler: Voids the transaction in Avalara
  • orderCompletedHandler: Commits the transaction in Avalara

This architecture ensures accurate tax calculations during checkout and proper transaction lifecycle management in Avalara's system. The Copy to clipboardwithAvalaraPlugin wrapper simplifies the setup by automatically configuring all these modules with proper dependencies and isolation.

πŸ”§ Troubleshooting

Migration Error: "relation 'public.avalara_product' does not exist"

If you encounter this error:

error: Failed to feed cache. Error: select "a0".* from "public"."avalara_product" as "a0" where "a0"."deleted_at" is null order by "a0"."created_at" desc limit 1000 - relation "public.avalara_product" does not exist. Please make sure migration adding avalara_product table has been run and cache module is injected to the module via medusa-config

Solution: Run the database migration:

npx medusa db:migrate

This ensures the Copy to clipboardavalara_product table is created and the cache module is properly configured.

Tax calculations returning $0

If you're seeing $0 tax amounts in your calculations, follow these troubleshooting steps:

  1. Check application logs for any error messages or warnings related to AvaTax API calls
  2. Verify shipping address - tax calculation is skipped if no valid shipping address is provided
  3. Validate Avalara account configuration:
    • Ensure your company location is properly configured in your Avalara account
    • Verify that tax jurisdictions are set up correctly for your business locations
    • Check that your company has nexus configured for the relevant states/regions
  4. Test tax calculation directly in Avalara:
    • Log into your Avalara account
    • Use the AvaTax API testing tools to verify tax calculations work with your setup
    • Test with the same addresses and product codes you're using in Medusa
  5. Review tax codes:
    • Ensure products have valid Avalara tax codes assigned
    • Verify that the tax codes are appropriate for your products and jurisdiction
  6. Check environment settings:
    • Confirm you're using the correct environment (sandbox vs production)
    • Verify your API credentials are valid and have the necessary permissions

βœ‹ Need help?

If you encounter any issues or need assistance with this plugin, please visit our GitHub Issues page. Our team actively monitors and responds to bug reports, feature requests, and questions from the community. We aim to provide timely support to ensure your integration with Avalara runs smoothly.

Need expert assistance or want our team to support your Medusa project? We're here to help! Contact us at https://u11d.com/contact/ for professional support and consultation services.

πŸ“– Learn More

Read our comprehensive blog article about integrating Avalara with Medusa: https://u11d.com/blog/automated-tax-calculations-medusa-avalara-integration

🀝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

You may also like

Browse all integrations

Build your own

Develop your own custom integraiton

Build your own integration with our API to speed up your processes. Make your integration available via npm for it to be shared in our Library with the broader Medusa community.

gift card interface

Ready to build your custom commerce setup?