Validate UK sort code + account number combinations against the official Pay.UK / VocaLink modulus-checking rules — the same rules used across BACS, Faster Payments and CHAPS to confirm an account number is structurally valid.
TypeScript-first, zero runtime dependencies, and validated against all 34 official test cases from the v8.90 specification (every algorithm and every exception, 1–14).
import { isValidAccount } from '@pametan/modulus-check';
isValidAccount('08-99-99', '66374958'); // true
isValidAccount('089999', '66374959'); // falseModulus checking catches mistyped account details before a payment is ever submitted. The rules themselves are public but fiddly: three algorithms, a 1,160-row weighting table, a sort-code substitution table, and fourteen exceptions with subtle interactions. This library implements the full specification so you don't have to, and proves it against Pay.UK's own test vectors.
Note: a passing modulus check means an account number is a possible number for that sort code — not that the account exists or is in use. Sort codes with no rule in the weight table cannot be checked and are reported as
checkable: false(and treated as valid).
npm install @pametan/modulus-checkRequires Node 24+. Ships ESM with bundled type declarations.
import { isValidAccount } from '@pametan/modulus-check';
isValidAccount('107999', '88837491'); // trueSeparators (spaces, dashes) in the inputs are ignored.
checkAccount returns which algorithm(s) ran and whether each passed — useful
for logging, debugging, or auditing.
import { checkAccount } from '@pametan/modulus-check';
checkAccount('202959', '63748472');
// {
// valid: true,
// checkable: true,
// sortCode: '202959',
// accountNumber: '63748472',
// checks: [
// { algorithm: 'MOD11', exception: 0, passed: true, performed: true },
// { algorithm: 'DBLAL', exception: 0, passed: true, performed: true },
// ],
// }Some institutions issue account numbers that aren't a plain 8 digits. Section 2.1.2 of the spec defines how to standardise them; those rules are exposed as small, explicit helpers so you apply the one that matches your data, then check:
import {
isValidAccount,
padShortAccount,
lastEightDigits,
standardiseSantander,
} from '@pametan/modulus-check';
isValidAccount('123456', padShortAccount('123456')); // 6-digit -> 00123456
isValidAccount('601613', lastEightDigits('0123456789')); // NatWest 10-digit
const { sortCode, accountNumber } = standardiseSantander('72-00-00', '1234567890');
isValidAccount(sortCode, accountNumber);| Export | Description |
|---|---|
isValidAccount(sortCode, accountNumber) |
boolean — quick validity check. |
checkAccount(sortCode, accountNumber) |
ModulusCheckResult — full detail. |
padShortAccount(acc) |
Left-pad 6/7-digit accounts to 8 digits. |
lastEightDigits(acc) / firstEightDigits(acc) |
10-digit standardisation. |
standardiseSantander(sortCode, acc) |
Santander/A&L adjustment. |
Types Algorithm, WeightRow, CheckDetail and ModulusCheckResult are
exported for consumers.
The rules come from two files published by Pay.UK / VocaLink, vendored in
data/ as the source of truth:
valacdos.txt— the modulus weight table (sort-code ranges, algorithm, weights, exception code).scsubtab.txt— the sort-code substitution table (exception 5).
npm run build:data regenerates src/generated/tables.ts
from those files. When Pay.UK publishes an update, drop in the new .txt files
and re-run it.
npm install
npm run build:data # regenerate tables from data/*.txt
npm run typecheck
npm test # runs all 34 official cases + behavioural tests
npm run build # emit dist/This library implements the published specification and passes Pay.UK's own
test vectors, but it is provided as an engineering aid, not as financial or
compliance advice. Always reconcile against the current specification and the
EISCD/ISCD for production use. See LICENSE (MIT).
We're Pametan — a specialist fintech/regtech engineering agency working across UK, US and Canadian rails (FCA · CFPB · FCAC). We build the regulated, audited, in-market version of tools like this: payment validation, BACS/Faster Payments integration, and the systems around them.