How to Manage Tax Rates
In this document, you’ll learn how to manage tax rates of a region using the admin APIs.
Overview
Tax rates are created per region. Each region has a default tax rate and code. However, you can create more tax rates for a region that have a different code or specific conditions. For example, you can override the default tax rate for a specific product type, product, or shipping option.
Scenario
You want to add or use the following admin functionalities:
- Manage tax rates. This includes listing tax rates, and creating, updating, and deleting a tax rate.
- Add or delete a tax rate’s association with products, product types, or shipping options.
Prerequisites
Medusa Components
It is assumed that you already have a Medusa backend installed and set up. If not, you can follow the quickstart guide to get started.
JS Client
This guide includes code snippets to send requests to your Medusa backend using Medusa’s JS Client, among other methods.
If you follow the JS Client code blocks, it’s assumed you already have Medusa’s JS Client installed and have created an instance of the client.
Medusa React
This guide also includes code snippets to send requests to your Medusa backend using Medusa React, among other methods.
If you follow the Medusa React code blocks, it's assumed you already have Medusa React installed and have used MedusaProvider higher in your component tree.
Authenticated Admin User
You must be an authenticated admin user before following along with the steps in the tutorial.
You can learn more about authenticating as an admin user in the API reference.
List Tax Rates
You can list the tax rates by sending a request to the List Tax Rates API Route:
import { useAdminTaxRates } from "medusa-react"
const TaxRates = () => {
const { tax_rates, isLoading } = useAdminTaxRates()
return (
<div>
{isLoading && <span>Loading...</span>}
{tax_rates && !tax_rates.length && (
<span>No Tax Rates</span>
)}
{tax_rates && tax_rates.length > 0 && (
<ul>
{tax_rates.map((tax_rate) => (
<li key={tax_rate.id}>{tax_rate.code}</li>
))}
</ul>
)}
</div>
)
}
export default TaxRates
You can pass to this API Route filter and search parameters as explained in the API reference.
The API Route returns an array of tax rate objects along with pagination parameters.
Listing Tax Rates for a Region
You can retrieve the tax rate of a region by passing the region_id
query parameter:
import { useAdminTaxRates } from "medusa-react"
const TaxRates = () => {
const { tax_rates, isLoading } = useAdminTaxRates({
region_id: "reg_123",
})
return (
<div>
{isLoading && <span>Loading...</span>}
{tax_rates && !tax_rates.length && (
<span>No Tax Rates</span>
)}
{tax_rates && tax_rates.length > 0 && (
<ul>
{tax_rates.map((tax_rate) => (
<li key={tax_rate.id}>{tax_rate.code}</li>
))}
</ul>
)}
</div>
)
}
export default TaxRates
In the example above, you pass the region’s ID as the value of the region_id
query parameter.
This query parameter also accepts an array of strings, allowing you to filter the tax rates by more than one region:
import { useAdminTaxRates } from "medusa-react"
const TaxRates = () => {
const { tax_rates, isLoading } = useAdminTaxRates({
region_id: ["reg_123", "reg_456"],
})
return (
<div>
{isLoading && <span>Loading...</span>}
{tax_rates && !tax_rates.length && (
<span>No Tax Rates</span>
)}
{tax_rates && tax_rates.length > 0 && (
<ul>
{tax_rates.map((tax_rate) => (
<li key={tax_rate.id}>{tax_rate.code}</li>
))}
</ul>
)}
</div>
)
}
export default TaxRates
Create Tax Rate
You can create a tax rate by sending a request to the Create Tax Rate API Route:
import { useAdminCreateTaxRate } from "medusa-react"
type Props = {
regionId: string
}
const CreateTaxRate = ({ regionId }: Props) => {
const createTaxRate = useAdminCreateTaxRate()
// ...
const handleCreate = (
code: string,
name: string,
rate: number
) => {
createTaxRate.mutate({
code,
name,
region_id: regionId,
rate,
}, {
onSuccess: ({ tax_rate }) => {
console.log(tax_rate.id)
}
})
}
// ...
}
export default CreateTaxRate
fetch(`<BACKEND_URL>/admin/tax-rates`, {
credentials: "include",
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
code: "TEST",
name: "New Tax Rate",
region_id,
rate: 10,
}),
})
.then((response) => response.json())
.then(({ tax_rate }) => {
console.log(tax_rate.id)
})
This API Route requires the following body parameters:
code
: a string indicating the tax codename
: a string indicating the name of the tax rateregion_id
: a string indicating the region this tax rate belongs to
You can optionally pass other parameters, such as rate
, which is a number that indicates the tax rate. Refer to the API reference for other optional parameters.
You can specify here the products, product types, or shipping options that this tax rate is created for as explained in the API reference. In this guide, you’ll be using other API Routes to add or delete these conditions on a tax rate.
The request returns the created tax rate as an object.
Update Tax Rate
You can update a tax rate by sending a request to the Update Tax Rate API Route:
import { useAdminUpdateTaxRate } from "medusa-react"
type Props = {
taxRateId: string
}
const TaxRate = ({ taxRateId }: Props) => {
const updateTaxRate = useAdminUpdateTaxRate(taxRateId)
// ...
const handleUpdate = (
name: string
) => {
updateTaxRate.mutate({
name
}, {
onSuccess: ({ tax_rate }) => {
console.log(tax_rate.name)
}
})
}
// ...
}
export default TaxRate
This API Route requires the tax rate ID to be passed as a path parameter.
In the request body, you can pass any of the tax rate’s fields as a parameter. In the example above, you pass the name
parameter to update the name of the tax rate. Refer to the API reference for other parameters you can pass in the request body.
The request returns the updated tax rate as an object.
Manage Tax Rate’s Products
This section explains how you can add and remove products from a tax rate.
Add Product to Tax Rate
You can add a product to a tax rate by sending a request to the Add Products API Route:
import { useAdminCreateProductTaxRates } from "medusa-react"
type Props = {
taxRateId: string
}
const TaxRate = ({ taxRateId }: Props) => {
const addProduct = useAdminCreateProductTaxRates(taxRateId)
// ...
const handleAddProduct = (productIds: string[]) => {
addProduct.mutate({
products: productIds,
}, {
onSuccess: ({ tax_rate }) => {
console.log(tax_rate.products)
}
})
}
// ...
}
export default TaxRate
fetch(`<BACKEND_URL>/admin/tax-rates/${taxRateId}/products/batch`, {
credentials: "include",
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
products: [
productId1,
],
}),
})
.then((response) => response.json())
.then(({ tax_rate }) => {
console.log(tax_rate.products)
})
This API Route requires the tax rate’s ID as a path parameter.
In the request body, the products
parameter is required. It’s an array of strings, each string being the ID of a product to add to the tax rate.
The request returns the updated tax rate as an object. You can access the tax rate’s products using the products
property of the tax rate object.
Remove Product from Tax Rate
You can remove a product from a tax rate by sending a request to the Delete Products API Route:
import { useAdminDeleteProductTaxRates } from "medusa-react"
const TaxRate = (
taxRateId: string
) => {
const removeProduct = useAdminDeleteProductTaxRates(taxRateId)
// ...
const handleRemoveProduct = (productIds: string[]) => {
removeProduct.mutate({
products: productIds,
}, {
onSuccess: ({ tax_rate }) => {
console.log(tax_rate.products)
}
})
}
// ...
}
export default TaxRate
fetch(`<BACKEND_URL>/admin/tax-rates/${taxRateId}/products/batch`, {
credentials: "include",
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
products: [
productId1,
],
}),
})
.then((response) => response.json())
.then(({ tax_rate }) => {
console.log(tax_rate.products)
})
This API Route requires the tax rate’s ID as a path parameter.
In the request body, the products
parameter is required. It’s an array of strings, each string being the ID of a product to remove from the tax rate.
The request returns the updated tax rate as an object. You can access the tax rate’s products using the products
property of the tax rate object.
Manage Tax Rate’s Product Types
This section explains how you can add and remove product types from a tax rate.
Add Product Type to Tax Rate
You can add a product type to a tax rate by sending a request to the Add Product Types API Route:
import {
useAdminCreateProductTypeTaxRates,
} from "medusa-react"
type Props = {
taxRateId: string
}
const TaxRate = ({ taxRateId }: Props) => {
const addProductTypes = useAdminCreateProductTypeTaxRates(
taxRateId
)
// ...
const handleAddProductTypes = (productTypeIds: string[]) => {
addProductTypes.mutate({
product_types: productTypeIds,
}, {
onSuccess: ({ tax_rate }) => {
console.log(tax_rate.product_types)
}
})
}
// ...
}
export default TaxRate
fetch(`<BACKEND_URL>/admin/tax-rates/${taxRateId}/product-types/batch`, {
credentials: "include",
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
product_types: [
productTypeId,
],
}),
})
.then((response) => response.json())
.then(({ tax_rate }) => {
console.log(tax_rate.product_types)
})
This API Route requires the tax rate’s ID as a path parameter.
In the request body, the product_types
parameter is required. It’s an array of strings, each string being the ID of a product type to add to the tax rate.
The request returns the updated tax rate as an object. You can access the tax rate’s product types using the product_types
property of the tax rate object.
Remove Product Type from Tax Rate
You can remove a product type from a tax rate by sending a request to the Delete Product Types API Route:
import {
useAdminDeleteProductTypeTaxRates,
} from "medusa-react"
type Props = {
taxRateId: string
}
const TaxRate = ({ taxRateId }: Props) => {
const removeProductTypes = useAdminDeleteProductTypeTaxRates(
taxRateId
)
// ...
const handleRemoveProductTypes = (
productTypeIds: string[]
) => {
removeProductTypes.mutate({
product_types: productTypeIds,
}, {
onSuccess: ({ tax_rate }) => {
console.log(tax_rate.product_types)
}
})
}
// ...
}
export default TaxRate
fetch(`<BACKEND_URL>/admin/tax-rates/${taxRateId}/product-types/batch`, {
credentials: "include",
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
product_types: [
productTypeId,
],
}),
})
.then((response) => response.json())
.then(({ tax_rate }) => {
console.log(tax_rate.id)
})
This API Route requires the tax rate’s ID as a path parameter.
In the request body, the product_types
parameter is required. It’s an array of strings, each string being the ID of a product type to remove from the tax rate.
The request returns the updated tax rate as an object. You can access the tax rate’s product types using the product_types
property of the tax rate object.
Manage Tax Rate’s Shipping Options
This section explains how you can add and remove shipping options from a tax rate.
Add Shipping Option to Tax Rate
You can add a shipping option to a tax rate by sending a request to the Add Shipping Option API Route:
import { useAdminCreateShippingTaxRates } from "medusa-react"
type Props = {
taxRateId: string
}
const TaxRate = ({ taxRateId }: Props) => {
const addShippingOption = useAdminCreateShippingTaxRates(
taxRateId
)
// ...
const handleAddShippingOptions = (
shippingOptionIds: string[]
) => {
addShippingOption.mutate({
shipping_options: shippingOptionIds,
}, {
onSuccess: ({ tax_rate }) => {
console.log(tax_rate.shipping_options)
}
})
}
// ...
}
export default TaxRate
fetch(`<BACKEND_URL>/admin/tax-rates/${taxRateId}/shipping-options/batch`, {
credentials: "include",
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
shipping_options: [
shippingOptionId,
],
}),
})
.then((response) => response.json())
.then(({ tax_rate }) => {
console.log(tax_rate.shipping_options)
})
This API Route requires the tax rate’s ID as a path parameter.
In the request body, the shipping_options
parameter is required. It’s an array of strings, each string being the ID of a shipping option to add to the tax rate.
The request returns the updated tax rate as an object. You can access the tax rate’s shipping options using the shipping_options
property of the tax rate object.
Remove Shipping Options from Tax Rate
You can remove a shipping option from a tax rate by sending a request to the Delete Shipping Options API Route:
import { useAdminDeleteShippingTaxRates } from "medusa-react"
const TaxRate = (
taxRateId: string
) => {
const removeShippingOptions = useAdminDeleteShippingTaxRates(
taxRateId
)
// ...
const handleRemoveShippingOptions = (
shippingOptionIds: string[]
) => {
removeShippingOptions.mutate({
shipping_options: shippingOptionIds,
}, {
onSuccess: ({ tax_rate }) => {
console.log(tax_rate.shipping_options)
}
})
}
// ...
}
export default TaxRate
fetch(`<BACKEND_URL>/admin/tax-rates/${taxRateId}/shipping-options/batch`, {
credentials: "include",
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
shipping_options: [
shippingOptionId,
],
}),
})
.then((response) => response.json())
.then(({ tax_rate }) => {
console.log(tax_rate.shipping_options)
})
This API Route requires the tax rate’s ID as a path parameter.
In the request body, the shipping_options
parameter is required. It’s an array of strings, each string being the ID of a shipping option to remove from the tax rate.
The request returns the updated tax rate as an object. You can access the tax rate’s shipping options using the shipping_options
property of the tax rate object.
Delete Tax Rate
You can delete a tax rate by sending a request to the Delete Tax Rate API Route:
import { useAdminDeleteTaxRate } from "medusa-react"
type Props = {
taxRateId: string
}
const TaxRate = ({ taxRateId }: Props) => {
const deleteTaxRate = useAdminDeleteTaxRate(taxRateId)
// ...
const handleDelete = () => {
deleteTaxRate.mutate(void 0, {
onSuccess: ({ id, object, deleted }) => {
console.log(id)
}
})
}
// ...
}
export default TaxRate
This API Route requires the tax rate’s ID as a path parameter.
The request returns the following fields:
id
: The ID of the deleted tax rate.object
: The type of object that was deleted. In this case, the value will betax-rate
.deleted
: A boolean value indicating whether the tax rate was deleted.