Bank Accounts & Prenotes
Bank account records hold a user’s KMS-encrypted account and routing numbers for ACH submission. Prenotes are zero-dollar ACH entries that verify an account before a live debit.
Account Records
Records are BANKINFO# items in the site-payments single table (schema), one per user and Plaid account_id. The API creates a record the first time a flow needs the account:
-
Fetch account number, routing number, and the official account mask from the Transactions Service (Plaid Auth).
-
Compute
account_routing_hash, a salted SHA-256 of account + routing (site/saltsecret). -
KMS-encrypt the account and routing numbers with
alias/site-payments-bank-account. -
Store the record; later reads decrypt inside the Lambda at submission time.
A record with no mask attribute has its mask backfilled from the Transactions Service accounts endpoint on the next read. A failed backfill leaves the record unchanged, and a later read retries.
Source: pkg/bankaccount/bankaccount.go, pkg/bankaccount/store/
Account Mask
GET /{user_id}/bank-accounts/{account_id} and every payment record’s masked_account_number use the official account mask (last 2–4 characters), falling back to the last 4 digits of the auth account number when no mask is stored.
For some institutions the auth account number is a tokenized account number (TAN) whose digits differ from the account the user knows. Match on mask, not on the auth number’s last 4.
|
Removal
| Path | Effect |
|---|---|
|
Deletes the |
Return-code engine invalidate-bank action |
Deletes the item and writes |
GET /check-bank-account returns the user IDs holding a given account_routing_hash (Fraud Detection).
Prenotes
| Endpoint | Submission |
|---|---|
|
JPM ACH debit for |
|
Usio ACH prenote against the named |
Both endpoints load the user’s bank account record, submit, and on provider success save a payment record: payment_status = ACHSENT, amount = 0, payment_provider = jpm or usio, event_type = PRENOTE_SUBMITTED (published immediately — Events). A provider failure returns 500 and writes nothing; a missing bank account returns 404.
Resolution follows the normal ACH paths:
-
Completion — check-ach-worker after the 3-business-day gate,
PRENOTE_COMPLETED— Check ACH. -
Return — JPM webhook or the Usio ACH-returns sync,
payment_status = FAILED,PRENOTE_RETURNED.
PRENOTE_RETURNED is outside the blocklist-handler’s Kinesis filter: a prenote return records the code and takes no bank or user action.
Some banks return R01 (insufficient funds) on a zero-dollar prenote. It does not mean the account is invalid for a live debit.
|