BACS Standard 18 Parser
Legacy compatible. Future ready. We speak the language of the 1970s so your HR team doesn't have to.
Zero migration. Zero retraining.
90% of UK employers run payroll through BACS Standard 18 — a fixed-width file format from the 1970s. tPay365 reads it natively. HR uploads the same file they've always uploaded. No new software. No retraining. No migration project.
For the other 10%, we accept CSV uploads as a fallback. But for the vast majority, integration is as simple as pointing the existing payroll export at tPay365.
Upload
HR uploads the same BACS Standard 18 file they already generate. Drag and drop or API.
Parse & Validate
Fixed-width records are sliced, validated, and enriched. Errors collected per-line, never thrown.
Orchestrate
Parsed records trigger the Clean Paycheck engine. Each employee gets vaults, routing, and yield.
From fixed-width to structured data
A real BACS Standard 18 file, parsed into clean JSON in under 50ms
VOL1 HDR1A000000 0000000000001 000000 0260210 0260210 000000 HDR2F0200000100 UHL1 260210 000000 000001 0617943012345678TPAY365LTD 00000250000ALICE SMITH 1720241501 0617943087654321TPAY365LTD 00000180000BOB JONES 1720241501 EOF1A000000 0000000000001 000000 0260210 EOF2F0200000100 UTL10000000000000000043000000000000000002 0000000000000000000000000
{
"header": {
"processing_date": "2026-02-10",
"file_number": "000001",
"originator": "TPAY365LTD"
},
"records": [
{
"sort_code": "617943",
"account_number": "01234567",
"amount_pence": 250000,
"amount_pounds": 2500.00,
"name": "ALICE SMITH",
"reference": "172024",
"transaction_code": "99",
"status": "valid"
},
{
"sort_code": "617943",
"account_number": "87654321",
"amount_pence": 180000,
"amount_pounds": 1800.00,
"name": "BOB JONES",
"reference": "172024",
"transaction_code": "99",
"status": "valid"
}
],
"trailer": {
"total_debit_pence": 430000,
"record_count": 2,
"checksum": "valid"
},
"parse_errors": []
}Parsing rules
Technical Architecture
Technical Specification
Format: BACS Standard 18 (fixed-width, 100 chars/record) Record types: VOL, HDR1, HDR2, UHL1, entries, EOF, UTL Parsing: string.slice() — never regex on fixed-width Validation: Modulus check on sort code + account number Idempotency: hash(content + employer_id + pay_period) Error handling: Collects per-line errors, returns partial Fallback: CSV upload for non-BACS systems Max file: 10MB, 10,000 records
Parse speed
<50ms
For 10,000 record file
Max file size
10 MB
10,000 records per file
Error handling
Partial results
Errors collected, never thrown
Disaster recovery
Server B (this application) is the primary BACS parser. If it fails, Server A activates its Python fallback implementation. Both produce identical outputs, verified via shared test fixtures. Zero downtime for payroll processing.