Skip to content

Dataset

Antonio Membrides Espinosa edited this page Aug 14, 2026 · 6 revisions

Test Dataset: default users, cards and bank accounts

This page lists the default test users seeded by the PSP demo and the data needed to run card payments and bank transfers (ACH / SEPA / SWIFT) end to end, without data-entry errors. It is aligned with the seeders and with the built-in validation modules (card issuer, account information, rail engine), and it shows how movements are approved or blocked following standard PSP procedures.

These are fictitious test values. No real cardholder data (full PAN / CVV) is stored by the PSP: seeded cards are PAN-masked, and card numbers below are standard Luhn-valid test ranges only.

Source of truth (do not hand-edit user lists)

The login users are the same ones served by the login screen. The authoritative, always-current list comes from the endpoint, so it never drifts from the seeders:

GET /api/v1/auth/users            (optionally ?featured=true)

Backing: auth.controller.ts -> getDemoUsers (auth.service.ts), collection customerAuthenticationAssessment, seeded from backend/data/customerAuthentications.json. Password for every demo user: demo-password. Regenerate the tables below from that endpoint plus backend/data/parties.json, paymentCards.json and payoutAccounts.json whenever seeds change.

Login users (featured roster)

Name Username (email) Password Role
Luis Fernandez luis.fernandez@back.es demo-password customer
Julia Santos julia.santos@back.es demo-password customer
Amara Okafor amara.okafor@back.es demo-password customer
Carlos Garcia carlos.garcia@back.es demo-password customer
David Chen david.chen@back.es demo-password merchant_officer
Rachel Torres rachel.torres@back.es demo-password merchant_officer
Sarah Chen sarah.chen@back.es demo-password level1_analyst
Michael Obi michael.obi@back.es demo-password level2_investigator
Anna Kowalski anna.kowalski@back.es demo-password level1_analyst
James Wright james.wright@back.es demo-password level2_investigator
Diego Sans diego.sans@back.es demo-password security_auditor
Sophie Martin sophie.martin@back.es demo-password security_auditor
Alex Rivera alex.rivera@back.es demo-password manager

Payout accounts (per customer, from payoutAccounts.json)

Customer Account alias Currency Rail IBAN (full) Available
Luis Fernandez espressoworks-ledger EUR internal_ledger 2847.50
Luis Fernandez Luis SEPA account EUR sepa ES9121000418450200051332 3500.00
Luis Fernandez Luis Santander EUR sepa ES7620770024003102575766 4800.00
Julia Santos Julia main account EUR sepa GB29NWBK60161331926819 3800.00
Julia Santos Julia Barclays EUR sepa GB94BARC10201530093459 5200.00
Amara Okafor okafor-digital-ledger EUR internal_ledger 1540.75
Amara Okafor Amara Barclays EUR sepa GB33BUKB20201555555555 4500.00
Amara Okafor Amara Monzo EUR sepa GB69MONZ04000482991234 3200.00
Carlos Garcia Carlos BBVA EUR sepa ES8023100001180000012345 4100.00
Carlos Garcia Carlos Santander EUR sepa ES1120807182183625664112 3600.00
Carlos Garcia Carlos CaixaBank (suspended) EUR sepa ES6621000418401234567891 0.00
David Chen fischer-web-ledger EUR internal_ledger 9800.00

The four featured customers (Luis, Julia, Amara, Carlos) each hold at least two active bank accounts funded above 3000 EUR so card-payment and funds-gate tests pass. Their registered cards are spread across their own accounts (a card funds from exactly one account; an account may back several cards) and no card is funded by an account belonging to another party.

All IBANs above are ISO 13616 (mod-97) valid — use the full IBAN verbatim on the "New bank account" tab of /system/transfer/bank or when registering a payout account. Copy the exact value; a different IBAN registers a different account and will not reconcile with the balances/tests documented here.

Registered cards (per customer, from paymentCards.json)

Each row is a card saved to the customer's wallet with the full card number to type at card-payment flows, its funding bank account, and status.

