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 numbers supported across major card-acceptance sandboxes (Stripe, Adyen, Worldpay, etc.). The same numbers work whether your sandbox merchant routes through a real-processor sandbox OR the Vonpay-owned sandbox iframe served via vora.js for embedded checkout.

For the hosted-checkout sandbox today (mock gateway), outcomes are chosen by session amount — 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.