How to Create a Tax Provider

In this document, you’ll learn how to create a tax provider to use with the Tax Module, and the methods to implement.


Overview#

A tax provider is used to retrieve the tax lines in a provided context. The Tax Module provides a default system provider. You can create your own tax provider, either in a plugin, in a module provider, or directly in your Medusa application's codebase, then use it in any tax region.


Understanding Tax Provider Implementation#

The Tax Module Provider handles calculating taxes with a third-party provirder. However, it's not responsible for managing tax concepts within Medusa, such as creating a tax region. The Tax Module uses your tax provider within core operations.

For example, during checkout, the tax provider of the tax region that the customer is in is used to calculate the tax for the cart and order. So, you only have to implement the third-party tax calculation logic in your tax provider.


1. Create Module Provider Directory#

Start by creating a new directory for your module provider.

If you're creating the module provider in a Medusa application, create it under the src/modules directory. For example, src/modules/my-tax.

If you're creating the module provider in a plugin, create it under the src/providers directory. For example, src/providers/my-tax.

NoteThe rest of this guide always uses the src/modules/my-tax directory as an example.

2. Create the Tax Provider Service#

Create the file src/modules/my-tax/service.ts that holds the module's main service. It must extend the ITaxProvider class imported from @medusajs/framework/types:

src/modules/my-tax/service.ts
1import { ITaxProvider } from "@medusajs/framework/types"2
3export default class MyTaxProvider implements ITaxProvider {4  // TODO implement methods5}

Identifier Property#

The identifier property in a tax provider is used when the tax provider is loaded by the Tax Module and added to the database. A tax provider is represented in the database by the TaxProvider data model.

For example:

src/modules/my-tax/service.ts
1export default class MyTaxProvider implements ITaxProvider {2  static identifier = "my-tax"3  // ...4}

constructor#

You can use the constructor of your tax provider to access the resources registered in the Module Container.

You can also use the constructor to initialize your integration with the third-party provider. For example, if you use a client to connect to the third-party provider’s APIs, you can initialize it in the constructor and use it in other methods in the service.

Additionally, if you’re creating your tax provider as a plugin or a module provider to be installed in any Medusa application and you want to access its options, you can access them in the second parameter of the constructor.

For example:

Code
1export default class MyTaxProvider implements ITaxProvider {2  // ...3  constructor(container, options) {4    // you can access options here5
6    // you can also initialize a client that7    // communicates with a third-party service.8    this.client = new Client(options)9  }10}

getTaxLines#

This method is used to retrieve the tax lines of items and shipping methods. It's used during checkout when the getTaxLines method of the Tax Module's main service is called for a tax region that uses this tax provider.

Example

An example of how this method is implemented in the system provider:

Code
1// ...2
3export default class SystemTaxService implements ITaxProvider {4  // ...5
6  async getTaxLines(7    itemLines: TaxTypes.ItemTaxCalculationLine[],8    shippingLines: TaxTypes.ShippingTaxCalculationLine[],9    _: TaxTypes.TaxCalculationContext10  ): Promise<(TaxTypes.ItemTaxLineDTO | TaxTypes.ShippingTaxLineDTO)[]> {11    let taxLines: (TaxTypes.ItemTaxLineDTO | TaxTypes.ShippingTaxLineDTO)[] =12      itemLines.flatMap((l) => {13        return l.rates.map((r) => ({14          rate_id: r.id,15          rate: r.rate || 0,16          name: r.name,17          code: r.code,18          line_item_id: l.line_item.id,19          provider_id: this.getIdentifier(),20        }))21      })22
23    taxLines = taxLines.concat(24      shippingLines.flatMap((l) => {25        return l.rates.map((r) => ({26          rate_id: r.id,27          rate: r.rate || 0,28          name: r.name,29          code: r.code,30          shipping_line_id: l.shipping_line.id,31          provider_id: this.getIdentifier(),32        }))33      })34    )35
36    return taxLines37  }38}

Parameters

The line item lines to calculate taxes for.
The shipping method lines to calculate taxes for.
The context relevant and useful for the taxes calculation.

Returns

PromisePromise<(ItemTaxLineDTO | ShippingTaxLineDTO)[]>
The list of calculated line item and shipping tax lines. If an item in the array has the shipping_line_id property, then it's a shipping tax line. Otherwise, if it has the line_item_id property, then it's a line item tax line.

3. Create Module Definition File#

Create the file src/modules/my-tax/index.ts with the following content:

src/modules/my-tax/index.ts
1import MyTaxProvider from "./service"2import { 3  ModuleProvider, 4  Modules5} from "@medusajs/framework/utils"6
7export default ModuleProvider(Modules.TAX, {8  services: [MyTaxProvider],9})

This exports the module's definition, indicating that the MyTaxProvider is the module's service.


4. Use Module#

To use your Tax Module Provider, add it to the providers array of the Tax Module in medusa-config.ts:

medusa-config.ts
1module.exports = defineConfig({2  // ...3  modules: [4    {5      resolve: "@medusajs/medusa/tax",6      options: {7        providers: [8          {9            // if module provider is in a plugin, use `plugin-name/providers/my-tax`10            resolve: "./src/modules/my-tax",11            id: "my-tax",12            options: {13              // provider options...14            },15          },16        ],17      },18    },19  ]20})
Was this page helpful?
Ask Anything
FAQ
What is Medusa?
How can I create a module?
How can I create a data model?
How do I create a workflow?
How can I extend a data model in the Product Module?
Recipes
How do I build a marketplace with Medusa?
How do I build digital products with Medusa?
How do I build subscription-based purchases with Medusa?
What other recipes are available in the Medusa documentation?
Chat is cleared on refresh
Line break