{
  "openapi": "3.1.0",
  "info": {
    "title": "CalcBloc API",
    "version": "1.2.0",
    "description": "Free take-home pay, employer cost and official tax-table data for the US, UK, Australia, New Zealand, Canada, Ireland and India, from the same engines and official sources as calcbloc.com.\n\nFree use requires a visible link to calcbloc.com wherever the figures are shown: every response carries an attribution block. Terms: https://calcbloc.com/developers/terms.\n\nLimits: free key 5,000 requests a day (burst 60 a minute). Without a key, reference endpoints allow 50 a day per IP (burst 5 a minute). Commercial volumes: contact hello@calcbloc.com.",
    "termsOfService": "https://calcbloc.com/developers/terms",
    "contact": {
      "name": "CalcBloc",
      "url": "https://calcbloc.com/developers",
      "email": "hello@calcbloc.com"
    },
    "x-logo": {
      "url": "https://calcbloc.com/icon-512.png"
    }
  },
  "externalDocs": {
    "url": "https://calcbloc.com/developers"
  },
  "servers": [
    {
      "url": "https://calcbloc.com"
    }
  ],
  "components": {
    "securitySchemes": {
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key"
      }
    },
    "schemas": {
      "Attribution": {
        "type": "object",
        "required": [
          "source",
          "url",
          "required",
          "text"
        ],
        "properties": {
          "source": {
            "const": "CalcBloc"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "required": {
            "const": true
          },
          "text": {
            "type": "string"
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error",
          "attribution"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message",
              "docs"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "docs": {
                "type": "string",
                "format": "uri"
              }
            }
          },
          "attribution": {
            "$ref": "#/components/schemas/Attribution"
          }
        }
      }
    }
  },
  "paths": {
    "/api/v1/countries": {
      "get": {
        "operationId": "countries",
        "summary": "Supported countries, regions, years and parameters",
        "description": "Lists every country with its tax year, the regions and parameters each endpoint accepts, and links to the matching calculator and tax-table pages. Works without a key (anonymous limits) or with one.",
        "parameters": [],
        "security": [
          {},
          {
            "ApiKeyHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK. Cache-Control: public, s-maxage=86400, max-age=3600.",
            "headers": {
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                },
                "description": "Requests allowed per day for this key or address."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds until the daily window resets (UTC midnight)."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "type": "object",
                      "properties": {
                        "countries": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          }
                        }
                      }
                    },
                    {
                      "type": "object",
                      "required": [
                        "attribution"
                      ],
                      "properties": {
                        "attribution": {
                          "$ref": "#/components/schemas/Attribution"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Unknown parameter, invalid value or unsupported country, region or year.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "API key missing (calculation endpoints) or not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such endpoint, country or year.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait."
              }
            }
          }
        }
      }
    },
    "/api/v1/net-salary": {
      "get": {
        "operationId": "netSalary",
        "summary": "Take-home pay for a salary",
        "description": "Runs the country's take-home pay engine (the same code and official data as the calculator on calcbloc.com) and returns net pay, taxes and contributions. Per-country parameters are whitelisted; see /api/v1/countries. Requires an API key.",
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "required": true,
            "description": "Country code.",
            "schema": {
              "type": "string",
              "enum": [
                "singapore",
                "france",
                "netherlands",
                "spain",
                "germany",
                "us",
                "uk",
                "australia",
                "new-zealand",
                "canada",
                "ireland",
                "india"
              ]
            }
          },
          {
            "name": "salary",
            "in": "query",
            "required": true,
            "description": "Annual salary in the country's currency (India net-salary: annual CTC).",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 1000000000
            }
          },
          {
            "name": "year",
            "in": "query",
            "required": false,
            "description": "Tax year: latest (default) or the current year. Calculations use the current year only; earlier years are served as tax tables. The resolved year is echoed as year.",
            "schema": {
              "type": "string",
              "enum": [
                "2026",
                "latest",
                "2026-27",
                "2025-26"
              ],
              "default": "latest"
            }
          },
          {
            "name": "bonus",
            "in": "query",
            "required": false,
            "description": "Bonus for the year (additional wages), SGD. Countries: singapore.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 10000000,
              "default": 0
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "citizen (citizen or PR from the 3rd year: CPF applies), resident (foreigner resident for tax) or nonResident. Countries: singapore, ireland.",
            "schema": {
              "type": "string",
              "enum": [
                "citizen",
                "resident",
                "nonResident",
                "single",
                "single-parent",
                "widowed",
                "married-one",
                "married-two"
              ]
            }
          },
          {
            "name": "age",
            "in": "query",
            "required": false,
            "description": "Age (sets the CPF rates and Earned Income Relief). Countries: singapore, spain, india.",
            "schema": {
              "type": "integer",
              "minimum": 16,
              "maximum": 100
            }
          },
          {
            "name": "cadre",
            "in": "query",
            "required": false,
            "description": "Cadre (executive) status (Apec and the cadre pension rules). Countries: france.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "children",
            "in": "query",
            "required": false,
            "description": "Dependent children (household parts for income tax). Countries: france, spain, germany, us.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 15,
              "default": 0
            }
          },
          {
            "name": "holiday_allowance",
            "in": "query",
            "required": false,
            "description": "Add the 8% holiday allowance on top of the salary. Countries: netherlands.",
            "schema": {
              "type": "boolean",
              "default": true
            }
          },
          {
            "name": "pension_pct",
            "in": "query",
            "required": false,
            "description": "Employee pension contribution, percent of salary. Countries: netherlands, uk, ireland. Unit: percent (5 = 5%).",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "default": 0
            }
          },
          {
            "name": "expat_ruling",
            "in": "query",
            "required": false,
            "description": "Apply the 30% ruling. Countries: netherlands.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "under_30_masters",
            "in": "query",
            "required": false,
            "description": "Under 30 with a master's degree (lower salary norm for the ruling). Countries: netherlands.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "region",
            "in": "query",
            "required": false,
            "description": "Autonomous community code (e.g. md, ct, an) or Basque territory (bi, gi, al); Navarra is not in the calculation engine yet. Default md. Countries: spain, germany, us, uk, canada, india. Values by country are listed by /api/v1/countries.",
            "schema": {
              "type": "string",
              "enum": [
                "al",
                "an",
                "ar",
                "as",
                "bi",
                "cn",
                "cb",
                "cl",
                "cm",
                "ct",
                "ce",
                "md",
                "vc",
                "ex",
                "ga",
                "gi",
                "ib",
                "ri",
                "ml",
                "mc",
                "bw",
                "by",
                "be",
                "bb",
                "hb",
                "hh",
                "he",
                "mv",
                "ni",
                "nw",
                "rp",
                "sl",
                "sn",
                "st",
                "sh",
                "th",
                "ak",
                "az",
                "ca",
                "co",
                "de",
                "dc",
                "fl",
                "hi",
                "id",
                "il",
                "in",
                "ia",
                "ks",
                "ky",
                "la",
                "me",
                "ma",
                "mi",
                "mn",
                "ms",
                "mo",
                "mt",
                "ne",
                "nv",
                "nh",
                "nj",
                "nm",
                "ny",
                "nc",
                "nd",
                "oh",
                "ok",
                "or",
                "pa",
                "sc",
                "sd",
                "tn",
                "tx",
                "ut",
                "vt",
                "va",
                "wa",
                "wv",
                "wi",
                "wy",
                "england",
                "scotland",
                "wales",
                "on",
                "qc",
                "bc",
                "ab",
                "mb",
                "nb",
                "nl",
                "ns",
                "pe",
                "sk",
                "nt",
                "nu",
                "yt",
                "ap",
                "br",
                "gj",
                "ka",
                "kl",
                "mp",
                "mh",
                "pb",
                "tg",
                "wb",
                "od",
                "hr",
                "dl",
                "ch",
                "none"
              ]
            }
          },
          {
            "name": "payments",
            "in": "query",
            "required": false,
            "description": "Payments a year: 14 (two extra payments) or 12. Countries: spain.",
            "schema": {
              "type": "string",
              "enum": [
                "14",
                "12"
              ],
              "default": "14"
            }
          },
          {
            "name": "contract",
            "in": "query",
            "required": false,
            "description": "permanent (indefinido) or temporary (fixed-term). Countries: spain.",
            "schema": {
              "type": "string",
              "enum": [
                "permanent",
                "temporary"
              ],
              "default": "permanent"
            }
          },
          {
            "name": "under_one_year",
            "in": "query",
            "required": false,
            "description": "Contract shorter than one year (2% minimum withholding). Countries: spain.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "situation",
            "in": "query",
            "required": false,
            "description": "Family situation for withholding. Countries: spain.",
            "schema": {
              "type": "string",
              "enum": [
                "other",
                "spouseLowIncome",
                "singleParent"
              ],
              "default": "other"
            }
          },
          {
            "name": "children_under_3",
            "in": "query",
            "required": false,
            "description": "Of whom under 3. Countries: spain.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10,
              "default": 0
            }
          },
          {
            "name": "tax_class",
            "in": "query",
            "required": false,
            "description": "Wage tax class (Steuerklasse) 1 to 6. Countries: germany.",
            "schema": {
              "type": "string",
              "enum": [
                "1",
                "2",
                "3",
                "4",
                "5",
                "6"
              ],
              "default": "1"
            }
          },
          {
            "name": "church",
            "in": "query",
            "required": false,
            "description": "Church member paying church tax. Countries: germany.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "over_23",
            "in": "query",
            "required": false,
            "description": "Aged 23 or over (childless care surcharge applies without children). Countries: germany.",
            "schema": {
              "type": "boolean",
              "default": true
            }
          },
          {
            "name": "health_add_on_pct",
            "in": "query",
            "required": false,
            "description": "The health fund's additional contribution rate, percent (default: the 2026 average). Countries: germany. Unit: percent (5 = 5%).",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 10,
              "default": 2.9
            }
          },
          {
            "name": "filing_status",
            "in": "query",
            "required": false,
            "description": "Form W-4 filing status. Countries: us.",
            "schema": {
              "type": "string",
              "enum": [
                "single",
                "mfj",
                "hoh"
              ],
              "default": "single"
            }
          },
          {
            "name": "frequency",
            "in": "query",
            "required": false,
            "description": "Pay frequency used for the per-period figures in the calculator's output. Countries: us, uk, australia, new-zealand, canada.",
            "schema": {
              "type": "string",
              "enum": [
                "weekly",
                "biweekly",
                "semimonthly",
                "monthly",
                "fortnightly",
                "fourWeekly",
                "four-weekly"
              ]
            }
          },
          {
            "name": "multiple_jobs",
            "in": "query",
            "required": false,
            "description": "Form W-4 Step 2 box: multiple jobs or spouse works. Countries: us.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "other_dependents",
            "in": "query",
            "required": false,
            "description": "Other dependents (W-4 Step 3). Countries: us.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 15,
              "default": 0
            }
          },
          {
            "name": "retirement_pct",
            "in": "query",
            "required": false,
            "description": "Traditional 401(k) contribution, percent of gross pay. Countries: us. Unit: percent (5 = 5%).",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "default": 0
            }
          },
          {
            "name": "pension_method",
            "in": "query",
            "required": false,
            "description": "How the pension is paid: netpay, ras (relief at source) or sacrifice (salary sacrifice). Countries: uk.",
            "schema": {
              "type": "string",
              "enum": [
                "netpay",
                "ras",
                "sacrifice"
              ],
              "default": "netpay"
            }
          },
          {
            "name": "student_loan",
            "in": "query",
            "required": false,
            "description": "Student loan plan. Countries: uk, new-zealand.",
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "plan1",
                "plan2",
                "plan4",
                "plan5"
              ]
            }
          },
          {
            "name": "postgraduate_loan",
            "in": "query",
            "required": false,
            "description": "Repaying a Postgraduate Loan. Countries: uk.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "over_state_pension_age",
            "in": "query",
            "required": false,
            "description": "Over State Pension age (no employee National Insurance). Countries: uk.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "super_mode",
            "in": "query",
            "required": false,
            "description": "plus = super paid on top of salary; package = salary includes super. Countries: australia.",
            "schema": {
              "type": "string",
              "enum": [
                "plus",
                "package"
              ],
              "default": "plus"
            }
          },
          {
            "name": "residency",
            "in": "query",
            "required": false,
            "description": "Tax residency: resident, foreign or whm (working holiday maker). Countries: australia.",
            "schema": {
              "type": "string",
              "enum": [
                "resident",
                "foreign",
                "whm"
              ],
              "default": "resident"
            }
          },
          {
            "name": "tax_free_threshold",
            "in": "query",
            "required": false,
            "description": "Claiming the tax-free threshold (residents). Countries: australia.",
            "schema": {
              "type": "boolean",
              "default": true
            }
          },
          {
            "name": "help_debt",
            "in": "query",
            "required": false,
            "description": "Has a HELP or other study loan. Countries: australia.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "salary_sacrifice",
            "in": "query",
            "required": false,
            "description": "Salary sacrificed into super per year. Countries: australia.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 1000000,
              "default": 0
            }
          },
          {
            "name": "private_hospital_cover",
            "in": "query",
            "required": false,
            "description": "Has private hospital cover (no Medicare levy surcharge). Countries: australia.",
            "schema": {
              "type": "boolean",
              "default": true
            }
          },
          {
            "name": "tax_code",
            "in": "query",
            "required": false,
            "description": "Tax code: M, ME, or a secondary code. Countries: new-zealand.",
            "schema": {
              "type": "string",
              "enum": [
                "M",
                "ME",
                "SB",
                "S",
                "SH",
                "ST",
                "SA"
              ],
              "default": "M"
            }
          },
          {
            "name": "kiwisaver_rate",
            "in": "query",
            "required": false,
            "description": "Employee KiwiSaver rate in percent (0 = not a member). Countries: new-zealand.",
            "schema": {
              "type": "string",
              "enum": [
                "0",
                "3",
                "3.5",
                "4",
                "6",
                "8",
                "10"
              ],
              "default": "3.5"
            }
          },
          {
            "name": "rrsp",
            "in": "query",
            "required": false,
            "description": "RRSP contributions through payroll per year. Countries: canada.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 1000000,
              "default": 0
            }
          },
          {
            "name": "dependants",
            "in": "query",
            "required": false,
            "description": "Dependants (Ontario tax reduction). Countries: canada.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10,
              "default": 0
            }
          },
          {
            "name": "spouse_income",
            "in": "query",
            "required": false,
            "description": "Spouse's income when status=married-two. Countries: ireland.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 10000000,
              "default": 35000
            }
          },
          {
            "name": "age_band",
            "in": "query",
            "required": false,
            "description": "Age band (sets the pension relief limit and age credits). Countries: ireland.",
            "schema": {
              "type": "string",
              "enum": [
                "under-30",
                "30-39",
                "40-49",
                "50-54",
                "55-59",
                "60-64",
                "65-69",
                "70-plus"
              ],
              "default": "30-39"
            }
          },
          {
            "name": "medical_card",
            "in": "query",
            "required": false,
            "description": "Holds a full medical card (reduced USC where eligible). Countries: ireland.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "regime",
            "in": "query",
            "required": false,
            "description": "Income tax regime: new (default) or old. Countries: india.",
            "schema": {
              "type": "string",
              "enum": [
                "new",
                "old"
              ],
              "default": "new"
            }
          },
          {
            "name": "basic_pct",
            "in": "query",
            "required": false,
            "description": "Basic + DA as a percent of CTC. Countries: india. Unit: percent (5 = 5%).",
            "schema": {
              "type": "number",
              "minimum": 10,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "pf_mode",
            "in": "query",
            "required": false,
            "description": "Provident fund: capped (on the wage ceiling), full (on all basic) or none. Countries: india.",
            "schema": {
              "type": "string",
              "enum": [
                "capped",
                "full",
                "none"
              ],
              "default": "capped"
            }
          },
          {
            "name": "gratuity_in_ctc",
            "in": "query",
            "required": false,
            "description": "CTC includes a gratuity accrual. Countries: india.",
            "schema": {
              "type": "boolean",
              "default": true
            }
          }
        ],
        "security": [
          {
            "ApiKeyHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK. Cache-Control: public, s-maxage=86400, max-age=3600.",
            "headers": {
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                },
                "description": "Requests allowed per day for this key or address."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds until the daily window resets (UTC midnight)."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "type": "object",
                      "properties": {
                        "endpoint": {
                          "type": "string"
                        },
                        "country": {
                          "type": "string"
                        },
                        "countryName": {
                          "type": "string"
                        },
                        "year": {
                          "type": "string",
                          "description": "The tax year used (latest resolves to the current year)."
                        },
                        "requested_year": {
                          "type": "string",
                          "description": "Added in 1.1.0: the year as requested (latest unless given)."
                        },
                        "currency": {
                          "type": "string"
                        },
                        "inputs": {
                          "type": "object",
                          "description": "The validated inputs used (defaults filled in)."
                        },
                        "summary": {
                          "type": "object",
                          "additionalProperties": {
                            "type": [
                              "number",
                              "null"
                            ]
                          }
                        },
                        "results": {
                          "type": "object",
                          "description": "Every numeric output of the calculator engine, annual unless the key says otherwise.",
                          "additionalProperties": {
                            "type": "number"
                          }
                        },
                        "breakdown": {
                          "type": [
                            "object",
                            "null"
                          ]
                        },
                        "notes": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "calculatorUrl": {
                          "type": "string"
                        },
                        "warnings": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    {
                      "type": "object",
                      "required": [
                        "attribution"
                      ],
                      "properties": {
                        "attribution": {
                          "$ref": "#/components/schemas/Attribution"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Unknown parameter, invalid value or unsupported country, region or year.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "API key missing (calculation endpoints) or not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such endpoint, country or year.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait."
              }
            }
          }
        }
      }
    },
    "/api/v1/employer-cost": {
      "get": {
        "operationId": "employerCost",
        "summary": "Total cost of employing someone",
        "description": "Runs the country's employer-cost engine: salary plus employer social security, payroll taxes, pension and other on-costs, as on the calcbloc.com employer cost calculators. Requires an API key.",
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "required": true,
            "description": "Country code.",
            "schema": {
              "type": "string",
              "enum": [
                "singapore",
                "netherlands",
                "spain",
                "germany",
                "us",
                "uk",
                "australia",
                "new-zealand",
                "canada",
                "ireland",
                "india"
              ]
            }
          },
          {
            "name": "salary",
            "in": "query",
            "required": true,
            "description": "Annual salary in the country's currency (India net-salary: annual CTC).",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 1000000000
            }
          },
          {
            "name": "year",
            "in": "query",
            "required": false,
            "description": "Tax year: latest (default) or the current year. Calculations use the current year only; earlier years are served as tax tables. The resolved year is echoed as year.",
            "schema": {
              "type": "string",
              "enum": [
                "2026",
                "latest",
                "2026-27",
                "2025-26"
              ],
              "default": "latest"
            }
          },
          {
            "name": "bonus",
            "in": "query",
            "required": false,
            "description": "Bonus for the year (additional wages), SGD. Countries: singapore.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 10000000,
              "default": 0
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "citizen (employer CPF applies), resident or nonResident (no CPF). Countries: singapore.",
            "schema": {
              "type": "string",
              "enum": [
                "citizen",
                "resident",
                "nonResident"
              ],
              "default": "citizen"
            }
          },
          {
            "name": "age",
            "in": "query",
            "required": false,
            "description": "Age (sets the employer CPF rate). Countries: singapore.",
            "schema": {
              "type": "integer",
              "minimum": 16,
              "maximum": 100,
              "default": 30
            }
          },
          {
            "name": "holiday_allowance",
            "in": "query",
            "required": false,
            "description": "Add the 8% holiday allowance. Countries: netherlands.",
            "schema": {
              "type": "boolean",
              "default": true
            }
          },
          {
            "name": "contract",
            "in": "query",
            "required": false,
            "description": "Contract type (sets the AWf unemployment premium). Countries: netherlands, spain.",
            "schema": {
              "type": "string",
              "enum": [
                "permanent",
                "flexible",
                "temporary"
              ],
              "default": "permanent"
            }
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "description": "Employer size (sets the Aof disability premium). Countries: netherlands.",
            "schema": {
              "type": "string",
              "enum": [
                "small",
                "large"
              ],
              "default": "small"
            }
          },
          {
            "name": "whk_pct",
            "in": "query",
            "required": false,
            "description": "Return-to-work premium (Whk), percent, set per employer. Countries: netherlands. Unit: percent (5 = 5%).",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 15,
              "default": 0
            }
          },
          {
            "name": "region",
            "in": "query",
            "required": false,
            "description": "Autonomous community code or Basque territory (bi, gi, al). Default md. Countries: spain, germany, us, australia, canada, india. Values by country are listed by /api/v1/countries.",
            "schema": {
              "type": "string",
              "enum": [
                "al",
                "an",
                "ar",
                "as",
                "bi",
                "cn",
                "cb",
                "cl",
                "cm",
                "ct",
                "ce",
                "md",
                "vc",
                "ex",
                "ga",
                "gi",
                "ib",
                "ri",
                "ml",
                "mc",
                "bw",
                "by",
                "be",
                "bb",
                "hb",
                "hh",
                "he",
                "mv",
                "ni",
                "nw",
                "rp",
                "sl",
                "sn",
                "st",
                "sh",
                "th",
                "ak",
                "az",
                "ca",
                "co",
                "de",
                "dc",
                "fl",
                "hi",
                "id",
                "il",
                "in",
                "ia",
                "ks",
                "ky",
                "la",
                "me",
                "ma",
                "mi",
                "mn",
                "ms",
                "mo",
                "mt",
                "ne",
                "nv",
                "nh",
                "nj",
                "nm",
                "ny",
                "nc",
                "nd",
                "oh",
                "ok",
                "or",
                "pa",
                "sc",
                "sd",
                "tn",
                "tx",
                "ut",
                "vt",
                "va",
                "wa",
                "wv",
                "wi",
                "wy",
                "nsw",
                "vic",
                "qld",
                "sa",
                "tas",
                "act",
                "nt",
                "on",
                "qc",
                "bc",
                "ab",
                "mb",
                "nb",
                "nl",
                "ns",
                "pe",
                "sk",
                "nu",
                "yt",
                "ap",
                "br",
                "ch",
                "dl",
                "gj",
                "hr",
                "ka",
                "kl",
                "mp",
                "mh",
                "od",
                "pb",
                "tg",
                "wb",
                "other"
              ]
            }
          },
          {
            "name": "payments",
            "in": "query",
            "required": false,
            "description": "Payments a year: 14 or 12. Countries: spain.",
            "schema": {
              "type": "string",
              "enum": [
                "14",
                "12"
              ],
              "default": "14"
            }
          },
          {
            "name": "atep_pct",
            "in": "query",
            "required": false,
            "description": "Work-accident insurance rate (AT/EP), percent, from the premium table for the activity. Countries: spain. Unit: percent (5 = 5%).",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 10,
              "default": 0
            }
          },
          {
            "name": "health_add_on_pct",
            "in": "query",
            "required": false,
            "description": "The employee's health fund additional rate, percent (the employer pays half). Countries: germany. Unit: percent (5 = 5%).",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 10,
              "default": 2.9
            }
          },
          {
            "name": "small_employer",
            "in": "query",
            "required": false,
            "description": "Up to 30 employees (the U1 sick-pay levy applies). Countries: germany.",
            "schema": {
              "type": "boolean",
              "default": true
            }
          },
          {
            "name": "u1_pct",
            "in": "query",
            "required": false,
            "description": "U1 sick-pay levy rate, percent (set by the health fund). Countries: germany. Unit: percent (5 = 5%).",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 10,
              "default": 0.8
            }
          },
          {
            "name": "u2_pct",
            "in": "query",
            "required": false,
            "description": "U2 maternity levy rate, percent (set by the health fund). Countries: germany. Unit: percent (5 = 5%).",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 5,
              "default": 0.22
            }
          },
          {
            "name": "health_per_month",
            "in": "query",
            "required": false,
            "description": "Employer share of health insurance per month. Countries: us.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 10000,
              "default": 500
            }
          },
          {
            "name": "retirement_match_pct",
            "in": "query",
            "required": false,
            "description": "401(k) match, percent of pay. Countries: us. Unit: percent (5 = 5%).",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 25,
              "default": 3
            }
          },
          {
            "name": "other_benefits",
            "in": "query",
            "required": false,
            "description": "Other annual benefits. Countries: us.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 1000000,
              "default": 0
            }
          },
          {
            "name": "paid_days_off",
            "in": "query",
            "required": false,
            "description": "Paid days off per year (for cost per hour worked). Countries: us.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 100,
              "default": 15
            }
          },
          {
            "name": "overhead_pct",
            "in": "query",
            "required": false,
            "description": "Overhead, percent of wages. Countries: us. Unit: percent (5 = 5%).",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 200,
              "default": 0
            }
          },
          {
            "name": "ni_category",
            "in": "query",
            "required": false,
            "description": "Employer National Insurance category letter. Countries: uk.",
            "schema": {
              "type": "string",
              "enum": [
                "A",
                "M",
                "H",
                "V"
              ],
              "default": "A"
            }
          },
          {
            "name": "pension_mode",
            "in": "query",
            "required": false,
            "description": "auto = auto-enrolment minimum; custom = pension_pct of salary. Countries: uk.",
            "schema": {
              "type": "string",
              "enum": [
                "auto",
                "custom"
              ],
              "default": "auto"
            }
          },
          {
            "name": "pension_pct",
            "in": "query",
            "required": false,
            "description": "Employer pension contribution when pension_mode=custom, percent of salary. Countries: uk. Unit: percent (5 = 5%).",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "default": 5
            }
          },
          {
            "name": "employment_allowance",
            "in": "query",
            "required": false,
            "description": "Employment Allowance set against this employee's employer NI. Countries: uk.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 10500,
              "default": 0
            }
          },
          {
            "name": "apprenticeship_levy",
            "in": "query",
            "required": false,
            "description": "Pay bill over the levy threshold (adds the levy on this employee's pay). Countries: uk.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "other_costs",
            "in": "query",
            "required": false,
            "description": "Other annual costs. Countries: uk, australia, new-zealand, canada, ireland, india.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 1000000000,
              "default": 0
            }
          },
          {
            "name": "super_mode",
            "in": "query",
            "required": false,
            "description": "plus = super on top of salary; package = salary includes super. Countries: australia.",
            "schema": {
              "type": "string",
              "enum": [
                "plus",
                "package"
              ],
              "default": "plus"
            }
          },
          {
            "name": "total_wages",
            "in": "query",
            "required": false,
            "description": "Employer's total annual Australian wages (for payroll tax; 0 = this employee only). Countries: australia.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 10000000000,
              "default": 0
            }
          },
          {
            "name": "workers_comp_pct",
            "in": "query",
            "required": false,
            "description": "Workers' compensation premium, percent of wages. Countries: australia. Unit: percent (5 = 5%).",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 20,
              "default": 0
            }
          },
          {
            "name": "kiwisaver_member",
            "in": "query",
            "required": false,
            "description": "Employee is a KiwiSaver member. Countries: new-zealand.",
            "schema": {
              "type": "boolean",
              "default": true
            }
          },
          {
            "name": "employer_rate",
            "in": "query",
            "required": false,
            "description": "Employer KiwiSaver contribution, percent of gross pay. Countries: new-zealand. Unit: percent (5 = 5%).",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 20,
              "default": 3.5
            }
          },
          {
            "name": "acc_work_levy_rate",
            "in": "query",
            "required": false,
            "description": "ACC Work levy rate per $100 of liable earnings (from the business's ACC invoice). Countries: new-zealand.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 20,
              "default": 0
            }
          },
          {
            "name": "total_payroll",
            "in": "query",
            "required": false,
            "description": "Employer's total annual payroll in the province (for health and payroll taxes; 0 = this employee only). Countries: canada.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 1000000000,
              "default": 0
            }
          },
          {
            "name": "wcb_rate",
            "in": "query",
            "required": false,
            "description": "Workers' compensation rate per $100 of insurable earnings. Countries: canada.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 50,
              "default": 0
            }
          },
          {
            "name": "wcb_max",
            "in": "query",
            "required": false,
            "description": "Maximum assessable earnings for workers' compensation (0 = no maximum). Countries: canada.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 1000000,
              "default": 0
            }
          },
          {
            "name": "employer_pension_pct",
            "in": "query",
            "required": false,
            "description": "Employer pension contribution, percent of salary. Countries: ireland. Unit: percent (5 = 5%).",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 100,
              "default": 5
            }
          },
          {
            "name": "prsi_class",
            "in": "query",
            "required": false,
            "description": "PRSI class: A or J. Countries: ireland.",
            "schema": {
              "type": "string",
              "enum": [
                "A",
                "J"
              ],
              "default": "A"
            }
          },
          {
            "name": "basic_pct",
            "in": "query",
            "required": false,
            "description": "Basic + DA as a percent of gross. Countries: india. Unit: percent (5 = 5%).",
            "schema": {
              "type": "number",
              "minimum": 10,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "pf_mode",
            "in": "query",
            "required": false,
            "description": "Employer PF on the wage ceiling, on actual basic, or none. Countries: india.",
            "schema": {
              "type": "string",
              "enum": [
                "ceiling",
                "actual",
                "none"
              ],
              "default": "ceiling"
            }
          },
          {
            "name": "wage_rule",
            "in": "query",
            "required": false,
            "description": "Apply the 50% wage rule of the Code on Wages. Countries: india.",
            "schema": {
              "type": "boolean",
              "default": true
            }
          },
          {
            "name": "gratuity",
            "in": "query",
            "required": false,
            "description": "Include a gratuity provision. Countries: india.",
            "schema": {
              "type": "boolean",
              "default": true
            }
          },
          {
            "name": "bonus_pct",
            "in": "query",
            "required": false,
            "description": "Statutory or other bonus, percent of wages. Countries: india. Unit: percent (5 = 5%).",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 20,
              "default": 0
            }
          }
        ],
        "security": [
          {
            "ApiKeyHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK. Cache-Control: public, s-maxage=86400, max-age=3600.",
            "headers": {
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                },
                "description": "Requests allowed per day for this key or address."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds until the daily window resets (UTC midnight)."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "type": "object",
                      "properties": {
                        "endpoint": {
                          "type": "string"
                        },
                        "country": {
                          "type": "string"
                        },
                        "countryName": {
                          "type": "string"
                        },
                        "year": {
                          "type": "string",
                          "description": "The tax year used (latest resolves to the current year)."
                        },
                        "requested_year": {
                          "type": "string",
                          "description": "Added in 1.1.0: the year as requested (latest unless given)."
                        },
                        "currency": {
                          "type": "string"
                        },
                        "inputs": {
                          "type": "object",
                          "description": "The validated inputs used (defaults filled in)."
                        },
                        "summary": {
                          "type": "object",
                          "additionalProperties": {
                            "type": [
                              "number",
                              "null"
                            ]
                          }
                        },
                        "results": {
                          "type": "object",
                          "description": "Every numeric output of the calculator engine, annual unless the key says otherwise.",
                          "additionalProperties": {
                            "type": "number"
                          }
                        },
                        "breakdown": {
                          "type": [
                            "object",
                            "null"
                          ]
                        },
                        "notes": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "calculatorUrl": {
                          "type": "string"
                        },
                        "warnings": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    {
                      "type": "object",
                      "required": [
                        "attribution"
                      ],
                      "properties": {
                        "attribution": {
                          "$ref": "#/components/schemas/Attribution"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Unknown parameter, invalid value or unsupported country, region or year.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "API key missing (calculation endpoints) or not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such endpoint, country or year.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait."
              }
            }
          }
        }
      }
    },
    "/api/v1/compare": {
      "get": {
        "operationId": "compare",
        "summary": "Same salary, two countries",
        "description": "Converts the salary at the European Central Bank reference rate and runs each country's take-home engine, as on calcbloc.com/compare/salary. Requires an API key.",
        "parameters": [
          {
            "name": "a",
            "in": "query",
            "required": true,
            "description": "First country.",
            "schema": {
              "type": "string",
              "enum": [
                "australia",
                "canada",
                "france",
                "germany",
                "india",
                "ireland",
                "netherlands",
                "new-zealand",
                "singapore",
                "spain",
                "uk",
                "us"
              ]
            }
          },
          {
            "name": "b",
            "in": "query",
            "required": true,
            "description": "Second country (must differ from a).",
            "schema": {
              "type": "string",
              "enum": [
                "australia",
                "canada",
                "france",
                "germany",
                "india",
                "ireland",
                "netherlands",
                "new-zealand",
                "singapore",
                "spain",
                "uk",
                "us"
              ]
            }
          },
          {
            "name": "salary",
            "in": "query",
            "required": true,
            "description": "Annual salary before tax (India: CTC), in `currency`.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 10000000
            }
          },
          {
            "name": "currency",
            "in": "query",
            "required": false,
            "description": "Currency of `salary`: a's or b's currency. Default: a's currency.",
            "schema": {
              "type": "string",
              "enum": [
                "AUD",
                "CAD",
                "EUR",
                "INR",
                "NZD",
                "SGD",
                "GBP",
                "USD"
              ]
            }
          },
          {
            "name": "us_state",
            "in": "query",
            "required": false,
            "description": "US state (when a or b is us).",
            "schema": {
              "type": "string",
              "enum": [
                "al",
                "ak",
                "az",
                "ar",
                "ca",
                "co",
                "ct",
                "de",
                "dc",
                "fl",
                "ga",
                "hi",
                "id",
                "il",
                "in",
                "ia",
                "ks",
                "ky",
                "la",
                "me",
                "md",
                "ma",
                "mi",
                "mn",
                "ms",
                "mo",
                "mt",
                "ne",
                "nv",
                "nh",
                "nj",
                "nm",
                "ny",
                "nc",
                "nd",
                "oh",
                "ok",
                "or",
                "pa",
                "ri",
                "sc",
                "sd",
                "tn",
                "tx",
                "ut",
                "vt",
                "va",
                "wa",
                "wv",
                "wi",
                "wy"
              ],
              "default": "ny"
            }
          },
          {
            "name": "uk_region",
            "in": "query",
            "required": false,
            "description": "UK nation (Northern Ireland uses England's bands).",
            "schema": {
              "type": "string",
              "enum": [
                "england",
                "scotland",
                "wales"
              ],
              "default": "england"
            }
          },
          {
            "name": "ca_province",
            "in": "query",
            "required": false,
            "description": "Canadian province or territory.",
            "schema": {
              "type": "string",
              "enum": [
                "on",
                "qc",
                "bc",
                "ab",
                "mb",
                "nb",
                "nl",
                "ns",
                "pe",
                "sk",
                "nt",
                "nu",
                "yt"
              ],
              "default": "on"
            }
          },
          {
            "name": "in_state",
            "in": "query",
            "required": false,
            "description": "Indian state for professional tax and LWF.",
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "mh",
                "ka",
                "wb",
                "tn",
                "tg",
                "ap",
                "gj",
                "mp",
                "as",
                "kl",
                "br",
                "pb",
                "od",
                "hr",
                "ga",
                "dl",
                "ch"
              ],
              "default": "mh"
            }
          }
        ],
        "security": [
          {
            "ApiKeyHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK. Cache-Control: public, s-maxage=86400, max-age=3600.",
            "headers": {
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                },
                "description": "Requests allowed per day for this key or address."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds until the daily window resets (UTC midnight)."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "type": "object",
                      "properties": {
                        "endpoint": {
                          "type": "string"
                        },
                        "inputs": {
                          "type": "object"
                        },
                        "a": {
                          "type": "object",
                          "additionalProperties": true
                        },
                        "b": {
                          "type": "object",
                          "additionalProperties": true
                        },
                        "exchangeRate": {
                          "type": "object"
                        },
                        "difference": {
                          "type": "object"
                        },
                        "interpretation": {
                          "type": "string"
                        },
                        "calculatorUrl": {
                          "type": "string"
                        },
                        "warnings": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    {
                      "type": "object",
                      "required": [
                        "attribution"
                      ],
                      "properties": {
                        "attribution": {
                          "$ref": "#/components/schemas/Attribution"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Unknown parameter, invalid value or unsupported country, region or year.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "API key missing (calculation endpoints) or not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such endpoint, country or year.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait."
              }
            }
          }
        }
      }
    },
    "/api/v1/tax-tables/{country}/{year}": {
      "get": {
        "operationId": "taxTables",
        "summary": "Official tax tables for a country and tax year",
        "description": "Every income tax band, threshold, employee contribution and employer rate in the dataset, with effective dates and the official source of each figure. Add region= for a US state, Canadian province or territory, or Scotland or Wales. Works without a key (anonymous limits) or with one.",
        "parameters": [
          {
            "name": "country",
            "in": "path",
            "required": true,
            "description": "Country code.",
            "schema": {
              "type": "string",
              "enum": [
                "us",
                "uk",
                "australia",
                "new-zealand",
                "canada",
                "ireland",
                "india",
                "germany",
                "spain",
                "netherlands",
                "france",
                "singapore",
                "uae",
                "italy",
                "portugal",
                "switzerland",
                "denmark",
                "sweden",
                "austria",
                "poland",
                "luxembourg",
                "czechia",
                "norway",
                "finland",
                "slovenia",
                "romania",
                "hungary",
                "slovakia",
                "greece",
                "latvia",
                "croatia",
                "estonia",
                "bulgaria",
                "lithuania",
                "malta",
                "cyprus",
                "iceland"
              ]
            }
          },
          {
            "name": "year",
            "in": "path",
            "required": true,
            "description": "Tax year as listed in years_available by /api/v1/countries, or latest for the current year (resolved year echoed as year).",
            "schema": {
              "type": "string",
              "enum": [
                "latest",
                "2026",
                "2026-27",
                "2025-26"
              ]
            }
          },
          {
            "name": "region",
            "in": "query",
            "required": false,
            "description": "Optional region code (us: state code; canada: province code; uk: scotland or wales). Returns the regional figures only.",
            "schema": {
              "type": "string",
              "enum": [
                "al",
                "ak",
                "az",
                "ar",
                "ca",
                "co",
                "ct",
                "de",
                "dc",
                "fl",
                "ga",
                "hi",
                "id",
                "il",
                "in",
                "ia",
                "ks",
                "ky",
                "la",
                "me",
                "md",
                "ma",
                "mi",
                "mn",
                "ms",
                "mo",
                "mt",
                "ne",
                "nv",
                "nh",
                "nj",
                "nm",
                "ny",
                "nc",
                "nd",
                "oh",
                "ok",
                "or",
                "pa",
                "ri",
                "sc",
                "sd",
                "tn",
                "tx",
                "ut",
                "vt",
                "va",
                "wa",
                "wv",
                "wi",
                "wy",
                "scotland",
                "wales",
                "on",
                "qc",
                "bc",
                "ab",
                "mb",
                "nb",
                "nl",
                "ns",
                "pe",
                "sk",
                "nt",
                "nu",
                "yt",
                "md",
                "ct",
                "an",
                "vc",
                "ga",
                "cl",
                "ar",
                "cn",
                "cm",
                "mc",
                "as",
                "ib",
                "ex",
                "cb",
                "ri",
                "ce",
                "ml",
                "bi",
                "gi",
                "al",
                "nc",
                "abr",
                "bas",
                "bz",
                "cal",
                "cam",
                "emr",
                "fvg",
                "laz",
                "lig",
                "lom",
                "mar",
                "mol",
                "pie",
                "pug",
                "sar",
                "sic",
                "tos",
                "tn",
                "umb",
                "vda",
                "ven",
                "ma",
                "ac",
                "zh",
                "be",
                "lu",
                "ur",
                "sz",
                "ow",
                "nw",
                "gl",
                "zg",
                "fr",
                "so",
                "bs",
                "bl",
                "sh",
                "ar",
                "ai",
                "sg",
                "gr",
                "ag",
                "tg",
                "ti",
                "vd",
                "vs",
                "ne",
                "ge",
                "ju",
                "hovedstaden",
                "sjaelland",
                "syddanmark",
                "midtjylland",
                "nordjylland",
                "ab",
                "c",
                "d",
                "e",
                "f",
                "g",
                "h",
                "i",
                "k",
                "m",
                "n",
                "o",
                "s",
                "t",
                "u",
                "w",
                "x",
                "y",
                "z",
                "ac",
                "bd",
                "uusimaa",
                "southwest-finland",
                "satakunta",
                "kanta-hame",
                "pirkanmaa",
                "paijat-hame",
                "kymenlaakso",
                "south-karelia",
                "south-savo",
                "north-savo",
                "north-karelia",
                "central-finland",
                "south-ostrobothnia",
                "ostrobothnia",
                "central-ostrobothnia",
                "north-ostrobothnia",
                "kainuu",
                "lapland",
                "aland",
                "zagreb-county",
                "krapina-zagorje",
                "sisak-moslavina",
                "karlovac",
                "varazdin",
                "koprivnica-krizevci",
                "bjelovar-bilogora",
                "primorje-gorski-kotar",
                "lika-senj",
                "virovitica-podravina",
                "pozega-slavonia",
                "brod-posavina",
                "zadar",
                "osijek-baranja",
                "sibenik-knin",
                "vukovar-srijem",
                "split-dalmatia",
                "istria",
                "dubrovnik-neretva",
                "medimurje",
                "city-of-zagreb"
              ]
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "json (default) or csv (one row per band or value; rates are decimals).",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "csv"
              ],
              "default": "json"
            }
          }
        ],
        "security": [
          {},
          {
            "ApiKeyHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK. Cache-Control: public, s-maxage=86400, max-age=3600.",
            "headers": {
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                },
                "description": "Requests allowed per day for this key or address."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds until the daily window resets (UTC midnight)."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "type": "object",
                      "properties": {
                        "country": {
                          "type": "string"
                        },
                        "countryName": {
                          "type": "string"
                        },
                        "year": {
                          "type": "string"
                        },
                        "region": {
                          "type": [
                            "object",
                            "null"
                          ]
                        },
                        "currency": {
                          "type": "string"
                        },
                        "effectiveFrom": {
                          "type": "string",
                          "format": "date"
                        },
                        "effectiveTo": {
                          "type": "string",
                          "format": "date"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "verified",
                            "unverified"
                          ]
                        },
                        "yearLabel": {
                          "type": "string"
                        },
                        "isCurrent": {
                          "type": "boolean",
                          "description": "false for an earlier year kept for reference (superseded)."
                        },
                        "requested_year": {
                          "type": "string",
                          "description": "Added in 1.1.0: the year in the request (latest or a year)."
                        },
                        "current_year": {
                          "type": "string",
                          "description": "Added in 1.1.0: the country's current tax year."
                        },
                        "years_available": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Added in 1.1.0: every served year, current first."
                        },
                        "sections": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          }
                        },
                        "sources": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          }
                        },
                        "rows": {
                          "type": "array",
                          "description": "Added in 1.1.0: one flat row per band or value, the same rows as the CSV, each with its own tax year, effective dates, official source and status.",
                          "items": {
                            "type": "object",
                            "required": [
                              "section_id",
                              "label",
                              "unit",
                              "tax_year",
                              "effective_from",
                              "effective_to",
                              "source_title",
                              "source_url",
                              "retrieved_at",
                              "status"
                            ],
                            "properties": {
                              "section_id": {
                                "type": "string"
                              },
                              "section": {
                                "type": "string"
                              },
                              "group": {
                                "type": "string",
                                "enum": [
                                  "income-tax",
                                  "employee",
                                  "employer",
                                  "other"
                                ]
                              },
                              "label": {
                                "type": "string"
                              },
                              "from": {
                                "type": [
                                  "number",
                                  "null"
                                ]
                              },
                              "to": {
                                "type": [
                                  "number",
                                  "null"
                                ]
                              },
                              "rate": {
                                "type": [
                                  "number",
                                  "null"
                                ],
                                "description": "Decimal (0.2 = 20%)."
                              },
                              "value": {
                                "type": [
                                  "number",
                                  "string",
                                  "null"
                                ]
                              },
                              "unit": {
                                "type": "string",
                                "enum": [
                                  "rate",
                                  "money",
                                  "number",
                                  "text"
                                ]
                              },
                              "basis": {
                                "type": "string"
                              },
                              "note": {
                                "type": "string"
                              },
                              "tax_year": {
                                "type": "string"
                              },
                              "effective_from": {
                                "type": "string",
                                "format": "date"
                              },
                              "effective_to": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "format": "date",
                                "description": "null: in force until changed."
                              },
                              "source_title": {
                                "type": "string"
                              },
                              "source_url": {
                                "type": "string",
                                "format": "uri"
                              },
                              "retrieved_at": {
                                "type": "string",
                                "format": "date"
                              },
                              "status": {
                                "type": "string",
                                "enum": [
                                  "verified",
                                  "under_review",
                                  "not_applicable"
                                ]
                              }
                            }
                          }
                        },
                        "pageUrl": {
                          "type": "string"
                        }
                      }
                    },
                    {
                      "type": "object",
                      "required": [
                        "attribution"
                      ],
                      "properties": {
                        "attribution": {
                          "$ref": "#/components/schemas/Attribution"
                        }
                      }
                    }
                  ]
                }
              },
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Unknown parameter, invalid value or unsupported country, region or year.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "API key missing (calculation endpoints) or not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such endpoint, country or year.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit reached. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds to wait."
              }
            }
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "operationId": "health",
        "summary": "Service health",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  }
}