← Back
Home › Systems › Payments and commerce

ach

Settles bulk bank payments such as payroll and bill payments in deferred batches, netting what banks owe each other.

FedACH, The Clearing House EPN, EBA STEP2

Open the ach pageach Batch checkpoint restartdistributed: Large batch jobs (end-of-day, settlement, payroll runs) that checkpoint and restart idempotentlyDouble-entry ledgerfinance: Append-only journal of transactions whose postings sum to zero per currency; balances are derived, so money can only move, never appear or vanish.›Idempotency keysfinance: Client-chosen unique key per logical operation, stored with a request fingerprint and the final response, so retries replay the first result instead of acting twice.›Iso 20022 messagesfinance: ISO 20022 XML payment and securities messages (pacs, pain, camt, sese): structure and validationMoney representationfinance: Store money as integer minor units with an explicit currency exponent, compute in wider integers, and round once with a named rounding mode.›Multilateral nettingfinance: Netting obligations across many parties into one net position per participant per currencyPayment state machinefinance: Persisted state machine for a payment lifecycle (authorize, capture, void, refund) that treats timeouts as unknown, retries with the same key and applies webhooks idempotently.›Real time gross settlementfinance: Per-payment final settlement against prefunded central-bank or settlement-bank balancesReconciliationfinance: Match internal ledger records against bank and processor statements by reference, then amount and date window; every unmatched or mismatched item becomes an exception.›External merge sortsearch-sort: Sort data larger than RAM: write memory-sized sorted runs, then k-way merge them with large sequential buffers; terabytes in one merge pass.›Fuzzy string matchingsearch-sort: Edit distance, Jaro-Winkler and trigram indexes for approximate name and address matchingDigital signatures (Ed25519)security: Small, fast, deterministic public-key signatures that prove who produced a message; the default for tokens, releases and protocols.›Hardware security module (HSM)security: A tamper-resistant device or service that generates keys, signs, decrypts and wraps with them internally, and releases a key only as ciphertext.›Mutual TLSsecurity: TLS where the client also proves a certificate key, so every connection carries a verified, rotatable machine identity.›Fixed width record parsingstorage: Parse fixed-column records by field offset and length: padding, implied decimals, packed decimal, record-type discriminators, batch control totalsGapless sequence numbersstorage: Gap-free, monotonic numbering (invoices, journal entries) under concurrency and rollbacksBusiness day calendarssystems: Holiday calendars, business-day adjustment rules (following, modified following) and settlement cyclesCalendar date arithmeticsystems: Civil dates, time zones (tzdb), DST gaps, month-end anchoring and duration mathWrite-ahead logstorage: Append each change to a checksummed sequential log and fsync it before touching data pages; the basis of crash durability in nearly every database.›Cron schedulingsystems: Cron expression parsing and next-fire-time computation, with catch-up and time-zone rulesLeasesdistributed: A lock that expires on its own: bounded-time ownership that survives crashes and partitions, given bounded clock drift and fencing tokens on writes.›Cryptographic hashes (SHA-2,BLAKE3)security: Collision-resistant fingerprints of data; SHA-256 for interoperability, BLAKE3 for speed, HMAC/HKDF for keyed uses.›Largest remainder roundingfinance: Splitting an amount into parts that sum exactly (largest remainder / Hamilton) for allocations, splits and prorationsExponential backoff with jittersystems: Retry after delays that grow geometrically and are randomized, so failed clients spread out instead of hammering a recovering service in synchronized waves.›Hash aggregationstorage: GROUP BY via hash tables with partitioning and spill to diskEvent sourcingfinance: Persist state changes as an append-only stream of immutable events per entity; current state is a fold over them, guarded by expected-version appends.›Hierarchical state machinesystems: Nest states so a substate inherits its parent's reactions and only overrides what differs, with ordered entry and exit actions along the path.›Hash joinstorage: Build a hash table on the smaller input's join key and probe it with every row of the larger one; the linear-time workhorse for equi-joins.›Buffer pools forzero-allocation I/Ohardware-os: Preallocate a fixed set of aligned I/O buffers and recycle them through a free list, so the hot path never mallocs, faults or unmaps. The bounded count doubles as back pressure.›K way mergesearch-sort: Merge k sorted streams with a heap or loser tree (merging iterators)+ 5 moreCRC32C checksumshardware-os: The Castagnoli CRC-32 with dedicated instructions on x86 (SSE4.2) and ARMv8. It is the standard fast integrity check for storage blocks, logs and network frames.›Fencing tokensdistributed: A number that grows with every lock grant and is checked by the protected resource, so a paused ex-holder's late write is rejected.›fsync, O_DSYNC and O_DIRECThardware-os: What fsync, fdatasync, O_DSYNC, O_DIRECT and F_FULLFSYNC really guarantee on Linux and macOS, and the exact call sequences for crash-safe files.›PRNGs (PCG, xoshiro)numerics: Small, fast, statistically strong non-cryptographic generators: PCG32 and xoshiro256**, with seeding, parallel streams and unbiased ranges.›Optimistic concurrency controlstorage: Run transactions without locks, record what they read, and validate at commit that nothing changed; fastest when conflicts are rare.›Memory orderingconcurrency: What Relaxed, Acquire, Release and SeqCst atomics actually guarantee, what they cost on x86 and ARM, and which one each pattern needs.›SIMD programminghardware-os: Process 4-16 lanes per instruction with AVX2, AVX-512 or NEON via Rust std::arch, with runtime dispatch and a portable fallback.›

