POST /api/v1/calculate returns totals.net_income, totals.effective_tax_rate, totals.monthly_net_income, and a full breakdown of income tax brackets and social contributions — in a single call, for any of 111 countries.
What the API returns
The POST /api/v1/calculate endpoint returns three things in every response: the totals (the numbers to display to users), the breakdown (the detailed tax logic), and the metadata (data provenance and confidence).
The totals object
This is what most products display directly to users:
net_income— annual take-home pay after all deductionstotal_tax— sum of income tax + all social contributionseffective_tax_rate— total tax as a percentage of gross incometake_home_percentage— the inverse: percentage of gross income retained (100 − effective rate)monthly_net_income— annual net divided by 12, pre-calculated for conveniencetotal_deductions— sum of all pre-tax deductions applied (personal allowances, etc.)
The breakdown object
This contains the detailed tax logic — useful if you want to show users how the number was reached:
deductions[]— named deductions applied before tax (e.g. Personal Allowance)taxable_income— gross income minus deductionsnational_income_tax— income tax amount, effective rate, marginal rate, and brackets appliedsocial_contributions[]— each social contribution (National Insurance, Medicare, etc.) with name, type, amount, and rate
The metadata object
For trust and compliance:
data_source— official government authority (e.g. "HMRC", "IRS")last_updated— ISO date the rates were last verifiedaccuracy_confidence— 0.95 (DB-backed, verified) or 0.7 (simplified estimate)calculation_date— ISO timestamp of the calculation
Step 1: Make the request
The minimum required fields are income and country. All other fields are optional.
curl -X POST https://api.countrytaxcalc.com/api/v1/calculate \
-H "Content-Type: application/json" \
-H "X-API-Key: your_api_key_here" \
-d '{
"income": 60000,
"country": "GB"
}' Optional fields you can add:
"currency": "USD"— income is in USD, convert to GBP before calculating"jurisdiction": "CA"— for US states or Canadian provinces (US/CA only)"tax_year": 2025— historical year data (Growth+ plans only)
Country can be specified as an ISO 3166-1 alpha-2 code ("GB") or as a country name ("United Kingdom"). Country codes are preferred — they're unambiguous. Use GET /api/v1/countries (no key required) to get the complete list of valid codes.
Step 2: Parse the response
Here's how to extract the key values in JavaScript and Python:
JavaScript
const response = await fetch(
"https://api.countrytaxcalc.com/api/v1/calculate",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": process.env.COUNTRYTAXCALC_API_KEY
},
body: JSON.stringify({ income: 60000, country: "GB" })
}
);
const data = await response.json();
// Core take-home values
const annualNetIncome = data.totals.net_income; // 45357
const monthlyNetIncome = data.totals.monthly_net_income; // 3779.75
const effectiveTaxRate = data.totals.effective_tax_rate; // 24.41
const takeHomePercent = data.totals.take_home_percentage; // 75.59
const totalTax = data.totals.total_tax; // 14643
// Breakdown
const incomeTax = data.breakdown.national_income_tax.amount; // 11432
const marginalRate = data.breakdown.national_income_tax.marginal_rate; // 0.40
// Social contributions
const socialTax = data.breakdown.social_contributions
.reduce((sum, c) => sum + c.amount, 0); // 3211
// Metadata
const confidence = data.metadata.accuracy_confidence; // 0.95
const source = data.metadata.data_source; // "HMRC" Python
import requests
resp = requests.post(
"https://api.countrytaxcalc.com/api/v1/calculate",
headers={
"Content-Type": "application/json",
"X-API-Key": "your_api_key_here"
},
json={"income": 60000, "country": "GB"}
)
data = resp.json()
totals = data["totals"]
breakdown = data["breakdown"]
annual_net = totals["net_income"] # 45357
monthly_net = totals["monthly_net_income"] # 3779.75
effective_rate = totals["effective_tax_rate"] # 24.41
total_tax = totals["total_tax"] # 14643
income_tax = breakdown["national_income_tax"]["amount"] # 11432
# Social contributions as a dict
social = {
c["name"]: c["amount"]
for c in breakdown["social_contributions"]
}
# e.g. {"National Insurance": 3211} Error handling
Always check the HTTP status code before parsing. The API uses standard codes:
200— success, parseresponse.json()normally400— bad request (missing fields, invalid income value) — checkerrorfield401— invalid or missing API key404— country not found — use the countries list endpoint to validate codes422— currency conversion failed (rare, obscure currency pairs)429— rate limit exceeded — checkretry_after_secondsorreset_at500— internal error — retry with exponential backoff
Step 3: Display to users
The fields you choose to display depend on your product. Here are the most common display patterns:
Simple take-home calculator
Display totals.net_income and totals.effective_tax_rate. Add totals.monthly_net_income as a secondary figure. This is sufficient for most user-facing calculators.
// Minimal display
const netLabel = confidence >= 0.9
? `£${annualNetIncome.toLocaleString()}`
: `~£${annualNetIncome.toLocaleString()} (estimated)`;
// Full card display
`Annual take-home: ${netLabel}
Monthly: £${monthlyNetIncome.toLocaleString()}
Effective tax rate: ${effectiveTaxRate}%
You keep: ${takeHomePercent}% of gross` Detailed breakdown view
For users who want to see how the number was calculated, render the breakdown object as a line-item list:
const displayBreakdown = [
{ label: "Gross income", amount: data.gross_income, bold: true },
...data.breakdown.deductions.map(d => ({
label: d.name,
amount: -d.amount,
note: "deduction"
})),
{ label: "Taxable income", amount: data.breakdown.taxable_income, note: "subtotal" },
{ label: "Income tax", amount: -data.breakdown.national_income_tax.amount },
...data.breakdown.social_contributions.map(c => ({
label: c.name,
amount: -c.amount
})),
{ label: "Net take-home", amount: data.totals.net_income, bold: true }
]; Compliance requirement
Worked example: UK £60,000 salary (2026/27)
The following example uses verified HMRC 2026/27 rates. This is the exact response structure for a UK gross salary of £60,000.
// Request
POST /api/v1/calculate
{
"income": 60000,
"country": "GB"
}
// Response
{
"country": "United Kingdom",
"country_code": "GB",
"tax_year": 2026,
"currency": "GBP",
"currency_symbol": "£",
"gross_income": 60000,
"breakdown": {
"deductions": [
{ "name": "Personal Allowance", "amount": 12570 }
],
"taxable_income": 47430,
"national_income_tax": {
"amount": 11432,
"effective_rate": 0.1905,
"marginal_rate": 0.40,
"brackets_applied": [
{ "threshold": 0, "rate": 0.20, "tax": 7540 },
{ "threshold": 50270, "rate": 0.40, "tax": 3892 }
]
},
"social_contributions": [
{
"name": "National Insurance",
"type": "social_security",
"amount": 3211,
"rate": 0.08,
"capped": false
}
]
},
"totals": {
"total_deductions": 12570,
"total_tax": 14643,
"net_income": 45357,
"effective_tax_rate": 24.41,
"take_home_percentage": 75.59,
"monthly_net_income": 3779.75
},
"metadata": {
"calculation_date": "2026-07-08T10:00:00.000Z",
"data_source": "HMRC",
"last_updated": "2026-04-06",
"accuracy_confidence": 0.95
}
} How the numbers are calculated
UK income tax 2026/27:
- Personal Allowance: £12,570 (tax-free)
- Basic rate 20%: £12,571–£50,270 → on the first £37,700 of taxable income = £7,540
- Higher rate 40%: £50,271–£60,000 → on £9,730 above the threshold = £3,892
- Income tax total: £11,432
National Insurance (employee, 2026/27):
- 8% on earnings £12,584–£50,284: £3,016 (rounded to nearest £)
- 2% on earnings above £50,284: £195
- NI total: £3,211
Total tax: £11,432 + £3,211 = £14,643. Net income: £60,000 − £14,643 = £45,357. Effective rate: £14,643 ÷ £60,000 = 24.41%.
Multi-country comparison
To compare take-home pay across multiple countries, call POST /calculate in a loop — one request per country. This is the approach available on all plan tiers. For the equivalent income in each country, use the currency field to convert from a single base currency.
// Compare UK vs Germany vs Netherlands at $80,000 USD equivalent
const countries = ["GB", "DE", "NL"];
const results = await Promise.all(
countries.map(country =>
fetch("https://api.countrytaxcalc.com/api/v1/calculate", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": process.env.COUNTRYTAXCALC_API_KEY
},
body: JSON.stringify({
income: 80000,
currency: "USD", // convert to local currency before calculating
country
})
}).then(r => r.json())
)
);
// Sort by net income descending
results.sort((a, b) => b.totals.net_income - a.totals.net_income);
results.forEach(r => {
console.log(
`${r.country}: ${r.currency_symbol}${r.totals.net_income.toLocaleString()} ` +
`net (${r.totals.effective_tax_rate}% effective)`
);
});
Each response includes a currency_conversion object showing the exchange rate used, so you can display it transparently to users.
Disclaimers and accuracy notes
The take-home figures the API returns are accurate for the modelled tax position — a standard single resident taxpayer with the income specified. There are circumstances where the actual take-home will differ:
- Filing status — the US, Germany, and several other countries have different rates for married filers. The API models single/standard by default.
- Employer contributions — some countries (notably Germany, France, Netherlands) have significant employer social contributions on top of employee contributions. The API models employee-side only — what the employee receives, not the total employment cost to the employer.
- Tax reliefs and deductions — pension contributions, mortgage interest relief, charitable giving, and other itemised deductions are not modelled. Users with significant deductions will have a lower actual tax bill.
- Non-resident taxation — most API calculations assume standard resident tax treatment. Non-residents, dual residents, and expats often have different rates or treaty-based reductions.
These limitations are reflected in the metadata.accuracy_confidence field. Countries where the model is known to be a simplification return 0.7 confidence; countries with a full verified calculation return 0.95.
Frequently asked questions
Q: Does the API return monthly take-home pay as well as annual?
Yes. The response includes totals.monthly_net_income — the annual net income divided by 12. For the UK £60,000 example, that's £3,779.75/month. You don't need to calculate it yourself.
Q: How do I get the total tax burden including social contributions?
totals.total_tax is the sum of income tax plus all social contributions. It's always the right number to use for 'total deducted from pay'. If you need the split, breakdown.national_income_tax.amount gives you income tax alone, and you can sum breakdown.social_contributions[].amount for social insurance separately.
Q: What's the difference between effective_tax_rate and marginal_rate?
effective_tax_rate is the percentage of gross income paid in total tax (income tax + social contributions combined). marginal_rate inside breakdown.national_income_tax is the rate that applies to the next pound of income — useful for showing users how additional earnings will be taxed. The effective rate is almost always what you want to display to end users.
Q: What does take_home_percentage represent?
totals.take_home_percentage is simply 100 - effective_tax_rate. If the effective rate is 24.41%, take-home percentage is 75.59%. It's a convenience field for display — 'you keep 75.6% of your salary' is often more intuitive to users than the equivalent tax rate.
Q: What if the country has no income tax (UAE, for example)?
The API returns a valid full response with totals.total_tax: 0, totals.effective_tax_rate: 0, and totals.net_income equal to gross income. The breakdown object is still present but national_income_tax.amount and social_contributions will be zero. Zero-tax jurisdictions are fully supported — useful for relocation comparison tools where the 0% result is often the most compelling.
Q: How do I handle the accuracy_confidence field?
Check metadata.accuracy_confidence — values of 0.95 indicate a DB-backed calculation from verified official data. Values of 0.7 indicate a simplified fallback estimate. For consumer-facing products, we recommend labelling 0.7-confidence results as 'approximate' — for example, prefixing the net income with '~'. See the global coverage guide for a worked implementation example.
Q: Can I pass a filing status or number of dependents?
The current API models standard/default tax positions for each country. It does not accept filing status, marital status, number of dependents, or itemised deductions. The calculation assumes a single resident taxpayer with no special circumstances. This is accurate for most use cases but users with complex situations (married filing jointly in the US, for example) should be directed to a qualified tax professional.