Schema-based payments data
Describe the tables, columns, and relationships of a card-payment system once. Rockfish generates a complete, referentially intact, behaviorally realistic dataset across the full payment lifecycle, carrying no real cardholder data.
real card data is radioactive
Real cardholder data lives under PCI-DSS. You can't drop it into a test environment, share it with a vendor, or hand it to a model team without heavy controls, and even a scrubbed extract still leaks and still takes months to approve. So the teams who need realistic payments data, to build fraud models, test systems, and run analytics, usually can't get it. Generated from a schema, this dataset carries no real cardholder data and is shareable on day one.
authorize, settle, and occasionally dispute
A card payment is not one row, it is a chain of events. A transaction is authorized (approved or declined); an approved authorization settles into a capture; and only a settled transaction can later be disputed (a chargeback) or refunded. Every step carries its own amounts, fees, statuses, and timestamps, and each one must agree with the step before it. Modeling payments well means modeling that chain, not just a flat table of amounts.
the Databricks payments_fintech industry model
The data model follows the public Databricks payments_fintech industry reference model, a recognizable shape for anyone who works with card data. It is a representative subset, not a 1:1 reproduction. The Rockfish generator is domain-neutral: the tables, columns, and relationships live entirely in the schema, so this same pattern points at your own model.
schema → platform → eight tables → validate
Eight tables, columns, keys, and relationships as one DataSchema.
Rockfish generates the data on the platform, referentially intact.
Accounts, cards, merchants, and the transaction lifecycle, as Parquet.
A battery of integrity and realism checks over every row.
primary keys, foreign keys, and the transaction spine
payment_txn is the spine: each transaction belongs to an account
and a card, hits a merchant, and has exactly one authorization. An approved authorization
settles into at most one capture; only a captured transaction can be disputed or refunded.
reference catalogs plus the transaction lifecycle
| Table | What it is | Rows |
|---|---|---|
cardholder_account | Accounts, with issuing country, currency, and tenure | 200 |
pan_record | Cards per account: Luhn-valid number, network, expiry, status | 398 |
merchant | Merchants, with an MCC, country, and category-driven risk rating | 150 |
payment_txn | Transactions: the spine of the model | 10,000,000 |
authorization | The authorization for each transaction (approved / declined) | 10,000,000 |
capture | The settlement of an approved authorization | 8,512,688 |
chargeback | Disputes on captured transactions | 42,050 |
refund | Refunds on captured transactions | 508,050 |
Reference tables (accounts, cards, merchants) stay a fixed catalog; the transaction and lifecycle tables scale with a single --scale-factor. Every transaction is authorized exactly once; 85% settle, and disputes (0.5% of settled) and refunds (6%) stay realistically rare.
most settle cleanly; disputes are a sliver
Every transaction is authorized exactly once; 85% settle, and refunds and disputes are deliberately rare. Drawn to true scale their bars nearly vanish, which is exactly how a healthy portfolio looks.
two real rows, traced across the tables
Actual generated rows, joined across the tables by their keys. The amount agrees at every step, and each event is stamped after the one before it.
The first settles cleanly and ends, like 85% of the portfolio. The second is the rare 0.5%: disputed two months later, its chargeback equal to the settled amount.
the lifecycle rules hold on every row, not on average
Capture exists only for approved authorizations; a decline ends the chain.
Chargebacks and refunds attach to settled money, and the two are near-disjoint.
Authorize, then settle, then dispute, each timestamped after its predecessor, none after the card expires.
Authorized equals the transaction; capture never exceeds authorized; a chargeback equals the settled amount, a refund never exceeds it. Exact to the cent.
the distributions a fraud or finance team would expect
interchange fees tiered accordingly
the way a real acquirer sees it
tiered, plus a fixed $0.10 floor
lognormal, right-skewed (median $47)
the top 10% of merchants carry 53%
high-risk: 9% of txns, 47% of disputes
Every card number is Luhn-valid and unique, with a BIN matching its network; activity is mostly domestic with a realistic cross-border minority.
the whole model is plain, editable Python
Every distribution is a value in schema_definition.py. Shift a
market share, a decline rate, or a fee tier and regenerate.
34 checks, all passing, over the full 10M transactions
validate.py reads every row and runs 34 cross-table checks, exiting
non-zero on any failure, so it doubles as a CI gate. Referential integrity and causal ordering
are the two groups no column-by-column generator can satisfy.
| Check group | Passed | What it proves |
|---|---|---|
| Referential integrity | 7 / 7 | Every foreign key resolves; the card belongs to the transaction's own account; currency and country agree. |
| Causal lifecycle & ordering | 8 / 8 | Declines are never captured; disputes and refunds only on captured transactions, never together; every event after the one before it; nothing past card expiry. |
| Monetary correctness | 8 / 8 | Authorized equals the transaction; captures within authorized; chargeback equals the settled amount; fees tiered with a $0.10 floor; exact to the cent. |
| Domain validity & distribution | 11 / 11 | Luhn-valid numbers whose BIN matches the network; decline rises with risk; chargebacks skew high-risk; Pareto merchant concentration; mostly domestic. |
the next step
This is one worked example on a public reference model. Rockfish generates schema-accurate, fully synthetic data across your own tables and relationships, referentially intact and carrying no real cardholder data. To see it on your schema, get in touch with the Rockfish team.