Jadpo is experimental and not ready for production. These docs follow the compiler's main branch as of 30 Oct 2026. What's built · Install 0.1.0
jadpo
Reference: Standard library

Standard library

Bank accounts

On this page

A BankAccount holds the details a payment to a bank account needs. It is a choice of the three ways an account is written down:

Variant What it holds Sent as
uk sort_code, a UkSortCode, and account_number, a UkAccountNumber {"tag": "uk", "sort_code": "089999", "account_number": "66374958"}
iban iban, an Iban {"tag": "iban", "iban": "GB29NWBK60161331926819"}
other country, a Country; bank_code, its bank's code where the country uses one (a US routing number, an Indian IFSC), or none; and account_number, each up to ISO 20022's lengths in capital letters and digits {"tag": "other", "country": "US", "bank_code": "021000021", "account_number": "123456789"}

other serves every other country, since no standard defines a US or other national account. The parts of uk and iban are the standard payment and identity numbers listed under Groups with the baseline only, and keep their rules: a sort code's six digits, an IBAN's mod-97 check and its country's length.

In other, bank_code is none where the bank is part of the account number, as in New Zealand. bank_code and account_number are capital letters and digits with no spaces or punctuation, as a document's number is, up to ISO 20022's lengths, 35 and 34.

Jadpo doesn't check any country's own form in other yet, as it doesn't check a document's number for a country without a published one. A release adds them as they are needed, such as a US bank code as an AbaRoutingNumber. other doesn't refuse a country that uses IBANs.

Showing and storing an account

A BankAccount is financial personal data, as an IBAN and a UK account number are on their own. text.format shows it masked to the last four characters of its number, as it shows a card number: •••• 4958. That is the last four of the account number for uk and other, and of the IBAN for iban. The sort code isn't shown, though it isn't secret, so one form serves every variant.

It has no single text form. It is stored as a choice is, like a Discount: its variant's name in kind, then a column for each part, sort_code, account_number, iban, country and bank_code. It has no shape, as no choice has one, so your app's own Object { sort_code, account_number } isn't type.standard_exists.

UK account numbers and the modulus check

A UK account number also has to fit its sort code, by the modulus check Vocalink publishes for Pay.UK's payment schemes. Jadpo can't ship the tables that check needs, so a BankAccount takes any sort code and account number that are each well formed. That follows the specification, which says to presume valid a sort code its tables don't cover. Neither construction nor json.read runs the check. The design notes say why, and what is ready for when the tables may ship.

A business pays its suppliers by the account on each invoice, reads a payee's account from a payments form, and shows each account only by its last four:

example
type FormText = Text {}type NotAnAccount = Failure {    kind: FailureKind.invalid_value}type ByFasterPayments = Bool {}/// A supplier's UK account, from the sort code and number on its invoice.function supplier_account(    printed_code: UkSortCode,    printed_number: UkAccountNumber) -> BankAccount {    return BankAccount.uk {        sort_code: printed_code        account_number: printed_number    }}/// A payee's account as the payments form sends it.function payee_account(sent: FormText) fails NotAnAccount -> BankAccount {    return attempt json.read(sent, as: BankAccount) {        malformed: NotAnAccount        mismatch: NotAnAccount    }}/// Whether a payment to the account goes by Faster Payments, which takes/// a UK sort code and account number.function paid_by_faster_payments(account: BankAccount) -> ByFasterPayments {    return match account {        BankAccount.uk -> true        BankAccount.iban -> false        BankAccount.other -> false    }}/// An account as a payment's confirmation shows it.function account_label(account: BankAccount, viewer: Locale) -> PresentationText {    return text.format(account, locale: viewer)}
example
test "an account is paid by its kind and shown by its last four" {    var supplier: BankAccount = supplier_account("089999", "66374958")    assert paid_by_faster_payments(supplier)    assert account_label(supplier, Locale.en_gb) == "•••• 4958"    var abroad: BankAccount = attempt payee_account(        "{\"tag\":\"iban\",\"iban\":\"DE89370400440532013000\"}"    )    assert not paid_by_faster_payments(abroad)    assert account_label(abroad, Locale.de_de) == "•••• 3000"    var in_dollars: BankAccount = attempt payee_account(        "{\"tag\":\"other\",\"country\":\"US\",\"bank_code\":\"021000021\",\"account_number\":\"123456789\"}"    )    assert account_label(in_dollars, Locale.en_us) == "•••• 6789"}test "an account whose parts break their rules isn't read" {    assert payee_account(        "{\"tag\":\"iban\",\"iban\":\"DE89370400440532013001\"}"    ) fails NotAnAccount    assert payee_account(        "{\"tag\":\"uk\",\"sort_code\":\"08-99-99\",\"account_number\":\"66374958\"}"    ) fails NotAnAccount    assert payee_account(        "{\"tag\":\"other\",\"country\":\"US\",\"bank_code\":\"021000021\",\"account_number\":\"1234-5678\"}"    ) fails NotAnAccount}

A sort code written out is checked while compiling, as any part's literal is:

example
/// The account the business's own payments go out from.function paying_account() -> BankAccount {    return BankAccount.uk {        sort_code: "08-99-99"        account_number: "66374958"    }}
text
error: `"08-99-99"` isn't a valid `BankAccount.uk.sort_code` --> main.jadpo:4:20  |4 |         sort_code: "08-99-99"  |                    ^^^^^^^^^^ not a valid `UkSortCode`  reason: The value isn't a valid `UkSortCode`: its pattern and check digits accept only `UkSortCode`'s canonical text, and a literal is checked while compiling.  next: Write a valid `UkSortCode` in its canonical text (agent)  rule: type.invalid_literal  help: https://jadpo.dev/docs/errors/type.invalid_literalcheck failed: 1 error, 1 file

Markdown for agents: /docs/bank-accounts.md.Built from Jadpo main at a707efb.