How it is built

Architecture overview

The Automated Clearing House is a deferred net settlement system for bulk payments: payrolls, bill payments, direct debits and account-to-account transfers. Banks do not send one payment at a time. They send files, each holding batches of credit and debit entries. The operator (FedACH or The Clearing House's EPN in the US, EBA Clearing's STEP2 for SEPA in Europe) validates each file, sorts all entries by receiving bank, delivers them in processing windows, and settles only the net position of every participant in central-bank money. A bank that sent a million entries and received nearly as many settles one number. Cheap clearing of huge volume is the point; the price is latency (hours to days) and a weaker kind of finality, because an entry can be returned after it has settled.

Two systems share the name and must not be confused. The operator is a closed, high-assurance batch engine run by a central bank or bank consortium. The participant side (originating bank, payment processor, payroll provider) builds files, tracks every entry through its lifecycle, and reconciles against what the operator reports. Most engineers touch the second one, so this page covers both, in that order of detail.

Parts:

 originator ──entries──► ODFI (originating bank) ── file (batches of entries) ──► operator (FedACH / EPN / STEP2)
                              ▲                                                     │ validate, dedupe, assign window
                              │ returns, NOCs                                       ▼
                              │                                          sort entries by RDFI (external merge sort)
                       entry lifecycle                                              │
                       (state machine)                                  ┌───────────┴───────────┐
                              ▲                                         ▼                       ▼
                              │                                  files to each RDFI      net positions per participant
                       reconciliation ◄── statements ──┐         (receiving bank)        (multilateral netting)
                              ▲                        │                │                       │
                              │                        │                ▼                       ▼
                      internal ledger ◄─────────── RDFI posts to accounts      settlement at central bank / settlement bank
                                                       └── exceptions ──► return entries in a later window

The shape is a pipeline over files: ingest, validate, sort, net, settle, deliver, with controls (counts, hash totals, dollar totals) checked at every hand-off. A file that does not add up to its own control record is rejected whole; a number that cannot be explained is worse than a late payment.

How the parts fit together

File intake

An ACH file is fixed-width text: records of 94 characters, in a strict sequence of file header, batch header, entry details with optional addenda, batch control and file control. The records carry the routing numbers of originating and receiving banks, an account number, a transaction code (credit or debit, checking or savings) and the amount in integer cents (Money representation). Parsing by offset (fixed-width-record-parsing, no page yet) is simple and fast; the work is the rules around it. Moov's open-source library documents the record sequence and field rules (see Sources).

Control totals do the integrity work. Each batch control record repeats the entry count, the sum of debits and credits, and an entry hash, the sum of the receiving banks' eight-digit routing numbers (check digit left out), keeping the ten low-order digits. A parser that recomputes these catches truncation, a dropped line or a corrupted field. The same job on the transport layer uses a checksum such as CRC32C for blocks, but the payment-level totals are the ones that count. Trace numbers (an originating-bank prefix plus a sequence) make each entry unique across the network, which is what duplicate detection and returns depend on.

Files arrive over authenticated channels: mutual TLS between institution and operator, so each connection carries a verified, rotatable identity, and in some set-ups signatures over the file itself so the content can be proven later. In the SEPA world the same intake validates ISO 20022 messages (iso-20022-messages, no page yet) instead of the fixed record format; the structure is XML but the principle of "validate fully, reject whole, report why" is the same.

Window scheduler

Entries are not processed on arrival. The operator publishes several processing windows per business day, each with a cut-off for submission and a settlement time. An entry's effective date decides which window it joins, and weekends and holidays move dates. This is a calendar problem, not a clock problem: business-day-calendars (no page yet) with adjustment rules, calendar-date-arithmetic (no page yet) for time zones and month ends, and cron-scheduling (no page yet) with catch-up for a window that started late. Bugs here are quiet and expensive: a payroll that misses a window arrives a day late with no error.

Sorter and distributor

