Developer API

Free, no API key, no rate-limited tiers — the same math ten of TaxLane's eleven calculators use, as a JSON API. (Payroll is the one exception — its CSV-upload flow is inherently a batch of calculations, not this API's one-request-one-calculation contract.)

POST /v1/paye

Calculates PAYE tax exactly the way the PAYE calculator does. Only grossAnnualIncome is required — every other field defaults to 0.

bash
curl -X POST https://api.taxlane.ng/v1/paye \
  -H "content-type: application/json" \
  -d '{"grossAnnualIncome": 6000000, "annualRentPaid": 1200000}'

Request fields

FieldDetails
grossAnnualIncomeType numberRequired YesDefault —
secondaryAnnualIncomeType numberRequired NoDefault 0
annualRentPaidType numberRequired NoDefault 0
terminationBenefitType numberRequired NoDefault 0
pensionContributionType numberRequired NoDefault 0
nhfContributionType numberRequired NoDefault 0
nhisContributionType numberRequired NoDefault 0
lifeAssurancePremiumContributionType numberRequired NoDefault 0

Response

The full PAYE result: taxableIncome, payeTax, annualTax, monthlyTax, a reliefs breakdown, and a bandBreakdown array showing how much tax fell in each band.

json200 OK
{
  "taxableIncome": 6000000,
  "payeTax": 870000,
  "annualTax": 870000,
  "monthlyTax": 72500,
  "reliefs": {
    "rentRelief": 0,
    "pensionRelief": 0,
    "nhfRelief": 0,
    "nhisRelief": 0,
    "lifeAssurancePremiumRelief": 0,
    "minimumWageExempt": false,
    "taxableTerminationBenefit": 0
  },
  "bandBreakdown": [
    { "from": 800000, "to": 3000000, "rate": 0.15, "taxInBand": 330000 },
    { "from": 3000000, "to": 6000000, "rate": 0.18, "taxInBand": 540000 }
  ]
}

POST /v1/payroll/batch

Calculates PAYE for a whole payroll run in one request — an array of up to 1,000 employees, each the same shape /v1/paye takes. results[i] is exactly what /v1/paye would have returned for employees[i], in the same order — there is no employee identifier field, so correlate by index. An invalid item 400s the whole batch, prefixed employees[i]. so you can find the failing row; there is no partial-success mode.

bash
curl -X POST https://api.taxlane.ng/v1/payroll/batch \
  -H "content-type: application/json" \
  -d '{"employees": [{"grossAnnualIncome": 6000000}, {"grossAnnualIncome": 900000, "annualRentPaid": 400000}]}'

Request fields

FieldDetails
employeesType PayeInput[] (1–1000 items)Required YesDefault —

Response

results: an array of PAYE results, one per employee, in request order.

json200 OK
{
  "results": [
    {
      "taxableIncome": 6000000,
      "payeTax": 870000,
      "annualTax": 870000,
      "monthlyTax": 72500,
      "reliefs": {
        "rentRelief": 0,
        "pensionRelief": 0,
        "nhfRelief": 0,
        "nhisRelief": 0,
        "lifeAssurancePremiumRelief": 0,
        "minimumWageExempt": false,
        "taxableTerminationBenefit": 0
      },
      "bandBreakdown": [
        { "from": 800000, "to": 3000000, "rate": 0.15, "taxInBand": 330000 },
        { "from": 3000000, "to": 6000000, "rate": 0.18, "taxInBand": 540000 }
      ]
    },
    {
      "taxableIncome": 820000,
      "payeTax": 3000,
      "annualTax": 3000,
      "monthlyTax": 250,
      "reliefs": {
        "rentRelief": 80000,
        "pensionRelief": 0,
        "nhfRelief": 0,
        "nhisRelief": 0,
        "lifeAssurancePremiumRelief": 0,
        "minimumWageExempt": false,
        "taxableTerminationBenefit": 0
      },
      "bandBreakdown": [
        { "from": 800000, "to": 820000, "rate": 0.15, "taxInBand": 3000 }
      ]
    }
  ]
}

POST /v1/vat

Calculates VAT exactly the way the VAT calculator does, at the standard 7.5% rate.

bash
curl -X POST https://api.taxlane.ng/v1/vat \
  -H "content-type: application/json" \
  -d '{"amount": 100000, "mode": "exclusive"}'

Request fields

FieldDetails
amountType numberRequired YesDefault —
modeType "exclusive" | "inclusive"Required YesDefault —
zeroRatedType booleanRequired NoDefault false

Response

net, vat, and gross amounts.

json200 OK
{
  "net": 100000,
  "vat": 7500,
  "gross": 107500
}

POST /v1/presumptive

Calculates Presumptive Tax exactly the way the Presumptive Tax calculator does. turnover is the only field.

