A “tax” in FoxyCart is a standalone set of properties that define a particular tax that can be applied to your product categories. Your store can have zero tax rates or 100, and they can be applied individually or in parallel, but the best way to understand how taxes work in FoxyCart is to dive into the admin to look at the available options.
The section below will discuss each individual option you'll see when you hit the “taxes” menu item in your store's admin.
country
or region
taxes to set tax rates automatically. See below for more details.17.5
, not 0.175
.Taxes, by themselves, don't actually do anything. In order for a tax to be applied it must be associated with a category. Once associated, any products in that category will get the appropriate taxes applied. To associate a tax with a category, simply check the appropriate checkbox(es) when you edit your category.
If you have multiple non-3rd party taxes (ie. not AvaTax, TaxJar, etc.) to be applied in one transaction they will be applied individually. Here's a quick example of what your cart could look like on pageload on checkout, when certain taxes are “TBD” because the address info hasn't been completed yet:
If you are using AvaTax, TaxJar, or another 3rd-party tax system, that service will override any other taxes configured in Foxy. All taxes must be configured through the 3rd party.
FoxyCart applies taxes based on the shipping address. If a separate shipping address is not specified, the billing address is assumed to be the shipping address, and taxes are applied accordingly. While there is some debate online as to whether or not this is correct, we have asked multiple tax experts and tax rate services, and this approach is what we believe to be the most correct at this point.
To allow customers to opt out of taxes, you first need to understand how the “exempt customers with a tax id” checkbox works. If you've enabled this option and a customer checks out with a non-empty customer_tax_id
value, FoxyCart will remove the appropriate taxes.
To enable the option to exempt customers with tax id, first go to your Taxes Settings and select the tax for which you'd like to offer the exemption. Check the exempt customers with a tax id:
option and save. You'll need to repeat this for each tax you have set up where you'd like to offer the exemption.
You can add a Customer Tax ID input to your checkout easily in the template configuration page of your admin, under the checkout → “Customize which checkout fields are shown and required” section. Here you can hide the field (default), make it optional, or make it required.
To pass the tax ID value for a customer from your own website through the cart, you can do that by making use of prepopulation. This simply means calling your cart with the name of the field included, and can be with a product add to cart, or a separate JSONP call to the cart. Because the tax ID could be in the billing or the shipping address, there are two possible fields you'll need to prepopulate, shipping_tax_id
and billing_tax_id
. As an example of doing that with JSONP:
var customer_tax_id = "#########"; FC.client.request('https://'+FC.settings.storedomain+'/cart?shipping_tax_id=' + customer_tax_id + '&billing_tax_id=' + customer_tax_id);
If you want to run that code on your own website - it will need to be wrapped within an onLoad
function and a ready.done
event function to ensure it runs when the FoxyCart javascript has initialised. That would look like this:
var FC = FC || {}; FC.onLoad = function() { FC.client.on("ready.done", function() { var customer_tax_id = "#########"; FC.client.request('https://'+FC.settings.storedomain+'/cart?shipping_tax_id=' + customer_tax_id + '&billing_tax_id=' + customer_tax_id); }); }
You can also add this value via the API, if you'd like to control things more tightly. (We plan on adding the ability to modify customers in our admin in a future release.) Even if the field is not visible on the checkout, if the customer has a customer_tax_id
, the taxes will behave as expected on the checkout. In this way, you could have that field hidden, and manually apply tax ID numbers (via an API script) after doing your own validation, and allow only approved customers to be tax-exempt.
Note that no validation on the number is performed.
For users in countries where tax-inclusive pricing is common, Foxy allows tax-inclusive pricing. This can get a little more complicated than you might anticipate, so please test this functionality (particularly if you're using coupons and discounts) to ensure thing function as expected for your region.
Foxy's tax-inclusive functionality is largely a display-only change, and is set (inclusive or exclusive) on the template set. (As such, you cannot display both tax-inclusive and tax-exclusive in the same cart.) The price
value of your products will always be the tax-exclusive value.
This is easiest to communicate by way of example. Assume an $83.33 product and a 20% tax. In both cases, the item should be price=83.33
. (Note that there may be situations where, due to rounding, you may need to specify a more accurate price, such as price=83.3333
. Foxy can handle that specificity to fix rounding issues.)
In that sense, this can be considered a “display only” change. All other aspects of Foxy's tax functionality remain effectively unchanged. For example, a tax-exempt customer will pay the price
value of the item(s) in the cart, and it will look identical to how it'd look for a tax-exclusive cart.
Please also review the coupon and discount documentation if you're doing tax-inclusive pricing with coupons or discounts, as that has some possibilities that each individual merchant (and/or their accountants) will want to review.
If you're utilising Avalara Avatax, TaxJar or Thomson Reuters ONESOURCE, we utilise the tax figure that they pass us, so you shouldn't see any discrepancies there.
For any taxes that are set with a manual rate, or set to calculate automatically through the “FoxyCart Default” option, some rounding does occur within the calculations. Taxes are calculated on three distinct portions of the order, depending on the aspects that are included. These are on the product subtotal per category, on any taxable coupon discounts, and shipping if any taxes are configured to tax that. Each of these totals are rounded to 2 decimal places and combined together to form the final taxes displayed to the customer.
If the “Tax is Calculated Automatically” checkbox is checked for a given tax, taxes will be calculated automatically within the designated area for that tax. The default service provider allows for automatic rates in United States and Canada, or when the “Union” tax type is set. If you have an Avalara, TaxJar or ONESOURCE account, you can also configure that native integration for live tax rates in all countries and regions they support.
As an example of auto-calculated tax, if you have a tax set for California that is set to calculate automatically, FoxyCart will query the tax database based on the customer's zip code and/or city, and apply the appropriate tax rate (which may include state, county, city, or other tax jurisdictions). This automatic lookup will dictate if the tax should apply to shipping or not, and if it relates to the billing or shipping address.
Our tax database is provided by Thomson Reuters ONESOURCE (formerly Tax Data Systems), which is updated on a monthly basis. Note that neither FoxyCart nor Thomson Reuters makes any warranty or claim as to the accuracy of the tax data returned, but many very large merchants use Tax Data Systems. (Note that we also support ONESOURCE Indirect, which is a separate integration suited for medium and large businesses.) Currently we use a two different versions of the database:
Though the Onesource database is generally very accurate, it's not perfect. If you believe you've got a transaction with an incorrect tax rate, please do the following:
We will then contact the tax database provider to alert them. Typically, the rate will then be corrected on the next monthly update. Please note that we can't guarantee whether updates will be made, but we can say from experience that updates do tend to be pretty quick.
If this uncertainty presents too significant a challenge, we do support other tax rate integrations with AvaTax, TaxJar, and Thomson Reuters ONESOURCE Indirect.
The EU VAT is complicated, and the changes at the beginning of 2015 certainly didn't help. While we're not tax experts on our end, we have tried to give enough flexibility for any merchant that needs to collect the EU VAT. We encourage you to familiarize yourself with the options on the “Union” tax, but here are a few notes:
Please note that the EU VAT requirements are many, and we cannot guarantee our functionality as it relates to any country's tax requirements. At this point, there are a few known issues you should be aware of:
The following notes apply for AvaTax, TaxJar, OneSource Indirect, and any other 3rd party tax integrations that may be added to Foxy. The custom tax endpoint has similar considerations.
tl;dr:
Basically, you should consider the tax provider to be the authority, and Foxy will do everything it can to ensure that system has all transaction data.
If your store is configured with an AvaTax, TaxJar, or OneSource Indirect tax rate for a specific country, that provider will always be the authority for transactions in that country, even if the tax configuration in Foxy doesn't specify using that provider for a specific region (state, province, country, etc.). This ensures that the correct tax is charged even if you forgot to update your Foxy settings to match your AvaTax settings.
For instance, if you only have a state-level tax configured in Foxy to use AvaTax for California, but you have California and Texas configured in AvaTax, the customer will ultimately be charged Texas sales tax, even though no taxes for Texas are configured in Foxy. This is because Foxy will always defer to AvaTax, if any AvaTax taxes are configured. Similarly, if you have another tax rate (for instance, a static rate) configured in Foxy but not in AvaTax, that tax will ultimately be ignored, as AvaTax is the authority.
There are four important items to note here:
With the tax provider integrations (Avalara, TaxJar, OneSource) above, Foxy will always use the tax total returned from the provider when charging the customer. But… as of Foxy v2.0, the rates displayed to the customer prior to completing their transaction (on the cart and checkout) are calculated dynamically by Foxy based on the tax rate(s) provided by the provider. This may result in the tax displayed to the customer (prior to completing the checkout and proceeding to the receipt) being slightly off (typically by 1¢ due to rounding; if the amount is off by more, it should generally be lower than what's displayed to the customer).
When the customer completes their transaction, the amount of tax charged and displayed on the receipt and in the admin will match exactly what was returned from the provider.
If this may present a problem for your store, we suggest adding an “(estimated)” text. You can do this by changing the “Tax” language string in the Foxy admin to “Tax (estimated)”, in the “language” page of your store's admin. Please contact our support team for assistance with this if you'd like help.
If you have an Avalara account, you can add your credentials to the integrations page as shown (Here, the service url:
is for a sandbox environment. If you're using an Avalara production account, you should use https://avatax.avalara.net) :
Important Notes
For more information about each setting, see the inline help in the admin by clicking on the ? box. If you have further questions about the configuration information here, please contact Avalara.
Please see the “Possible Mismatch between Displayed & Charged Taxes” section above.
Once your native Avalara integration is configured, you can select it as a service provider when configuring a tax.
Address Validation
The “use address validation” option within your Avalara settings will ensure customer addresses used on the checkout page in the supported countries you specify are validated via Avalara's address validation system and confirmed by the customer as shown below:
If the address is invalid, your customers will see this message, and they will still be able to complete the checkout or modify the address:
We support TaxJar for automatic rate calculation as well.
Please review the notes above to ensure you're familiar with how TaxJar works with Foxy.
If you have an TaxJar account, you can add your credentials to the integrations page as shown under “native integrations”:
For more information about each setting, see the inline help in the admin by clicking on the ? box. If you have further questions about the configuration information here, please contact TaxJar.
Please see the “Possible Mismatch between Displayed & Charged Taxes” section above.
Once your native TaxJar integration is configured, you can select it as a service provider when configuring a tax:
We support ONESOURCE for automatic rate calculation as well. There are many different systems within the ONESOURCE brand, so please contact us for more details. Some things to keep in mind:
Please let us know if you have any questions.
If you have specific tax integration requirements, or a separate 3rd party system we don't support, you can use the custom tax endpoint functionality. This is similar to our custom shipping endpoint functionality. Foxy will send a payload (mirroring the API format) to your endpoint, and you can respond back with a response like this:
{ "ok":true, "details":"", "name":"Custom Tax", "expand_taxes":[ { "name":"Super Tax", "rate":0.045, "amount":0.23 }, { "name":"Mega Tax", "rate":0.053, "amount":0.27 }, { "name":"Little Tax", "rate":0.021, "amount":0.11 } ], "total_amount":0.6, "total_rate":0.119 }
Attribute | Description |
---|---|
ok | Show that tax was calculate normally or there is some error. |
details | If you have any errors write them here. |
name | This name will be shown on the cart/checkout page. |
expand_taxes | More detail description of applied taxes, should be at least one item. These details are shown on receipt and in the admin, so if there is more than one tax included within expand_taxes , they will be shown individually on the receipt and in the admin. |
expand_taxes.name | Name of the individual tax. |
expand_taxes.amount | Tax amount for the individual tax. |
expand_taxes.rate | Rate for the individual tax, as a decimal (5% is 0.05 ). |
total_amount | Total tax amount, this amount is used for adding to the total order amount. Should be the combined total of the tax amount s within the expand_taxes array. |
total_rate | Total combined tax rate, as a decimal (5% is 0.05 ), shown on the cart/checkout page. Should be the combined total of the rate s within the expand_taxes array. |
If you want to return a successful response that has no taxes to display, you can return a payload as follows:
{ "ok": true, "details": "", "name": "", "expand_taxes": [ ], "total_amount": 0, "total_rate": 0 }
An example of an error response payload is as follows. NOTE that this will prevent customers from checking out. Similarly, if we don't get a valid response from your custom endpoint, it will display a default error and prevent the checkout.
{ "ok":false, "details":"Your error" }
To display taxes without a % rate omit the rate
param:
{ "ok": true, "details": "", "name": "", "expand_taxes": [ ], "total_amount": 0 }
To display 0% taxes, set the rate to 0
:
{ "ok": true, "details": "", "name": "Zero Amount", "expand_taxes": [ { "name": "Tax", "rate": 0, "amount": 0 } ], "total_amount": 0, "total_rate": 0 }
There are currently the following types of requests, differentiated by a header named foxy-webhook-event
with the following values:
tax/calculate
: This is for cart
resources and mostly mirrors the custom shipping endpoint (which itself looks like the API's ''cart'' resource).tax/report
: This happens when the transaction is completed, and the request body mirrors a zoomed ''transaction'' API resource.tax/refund
: Similar to tax/report
, but sent when a full refund is issued.tax/void
: Identical to tax/refund
, but sent when a payment is voided. (For accounting or reporting purposes, this may necessitate different handling on your end.)tax/update
: Similar to tax/report
, but sent when a partial refund is issued. There is a separate header to indicate the trigger for the event. Currently we only have one trigger:
checkout/submit
: This accompanies a tax/calculate
event, and will only be present if the customer has clicked the button to submit their checkout. In other words, this header is not when the cart changes, or when the checkout updates with the customer's address. It happens right before the pre-payment webhook.Foxy has a Netlify function available for the Custom Tax Endpoint to help you get started. You'll need a Netlify account, then you can follow the directions on our Netlify repo on GitHub and follow the instructions in the readme for setting up the function.
The repository provides an example function, which you can tailor to your needs.
Though cumulative taxes can almost always be supported (with FoxyCart's current functionality) with just a little bit of basic algebra, please contact us if this is of interest to you.