Why the full number matters. The surrogate token stored per card is derived deterministically from the card number: token = "pm_" + HMAC-SHA256(cardNumber, key).hex[0:24] + last4 (see frontend/src/lib/cardTokenize.ts, key demo-psp-tokenization-key-v1). The same card number always yields the same token, so entering the exact number below makes the system recognise the card as this customer's registered card. A different number derives a different token — the system would treat it as a brand-new card, silently breaking any test that assumes you are paying with a specific registered card. The four featured customers share no card number between them.

Expiry. Any date in the future is accepted; a past date is declined with 54 expired_card. The demo clock runs ahead of real time, so check today's date in the app before reusing an old expiry. The stored expiry shown below is what the card would print; you may type any future date.

CVV. A wrong value is declined with 82 invalid_cvv, so it is not "any 3 digits". The module runs in cvvMode: both (default), which accepts EITHER of two values per card:

  • Global demo CVV 123 (validCvv at Admin -> Modules -> Card issuer). Works on every card. Use it for anything that is not specifically testing per-card CVV.
  • Derived CVV, the realistic one a real issuer recomputes in its HSM: digits(HMAC-SHA256(CVK, cardToken | expiryMMYY | serviceCode))[0:cvvLength]. It is never stored (it is Sensitive Authentication Data), only derived on demand. The value per card is in the table below, and is what you need to test cvvMode: per_card or the reveal flow.

The derived CVV is environment-specific. The CVK is minted randomly at setup, so every fresh deployment (and any --reset that drops the key vault) produces a DIFFERENT set of derived CVVs. The values below are the ones in force right now; re-read them after a reset (see Re-reading the derived CVVs under the table). The global 123 is unaffected by resets.

Customer Brand Card number (full) Masked Expiry CVV (global) CVV (derived) Status Alias Funding account
Luis Fernandez Visa 4539 0010 0007 0144 ****-0144 05/27 123 854 active Emergency Luis SEPA account
Luis Fernandez Visa 4539 0010 0001 0348 ****-0348 12/28 123 039 active Work Luis SEPA account
Luis Fernandez Visa 4539 0010 0004 1202 ****-1202 11/27 123 399 active Business Luis SEPA account
Luis Fernandez Visa 4539 0010 0006 3040 ****-3040 10/31 123 328 blocked Subscriptions Luis Santander
Luis Fernandez Mastercard 5555 0010 0005 2262 ****-2262 11/27 123 158 active Family card Luis Santander
Julia Santos Mastercard 5555 0010 0001 1177 ****-1177 10/31 123 801 active Online shopping Julia main account
Julia Santos Mastercard 5555 0010 0007 5909 ****-5909 02/30 123 941 active Work Julia main account
Julia Santos Visa 4539 0010 0004 4685 ****-4685 09/30 123 919 active Personal Julia main account
Julia Santos Visa 4539 0010 0006 2224 ****-2224 10/27 123 791 active Subscriptions Julia Barclays
Julia Santos Visa 4539 0010 0007 2041 ****-2041 08/30 123 452 active Shared home Julia Barclays
Amara Okafor Visa 4539 0010 0009 2403 ****-2403 09/28 123 179 active Family Amara Barclays
Amara Okafor Mastercard 5555 0010 0001 1599 ****-1599 11/30 123 249 active Business Amara Barclays
Amara Okafor Visa 4539 0010 0008 5100 ****-5100 06/30 123 201 active Personal Amara Monzo
Amara Okafor Mastercard 5555 0010 0003 5739 ****-5739 11/31 123 578 active Online shopping Amara Monzo
Carlos Garcia Visa 4539 0010 0006 6266 ****-6266 11/27 123 266 active Savings-linked Carlos BBVA
Carlos Garcia Visa 4539 0010 0005 1243 ****-1243 01/27 123 084 active Subscriptions Carlos BBVA
Carlos Garcia Mastercard 5555 0010 0006 4093 ****-4093 05/30 123 170 active Business Carlos Santander

The derived value is bound to the card token AND the expiry above. Type a different (still future) expiry and the derived CVV no longer matches: use 123, or re-derive for that expiry.

Re-reading the derived CVVs (after a reset or on another environment)