The operator receives entries from many originators, but each receiving bank needs only its own, in one file. This is a group-by on the receiving routing number over data that exceeds memory, so it is an external merge sort: sort memory-sized runs (with pdqsort in memory), then merge them with k-way-merge (no page yet), writing sequentially. Buffer pools keep aligned I/O buffers recycled instead of allocated per record, which matters because the job is bound by sequential disk and network throughput, not by CPU. The contract with the next stage: output is ordered by receiving bank and, within it, by a stable key, so a re-run produces byte-identical files.

Netting and settlement

multilateral-netting (no page yet) is the reason ACH is cheap. While the sorter streams entries it accumulates, per participant and per window, total credits and total debits by hash-aggregation (no page yet): a hash table keyed by participant, a counter pair per key. The net position of a bank is credits received minus debits sent plus the reverse, in integer cents. The sum of all net positions is zero, which is the self-check: if it is not, something was dropped.

Settlement then moves the net amounts between accounts at the central bank or a settlement bank, posted as a double-entry ledger transaction whose postings sum to zero; journal entries get gapless-sequence-numbers (no page yet) so auditors can prove nothing was removed. The alternative is real-time-gross-settlement (no page yet): settle each payment individually against prefunded balances. RTGS needs liquidity for every payment; netting needs liquidity only for the net, at the price of credit exposure until settlement. Real-time retail rails such as FedNow are built on the gross model.

Entry lifecycle (participant side)

Each entry lives through a persisted payment state machine: created, batched, submitted, accepted by the operator, settled, and then, rarely, returned. Hierarchical states fit the real structure: "submitted" holds "awaiting acknowledgement" and "acknowledged". Transitions are events in an append-only log (Event sourcing), which also gives the audit trail a regulator asks for.

