Use case
Banking systems are defined by what happens when things go wrong. A payment to a closed account must be returned with the right reason. A disputed card transaction must open a case that still points at the transaction weeks later. A frozen account must refuse outgoing transfers but still accept a reversal. Test data copied from yesterday's production mostly contains the ordinary days, and the failures it does contain belong to real customers whose data should not be in a test environment.
The scenario
The payments team is changing how outgoing payments are retried. Their tests need payments that fail for different reasons on different rails, card transactions that were declined, reversed or charged back, fraud cases linked to those transactions, accounts in non-open states and loans in different stages. Every reference must resolve: a fraud case pointing at a transaction that is not in the dataset turns a business test into a data-quality incident.
The Financial Services pack generates these situations synthetically. The script below inventories its public sample and checks the relationships the payments tests depend on.
Run it
Python 3.10 or later, standard library only.
import csv
import io
import os
import urllib.request
from collections import Counter
BASE = os.environ.get("DATANIVRA_DOWNLOADS", "https://www.datanivra.com/downloads")
BUNDLE = f"{BASE}/packs/financial-services/2.1.0/synthetic"
def rows(name):
with urllib.request.urlopen(f"{BUNDLE}/{name}") as response:
return list(csv.DictReader(io.TextIOWrapper(response, encoding="utf-8")))
accounts = rows("core_banking.accounts.csv")
transactions = rows("payments.transactions.csv")
payments = rows("payments.payments.csv")
fraud = rows("fraud.fraud_cases.csv")
loans = rows("lending.loans.csv")
tx_ids = {t["transaction_id"] for t in transactions}
account_ids = {a["account_id"] for a in accounts}
print(
"transaction status:",
", ".join(f"{k}={v}" for k, v in sorted(Counter(t["status"] for t in transactions).items())),
)
print(
"payment status:",
", ".join(f"{k}={v}" for k, v in sorted(Counter(p["status"] for p in payments).items())),
)
for p in payments:
if p["failure_reason"]:
print(f" failed payment {p['payment_id']} on {p['payment_rail']}: {p['failure_reason']}")
print(
"fraud case types:",
", ".join(f"{k}={v}" for k, v in sorted(Counter(f["case_type"] for f in fraud).items())),
)
linked = sum(1 for f in fraud if f["transaction_ref"] in tx_ids)
print(f"fraud cases linked to an existing transaction: {linked} of {len(fraud)}")
print(
"account status:",
", ".join(f"{k}={v}" for k, v in sorted(Counter(a["status"] for a in accounts).items())),
)
for loan in loans:
print(f"loan {loan['loan_id']}: {loan['status']}, {loan['days_past_due']} days past due")
orphans = sum(1 for t in transactions if t["account_ref"] not in account_ids)
print(f"transactions without an account: {orphans}")Expected output
transaction status: CHARGED_BACK=3, DECLINED=2, PENDING=5, POSTED=43, REVERSED=1
payment status: COMPLETED=7, FAILED=4
failed payment 1 on ZZ_WIRE: BENEFICIARY_ACCOUNT_INVALID
failed payment 6 on ZZ_INSTANT: LIMIT_EXCEEDED
failed payment 8 on ZZ_WIRE: ACCOUNT_CLOSED
failed payment 11 on ZZ_WIRE: BENEFICIARY_ACCOUNT_INVALID
fraud case types: CHARGEBACK=3, FIRST_PARTY=2
fraud cases linked to an existing transaction: 5 of 5
account status: FROZEN=1, OPEN=11
loan 1: PAID_OFF, 0 days past due
transactions without an account: 0Four of eleven outgoing payments fail, each with a distinct, enumerated reason; three card transactions were charged back and each has a matching chargeback case; one account is frozen. Payment rails carry a ZZ_ prefix so no test can mistake them for a real scheme identifier.
Schema
| Scenario (pack code) | Table | Signal |
|---|---|---|
FS_FAILED_PAYMENTS | payments.payments | status = FAILED with a failure_reason |
FS_CHARGEBACKS | payments.transactions, fraud.fraud_cases | CHARGED_BACK transactions with CHARGEBACK cases |
FS_ACCOUNT_STATUS_CHANGES | core_banking.accounts | frozen, dormant or closed with status_changed_at |
FS_LOAN_DELINQUENCY | lending.loans | days_past_due 30–180, balance outstanding |
FS_BALANCE_BOUNDARIES | core_banking.accounts | balances at zero and at the overdraft limit, one cent either side |
The sample is small: delinquent loans and balance boundaries are scenarios you request at generation time rather than cases present in every bundle.
What DataNivra does with your own data
Activated in your organisation, the pack's policy templates classify card numbers, account numbers, tax ids and beneficiary details, and a dataset request can combine a masked subset of your core-banking source with synthetic scenario rows such as failed payments or chargebacks. The agent does the row-level work in your network; deterministic masking keeps an account number consistent across the core ledger, the card system and the fraud system so cross-system tests still join. Certification gates — including referential integrity and orphan detection — must pass before a dataset can be provisioned. Certification here means DataNivra-certified against configured policy gates; it is not a regulatory or third-party certification and does not make a system compliant with any regulation.
Limits to plan around
- The sample's single loan is paid off; delinquency, default and boundary balances appear when those scenarios are requested at a larger scale.
- Rails, merchant categories and reason codes are synthetic enumerations. Tests against a real scheme's message formats need a mapping to the scheme's codes.
- Synthetic transaction patterns are modelled, not learned from your customers; fraud-model evaluation needs masked real data or carefully designed synthetic distributions.
Next steps
Read the financial services test data tutorial and the banking test data guide, and browse the Financial Services pack.
Synthetic downloads
Files from the Financial Services pack 2.1.0 bundle. Everything in it is synthetic, generated from a fixed seed, and listed with its SHA-256 digest in the bundle's MANIFEST.json.
synthetic/payments.transactions.csv synthetic/payments.payments.csv synthetic/fraud.fraud_cases.csv synthetic/core_banking.accounts.csv synthetic/lending.loans.csv schema/payments.sql
Industry pack: Financial Services — its entities, scenarios, policy templates and the complete asset bundle.
Try it with DataNivra
The synthetic playground walks through discovery, subsetting, masking, validation and certification in your browser, with no account. Starting free gives you the hosted synthetic sandbox; your own sources need an agent in your network.