Miracle Docs

Test Cards

Use these test card numbers in sandbox to simulate different payment scenarios. All test cards only work with test API keys (sk_test_ / pk_test_).

For all test cards: use any future expiry date (e.g., 12/30) and any 3-digit CVC (e.g., 123).


Test cards

The sandbox test adapter picks the outcome from the last 4 digits.

ScenarioCard NumberExpected Result
Successful payment4242 4242 4242 0000Payment succeeds (APPROVED)
Successful payment (variant)4242 4242 4242 0026Payment succeeds (APPROVED)
3DS required4242 4242 4242 0018Enters pending_user_action, returns paymentAction.type = 'redirect' to the 3DS challenge page
Decline — insufficient funds4242 4242 4242 0034Payment fails with INSUFFICIENT_FUNDS
Decline — do not honor4242 4242 4242 0042Payment fails with DO_NOT_HONOR
Pending (async)4242 4242 4242 0059Enters async processing, resolves via callback
Gateway timeout4242 4242 4242 0091Retryable provider error (GATEWAY_TIMEOUT)

Use these exact numbers, prefix included. On a hosted payment page the card never reaches the adapter — the Vault tokenizes it first, and only the token travels on. The Vault recognises the reserved 4242 4242 4242 ____ range and carries the scenario inside the token it issues; any other PAN gets an ordinary random token, and the payment succeeds no matter what it ends with.

Calling the API directly with a raw PAN or a tok_test_NNNN token you built yourself, the suffix alone is enough — the adapter reads the last four digits. The prefix rule is what makes the two paths behave the same, so follow it either way.


Payment lifecycle per scenario

Each scenario produces a different sequence of status transitions. Use these to test your webhook handling and UI state management.

Successful payment:

created --> processing --> succeeded

Declined payment:

created --> processing --> failed

3DS required (success):

created --> processing --> pending_user_action --> processing --> succeeded

When a payment enters pending_user_action, the API response includes a paymentAction with type: 'redirect' and a sandbox 3DS challenge URL. After the cardholder completes the challenge, call POST /v1/payments/{id}/complete-action with redirectResult to resume processing.

3DS required (failed):

created --> processing --> pending_user_action --> failed

Pending (async):

created --> processing --> pending --> succeeded

The pending state resolves automatically via a test callback after a short delay.


3DS test scenarios

Use the card suffix 0018 to trigger a 3DS redirect. The payment enters pending_user_action status and the response includes a paymentAction with type: 'redirect' pointing to the sandbox 3DS challenge page.

After the cardholder completes (or abandons) the challenge, call POST /v1/payments/{id}/complete-action with a redirectResult value. The test adapter maps redirectResult to a realistic 3DS outcome:

redirectResult valueOutcomeDescription
successPayment succeeds3DS challenge authenticated. Liability shift = yes.
failurePayment fails3DS challenge failed (not_authenticated). Error: AUTHENTICATION_REQUIRED.
rejectedPayment fails3DS authentication explicitly rejected by issuer. Error: AUTHENTICATION_REQUIRED.
attemptedPayment succeeds3DS challenge attempted but not fully authenticated. Liability shift = no.
frictionlessPayment succeeds3DS performed silently — no challenge shown. Liability shift = yes.
unavailablePayment succeeds3DS service unavailable. Proceeds without 3DS.
not_enrolledPayment succeedsCard not enrolled in 3DS. Proceeds without 3DS.

The sandbox 3DS challenge page is hosted locally at http://localhost:3002/3ds-challenge during development. It presents buttons for each redirectResult value so you can simulate different 3DS outcomes.


Refund test scenarios

Refunds in sandbox follow the same flow as live. Create a payment with a success card, then refund it:

# 1. Create a successful payment (card ending 0000)
# 2. Refund it
curl -X POST https://<api-host>/v1/payments/pay_abc123/refunds \
  -H "Authorization: Bearer sk_test_your_secret_key" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: test-refund-001" \
  -d '{
    "reason": "Testing refund flow"
  }'

Refund status transitions in sandbox:

pending --> processing --> succeeded

You will receive refund.created and refund.succeeded webhook events, identical to live.


Magic amounts

Magic amounts are not currently active. Only magic card suffixes control test outcomes. The rules below describe the planned magic amount behavior.

In addition to card numbers, the test adapter will also check the last two digits of the amount (in minor units) for special behavior:

Amount endingOutcomeDescription
66DeclineAmount-based decline trigger
773DS requiredAmount-based 3DS trigger

For example, an amount of 1066 (10.66 USD) will trigger a decline regardless of the card number used.

When both a magic card rule and a magic amount rule apply, the card rule will take precedence.


Important notes

  • Test cards only work with test API keys (sk_test_). Using them with a live key will result in a rejected transaction.
  • Never use real card numbers in sandbox. The sandbox is not PCI-scoped for real card data. Use the test card numbers on this page.
  • Test cards are rejected in live mode. When you switch to live keys, you must use real card numbers.

On this page