Getting Started with FraudTwin#

FraudTwin can be used directly as a Python library. This tutorial generates a small, deterministic payment world entirely in memory.

1. Install FraudTwin#

Install FraudTwin in your Python environment before importing it. The command below is shown for reference and is intentionally not executed by this tutorial.

pip install fraudtwin

If FraudTwin is already imported, restart the kernel after installation so the notebook loads the newly installed version.

2. Generate a payment world#

The default is in-memory generation, so no temporary directories or command-line wrappers are needed.

import fraudtwin

data = fraudtwin.generate()

print(data.run_id)
RUN-19652188a1efbe6c

3. Inspect the generated data#

The result contains reproducibility metadata and typed Python objects. You can inspect counts without reading files or calling the CLI.

print("Entities:")
for name, count in data.manifest.entity_counts.items():
    print(f"  {name}: {count:,}")

print("Events (non-zero):")
for name, count in data.manifest.event_counts.items():
    if count:
        print(f"  {name}: {count:,}")
Entities:
  customers: 10
  institutions: 3
  accounts: 15
  cards: 12
  merchants: 3
  devices: 12
  pix_keys: 8
  behavior_profiles: 10
Events (non-zero):
  payments: 100
  payment_events: 433
  ledger_entries: 176
  card_lifecycle_events: 337
  pix_lifecycle_events: 71
  CARD_PAYMENT_INITIATED: 63
  CARD_AUTHORIZATION_REQUESTED: 63
  CARD_AUTHORIZED: 50
  CARD_DECLINED: 13
  CARD_REVERSED: 3
  CARD_CAPTURED: 47
  CARD_CLEARED: 47
  CARD_SETTLED: 47
  CARD_REFUNDED: 4
  PIX_INITIATED: 12
  PIX_VALIDATED: 12
  PIX_AUTHORIZED: 11
  PIX_SUBMITTED: 11
  PIX_SETTLED: 11
  PIX_RECEIVED: 11
  PIX_REJECTED: 1
  PIX_RETURN_REQUESTED: 1
  PIX_RETURNED: 1
for payment in data.behavior.payments[:3]:
    print(
        {
            "payment_id": payment.payment_id,
            "rail": payment.payment_rail,
            "amount": payment.amount,
            "status": payment.current_status,
        }
    )
{'payment_id': 'PAY-00000001', 'rail': 'ACCOUNT_TRANSFER', 'amount': 15.29, 'status': 'COMPLETED'}
{'payment_id': 'PAY-00000002', 'rail': 'PIX', 'amount': 21.7, 'status': 'RECEIVED'}
{'payment_id': 'PAY-00000003', 'rail': 'CARD', 'amount': 15.63, 'status': 'SETTLED'}

4. Use the ML dataset#

The minimal configuration also builds point-in-time ML rows. The returned dataset can be used directly as a Polars DataFrame.

