Prerequisites
For the lookup steps you need three things (the formula needs nothing at all):
- Python 3.8 or newer.
- The
requestslibrary. - A free API Ninjas API key — issued instantly, no credit card. If you already have an account, it's on your profile page.
pip install requestsStep 1: Look up the combined rate
The rate you charge is almost never just the state rate — counties, cities, and special districts each add their own. The Sales Tax API returns the full breakdown for any ZIP code (or city and state):
import requests
response = requests.get(
'https://api.api-ninjas.com/v1/salestax',
params={'zip_code': '90210'},
headers={'X-Api-Key': 'YOUR_API_KEY'},
timeout=10,
)
response.raise_for_status()
rate_info = response.json()[0]
print(f"Combined rate: {float(rate_info['total_rate']) * 100:.2f}%")
# Combined rate: 9.75%[
{
"zip_code": "90210",
"state_rate": "0.06",
"city_rate": "0.01",
"county_rate": "0.0025",
"additional_rate": "0.025",
"total_rate": "0.0975"
}
]Rates are decimals — "0.0975" means 9.75% — and they sum: for 90210, California's 6% + LA County's 0.25% + Beverly Hills' 1% + 2.5% of special districts = 9.75%. Combined rates nationwide run from 0% (Delaware, Montana, New Hampshire, Oregon) past 10% in the highest-tax parts of Louisiana and Alabama. Detailed breakdown fields beyond the state rate are available on premium plans.
Step 2: Apply the formula
With the rate in hand, the calculation is elementary:
| What you want | Formula | Example (9.75%) |
|---|---|---|
| Sales tax owed | price × rate | $100 × 0.0975 = $9.75 |
| Total with tax | price × (1 + rate) | $100 × 1.0975 = $109.75 |
| Pre-tax price from a total | total ÷ (1 + rate) | $109.75 ÷ 1.0975 = $100.00 |
price = 100.00
rate = 0.0975 # 9.75% as a decimal
sales_tax = price * rate # 9.75
total = price * (1 + rate) # 109.75
print(f'Tax: ${sales_tax:.2f}')
print(f'Total: ${total:.2f}')The one mistake to avoid: convert the percentage to a decimal before multiplying — 9.75% is 0.0975, not 9.75.
Step 3: Calculate automatically
If you want dollar amounts rather than rates — what a receipt actually shows — the Sales Tax Calculator API does the multiplication for you, itemized per jurisdiction:
response = requests.get(
'https://api.api-ninjas.com/v1/salestaxcalculator',
params={'zip_code': '90210', 'amount': 100},
headers={'X-Api-Key': 'YOUR_API_KEY'},
timeout=10,
)
response.raise_for_status()
breakdown = response.json()[0]
print(f"Total tax: ${breakdown['total_tax']}")
# Total tax: $9.75[
{
"zip_code": "90210",
"pre_tax_amount": "100",
"state_rate": 0.06,
"city_rate": 0.01,
"county_rate": 0.0025,
"additional_rate": 0.025,
"total_rate": 0.0975,
"state_tax": 6,
"city_tax": 1,
"county_tax": 0.25,
"additional_tax": 2.5,
"total_tax": 9.75
}
]state_tax, county_tax, city_tax, and additional_tax arrive separately, with total_tax summing them — no float arithmetic on your side.
Step 4: Calculate backwards
Given a receipt total and the rate, recover the pre-tax price by dividing by 1 + rate. Multiplying the total by the rate is the classic mistake — it overstates the tax:
total_paid = 109.75
rate = 0.0975
pre_tax_price = total_paid / (1 + rate) # 100.00 — divide, don't multiply
sales_tax = total_paid - pre_tax_price # 9.75
print(f'Pre-tax price: ${pre_tax_price:.2f}')
print(f'Sales tax: ${sales_tax:.2f}')Step 5: Wire it into checkout
In production, look the tax up per order at request time — rates change during the year, and hard-coded tables drift. The client shape is the usual one: key from the environment, one shared session, a timeout:
import os
import requests
session = requests.Session()
session.headers['X-Api-Key'] = os.environ.get('API_NINJAS_KEY', 'YOUR_API_KEY')
def sales_tax_for_order(zip_code: str, subtotal: float) -> dict:
"""Return the full tax breakdown for an order at checkout time."""
response = session.get(
'https://api.api-ninjas.com/v1/salestaxcalculator',
params={'zip_code': zip_code, 'amount': subtotal},
timeout=10,
)
response.raise_for_status()
return response.json()[0]
order = sales_tax_for_order('90210', 249.99)
print(f"Subtotal: ${order['pre_tax_amount']}")
print(f"Tax rate: {float(order['total_rate']) * 100:.2f}%")
print(f"Tax due: ${order['total_tax']:.2f}")For the few ZIP codes that span multiple tax districts, pass street_address together with city and state for an exact jurisdiction match. And if you sell across states, whether you must collect at all is an economic-nexus question — the /v1/salestaxnexus endpoint checks your sales figures against every state's thresholds.
Where to go from here
For European transactions the VAT Rates API covers every EU member state, and the Income Tax and Property Tax APIs round out the US tax picture. The complete script is below.