Sandbox behaviour and test data

Test mode is a separate ledger with its own keys, its own events and its own data. This is the reference for making it produce the outcome you need — including the ones you would rather not meet for the first time in production.

  • Reviewed
  • 8 min read
  • API version 2026-04-01

What test mode is

Every account has two ledgers. They share nothing: separate keys, separate objects, separate webhook endpoints, separate reports. A sk_test_ key cannot read or move live funds under any circumstance, which makes the sandbox safe to hand to a contractor.

  • Isolation Your sandbox is yours alone. It is not a shared mock, so one team's data never appears in another's list call.
  • Parity Same endpoints, same fields, same errors, same event names. The only difference in your code should be which key it reads.
  • Speed Settlement is compressed: what takes a working day in live mode resolves in seconds, so an end-to-end test finishes inside a CI run.
  • Reset Clear the sandbox from the dashboard at any time. Objects go, keys and endpoint configuration stay.

Test cards

Use any future expiry date, any three-digit CVC and any postcode. The number decides the outcome. All of them run through hosted fields exactly as a real card would.

Card numbers and the outcome each one forces
Number Brand Outcome
4242 4242 4242 4242 Visa succeeded frictionless, no challenge
5555 5555 5555 4444 Mastercard succeeded frictionless
4000 0027 6000 3184 Visa requires_action always challenges
4000 0000 0000 9995 Visa failed insufficient_funds
4000 0000 0000 0002 Visa failed do_not_honor
4000 0000 0000 0069 Visa failed expired_card
4100 0000 0000 0019 Visa failed fraud_suspected
4000 0000 0000 0259 Visa succeeded then dispute.opened after 60s

When you need a decline the card list does not cover, steer it with the amount instead. The trigger works on every method, so the same test fixture exercises cards and APMs alike.

amount-based outcome triggers
# the last two minor units steer the outcome in test modeamount: 4200   → succeededamount: 4201   → failed, insufficient_fundsamount: 4202   → failed, do_not_honoramount: 4203   → failed, fraud_suspectedamount: 4204   → processing for 90s, then succeededamount: 4205   → canceled by the payer# works on every method, including the APMs below

Live mode ignores these entirely — 4201 is simply 42.01 EUR there. The trigger table is a test-ledger behaviour, not a hidden API.

Forcing 3-D Secure outcomes

Authentication is where checkout conversion is won or lost, so it deserves more than one happy path in your suite. The sandbox challenge page offers every outcome the real flow can produce.

Sandbox authentication outcomes worth covering
Choose Result What it proves
Complete succeeded, liability shifted The happy path and your fulfilment trigger.
Fail authentication_failed Your retry copy. This one is safe to retry in-session.
Abandon canceled The payer closing the tab mid-challenge. Basket must survive.
Time out authentication_timeout A bank app that never answers. The slowest path your UI must tolerate.
Unavailable Frictionless approval, no shift Issuer directory down. Confirms you handle an unshifted success.
Test the exemption path too

Send an sca.request of exemption with any amount under 3000 minor units and the sandbox grants it; above that it forces a challenge regardless. That gives you both branches of the exemption logic without waiting on a real issuer's risk engine.

APM and bank simulators

Each alternative method redirects to a simulator that mirrors the real interface closely enough to test your copy and your timing, and offers the same outcome buttons.

Simulator behaviour per method
Method Simulator Notable behaviour
iDEAL Bank picker, then approve or decline Choosing "Test Bank Slow" holds at processing for 90 seconds.
Bancontact QR page, then approve or decline The QR is decorative in test mode. Use the buttons.
BLIK Six-digit code entry 777777 succeeds. 111111 expires so you can test the resend prompt.
EPS Bank picker, then approve or decline Declines return the same reason codes as cards.
Open banking Consent screen, then approve or decline "Revoke later" fires mandate.revoked five minutes after approval.
Apple Pay · Google Pay Wallet sheet on a real device Needs a registered test domain. The sheet does not render in a desktop simulator.

Payouts and disputes

Money leaving is easier to get wrong than money arriving, because the failure paths are rarer and therefore less tested. Two IBANs and one card cover the cases that matter.

Test beneficiaries and their behaviour
Value Outcome
NL02 BAZP 0000 0000 01 Settles over SEPA Instant in seconds. payout.settled.
NL02 BAZP 0000 0000 02 Falls back to SEPA Credit Transfer, settles next simulated working day.
NL02 BAZP 0000 0000 09 Rejected by the beneficiary bank. payout.returned with a reason.
4000 0000 0000 0259 Charges, then opens a dispute after 60 seconds so you can test evidence upload.

Disputes in the sandbox run the full lifecycle on a compressed clock: opened, evidence due, submitted, then won or lost depending on whether you uploaded anything. Both endings are worth wiring, because the accounting entries differ. See payouts and anti-fraud for what each state means commercially.

Triggering events by hand

You do not need a real object to test a handler. In test mode a single call fires any event type at every subscribed sandbox endpoint, correctly signed.

POST /v1/test/events
# force any event against a sandbox endpointcurl -X POST https://api.bazpay.com/v1/test/events \  -H "Authorization: Bearer sk_test_9f2c…" \  -d '{"type": "dispute.opened",       "payment": "pay_3fJ2Qk8vTn"}'{ "id": "evt_9Rt2Ny7cVb", "delivered_to": 1 }

delivered_to counts the endpoints that received it. Zero means nothing is subscribed to that type — the usual reason a handler seems not to run.

Three cases worth building into the suite while this is easy:

  • The same event twice, to prove your deduplication index actually holds.
  • A refund.settled before its payment.succeeded, to prove out-of-order arrivals do not corrupt an order.
  • A deliberate 500 from your handler, to watch the retry ladder and confirm the event eventually lands.

Signature verification and the retry schedule: the webhooks guide.

What the sandbox cannot tell you

A green test suite is necessary and not sufficient. Four things behave differently once real money and real issuers are involved, and knowing which four is the point of this section.

  • Approval rates Sandbox issuers always follow the script. Real ones decline for reasons no simulator models — velocity, geography, an issuer's own outage.
  • Latency Test authorisations return in milliseconds. Live card authorisations take a few hundred, and a bank redirect depends on how fast the payer opens their app.
  • Settlement timing The sandbox compresses days into seconds. Reconciliation logic that assumes same-day settlement will pass here and fail in production.
  • Fraud rules Your live rule set is tuned against your own traffic. Sandbox scoring is deterministic and will not surprise you the way a real ruleset can.
Before you switch keys

Take one real payment of a small amount on the live account, from a real card, and refund it. It costs a few cents in fees and it is the only test that exercises the whole chain — underwriting, routing, the live issuer, settlement and your reconciliation — at once. The go-live checklist puts it in sequence with everything else.