Sandbox and test cards

Everything you need to test a Scan to Pay integration end to end without touching production.

The Scan to Pay sandbox is a full clone of the production platform that routes transactions to a simulated bank node. Real card schemes never see your traffic. You can test the entire integration — code creation, payment, webhook, refund, reversal — without moving real money.

This page covers everything sandbox-specific: how to get in, how the test environment differs from production, the test card numbers and what they trigger, and the amount-suffix trick for simulating any bank response code.


Sandbox endpoint

https://qa.scantopay.io/pluto/

Every code, query, refund, and reversal call in the Quickstart and the Merchant / PSP guides uses this base URL. The production base is documented per integration in Going live.


Getting sandbox credentials

Sandbox onboarding is handled by the support team.

To request access, email [email protected] with:

  • Your company name and the merchant or PSP name you want loaded.
  • The administrator's email address (this becomes your login for the Scan to Pay Portal).
  • Which integrations you plan to test (e-commerce, in-store QR, in-app, USSD, etc.).

You'll receive:

  • A link to set your portal password (expires after 24 hours).
  • An API username in the form merchant-{id} (e.g. merchant-25) or psp-{id} for PSPs.
  • Instructions to retrieve your API password from the portal under the API tab.

If you're integrating the Library Lite SDK, you'll also need a separate Lib Lite token. Log in to the portal → email dropdown → Lib Lite TokensNew API Password. The Lib Lite token is different from your API password.


Switching the Scan to Pay app to test mode

To pay sandbox QR codes, the Scan to Pay app on your test device has to be switched from live to test mode. The app ships in live mode by default.

  1. Install the Scan to Pay app on a test phone (Android or iOS).
  2. Open the app and tap the QR scanner.
  3. Scan the QR code below.
Test mode toggle QR

Scan to flip between live and test mode

The same QR toggles back to live mode when you scan it again. The app indicates the current mode on its home screen.

📘

In-App / Library Lite testing

Library Lite payments use a different test toggle — the system: "TEST" parameter passed to the SDK at invocation time. The QR above only affects the standalone Scan to Pay app. See In-App Payments.


Test cards

All test cards are 18 digits and break down as follows:

PositionsLengthPurpose
1-1414 digitsCard prefix — determines which simulated bank response fires
15-173 digitsArbitrary — pick any digits
181 digitLuhn check digit — computed from the first 17 digits to make the whole card pass Luhn validation

The cards only work in test mode.

Debit card prefixes

Card prefix (first 14)TriggersISO response code
50010001000105Successful purchase00
50010001000101Insufficient funds51
50010001000102Pick up card04
50010001000103Issuer or switch inoperative / bank unavailable91
50010001000104Incorrect PIN55
50010001000106Forced timeout (40-second delay, then bank unavailable)91
52620501000105Format error30

Credit card prefixes

Card prefix (first 14)TriggersISO response code
50020001000105Successful purchase00
50020001000101Insufficient funds51
50020001000102Pick up card04
50020001000103Issuer or switch inoperative / bank unavailable91
50020001000104Incorrect PIN55
50020001000106Forced timeout (40-second delay, then bank unavailable)91
52620501000104Format error30

Specific full PAN (16-digit, AMT flow only)

Full PANTriggersISO response code
5284971234225595Withdrawal amount limit exceeded61

This PAN is recognised exactly (not as a prefix) by the AMT (PIN-based) flow only — Secure Code, Token, CNP, and MPOS flows ignore it and fall through to the default success response.

Expired-card simulation

Any test card submitted with an expiry date in the past forces ISO response code 33 (expired card). Useful for testing "Your card has expired" UX without needing a separate prefix.


Computing the Luhn check digit

The platform runs Luhn validation on every PAN — same check the real card schemes use. The 18th digit must be the Luhn check digit computed from the first 17, or the transaction is rejected before it reaches the simulated bank node.

Use this calculator to compute it: https://simplycalc.com/luhn-calculate.php

  1. Take a card prefix from the table above
  2. Append any 3 digits of your choice (positions 15-17)
  3. Paste the 17-digit result into the calculator
  4. Append the returned check digit

Example50010001000105 (success debit) + 000 (arbitrary) → paste 50010001000105000 into the calculator → it returns 1 → full PAN is 500100010001050001.

A few pre-computed examples:

17-digit inputCheck digitFull valid PANTriggers
50010001000105 + 0001500100010001050001Successful debit
50010001000101 + 0005500100010001010005Insufficient funds
50010001000102 + 0004500100010001020004Pick up card
50010001000103 + 0003500100010001030003Switch inoperative
50010001000104 + 0002500100010001040002Incorrect PIN
50010001000106 + 0000500100010001060000Forced timeout
52620501000105 + 0000526205010001050000Format error (debit)
50020001000105 + 0000500200010001050000Successful credit

Any PIN, CVV, and future expiry date work in test mode — only the PAN needs to be Luhn-valid.

⚠️

For 3D Secure flows

The test cards above bypass 3DS. To test the 3DS challenge, use the amount-suffix trick below with code 05 (incorrect CVV / 3DS rejection).


Simulate any bank response code via amount

For any scenario that isn't covered by the prefixes above — anything from 01 (refer to card issuer) to 91 (switch inoperative) — set the cents of the amount to the response code you want simulated, with rand value 123.

AmountSimulated ISO responseMeaning
R123.0000Success (alternative to the success cards above)
R123.0505Do not honour / incorrect CVV
R123.5151Insufficient funds
R123.5454Expired card
R123.5555Incorrect PIN
R123.9191Issuer or switch inoperative
R123.xxxxAny other ISO response code

This works with any test card number as long as your merchant is configured to use the debug bank node (the default in sandbox). The amount-suffix mechanism overrides the card-prefix mechanism, so use it when you want a specific failure mode that isn't tied to a card.

The full list of ISO response codes is on ISO response codes.


Differences between sandbox and production

The sandbox is not a perfect mirror. Understand these gaps before you go live.

ConcernSandboxProduction
Card networkSimulated bank node — no traffic reaches Visa or MastercardReal card scheme traffic
SettlementNo actual settlement to merchant bank accountReal settlement per acquirer schedule
Limits and velocity rulesConfigurable per test merchant; may be relaxedProduction rules enforced by Sky service
Fraud detectionMay be disabled or use test policiesFull fraud rules active
Webhook deliverySame retry / timeout behaviour as productionSame
Notification encryptionSame AES/CBC payload format and key flowSame
Response timingSlightly faster than productionVariable based on bank response time
Data persistenceTest data is not cleaned automatically
Test cardsWork only in test modeReal cards only; test prefixes rejected

The most common surprise: webhook payload formats and signing are identical between sandbox and production, so your webhook handler tested in sandbox works unchanged on go-live.


Resetting test data

Test transactions, codes, and notifications persist in the sandbox indefinitely — they don't reset automatically. If you need a clean slate (for example, to repeat an acceptance test from scratch), email [email protected] with your merchant ID.

You can also create unlimited new test merchants. Many integrators keep one per integration variant (web checkout, in-store, in-app) to keep results separated.


What's next