Skip to content

Test Cards

Use this card to simulate a successful payment:

Field Value
Number 4111 1111 1111 1111
Expiry Any future date (e.g. 12/30)
CVC Any 3 digits (e.g. 123)

The widget detects the card brand from the card number prefix:

Brand Number prefix
Visa 4
Mastercard 51–55
American Express 34, 37
Discover 6011, 65
Diners Club 36, 38
JCB 35

For Australian bank account (BECS) payments:

Field Value
BSB 062-000
Account number Any number
Account name Any name

A bank account saved with those details has no direct debit mandate, so its debits can’t be collected. For a bank account a plan can debit, save the fixture token instead. It saves a sandbox bank account with an accepted mandate:

Terminal window
curl -X POST https://api.elasticpay.co/api/v1/payment_methods \
-H "Authorization: Bearer sk_sandbox_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"type": "au_becs_debit",
"customer_reference": "cus_xxx",
"payment_method_data": {
"token_metadata": { "type": "fixture", "token": "tok_sandbox_au_becs_debit" }
}
}'

Its debits settle two business days after they’re sent, counted on your account’s calendar (its time zone and country’s public holidays), unless a test helper fails them. Three more tokens save a bank account that fails every debit the same way, as the declining cards do:

Token Every debit
tok_sandbox_au_becs_debit_dishonour_insufficient_funds is dishonoured for insufficient funds when it would settle; the account stays usable
tok_sandbox_au_becs_debit_dishonour_account_closed is dishonoured as account closed; the account is stopped
tok_sandbox_au_becs_debit_late_return settles, then is returned late seven business days later

All four tokens are refused on a live account, as the card fixture tokens are.

These sandbox-only test helpers fail one bank debit, as the bank would. The outcome lands at the customer’s test clock time, or now:

Endpoint For a debit that is code
POST /api/v1/test_helpers/payment_intents/{id}/dishonour sent to the bank and not yet settled (processing) insufficient_funds, account_closed, payment_stopped, invalid_bsb, no_account, refer_to_customer, customer_deceased, ddr_cancelled_at_bank, technically_invalid
POST /api/v1/test_helpers/payment_intents/{id}/late_return settled (succeeded) late_return, late_return_insufficient_funds, dd_claim, recall
Terminal window
curl -X POST https://api.elasticpay.co/api/v1/test_helpers/payment_intents/pi_xxx/late_return \
-H "Authorization: Bearer sk_sandbox_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "code": "late_return" }'

The response is the failed payment intent. Each outcome is handled as a real return:

  • insufficient_funds, refer_to_customer, late_return and late_return_insufficient_funds leave the bank account usable, so a plan collects the amount again under its failure behaviour.
  • invalid_bsb, account_closed, no_account and technically_invalid stop the bank account. This suspends the plans that use it until the customer adds a new payment method.
  • payment_stopped, ddr_cancelled_at_bank, customer_deceased, dd_claim and recall are about the customer: they stop the bank account and suspend every plan of the customer for your review, and no email is sent to the customer. Only /resume ends it.

A debit in the wrong state is refused with 409 (payment_intent_not_dishonourable or payment_intent_not_returnable), and a live account with 403 (sandbox_only).

To force a specific outcome regardless of card details, set _sandbox_outcome in the payment intent’s metadata:

Terminal window
curl -X POST https://api.elasticpay.co/api/v1/payment_intents \
-H "Authorization: Bearer sk_sandbox_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"amount": 1999,
"currency": "AUD",
"metadata": {"_sandbox_outcome": "decline"}
}'
Value Result
succeed Payment succeeds (the default without an override)
decline Payment fails with insufficient_funds
requires_action Simulates a 3D Secure challenge
timeout Payment fails with gateway_timeout

This works for any payment method and takes priority over card-number-based outcomes. Refunds have a parallel override — set "_sandbox_refund_outcome": "fail" in the refund request’s metadata to make the refund fail (refunds succeed by default).

Fixture tokens — server-side testing without the widget

