Skip to main content

Test Cards

Use these card numbers in test mode to simulate different payment outcomes. Any future expiry date and any 3-digit CVC will work (Amex takes a 4-digit CID).

These are the canonical industry test numbers, and they drive the outcomes below in the Vonpay-owned sandbox.

These numbers are for the Vonpay sandbox, not a real-processor sandbox

If your merchant is boarded onto a real processor's sandbox (rather than the Vonpay-owned one), the table below does not apply. That processor decides the outcome, and these numbers usually carry no special meaning to it — a card listed here as a decline will typically be approved, with no error and nothing to indicate the test did not do what you expected.

That failure is quiet by nature: you get a successful payment, which looks like your integration working. Use the test cards published by whichever processor your sandbox is boarded onto. If you are not sure which kind of sandbox you have, ask us.

For the hosted-checkout sandbox today (mock gateway), outcomes are chosen by session amount, not by card number — see Sandbox & Test Mode → Sandbox outcomes.

For the embedded-checkout sandbox (sandbox iframe via vora.js), outcomes are chosen by card number per the table below. The sandbox iframe locks down to these numbers only — any other input is rejected, both as a real-card safety lock and to keep outcomes deterministic. Embedded fields are collected and submitted through the canonical collection path — const elements = vora.elements.create(); const card = elements.create("card", {}); card.mount("#card-element"); const result = await elements.submit(); — not a single-field tokenize() call.

Card Numbers

CardBrandOutcomeWebhook eventUse for
4242 4242 4242 4242VisaSuccesspayment_intent.succeededHappy path
5555 5555 5555 4444MastercardSuccesspayment_intent.succeededMastercard testing
3782 822463 10005AmexSuccesspayment_intent.succeededAmex testing
4000 0000 0000 0002VisaGeneric declinepayment_intent.failed (failure_code: card_declined)Generic error handling
4000 0000 0000 9995VisaInsufficient fundspayment_intent.failed (failure_code: insufficient_funds)Buyer-fundable error path
4000 0000 0000 0069VisaExpired cardpayment_intent.failed (failure_code: expired_card)Re-prompt UX
4000 0000 0000 0119VisaProcessing errorpayment_intent.failed (failure_code: processing_error)Transient-failure UX
4000 0027 6000 3184Visa3DS required → successpayment_intent.succeededHappy-path 3DS
4000 0084 0000 0029Visa3DS required → fail (fraud)payment_intent.failed (failure_code: fraudulent)3DS challenge rejection

Synthetic token shape (embedded sandbox)

When the embedded sandbox submits a test card and the charge succeeds, the result carries a final synthetic vp_pmt_test_* token (tokenIsFinal: true) with the outcome encoded in the middle segment. The sandbox iframe mints this synthetic token on every success branch — it does not emulate the production binder's guest charge-only path. Still read the submit result defensively as the 3-way { token } | { charged: true } | { error } union, never result.token unconditionally, so the same handler works against a live binder:

Card outcomeToken shape
Successvp_pmt_test_success_<random>
Declinevp_pmt_test_decline_<reason>_<random> (e.g. vp_pmt_test_decline_insufficient_funds_abc123)
3DS requiredvp_pmt_test_3ds_success_<random> or vp_pmt_test_3ds_fail_<random>

The encoded outcome means the server-side mock binder recognises the intended payment-intent result from the token prefix alone — no DB lookup, no card-number round-trip. The canonical map is in the @vonpay/test-cards workspace package; both the iframe and the server import from there so the list cannot drift.

vp_pmt_test_* tokens are sandbox-only — a test token used with a live-mode key is rejected with HTTP 400 payment_method_mode_mismatch (the cross-mode guard). (Don't confuse this with payment_method_inactive, which is HTTP 422 and means the token was revoked.)

Lifecycle ops with synthetic tokens

Every existing payment-intent lifecycle op works against a synthetic success token. The same mock binder that handles hosted sandbox today extends to embedded via the token-prefix recognition:

OperationSandbox behavior with vp_pmt_test_success_*Webhook fired
POST /v1/payment_intents (auto-capture)succeededpayment_intent.succeeded then charge.succeeded
POST /v1/payment_intents (capture_method=manual)authorizedpayment_intent.succeeded (the authorization; capture is separate)
POST /v1/payment_intents/:id/capturesucceededcharge.succeeded
POST /v1/payment_intents/:id/voidvoidedpayment_intent.cancelled
POST /v1/refunds→ refund settledcharge.refunded

Access via MCP

AI agents can retrieve test cards using the vonpay_checkout_list_test_cards tool. See MCP Server for setup.