Sales Tax Calculations

Table of Contents
  1. Introduction
Guidelines

    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:

    TaxJar API Accuracy

    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:

    Graham at TaxJar Most origin states consider the location at which the seller received the order from the customer the situs of the sale. If the location at which the seller receives the order is in the state, then it trumps the ship-from location. If the location at which the seller receives the order is located outside the state, some states will source the sale to the ship-from location if that location is in the state (example: CA), and some will source it to destination (example: TX). Sales for which the order was received at a location in state but shipped from a location outside the state are virtually always sourced to the location at which the seller receives the order. Sales for which the order was received out of state and shipped from out of state are always destination.

    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:

    Magento 2 Nexus Addresses

    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: TaxJar Calculations Config


    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…
    

    Next: Sales Tax Reporting

    © 2024 TaxJar