Skip to content

API Reference

All functions take an annual gross salary in GBP (£) as f64 and return f64. None allocate. There are no external dependencies.

The crate exposes four functions and a set of public constants for the 2025/26 tax year. Import the crate as uk_paye (the underscore form, since crates.io rejects hyphens in identifiers).

use uk_paye::{income_tax, personal_allowance, national_insurance, take_home};

personal_allowance

pub fn personal_allowance(gross: f64) -> f64

The Personal Allowance for a given gross salary, after the £100k taper. Below £100,000 this is the full £12,570. Above £100,000 the allowance is reduced by £1 for every £2 of income over £100,000, reaching zero at £125,140. Floors at 0 — it never goes negative.

The taper is the well-known edge case a naive band calculator gets wrong: between £100k and £125,140 each extra £2 of salary both adds 40% higher-rate tax and pulls £1 of income out of the 0% band into the 40% band, producing a 60% effective marginal rate.

Gross Personal Allowance
£40,000 £12,570.00
£100,000 £12,570.00
£110,000 £7,570.00
£125,140 £0.00
use uk_paye::personal_allowance;

assert!((personal_allowance(100_000.0) - 12_570.0).abs() < 1e-6);
assert!((personal_allowance(110_000.0) - 7_570.0).abs() < 1e-6);
assert!(personal_allowance(125_140.0).abs() < 1e-6);

income_tax

pub fn income_tax(gross: f64) -> f64

Annual UK income tax (excluding Scotland) for a gross salary. Applies the tapered Personal Allowance first, then the three marginal bands:

Band Rate Taxable income (2025/26)
Basic rate 20% £12,571 – £50,270
Higher rate 40% £50,271 – £125,140
Additional rate 45% over £125,140

Because the allowance tapers above £100,000, income_tax is not piecewise linear across the whole range — the taper is applied internally, so callers never need to handle it separately.

use uk_paye::income_tax;

// £40,000: allowance £12,570 -> taxable £27,430 @ 20% = £5,486.00
assert!((income_tax(40_000.0) - 5_486.00).abs() < 1e-6);

// £50,000: taxable £37,430 @ 20% = £7,486.00
assert!((income_tax(50_000.0) - 7_486.00).abs() < 1e-6);

// £150,000: allowance tapered to £0; basic + higher + 45% on the excess
assert!((income_tax(150_000.0) - 54_331.50).abs() < 1e-6);

national_insurance

pub fn national_insurance(earnings: f64) -> f64

Class 1 employee National Insurance contributions for annual earnings. Employee NI does not use the tapered Personal Allowance — it has its own thresholds:

Threshold 2025/26 Rate above it
Primary Threshold (PT) £12,570 8% from PT up to the UEL
Upper Earnings Limit (UEL) £50,270 2% on everything above

So 8% applies to the slice between £12,570 and £50,270, and 2% to everything above £50,270. Earnings at or below £12,570 pay £0.

use uk_paye::national_insurance;

// £50,000 earnings: 8% on (50,000 - 12,570) = £2,994.40
assert!((national_insurance(50_000.0) - 2_994.40).abs() < 1e-6);

// £60,000: 8% on the UEL-PT band + 2% on the excess over £50,270
let expect = 0.08 * (50_270.0 - 12_570.0) + 0.02 * (60_000.0 - 50_270.0);
assert!((national_insurance(60_000.0) - expect).abs() < 1e-6); // £3,210.60

take_home

pub fn take_home(gross: f64) -> (f64, f64, f64)

The headline function: net pay, income tax, and National Insurance as a tuple (net, tax, ni). Equivalent to:

let t = income_tax(gross);
let n = national_insurance(gross);
let net = gross - t - n;   // (net, t, n)
use uk_paye::take_home;

let (net, tax, ni) = take_home(50_000.0);
assert!((net - 39_519.60).abs() < 1e-6);
assert!((tax - 7_486.00).abs()  < 1e-6);
assert!((ni  - 2_994.40).abs()  < 1e-6);

Constants

The 2025/26 thresholds are exposed as public constants for callers that need to reference or display the bands directly:

Constant Value Meaning
PERSONAL_ALLOWANCE 12_570.0 0% band ceiling
BASIC_LIMIT 50_270.0 20% band ceiling
HIGHER_LIMIT 125_140.0 40% band ceiling / additional starts
PA_TAPER_START 100_000.0 Allowance begins tapering
NI_PRIMARY_THRESHOLD 12_570.0 Employee NI 8% starts
NI_UPPER_LIMIT 50_270.0 Employee NI drops to 2%
NI_MAIN_RATE 0.08 8% between PT and UEL
NI_UPPER_RATE 0.02 2% above UEL

These are frozen for the 2025/26 tax year. If HMRC changes them, update the constants and every function follows.