A mock bank that speaks ISO 20022 and NACHA, over HTTP and over a drop folder, so you can test a payment integration without a bank, a test IBAN, or six weeks of onboarding. It is not a ledger and not a payment provider: it holds four accounts, moves balances in minor units, and refuses by name anything it does not implement.
you ──pain.001──▶ mock-bank
◀──pain.002── 2 accepted, 2 rejected (AC04, RC01)
◀──camt.054── debited, on the settlement date
◀──camt.053── the day's statement, and it reconciles
◀──pacs.004── one came back, 3 business days later
Or the same four payments as an ACH file, for an account that banks in US formats. The choice is per account, so one file can produce both.
you ──NACHA────▶ mock-bank
◀──text───── ENTRY 999999990000002 INV-2026-0102 3400.50
REJECTED R02 the creditor account … is closed
◀──NACHA──── a return file: one 21 entry and addenda 99 per return
◀──BAI2───── 16,447,125000,Z,INV-2026-0101,…,Globex Supplies B.V./
16,447,1500000,Z,INV-2026-0104,…,Umbrella Logistics/
pain.001 or a 94-column NACHA file, over POST /payments or dropped in a folder, goes through the same decisions. An account whose format is nacha gets a plain-text acknowledgement where an ISO 20022 account gets a pain.002, an R-coded return file where it gets a pacs.004, and a BAI2 statement where it gets a camt.053. A NACHA file is held to the format: every record 94 bytes of printable ASCII and the file whole blocks of ten, or it is refused FF01 naming the line and the column.POST /_mock/credits lands a customer's payment in an account on its value date, or the next business day for a weekend, a holiday or a missed cutoff. It is reported like everything else: a camt.054 as it books and an entry on the day's camt.053, which still reconciles - the payer as Dbtr, the note in RmtInf/Ustrd, and the invoice reference in Strd apart from it, because a bank that reformats remittance is the reason cash application is hard. A short payment, one that names no invoice, one that settles several, and a reference split across lines are each one request away.pain.008, or a NACHA file of debit entries, collects from customers: the bank answers it as it answers a payment file, credits the account on the settlement date, and reports the money like any other that arrives. The customer's bank can refuse a collection before it settles or send it back after, as a pacs.004 or an R-coded return file - MD01 or R10 for a mandate the customer says they never gave. A customer whose account is at the same bank decides for itself: closed, or without the money, and the collection is rejected.AC04, one with no money, a bank identifier that is not the bank, a duplicate file, a statement with one payment missing, a payment that settles and then comes back days later, and an account that closes between the day a payment is accepted and the day it settles, so the payment is rejected rather than booked. The three behaviours the bank rejects for have NACHA twins: AM04 is R01, AC04 is R02, RC01 is R03.POST /_mock/advance moves. A three-day return is a line in a test, not a three-day wait. A mock left running over midnight issues that day's statement itself, the next time anything asks. And you need not wait for the day to end either: POST /_mock/accounts/<id>/report writes a camt.052 for the account as it stands now, which a reconciler can compare against the day's statement to find the entry a statement-gap leaves out.--drop-dir goes through the same decisions as POST /payments and lands in processed/ or failed/ with the answer written beside it.payment_run does what SAP's F110 does: select the open items that are due from mock-sap, pay them in one file, and post each statement back so SAP clears what was paid and reopens what came back. It lives in mock-acme now, with seventy-six tests run in its CI against the released mocks - twice, once over ISO 20022 and once over ACH, because the same run has to survive both.
pip install mock-bank
mock-bank --port 8090
curl -X POST --data-binary @pain001.xml http://127.0.0.1:8090/payments
Worked examples that use mock-bank: Procure to pay, Pay invoices and Payment run.