Why global tax data is hard to build yourself
If you've considered building your own tax data pipeline instead of using an API, the initial estimate is usually "a few weeks of data entry." The reality is considerably more complex.
Each country is a different problem
The UK has a single progressive income tax schedule with a personal allowance and National Insurance on top. Germany has a non-linear progressive formula (not simple brackets) plus solidarity surcharge and church tax. The US has 50 different state systems layered on top of federal tax, each with its own treatment of deductions, withholdings, and local levies. Canada has federal plus provincial tax with different rates in every province. Singapore has a straightforward progressive schedule. The UAE has no income tax at all.
Modelling all of these consistently — in a single unified schema — requires building a calculation engine, not just a data store.
The update cadence problem
Most countries update their tax rates annually. Some update mid-year. The UK Chancellor can change thresholds in the Autumn Statement. The IRS adjusts for inflation each November. Each update requires you to source the new rates, validate them against the official publication, implement them, and re-test edge cases (particularly around rounding, caps, and tapered allowances). Across 111 countries, this is a continuous engineering and research workload.
What the API abstracts away
When you use the CountryTaxCalc API, you get a single POST /calculate endpoint that handles all the above automatically. The response is always the same structure. Rate updates are deployed to the API and you get them immediately, without any code changes on your side.
What 111 countries actually includes
The full list is accessible via GET /api/v1/countries (no API key required). Here's the geographic breakdown:
| Region | Coverage highlights |
|---|---|
| North America | All 50 US states + DC (federal + state), all 13 Canadian provinces/territories (federal + provincial), Mexico |
| Europe | UK, Germany, France, Netherlands, Sweden, Switzerland, Spain, Italy, Belgium, Denmark, Norway, Finland, Ireland, Austria, Poland, Portugal, and more |
| Asia-Pacific | Australia, Japan, Singapore, South Korea, India, New Zealand, Hong Kong, Indonesia, Thailand, Malaysia, Philippines |
| Middle East | UAE (0% income tax), Saudi Arabia (0%), Bahrain (0%), Qatar (0%), Israel, Turkey |
| Latin America | Brazil, Mexico, Argentina, Colombia, Chile, Peru |
| Africa | South Africa, Nigeria, Kenya, Ghana, Egypt, Morocco, and others |
Zero-tax jurisdictions (UAE, Saudi Arabia, Bahrain, Cayman Islands, etc.) return valid responses with total_tax: 0 and effective_tax_rate: 0. These are correct and expected — useful for relocation comparison tools where the 0% option is often the most compelling result.
Data sourcing and official government authorities
Every country's tax data is sourced from its official government tax authority. Each API response includes:
metadata.data_source— the name of the official authority (e.g. "HMRC", "IRS", "Bundeszentralamt für Steuern")metadata.last_updated— the ISO date when the data was last verifiedmetadata.accuracy_confidence— a confidence score from 0.0 to 1.0
For the full sourcing methodology — including how rates are verified, the update cadence, and how edge cases are handled — see the data methodology page.
Endpoints overview
The global coverage is accessible across several endpoints depending on your use case:
| Endpoint | Method | What it does | Tier required |
|---|---|---|---|
/api/v1/countries | GET | List all 111 supported countries with codes and currencies | Free |
/api/v1/countries/{code} | GET | Country metadata: jurisdictions, complexity, features, source URL | Starter+ |
/api/v1/countries/{code}/rates | GET | Raw tax brackets, deductions, and social contribution data | Starter+ |
/api/v1/calculate | POST | Full tax calculation with breakdown for a specific income + country | Free |
/api/v1/summary | GET | Simplified tax snapshot ranked across all 111 countries at a given income | Growth+ |
/api/v1/compare | POST | Detailed multi-country comparison (up to 20 countries, with currency conversion) | Pro+ |
Listing all countries (no key required)
The countries list endpoint is openly accessible — no API key needed. Use it to build your country selector UI or validate country codes before passing them to /calculate:
curl https://api.countrytaxcalc.com/api/v1/countries
{
"countries": [
{
"country_code": "GB",
"country_name": "United Kingdom",
"currency": "GBP",
"currency_symbol": "£",
"currency_name": "British Pound",
"has_jurisdictions": false
},
{
"country_code": "US",
"country_name": "United States",
"currency": "USD",
"currency_symbol": "$",
"currency_name": "US Dollar",
"has_jurisdictions": true
}
// ... 109 more
],
"total": 111
} POST /calculate in a loop — the result is equivalent, it just consumes one request per country. See the salary comparison guide for a worked example of both approaches.
Currency conversion
For global comparisons, currency is often the hardest problem. If you want to compare a £80,000 UK salary against a €90,000 German salary, you need to convert both to a common currency before the effective rate comparison is meaningful.
Pass a currency field in the request and the API handles conversion automatically:
POST /api/v1/calculate
{
"income": 80000,
"currency": "USD",
"country": "GB"
}
// Response includes:
"currency_conversion": {
"input_income": 80000,
"input_currency": "USD",
"local_currency": "GBP",
"exchange_rate": 0.7842,
"converted_income": 62736,
"rate_date": "2026-07-07",
"rate_source": "api.frankfurter.dev (European Central Bank)",
"fx_source": "frankfurter",
"fx_rate_age_hours": 18
}
The fx_rate_age_hours field lets you surface a "rates may be outdated" indicator if the exchange rate is more than 24 hours old. In practice, ECB rates update every business day.
When currency conversion fails (rare, for obscure currency pairs), the API returns a 422 with a clear message rather than silently using wrong data.
Accuracy confidence scoring
Not all tax data is created equal. Some countries have highly stable, well-documented progressive tax systems that map cleanly to the API's model. Others have complex edge cases — tapered allowances, employer/employee contribution splits, local municipality taxes — that a simplified model may not fully capture.
Every calculation response includes metadata.accuracy_confidence:
- 0.95 — DB-backed calculation using verified official government data
- 0.7 — Simplified fallback estimate for countries with complex or partially modelled systems
Use this field in your product to show an "approximate" label for lower-confidence results. Example:
const { metadata, totals } = response;
const label = metadata.accuracy_confidence >= 0.9
? `£${totals.net_income.toLocaleString()} take-home`
: `~£${totals.net_income.toLocaleString()} estimated take-home`; Frequently asked questions
Q: How many countries does the API cover?
As of mid-2026, the API covers 111 jurisdictions. This includes all 50 US states plus DC, all 13 Canadian provinces and territories, and 80+ international countries. The full list is available via GET /api/v1/countries — no API key required for this endpoint.
Q: Does the API cover sub-national jurisdictions like US states?
Yes. For the US, pass "country": "US" and "jurisdiction": "CA" (state code) to get a federal + state combined breakdown including Social Security and Medicare. Canada works the same way — "country": "CA" with a province code like "ON". Use GET /api/v1/countries/US to see all available US state jurisdiction codes.
Q: How often is the tax data updated?
Tax rate data is audited quarterly and updated within 30 days of confirmed rate changes by official government tax authorities. Each response includes metadata.last_updated (the date the data was last refreshed) and metadata.data_source (the official authority). Rate changes are published in the API changelog.
Q: What currency does the API use?
Each country's calculation uses its local currency by default. You can optionally pass a currency field in the request (e.g. "currency": "USD") and the API will convert your income to the local currency before calculating, then include full currency conversion metadata in the response (exchange rate, rate date, source). Currency conversion uses ECB rates (primary) with exchangerate-api.com as fallback.
Q: Is the API GDPR-compliant?
The API does not store, log, or process personally identifiable information. Income values submitted to the API are used only for the tax calculation and are not retained after the response is returned. No user data is collected by the API. See the privacy policy for full details.
Q: Can I access historical tax year data?
Yes — Growth, Pro, and Enterprise plans can pass "tax_year": 2024 (or any supported prior year) in the request body. Free and Starter plans return current-year data only. Historical data is useful for building year-over-year comparisons or back-testing.
Q: What happens if I query a country the API doesn't support?
The API returns a 404 response: {"error": "Country not found", "message": "Country not found: XY"}. Use GET /api/v1/countries to get the definitive list of all supported country codes before building your UI, so you can handle unsupported countries gracefully.