Sandbox
Sandbox is a full copy of your account for testing. Payments run through a test processor: cards authorise end to end — including 3-D Secure — but no real money moves. Live and sandbox data are kept completely separate, so you can experiment freely.
Live and sandbox are two cabinets of the same account — one login, two sets of data. Nothing you do in sandbox touches live.
Switch cabinets in the dashboard
Use the environment switch at the bottom of the sidebar in your dashboard to move between Live and Sandbox. In sandbox, everything is test data:
- Home — sandbox metrics and charts
- Transactions — only sandbox payments
- Invoices — sandbox invoices
- Payment Links — sandbox products
- Search — scoped to the sandbox cabinet
A Sandbox banner across the top reminds you you're in test mode.
Invoices
Switch to Sandbox, then create an invoice as usual. It bills through the test processor, so its hosted payment link (checkout.securepayapi.com/?invoice=…) completes as a test payment. Sandbox invoices carry a sandbox badge and never mix with your live invoices, and the payment page shows a Test mode banner.
Products (payment links)
Products you create while in Sandbox are sandbox products. Their hosted checkout (checkout.securepayapi.com/<product-id>) runs in test mode — the page shows a Test mode banner and no real charge is taken. Which cabinet a product was created in decides how it charges: a sandbox product always tests, a live product always charges live. This is enforced on the server, so a product can't be pushed into the wrong mode from the URL.
Embedded widget
A payment is sandbox or live because of how its Payment Intent was created — pass mode: 'sandbox' to POST /api/v1/payment-intents on your server:
curl https://checkout.securepayapi.com/api/v1/payment-intents \
-H "Authorization: Bearer sp_secret_…" \
-H "Content-Type: application/json" \
-d '{ "amount": 2000, "currency": "USD", "mode": "sandbox" }'
Then mount the embedded widget with that intent's clientSecret. You may also pass mode: 'sandbox' to mount(), but it is only a safety check that must match the intent — it does not switch the payment:
<script src="https://checkout.securepayapi.com/sdk/v1/securepay.js"></script>
<div id="securepay-widget"></div>
<script>
SecurePay('sp_client_YOURKEY').mount('#securepay-widget', {
clientSecret: 'pi_..._secret_...', // created with mode: 'sandbox'
mode: 'sandbox' // must match the intent, or it's refused
});
</script>
The intent's mode is fixed at creation and the browser cannot change it, so a buyer can never move a live payment into sandbox. Mounting the widget with a mode that differs from the intent is refused with a mode_mismatch error. Create the intent with mode: 'live' (or omit it) for a real payment. In sandbox the widget shows a Test mode badge.
Test cards
In sandbox you pay with a test card — no real money is captured. Enter the cardholder Jonathan Suit (required — the test cards are bound to this name, any other is rejected), any future expiry (for example 03 / 2030), and CVC 737.
| Card number | Behaviour |
|---|---|
4111 1111 1111 1111 | Approves straight through |
5201 2815 0512 9736 | Frictionless 3-D Secure |
4212 3456 7891 0006 | Forces a 3-D Secure challenge |
4917 6100 0000 0000 | 3-D Secure without liability shift |
To simulate a rejected card, use CVC 736 (a failing CVC).
Going live
When your integration handles the full flow cleanly in sandbox, switch the dashboard back to Live and use live invoices, live products, or mode: 'live' (the default). Keep your secret key server-side and watch your first live payments from the dashboard.