Two ways, both without touching the database:

  1. Admin console. Admin -> Modules -> Card issuer exposes the reveal per card (GET /api/v1/modules/card-issuer/cards/{cardId}/cvv, operations officer only, audited as card.cvv.revealed).

  2. Internal loopback, handy to regenerate the whole table:

    curl -s -X POST "$PSP_API/api/v1/modules/card-issuer/reveal" \
      -H 'Content-Type: application/json' -H 'X-Integration-Source: psp-demo' \
      -d '{"cardId":"<paymentCardInstanceReference>"}'
    # -> {"cvv":"854","revealed":true}

    The card ids are deterministic (derived from the customer agreement), so they survive a reset even though the CVVs do not.

Both paths derive the value on demand and return it ephemerally; nothing is written. Card verification data is never stored, in cleartext or encrypted.

Card test numbers (Visa / Mastercard)

Enter these at checkout / card-payment flows. All are Luhn-valid standard test PANs accepted by the built-in card validator. Use any future expiry (MM/YY) and CVV 123.

Brand Card number Expiry CVV Expected outcome
Visa 4111 1111 1111 1111 12/29 123 Approved (00)
Visa 4012 8888 8888 1881 12/29 123 Approved (00)
Visa 4242 4242 4242 4242 12/29 123 Approved (00)
Mastercard 5555 5555 5555 4444 12/29 123 Approved (00)
Mastercard 5200 8282 8282 8210 12/29 123 Approved (00)
Mastercard 2223 0000 1018 1375 12/29 123 Approved (00)

The first five are exactly the Visa/Mastercard numbers offered by the simulator card picker (Simulator -> Setup), so anything you pick there behaves as listed here. The two Amex entries in that picker are subject to the CVV caveat below.

The built-in issuer has no per-PAN decline list. Numbers such as 4000 0000 0000 0002 or 4000 0000 0000 9995 (which decline at some real gateways) are approved here: the module decides on the card's own credentials, not on a table of magic numbers. To exercise a decline, use the triggers in the next section.

American Express cannot be paid with the default configuration. Amex expects a 4-digit CVV while the global demo CVV is 123 (3 digits), so every Amex attempt ends in 82 invalid_cvv. To demo Amex, set a 4-digit validCvv at Admin -> Modules -> Card issuer, or disable the AMEX network there.

How to trigger each card decline (verified against the built-in issuer)

To get Do this Response
Approved Any card above, future expiry, CVV 123 00 approved
Expired card Type an expiry in the past (e.g. 01/24) 54 expired_card
Wrong CVV Type any CVV other than 123 82 invalid_cvv
Missing CVV Leave the CVV empty on a flow that requires it (checkout, payment link, simulator) 82 cvv_required
Failed Luhn Change one digit of the card number 14 failed_luhn_check
Wrong length for the network Add or remove a digit 14 invalid_length_for_network
Unsupported network Disable the network at Admin -> Modules -> Card issuer 12 unsupported_or_disabled_network
Card not registered Charge a card-on-file token the PSP does not know (server-to-server API payment) 56 card_not_registered
No funding account Charge a registered card whose funding account is missing 57 no_funding_account
Cardholder name mismatch Enable name verification, then type a different name 05 cardholder_name_mismatch

The registration and funding-account checks apply to a card-on-file charge, where the token is the only credential. A card the payer PRESENTS (full number, or CVV plus expiry on a hosted page) is validated on its own credentials, so a first-time card can pay.

Bank transfer test destinations (rail engine)

Use these on the "New bank account" tab of /system/transfer/bank. The rail is auto-derived and the coordinates validate against ISO 13616 (IBAN), ISO 9362 (BIC) and the NACHA ABA checksum.

Rail Country Currency IBAN / account Routing / BIC Expected
SEPA DE EUR IBAN DE89 3704 0044 0532 0130 00 BIC DEUTDEFF Submitted (fee 0)
SEPA FR EUR IBAN FR14 2004 1010 0505 0001 3M02 606 (optional) Submitted (fee 0)
ACH US USD Account 123456789 Routing 021000021 Submitted (fee 0.25)
SWIFT SG SGD Account 000123 BIC DBSSSGSG Submitted (fee 15)
SWIFT SG SGD Account 000123 BIC DBSSSGSG + correspondent CHASUS33 Submitted (fee 25)
(invalid) DE EUR IBAN DE89 3704 0044 0532 0130 01 Blocked: IBAN fails mod-97 (AC01)
(invalid) US USD Account 1 Routing 021000020 Blocked: ABA checksum fails
(unsupported) US USD (no IBAN, no routing) Exception: unsupported corridor