data.require_dataset().frame.head()
shape: (5, 53)
dataset_row_idpayment_idevent_idcustomer_idaccount_idprediction_timebusiness_event_timeevent_timesource_available_atfeature_available_atlabel_available_atlabelfraud_truthamountpayment_railpayment_typemerchant_idcard_iddevice_idonlinetransaction_count_1mtransaction_count_5mtransaction_count_1htransaction_count_24htransaction_count_7dtransaction_count_30dtransaction_amount_1htransaction_amount_24htransaction_amount_7davg_transaction_amount_30dmax_transaction_amount_7damount_vs_customer_avgdistinct_merchants_1ddistinct_merchants_30dnew_merchant_flagmerchant_fraud_rate_historicaldistinct_countries_24hnew_country_flagdevice_age_daysnew_device_flagtrusted_device_flagdevice_customer_count_30dcustomers_per_device_24haccount_age_daysbalanceavailable_balancecredit_limitcredit_utilizationdays_since_last_paymentconfirmed_fraud_count_90dfraud_loss_365ddays_since_last_confirmed_fraudsplit
strstrstrstrstrdatetime[μs, UTC]datetime[μs, UTC]datetime[μs, UTC]datetime[μs, UTC]datetime[μs, UTC]datetime[μs, UTC]strboolf64strstrstrstrstrbooli64i64i64i64i64i64f64f64f64f64f64f64i64i64boolf64i64boolf64boolbooli64i64f64f64f64f64f64f64i64f64f64str
"DSR-4f7f1bad7761f562f65b8f73""PAY-00000002""EVT-00000002""CUS-000004""ACC-000014"2026-01-01 11:37:02 UTC2026-01-01 11:37:00 UTC2026-01-01 11:37:00 UTC2026-01-01 11:37:02 UTC2026-01-01 11:37:02 UTCnullnullnull21.7"PIX""TRANSFER"nullnull"DEV-000008"false00210101072.28304.24304.2430.42452.160.71325333false0.01false264.0falsetrue331377.011811.4311811.4317564.010.3275210.02155100.0-1.0"train"
"DSR-9b9062191b591fc98c6c11fb""PAY-00000003""EVT-00000003""CUS-000004""ACC-000014"2026-01-01 12:21:05 UTC2026-01-01 12:21:00 UTC2026-01-01 12:21:00 UTC2026-01-01 12:21:05 UTC2026-01-01 12:21:05 UTCnullnullnull15.63"CARD""PURCHASE""MER-000002""CARD-000008""DEV-000005"true00111111121.7325.94325.9429.63090952.160.5274933false0.01false596.0falsetrue111377.011789.7311789.7317564.010.3287560.03061300.0-1.0"train"
"DSR-8a8b9f485f29945b45bea7b8""PAY-00000004""EVT-00000004""CUS-000002""ACC-000011"2026-01-01 07:54:05 UTC2026-01-01 07:54:00 UTC2026-01-01 07:54:00 UTC2026-01-01 07:54:05 UTC2026-01-01 07:54:05 UTCnullnullnull29.24"CARD""PURCHASE""MER-000003""CARD-000009""DEV-000006"true00144443.22142.82142.8235.70544.970.81893322false0.01false613.0falsetrue1186.013798.7313798.7317960.110.2317010.0410300.0-1.0"train"
"DSR-4333e36023f21475b9fdb6e4""PAY-00000005""EVT-00000005""CUS-000006""ACC-000008"2026-01-01 14:33:02 UTC2026-01-01 14:33:00 UTC2026-01-01 14:33:00 UTC2026-01-01 14:33:02 UTC2026-01-01 14:33:02 UTCnullnullnull24.08"PIX""TRANSFER"nullnull"DEV-000006"false0003330.068.3968.3922.79666730.261.05629522false0.01false614.0truetrue221815.03285.013285.0135090.720.9063850.0854400.0-1.0"train"
"DSR-e78d4b792de2395482d0990d""PAY-00000006""EVT-00000006""CUS-000002""ACC-000011"2026-01-01 19:18:05 UTC2026-01-01 19:18:00 UTC2026-01-01 19:18:00 UTC2026-01-01 19:18:05 UTC2026-01-01 19:18:05 UTCnullnullnull25.82"CARD""PURCHASE""MER-000003""CARD-000012""DEV-000002"true0001111110.0369.74369.7433.61272753.340.76816133false0.01false287.0falsetrue2287.013575.8713575.8717960.110.244110.05769700.0-1.0"validation"

5. Count generated cases#

These counts are payment cases: a payment linked to a fraud record is counted as fraud, and the remaining payments are counted as non-fraud. The ML dataset may contain fewer point-in-time rows, and its labels can be unavailable when no fraud workflow is enabled.

total_cases = len(data.behavior.payments)
fraud_payment_ids = {record.payment_id for record in data.behavior.fraud_records}
fraud_cases = len(fraud_payment_ids)
non_fraud_cases = total_cases - fraud_cases
ml_points = data.require_dataset().frame.height

print(f"Payment cases: {total_cases}")
print(f"Fraud cases: {fraud_cases}")
print(f"Non-fraud cases: {non_fraud_cases}")
print(f"ML dataset points: {ml_points}")
Payment cases: 100
Fraud cases: 0
Non-fraud cases: 100
ML dataset points: 91

That is the complete basic workflow: install the package, generate data, inspect the returned Python objects, and understand the generated case counts.

Record the generated shape and tutorial contract.#

summary = {
    "payments": len(data.behavior.payments),
    "events": len(data.behavior.payment_events),
}
print(summary)
assert summary["payments"] >= 0
{'payments': 100, 'events': 433}

Inspect stable payment identities.#

ids = [item.payment_id for item in data.behavior.payments]
assert len(ids) == len(set(ids))
print({"unique_payment_ids": len(ids)})
{'unique_payment_ids': 100}

Compare event-time coverage.#

times = [event.event_time for event in data.behavior.payment_events]
print(
    {
        "first_event": min(times).isoformat() if times else None,
        "last_event": max(times).isoformat() if times else None,
    }
)
{'first_event': '2026-01-01T00:11:00+00:00', 'last_event': '2026-01-01T23:56:00+00:00'}

Record the generated shape and tutorial contract.#

summary = {
    "payments": len(data.behavior.payments),
    "events": len(data.behavior.payment_events),
}
print(summary)
assert summary["payments"] >= 0
{'payments': 100, 'events': 433}

Inspect stable payment identities.#

ids = [item.payment_id for item in data.behavior.payments]
assert len(ids) == len(set(ids))
print({"unique_payment_ids": len(ids)})
{'unique_payment_ids': 100}