Section titled “Fixture tokens — server-side testing without the widget”

For CI pipelines, server-side tests, and agents, you can skip the widget entirely: pass a fixture token as token_metadata.token when creating a payment method (sandbox keys only).

Terminal window
curl -X POST https://api.elasticpay.co/api/v1/payment_methods \
-H "Authorization: Bearer pk_sandbox_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"type": "card",
"payment_method_data": {
"token_metadata": {
"type": "fixture",
"token": "tok_sandbox_visa_succeed",
"data": ""
}
}
}'
Token Brand last4 Outcome when charged
tok_sandbox_visa_succeed Visa 4242 Succeeds
tok_sandbox_visa_decline_insufficient_funds Visa 0002 Declines — insufficient funds
tok_sandbox_visa_decline_card_lost Visa 9987 Declines — card lost
tok_sandbox_visa_decline_expired_card Visa 0069 Declines — expired card
tok_sandbox_visa_3ds_required Visa 3155 Requires 3D Secure authentication
tok_sandbox_visa_timeout Visa 0119 Fails — gateway timeout
tok_sandbox_mastercard_succeed Mastercard 4444 Succeeds
tok_sandbox_mastercard_decline_insufficient_funds Mastercard 9995 Declines — insufficient funds
tok_sandbox_mastercard_decline_account_closed Mastercard 0014 Declines — account closed
tok_sandbox_amex_succeed Amex 8431 Succeeds

The outcome travels with the saved payment method: every later charge against it resolves to that outcome, regardless of amount. That makes the declining tokens the right tool for testing recurring-billing failure handling — save a declining card, attach a payment plan, and advance a test clock to watch the dunning flow run.

Each declining fixture answers with the card scheme’s response code and merchant advice code that a real issuer would send for that decline. When a payment plan’s payment declines, those codes decide whether the plan may collect it again:

Token Response code Merchant advice code On a payment plan
tok_sandbox_visa_decline_insufficient_funds 51 2 (issuer can’t approve at this time) Retryable: the plan’s failure behaviour runs
tok_sandbox_visa_decline_card_lost 41 1 (issuer will never approve) Never retried: the card is stopped
tok_sandbox_visa_decline_expired_card 54 3 (new card details needed) The saved card is stopped and isn’t retried; updated card details are required before another attempt
tok_sandbox_mastercard_decline_insufficient_funds 51 02 (try again later) Retryable, at the first collection time at least 72 hours after the decline
tok_sandbox_mastercard_decline_account_closed 79 03 (do not try again) Never retried: the card is stopped

A decline that stops the card (the card-lost, expired-card and account-closed fixtures) runs no failure behaviour, and later scheduled payments aren’t sent to the card. If the customer has another usable saved card, the plan switches to it. Otherwise the customer is emailed a link to add a new one, and plans set up with that card as their payment method are suspended.

The decline override and amounts ending in 01 carry no codes. A live decline without a merchant advice code isn’t retried, and neither are these on a plan: no failure behaviour runs, but the card isn’t stopped. It stays the plan’s card for its next payment, and no recovery email is sent.

One-off payments don’t use these codes; see Exercising failure for what a declined one-off payment does.

When no metadata override or fixture outcome applies, the last two digits of the amount in cents select the outcome:

Amount ends in Outcome
01 Declines — insufficient funds
02 Requires 3D Secure authentication
99 Fails — gateway timeout
anything else Succeeds

For refunds, an amount ending in 03 fails; anything else succeeds.

Prefer _sandbox_outcome metadata or fixture tokens — they leave amounts free to carry realistic values, so a $19.99 subscription in a test stays $19.99. Watch for accidental triggers: a test amount of 1001 cents declines by design.

  1. _sandbox_outcome in the payment intent’s metadata (per-charge override)
  2. The saved payment method’s fixture outcome
  3. Amount-based fallback
  4. Default: succeed

All test transactions use mocked PSP responses. Webhook events still fire normally in sandbox mode, giving you a realistic integration test environment.