bash
curl -X POST https://api.taxlane.ng/v1/presumptive \
  -H "content-type: application/json" \
  -d '{"turnover": 20000000}'

Request fields

FieldDetails
turnoverType numberRequired YesDefault —

Response

turnover, taxOwed, belowFloor, monthlySetAside, and turnoverToFloor.

json200 OK
{
  "turnover": 20000000,
  "taxOwed": 200000,
  "belowFloor": false,
  "monthlySetAside": 16666.666666666668,
  "turnoverToFloor": 0
}

POST /v1/direct-assessment

Calculates Direct Assessment tax exactly the way the Direct Assessment calculator does. turnover and allowableExpenses are required; capital allowance fields default to no capital expenditure.

bash
curl -X POST https://api.taxlane.ng/v1/direct-assessment \
  -H "content-type: application/json" \
  -d '{"turnover": 10000000, "allowableExpenses": 3000000, "qualifyingCapitalExpenditure": 1000000, "capitalAllowanceAssetClass": "plantAgriculturalEquipmentFurniture"}'

Request fields

FieldDetails
turnoverType numberRequired YesDefault —
allowableExpensesType numberRequired YesDefault —
qualifyingCapitalExpenditureType numberRequired NoDefault 0
capitalAllowanceAssetClassType "buildingAgriculturalMastIntangibleHeavyTransport" | "plantAgriculturalEquipmentFurniture" | "motorVehicleSoftware"Required NoDefault "buildingAgriculturalMastIntangibleHeavyTransport"

Response

turnover, allowableExpenses, capitalAllowance, taxableProfit, taxOwed, and effectiveRate.

json200 OK
{
  "turnover": 10000000,
  "allowableExpenses": 3000000,
  "capitalAllowance": 200000,
  "taxableProfit": 6800000,
  "taxOwed": 1014000,
  "effectiveRate": 0.14911764705882352
}

POST /v1/cit

Calculates Companies Income Tax exactly the way the CIT calculator does. Eligibility fields (turnover, fixedAssets, isProfessionalServices) are always required and always returned under eligibility. standardRate is included only when taxableProfit is sent; developmentLevy is included only when assessableProfit is sent — the three are independently computed, not a single pipeline.

bash
curl -X POST https://api.taxlane.ng/v1/cit \
  -H "content-type: application/json" \
  -d '{"turnover": 30000000, "fixedAssets": 100000000, "isProfessionalServices": false, "taxableProfit": 5000000, "assessableProfit": 8000000}'

Request fields

FieldDetails
turnoverType numberRequired YesDefault —
fixedAssetsType numberRequired YesDefault —
isProfessionalServicesType booleanRequired YesDefault —
taxableProfitType numberRequired NoDefault omitted → standardRate omitted from response
assessableProfitType numberRequired NoDefault omitted → developmentLevy omitted from response

Response

eligibility always; standardRate and developmentLevy only when their triggering field was sent.

json200 OK
{
  "eligibility": {
    "turnover": 30000000,
    "fixedAssets": 100000000,
    "isProfessionalServices": false,
    "turnoverEligible": true,
    "fixedAssetsEligible": true,
    "eligible": true,
    "rate": 0
  },
  "standardRate": { "taxableProfit": 5000000, "annualTax": 1500000 },
  "developmentLevy": { "assessableProfit": 8000000, "developmentLevy": 320000 }
}

POST /v1/wht

Calculates Withholding Tax exactly the way the WHT calculator does. Set mode to "gross" if amount is the invoice figure, or "net" if amount is the figure the payee should receive after withholding.

bash
curl -X POST https://api.taxlane.ng/v1/wht \
  -H "content-type: application/json" \
  -d '{"transactionType": "professionalFees", "amount": 1000000, "mode": "gross"}'

Request fields

FieldDetails
transactionTypeType "professionalFees" | "technicalServices" | "rent" | "generalContracts" | "dividends" | "interest" | "royalties"Required YesDefault —
amountType numberRequired YesDefault —
modeType "gross" | "net"Required YesDefault —

Response

transactionType, mode, amount, rate, gross, withheld, and net.

json200 OK
{
  "transactionType": "professionalFees",
  "mode": "gross",
  "amount": 1000000,
  "rate": 0.05,
  "gross": 1000000,
  "withheld": 50000,
  "net": 950000
}

POST /v1/employer-cost

Calculates total employer cost exactly the way the Employer Cost calculator does. Only annualBasicSalary is required — every allowance defaults to 0.

bash
curl -X POST https://api.taxlane.ng/v1/employer-cost \
  -H "content-type: application/json" \
  -d '{"annualBasicSalary": 6000000, "annualHousingAllowance": 1000000, "annualTransportAllowance": 500000}'

Request fields