Approve / block scenarios (standard PSP procedures)

Each scenario states the input, the module that decides, and the standard code returned.

Scenario Input Deciding module Result Standard code
Card approved Visa 4111…1111, sufficient funds card issuer + funds gate Approved ISO 8583 00
Card do-not-honor Visa 4000…0002 card issuer (built-in) Declined ISO 8583 05
Insufficient funds amount over available balance account information (funds gate) Declined ISO 8583 51
SEPA transfer valid EUR IBAN, EEA rail engine + payment initiation Submitted -> settled ISO 20022
ACH return closed destination account payment initiation Failed NACHA R02
SEPA reject invalid IBAN rail engine (validate) Blocked ISO 20022 AC01
SWIFT error invalid BIC rail engine (validate) Blocked SW01
Unsupported corridor no IBAN/routing/BIC rail resolver Exception UNSUPPORTED_CORRIDOR
Fraud / sanctions high-risk beneficiary (see fraudCases.json) FDS / HRP / AML providers Blocked / review internal risk code

Seeded transfer executions (recipient-identity variants)

Three demo executions initiated by Luis (from pao00001…), one per Recipient variant, so the detail page /system/payment/history/{ref} shows the correct link / full destination:

Execution ref Recipient variant Detail shows
e0000001-0000-4000-8000-000000000001 Saved beneficiary (Carlos, cab00002…) Link → /system/beneficiaries/cab00002… + payout account
e0000002-0000-4000-8000-000000000002 Registered payout account (pau00001…) Link → /system/accounts/pau00001…
e0000003-0000-4000-8000-000000000003 Unregistered external IBAN Full IBAN ES1215830001109043445477 (Marie Dubois, ES)

Notes

  • Rail auto-derivation: EUR + IBAN + EEA country -> SEPA; USD + routing + account + US -> ACH; BIC cross-border -> SWIFT. The user can override the rail; validation still applies.
  • Unregistered destinations: the full destination IBAN is persisted on the execution encrypted at rest (QE:none DEK-exec-dest-iban, L2 only — GDPR Art. 32 / PSD2, not PCI) and shown to the owner; a masked form is kept plaintext for lists. Registered destinations link by reference instead.
  • KYC demographics (SD-13 Party) apply to every user, staff included: partyDateOfBirth, partyNationality and partyPostalAddress are backfilled deterministically by seedParties, so staff /system/profile pages are as complete as customers'. KYC verification + govId stay in SD-53 (customers); KYB is merchant-level. partyPostalAddress and partyDateOfBirth are GDPR PII, QE:none (L2 only) — encrypted at rest like the email/phone; shown to the party via a reveal toggle.
  • Seeded demo executions move the seeded balance: seedPaymentExecutions applies each completed transfer's debit/credit to the payout-account balance (after the opening deposit is logged), so the account-movement ledger reconciles (opening − Σ sent + Σ received). Only settled movements affect the running balance; failed/exception/pending transfers never shift it.
  • Every transfer emits a businessProcessEvent and a complianceProcessEvent sharing the execution reference as correlation id (PCI DSS Req 10 audit trail).

Multi-owner merchants + Operations Officer scope

The three seed merchants now carry realistic beneficial-owner cap tables: Espresso Works (60/40, 2 owners), Leafy Wallet (50/30/20, 3 owners), Fischer Web Studio (80/15 free-float, 2 owners). Owners reference existing seeded parties (b0000001, b0000002, b0000057-b0000061). The primary owner equals the legacy merchantOwnerPartyReference. The operations_officer demo user now also administers KYC/KYB records and beneficial owners (data correction); merchant_officer keeps the KYB decision. capabilityModuleConfiguration seeds decisionMode (KYC=automated, KYB=manual).

Added 2026-07-24.

Clone this wiki locally