Every platform handles sales tax calculations differently with a varying degree of accuracy. Most commonly you’ll find zip-based tax rates, allowing merchants to set up a tax rate by 5-digit postal code. These rates work fine in certain scenarios, but ideally you want to collect sales tax based on the street address for US calculations:
Beyond that, there’s plenty of other decisions most platforms don’t natively support around sales tax. Given the necessary data, the TaxJar API automatically handles the following for you:
- Street-level rooftop calculations
- Line item taxability and itemized discounts
- Shipping / freight taxability
- Product taxability and exemptions
- Customer exemptions
- Sourcing logic for interstate and intrastate orders
- Multiple nexus addresses per merchant
- Sales tax holidays
All of this is done through our sales tax calculation endpoint: /v2/taxes
. Let’s go through some best practices when using this API endpoint.
From Address
When making a request to /v2/taxes
, the first thing you’ll be asked to provide are the from_
parameters. According to the documentation, these are optional because we can determine nexus elsewhere:
- Using the
nexus_addresses[]
parameter. - From a merchant’s address on file in their TaxJar account.
json
{
"from_country": "US",
"from_zip": "92093",
"from_state": "CA",
"from_city": "La Jolla",
"from_street": "9500 Gilman Drive"
}
The concept of nexus is very important for US-based transactions. If a merchant doesn’t have nexus in the same state as the customer’s shipping address, no sales tax is collected.
However, it gets trickier in the US. Individual states in the US handle sales tax differently. Some want you to collect based on the destination of the buyer, others want you to collect based on your store’s origin.
If you ship an order from out of state into an origin-based state, that state may effectively become destination-based.
Based on this scenario, we highly recommend using the from_
parameters to ensure the correct sourcing logic for a state.
Using our state guides, you can find out the sourcing of a state and how we handle interstate orders.
Store Location
When determining the address to populate in the from_
parameters, we generally recommend using the store’s location or shipping origin. Here’s what Graham our sales tax analyst has to say:
To Address
Providing the to_
params for /v2/taxes
is more straightforward. At a minimum, to_country
, to_state
and to_zip
are required for all calculations.
json
{
"to_country": "US",
"to_zip": "90002",
"to_state": "CA",
"to_city": "Los Angeles",
"to_street": "1335 E 103rd St"
}
The more data you put into these parameters, the more you’ll get back. If you provide a way to estimate tax in the cart, less data is fine. Once the customer completes the checkout process, you’ll want to provide their entire address for the most accurate calculation.
We recommend providing the customer’s shipping address for the to_
parameters.
There are a couple scenarios when this may not apply:
-
If you’re selling digital / virtual products or SaaS subscriptions, consider using the customer’s billing address.
-
If you provide a local pickup shipping method, use the store’s location or a brick and mortar address.
Amount
The amount
param is always the total amount of the order, excluding shipping. It’s optional. You may opt to use line_items[]
instead. If you provide both amount
and line items, we’ll compare the two to make sure they match up.
json
{
"amount": 15
}
We recommend providing both params or simply line_items[]
for the most flexibility.
You’ll notice our API documentation classifies amounts as long
, referring to the long double
data type from languages such as C. Behind the scenes we use BigDecimal when working with monetary values for highly accurate calculations.
Shipping
At this time we only provide a shipping
param to cover freight tax. If you need to pass handling fees as well, consider using a separate line item.
json
{
"shipping": 1.5,
"line_items": [
{
"description": "Handling Fee",
"quantity": 1,
"unit_price": 0.5
}
]
}
Shipping discounts should be deducted from the shipping
param. For free shipping, pass $0 in the shipping
param.
Shipping taxability is automatically determined by state / region in the TaxJar API. If you need to override this functionality to always collect freight tax, consider using a separate line item for shipping and passing $0 in the shipping
param.
Nexus Addresses
Without providing nexus addresses, the TaxJar API will assume the merchant only has nexus based on their from_
address or any nexus states on file in their TaxJar account.
json
{
"nexus_addresses": [
{
"id": "Main Location",
"country": "US",
"zip": "92093",
"state": "CA",
"city": "La Jolla",
"street": "9500 Gilman Drive"
}
]
}
Depending on your requirements, it may be fine to only support one nexus address per merchant using the from_
address. Merchants with multiple nexus addresses will need to sign up for a TaxJar account and manage their nexus states inside the TaxJar app.
In order to support nexus_addresses[]
on your platform, you may need to introduce a way for merchants to manage multiple business addresses. Ideally, provide a way to manage nexus addresses directly through the TaxJar API similar to our Magento integrations:
Use our nexus regions endpoint to pull down a merchant’s nexus addresses from TaxJar and store them locally to pass via nexus_addresses[]
.
International Limitations
At this time, the TaxJar app is oriented toward US merchants.
Line Items
To support product taxability and itemized discounts, we always recommend using the line_items[]
param.
json
{
"line_items": [
{
"id": "1",
"quantity": 1,
"product_tax_code": "20010",
"unit_price": 15,
"discount": 0
}
]
}
The id
param should always be unique. If multiple line items share the same id
, you may receive an incorrect calculation. Avoid using a product ID for this param if it’s possible to add multiple line items with the same product, such as customizable products with variations. Consider using a unique ID associated with the line item itself.
The unit_price
should be the base price of the line item before taking into account the quantity
. We’ll multiply the unit_price
by quantity
in the TaxJar API.
Pay special attention to the discount
param. Pass the total discount of the line item and factor in the quantity. For example:
Unit Price: $5.00 Quantity: 3 Discount: $1.00 each
The discount
param would be $3.00, not $1.00.
json
{
"line_items": [
{
"id": "1",
"quantity": 3,
"unit_price": 5,
"discount": 3
}
]
}
For order-level discounts, distribute the total discount across line items. Try to match the way your platform handles this. For example:
Discount: 20%
One way is to distribute the discount across line items evenly.
json
{
"line_items": [
{
"id": "1",
"quantity": 3,
"unit_price": 5,
"discount": 2
},
{
"id": "2",
"quantity": 1,
"unit_price": 10,
"discount": 2
},
{
"id": "3",
"quantity": 1,
"unit_price": 5,
"discount": 2
}
]
}
Another way is to distribute the discount across line items proportionally.
json
{
"line_items": [
{
"id": "1",
"quantity": 3,
"unit_price": 5,
"discount": 3
},
{
"id": "2",
"quantity": 1,
"unit_price": 10,
"discount": 2
},
{
"id": "3",
"quantity": 1,
"unit_price": 5,
"discount": 1
}
]
}
If the platform does not distribute order-level discounts across line items, or if you’re not sure, apply either method consistently.
For example, some platforms might add the total discount as a separate line item rather than distributing it. In this case, distribute the discount proportionally or evenly in requests to the TaxJar API.
Product Exemptions
To handle product taxability, you’ll need to allow merchants to assign their products to a TaxJar product category. If you have a product tax class system built into your platform, consider associating a TaxJar product category with a tax class.
Our /v2/categories
endpoint is provided so you can pull down our product categories and keep them updated in your system. You can retrieve the category name and tax code for each category:
json
{
"categories": [
{
"name": "Clothing",
"product_tax_code": "20010",
"description": " All human wearing apparel suitable for general use"
}
]
}
Using this data, you could populate a dropdown for merchants to select a TaxJar product category when managing tax classes or individual products.
In most of our integrations we associate our tax codes with the notion of a tax class. This may differ based on your internal requirements. For example, a merchant selling clothing would create a “Clothing” tax class and assign it to “Clothing - 20010”, the category provided by TaxJar. When a clothing product is added to the cart, the tax class and associated tax code is retrieved. If a tax code is found, it’s passed via product_tax_code
.
Currently we provide a subset of common product categories and we’re planning to expand the list over time. Fully taxable products don’t require a product_tax_code
. We’ll automatically assume it’s taxable.
Customer Exemptions
To support end-to-end customer exemptions, you’ll need to use our customer endpoints to sync a merchant’s customers when they’re created or updated. After creating a customer in TaxJar with a designated exemption type such as wholesale
or government
, you can pass a customer_id
to our tax calculation and transaction endpoints. This allows us to determine whether or not the customer should be exempt from sales tax.
json
{
"customer_id": "123"
}
If your merchant already has exempt customers, you’ll need to backfill these customers using our API to make sure they’re in our system prior to calculating sales tax or pushing a transaction with the customer_id
.
Response
Use the amount_to_collect
attribute to return back the amount of sales tax to collect in your platform.
If you’d like to provide granular, itemized data by jurisdiction or line item you can access the breakdown
attribute. We’ll return back the amount to collect and corresponding rates at the state, county, city, and special district level for both the overall order and individual line items. At this time, we don’t provide the jurisdiction names but it’s on our roadmap.
json
{
"tax": {
"order_total_amount": 16.5,
"shipping": 1.5,
"taxable_amount": 15,
"amount_to_collect": 1.35,
"rate": 0.09,
"has_nexus": true,
"freight_taxable": false,
"tax_source": "destination",
"breakdown": {}
}
}
API Guidelines
Here’s the most important takeaway for calculating sales tax: Only make US-based calculation requests where the merchant has nexus.
- If an order is shipping to a merchant’s nexus state, make a request to
/v2/taxes
. - If an order is not shipping to a merchant’s nexus state, do not make a request. Ideally, fall back to your tax rate system.
This guideline may save your merchants some money on API calculations, so take note to implement. Here’s several more:
- Provide as much data as you can to ensure accurate calculations.
- If possible, cache your calculation API responses until an order detail changes (line item, address, shipping, etc).
- Review your code to ensure you’re conservatively making requests to the TaxJar API and avoiding duplicate calls.
- Always catch API request errors. Ideally, fall back to your tax rate system so merchants can utilize their own backup rates. If you see an ongoing problem, reach out to our support team.
- Log API requests and responses on your end for easy debugging.
As a backup we also provide minimum and average sales tax rates by region, in case our API becomes unavailable. You’re welcome to use our summarized rates endpoint to periodically pull down these rates to ensure sales tax is always collected.
Branding Guidelines
-
Sales tax calculations are powered by the TaxJar API. Generally, we use “Sales Tax API by TaxJar” or “TaxJar API” for headlines. Feel free to use “powered by TaxJar API” in explanation text.
-
For calculation checkbox and toggle switch fields, we generally use “Enabled for Checkout”, “Sales Tax Calculations”, or “Checkout Calculations” as the field label:
Testing Guidelines
-
Use a separate TaxJar account for testing calculations.
-
Write integration tests between your platform and the TaxJar API integration to ensure your checkout process properly handles sales tax. Review a checklist of scenarios to test.
-
Consider using HTTP response fixtures instead of making an API request for each test. Mocking and stubbing libraries may assist with capturing TaxJar API responses for ongoing use. Tax rates are subject to change, so using fixtures will help prevent tests from randomly breaking.
UX Guidelines
-
Try your best to use the settings and data already provided by the merchant on your platform for populating
from_
parameters, such as their store location. -
Respect your platform’s existing tax settings and implement ways for the TaxJar API to handle them. For example, adding a separate line item for handling fees or fixed product taxes.
-
If the TaxJar API doesn’t support all of your existing tax settings, make sure you communicate that to your merchants. For example, disabling specific settings if the TaxJar integration is enabled or adding a note to each field.
-
Set some intelligent defaults if certain settings don’t apply. For example, the merchant should usually use the customer’s shipping address when calculating tax, not the billing address or store location.
-
In addition to all of the above, make enabling sales tax calculations as simple as possible. It should only require a checkbox or toggle switch to activate.
-
Point merchants in the right direction to configure product exemptions, customer exemptions, and nexus address management if you plan to add this functionality.
-
When providing a dropdown list of TaxJar product categories, consider using this format:
Clothing (20010) Food & Groceries (40030) and so on…