FieldDetails
annualBasicSalaryType numberRequired YesDefault —
annualHousingAllowanceType numberRequired NoDefault 0
annualTransportAllowanceType numberRequired NoDefault 0
annualOtherAllowancesType numberRequired NoDefault 0
annualRentPaidType numberRequired NoDefault 0

Response

annualGrossPay, pensionablePay, the four statutory employer contributions, totalStatutoryEmployerCost, and a nested employeePaye object — the same shape /v1/paye returns, informational only.

json200 OK
{
  "annualGrossPay": 7500000,
  "pensionablePay": 7500000,
  "employerPensionContribution": 750000,
  "employerNhisContribution": 600000,
  "employerNsitfContribution": 75000,
  "employerItfContribution": 75000,
  "totalStatutoryEmployerCost": 9000000,
  "employeePaye": {
    "taxableIncome": 6600000,
    "payeTax": 978000,
    "annualTax": 978000,
    "monthlyTax": 81500,
    "reliefs": {
      "rentRelief": 0,
      "pensionRelief": 600000,
      "nhfRelief": 0,
      "nhisRelief": 300000,
      "lifeAssurancePremiumRelief": 0,
      "minimumWageExempt": false,
      "taxableTerminationBenefit": 0
    },
    "bandBreakdown": [
      { "from": 800000, "to": 3000000, "rate": 0.15, "taxInBand": 330000 },
      { "from": 3000000, "to": 6600000, "rate": 0.18, "taxInBand": 648000 }
    ]
  }
}

POST /v1/cgt

Calculates Capital Gains Tax exactly the way the CGT calculator does. digitalAssetCategory is required when assetType is "digital-asset", and ignored otherwise — every other conditional field is optional and only applies to its matching assetType/taxpayerType.

bash
curl -X POST https://api.taxlane.ng/v1/cgt \
  -H "content-type: application/json" \
  -d '{"taxpayerType": "individual", "assetType": "property", "disposalProceeds": 50000000, "costBase": 30000000}'

Request fields

FieldDetails
taxpayerTypeType "individual" | "company"Required YesDefault —
assetTypeType "property" | "shares" | "digital-asset" | "other"Required YesDefault —
disposalProceedsType numberRequired YesDefault —
costBaseType numberRequired YesDefault —
isPrincipalPrivateResidenceType booleanRequired NoDefault false (property only)
isFullyReinvestedInNigerianSharesType booleanRequired NoDefault false (shares only)
isRegulatedSecuritiesLendingTransferType booleanRequired NoDefault false (shares only)
digitalAssetCategoryType "crypto" | "stablecoin" | "security-token" | "utility-token" | "nft" | "sovereign-digital-currency"Required NoDefault required when assetType is "digital-asset", ignored otherwise
otherAnnualTaxableIncomeType numberRequired NoDefault 0 (individual only)
isSmallCompanyType booleanRequired NoDefault false (company only)

Response

chargeableGain, exempt, exemptReason (only when exempt), cgtLiability, and vaWithholdingEstimate (digital assets only, categories with a 1% disposal withholding).

json200 OK
{
  "chargeableGain": 20000000,
  "exempt": false,
  "cgtLiability": 3630000
}

POST /v1/stamp-duty

Calculates Stamp Duty exactly the way the Stamp Duty calculator does.

bash
curl -X POST https://api.taxlane.ng/v1/stamp-duty \
  -H "content-type: application/json" \
  -d '{"instrumentType": "tenancy", "amount": 12000000}'

Request fields

FieldDetails
instrumentTypeType "tenancy" | "propertyConveyance" | "shareCapital" | "loanCapital" | "marketableSecurities" | "electronicTransfer" | "other"Required YesDefault —
amountType numberRequired YesDefault —

Response

instrumentType, amount, rate (null for the two fixed-fee instrument types), duty, and exempt.

json200 OK
{
  "instrumentType": "tenancy",
  "amount": 12000000,
  "rate": 0.0078,
  "duty": 93600,
  "exempt": false
}

POST /v1/import-duty

Calculates import duty and landed cost exactly the way the Import Duty calculator does. Pass freight and insurance as 0 (their default) if you already have a combined CIF value in fob.

bash
curl -X POST https://api.taxlane.ng/v1/import-duty \
  -H "content-type: application/json" \
  -d '{"fob": 5000000, "freight": 300000, "insurance": 100000, "band": "20"}'

Request fields

FieldDetails
fobType numberRequired YesDefault —
freightType numberRequired NoDefault 0
insuranceType numberRequired NoDefault 0
bandType "0" | "5" | "10" | "20" | "35"Required YesDefault —
customDutyRatePercentType numberRequired NoDefault omitted → band rate applies

Response

fob, freight, insurance, cif, band, dutyRate, duty, surcharge, etls, fcs, vat, and totalLandedCost.

