RockfishRockfish  /  Schema → Data Card Payments · 8 tables · 10M transactions

Schema-based payments data

A card-payments dataset, synthesized from a schema.

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.

10M
transactions, the spine of the model
8
related tables, from one schema
~29M
rows, every foreign key resolved
0
real card numbers (Luhn-valid, synthetic)

Why this is hard to get

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.

The card-payment lifecycle

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.

Modeled on a real reference schema

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.

The flow, end to end

schema → platform → eight tables → validate

01

Schema

Eight tables, columns, keys, and relationships as one DataSchema.

02

Generate

Rockfish generates the data on the platform, referentially intact.

03

Eight tables

Accounts, cards, merchants, and the transaction lifecycle, as Parquet.

04

Validate

A battery of integrity and realism checks over every row.

The data model

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.

Eight related tables

reference catalogs plus the transaction lifecycle

TableWhat it isRows
cardholder_accountAccounts, with issuing country, currency, and tenure200
pan_recordCards per account: Luhn-valid number, network, expiry, status398
merchantMerchants, with an MCC, country, and category-driven risk rating150
payment_txnTransactions: the spine of the model10,000,000
authorizationThe authorization for each transaction (approved / declined)10,000,000
captureThe settlement of an approved authorization8,512,688
chargebackDisputes on captured transactions42,050
refundRefunds on captured transactions508,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.

The lifecycle at true scale

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.

A transaction, end to end

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.

PT-9437185 · Visa · Boston Acoustics (retail, MCC 5999) · CAD
payment_txn
$63.10
approved
Jun 1, 12:29:06
authorization
$63.10
approved · code 00
Jun 1, 12:29:07
+1s
capture
$63.10
completed
Jun 3, 10:29:07
+2 days
PT-315 · Mastercard · The Serendipity Dip (grocery, MCC 5411) · USD
payment_txn
$64.62
approved
Feb 17, 16:35:48
authorization
$64.62
approved · code 00
Feb 17, 16:36:04
+16s
capture
$64.62
completed
Feb 19, 18:36:04
+2 days
chargeback
$64.62
product_unacceptable
Apr 17, 18:36:04
+59 days

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.

Causal by construction

the lifecycle rules hold on every row, not on average

lifecycle

A declined transaction is never captured

Capture exists only for approved authorizations; a decline ends the chain.

lifecycle

Only a captured transaction is disputed or refunded

Chargebacks and refunds attach to settled money, and the two are near-disjoint.

time

Every event follows the one before it

Authorize, then settle, then dispute, each timestamped after its predecessor, none after the card expires.

money

Amounts agree across the chain

Authorized equals the transaction; capture never exceeds authorized; a chargeback equals the settled amount, a refund never exceeds it. Exact to the cent.

Realistic by construction

the distributions a fraud or finance team would expect

Card-network market share

interchange fees tiered accordingly

Visa55%
Mastercard30%
Amex10%
Discover5%

Decline rate by merchant risk

the way a real acquirer sees it

Low-risk MCC5% declined
Medium-risk MCC10% declined
High-risk MCC20% declined

Interchange fee by network

tiered, plus a fixed $0.10 floor

Ticket size

lognormal, right-skewed (median $47)

Merchant volume concentration

the top 10% of merchants carry 53%

Where disputes land

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.

Change anything in the schema

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.

# In schema_definition.py

# Card-network market share: Visa, Mastercard, Amex, Discover
weights=[0.55, 0.30, 0.10, 0.05]

# Decline rate rises with merchant risk
low_risk = ["approved", "declined"], weights=[0.95, 0.05]
medium_risk = ["approved", "declined"], weights=[0.90, 0.10]
high_risk = ["approved", "declined"], weights=[0.80, 0.20]

# Interchange is tiered by network, plus a $0.10 fixed floor

Validated, thoroughly

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 groupPassedWhat it proves
Referential integrity7 / 7Every foreign key resolves; the card belongs to the transaction's own account; currency and country agree.
Causal lifecycle & ordering8 / 8Declines are never captured; disputes and refunds only on captured transactions, never together; every event after the one before it; nothing past card expiry.
Monetary correctness8 / 8Authorized equals the transaction; captures within authorized; chargeback equals the settled amount; fees tiered with a $0.10 floor; exact to the cent.
Domain validity & distribution11 / 11Luhn-valid numbers whose BIN matches the network; decline rises with risk; chargebacks skew high-risk; Pareto merchant concentration; mostly domestic.

See it on your data

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.

Talk to Rockfish →

full size