Submitting twice is the worst mistake, since the second copy debits customers again. So the file submission and every entry carry an idempotency key (the file's identity, the trace number), the state machine refuses a second submit, and retries after a timeout use exponential backoff with jitter and first ask the operator whether the file was received. Optimistic concurrency guards the state rows when two workers see the same acknowledgement.

Returns

Debits are the risky direction. A receiving bank can reject an entry for a reason such as insufficient funds, closed account or no such account, and a consumer can dispute an unauthorized debit for a much longer period than a business payment. A return is a new entry in a later window that references the original trace number, so it runs through the whole pipeline again and must be matched to its original (by trace number, then amount and date). The lifecycle therefore has a long tail: "settled" is not "final". Funds-availability, hold and limit decisions are a business-risk layer on top of this tail.

Batch runner

A processing window is a deadline-bound batch job: millions of entries, hours of runtime, and a partner who is waiting at the other end. The pattern is batch-checkpoint-restart (no page yet): split the job into steps with persisted progress, make every step idempotent, and on restart resume from the last checkpoint, never from the start. The checkpoint record is a write-ahead log entry written before the step's effect and flushed with the right fsync discipline, so after a crash the runner knows whether the file was already sent. A lease with a fencing token ensures only one runner owns the job, so a node that was merely slow cannot overwrite the successor's work. Atomic counters shared across threads (entry counts, running totals) rely on the rules of memory ordering.

Reconciliation

Three views of the same day must agree: the operator's reports (what was accepted, settled, returned), the bank statement from the central or settlement bank, and the internal ledger. Reconciliation matches them by reference, then amount and date, and surfaces breaks. For high volume the match is a hash join between statement lines and ledger entries on the trace or reference number. Names on returns and exceptions are free text and often mangled, so the matching of those uses fuzzy-string-matching (no page yet) as a last resort after exact keys fail.

Signing and keys

Keys for transport, file signing and operator authentication sit in HSMs; the application asks to sign or encrypt and never holds the key. Changes to routing-sensitive configuration use dual-control-approval (no page yet): one person proposes, another approves. Secrets that must pass through process memory are erased with zeroization, keys are wrapped for storage (aes-key-wrap, no page yet), and random values come from the operating system's generator (csprng, no page yet).

Data and control flow

Entry from origination to settlement:

  1. The originator's instruction reaches its bank (the ODFI). The bank creates an entry with a trace number, amount in cents, and the receiver's routing and account number, in state created.
  2. A window job collects entries by effective date into batches by company and type, writes a file, computes control totals, and moves entries to batched. The file is staged, not yet sent.
  3. The job submits the file over the authenticated channel before the cut-off; the entries become submitted.
  4. The operator validates format and control totals, checks for a duplicate file, and either acknowledges or rejects the file whole. Acceptance moves entries to accepted.
  5. At the window, the operator sorts entries by receiving bank, accumulates the credits and debits per participant, builds the per-bank output files and the net positions.
  6. At the settlement time, net positions are posted to settlement accounts. Entries are settled in the operator's view. The receiving banks get their files and post to customer accounts.
  7. The originating bank's reconciliation matches the operator's settlement report against its ledger. The time goes mostly to sort and I/O at the operator, and to the waiting between cut-off and settlement for the participant.

A return: the receiving bank builds a return entry that references the original trace number and a reason code, and sends it in its own file in the next available window. The originating bank receives it, matches it to the original, moves that entry to returned and books a reversing posting in the ledger. The customer is notified and any hold or limit decision follows from the reason.

A restart after a failure: the runner starts, finds the checkpoint of the last completed step in its log, checks with the operator whether the file for that window was received (by file identity), and continues from the first step not recorded as done. If the file was received it does not send it again.

Scaling

The order in which limits bite:

  1. Window deadlines. Files must be built, signed and delivered before the cut-off. Lever: build files incrementally during the day (small batches, merged at the end), and start the final job early with a hard stop for late entries that roll to the next window.
  2. Sort and I/O throughput. The operator's sort over all entries is sequential-I/O bound. Levers: external merge sort with large runs and buffer reuse, partitioning by receiving-bank prefix across machines, fast local disks, and avoiding per-record allocation.
  3. Validation CPU. Parsing, checksum and hash-total computation are linear passes. Levers: parse by fixed offset without allocation, vectorized sums (SIMD), parallel workers per file.
  4. Reconciliation volume. Statement and ledger rows grow with every payment. Levers: hash joins on keys, incremental matching of new data, sharded ledgers.
  5. Latency. Batch ACH cannot be made instant by tuning. Lever: more windows per day (same-day processing), or route urgent payments to a real-time rail and keep ACH for bulk.

Failure modes

FailureSymptomCauseFix
Duplicate submissioncustomers debited or paid twiceretry after timeout without checking, or two workers sendingidempotency keys, state machine refusing a second submit, lease with fencing token, query operator before resend
File rejected at the cut-offpayroll arrives a day latecontrol totals mismatch, bad record format, expired certificatepre-validate with the same rules the operator applies, test in the window before the last one, alert on rejects
Entry hash or total wrongbatch rejected, or silently mis-sumswrong truncation of routing numbers, float arithmetic, off-by-one in countsintegers only, a golden-file test, recompute independently after writing
Missed windowentries arrive late without an errorcalendar bug: holiday, time zone, daylight-saving changeone calendar library, tested business-day rules, an alarm when a window has no file
Crash mid-batchhalf a file sent, unknown stateno checkpoint, or checkpoint written after the effectwrite-ahead checkpoint, idempotent steps, check the operator on restart
Unmatched returna returned debit stays settledtrace number lost, amount or date changed, return in a different formatstore the trace number as primary key; fuzzy match only for the review queue
Net positions do not sum to zerosettlement blockedan entry dropped, or counted in two windowszero-sum check on every window before posting; compare entry counts to control totals
Liquidity shortfallsettlement fails for a participanta bank sent more debits than it can coverintraday limits and collateral at the operator; prefunding in the participant's own risk system
Late unauthorized returnmoney already paid out is clawed backdebits can be disputed long after settlementrisk reserves, delay payouts on new customers, verify accounts before the first debit

Real implementations

namewhat it isrepolicencenotes
moov-io/achreader, writer and validator of Nacha ACH files, usable as a library or an HTTP servicemoov-io/achApache-2.0Go; the record sequence and field rules are documented in its docs
moov-io/achgatewayevent-driven engine for uploading, downloading and scheduling ACH filesmoov-io/achgatewayApache-2.0participant-side batch runner and file transport
FedACHthe Federal Reserve Banks' ACH operator (including a same-day service)— (proprietary)—see Federal Reserve Financial Services
EPNThe Clearing House's private-sector ACH operator— (proprietary)—see The Clearing House
STEP2EBA Clearing's pan-European clearing and settlement mechanism for SEPA payments— (proprietary)—ISO 20022 messages; see EBA Clearing

There is no open-source ACH operator; the operator side is described by its rules, and the open-source work sits on the participant side. Rules for the US network are published by Nacha as the Nacha Operating Rules.

Sources

  • Nacha, Nacha Operating Rules and Guidelines: formats, return reasons and time frames, same-day processing. rules
  • Nacha, ACH Network volume and value statistics. stats
  • Federal Reserve Financial Services, ACH services (FedACH, FedACH SameDay). FedACH · Federal Reserve overview
  • The Clearing House, Electronic Payments Network (EPN). EPN
  • EBA Clearing, STEP2. STEP2
  • Moov, ACH file structure (record sequence, control records, hash totals). docs · code

Similar systems

Share the most building blocks with this one.