json200 OK
{
  "fob": 5000000,
  "freight": 300000,
  "insurance": 100000,
  "cif": 5400000,
  "band": "20",
  "dutyRate": 0.2,
  "duty": 1080000,
  "surcharge": 75600,
  "etls": 27000,
  "fcs": 200000,
  "vat": 508695,
  "totalLandedCost": 7291295
}

POST /v1/pension-contribution

Projects RSA pension balances exactly the way the Pension (RSA) Contribution calculator does. Only annualBasicSalary is required — every other field defaults to the value the calculator itself starts with.

bash
curl -X POST https://api.taxlane.ng/v1/pension-contribution \
  -H "content-type: application/json" \
  -d '{"annualBasicSalary": 3000000, "yearsToProject": 10}'

Request fields

FieldDetails
annualBasicSalaryType numberRequired YesDefault —
annualHousingAllowanceType numberRequired NoDefault 0
annualTransportAllowanceType numberRequired NoDefault 0
voluntaryContributionType numberRequired NoDefault 0
currentRsaBalanceType numberRequired NoDefault 0
yearsToProjectType numberRequired NoDefault 10 (clamped to 50)
assumedAnnualGrowthRateType numberRequired NoDefault 0.07

Response

pensionablePay, employeeContribution, employerContribution, voluntaryContribution, totalAnnualContribution, and projection (an array of { year, balance }, one entry per year from 0 to yearsToProject).

json200 OK
{
  "pensionablePay": 3000000,
  "employeeContribution": 240000,
  "employerContribution": 300000,
  "voluntaryContribution": 0,
  "totalAnnualContribution": 540000,
  "projection": [
    { "year": 0, "balance": 0 },
    { "year": 1, "balance": 577800 },
    { "year": 2, "balance": 1196046 },
    { "year": 3, "balance": 1857569 },
    { "year": 4, "balance": 2565399 },
    { "year": 5, "balance": 3322777 },
    { "year": 6, "balance": 4133171 },
    { "year": 7, "balance": 5000293 },
    { "year": 8, "balance": 5928114 },
    { "year": 9, "balance": 6920882 },
    { "year": 10, "balance": 7983144 }
  ]
}

POST /v1/nhf-contribution

Calculates National Housing Fund contributions exactly the way the NHF Contribution calculator does.

bash
curl -X POST https://api.taxlane.ng/v1/nhf-contribution \
  -H "content-type: application/json" \
  -d '{"annualBasicSalary": 3000000}'

Request fields

FieldDetails
annualBasicSalaryType numberRequired YesDefault —

Response

annualBasicSalary, annualNhfContribution, and monthlyNhfContribution.

json200 OK
{
  "annualBasicSalary": 3000000,
  "annualNhfContribution": 75000,
  "monthlyNhfContribution": 6250
}

Errors

A missing or non-numeric required field returns 400 with an error message — every endpoint uses this same shape, with a field-specific message. This is the real body /v1/paye returns for a request missing grossAnnualIncome:

json400 Bad Request
{
  "error": "grossAnnualIncome is required and must be a number"
}

An unknown route returns 404. Its message key (not error) isn't inconsistent by accident — it's API Gateway's own default reject body for a route that was never registered, returned before the request ever reaches our code.

json404 Not Found
{
  "message": "Not Found"
}

Exceeding the shared rate limit returns 429 with the same message shape as the 404 above, plus the Retry-After header described under Limits below.

json429 Too Many Requests
{
  "message": "Too Many Requests"
}

Negative numbers are not rejected — they're clamped internally, matching the calculator UI's own behavior for the same input.

Limits

No API key required, no daily cap. Requests are limited to 50 per second (100 burst) at the shared Gateway level to keep the service available for everyone. Every response carries X-RateLimit-Limit/X-RateLimit-Remaining/X-RateLimit-Reset headers (plus Retry-After on a 429) so you can see how close you are to that ceiling and back off proactively — except for the narrow slice of requests Gateway rejects before ever reaching our code, which stay header-less (a platform limitation, not something we can add headers to).

For guidance only — not tax advice.

Official SDKs

JS/TS

JavaScript / TypeScript

npm install taxlaneView on GitHub →
PY

Python

pip install taxlaneView on GitHub →
PHP

PHP

composer require quineworks/taxlaneView on GitHub →

WordPress plugin

Run a WordPress site? The free TaxLane Nigeria Tax Calculators plugin drops any TaxLane calculator onto a page or post with one shortcode — no API key, no code.

TaxLane Nigeria Tax Calculators

WordPress 5.8+ · PHP 7.4+ · GPLv2-or-later · Free

Download .zip

Install via Plugins → Add New → Upload Plugin in your WordPress admin, activate it, then add [taxlane_calculator type="paye"] (or any calculator id listed on the plugin's own settings page) to any page or post.