Testing & Sandbox
Test mode routes every request through a sandbox that behaves identically to production — same API, same webhooks, same dashboards — but no real money moves and no real bank, wallet, or card is involved.
Do I need a real bank or GCash account to test?
No. Never use a real bank or wallet for testing — it's not required, and test-mode payments don't actually reach any real payment provider. Everything is simulated server-side.
The only time real banks come into play is once you're on sk_live_* keys in production, after KYB approval + activation. In test mode, all you need is your sk_test_* key.
Three ways to drive test payments
Pick whichever fits your workflow. All three use sk_test_ keys; all three fire real webhooks.
1. Dev Controls on the sandbox checkout page (easiest)
Every test payment's checkout_url opens the NexusPay sandbox page. In the top-right of that page there's a Dev controls toggle. Expand it and you get three buttons:
- ✓ Success — transitions the payment to
succeeded, credits the test ledger, firespayment.succeededwebhook. - ✕ Fail — transitions to
failed, firespayment.failed. - ◷ Expire — transitions to
expired, firespayment.expired.
Best for ad-hoc testing during development. You can flip through all outcomes in seconds.
2. Deterministic amounts (great for automated tests)
The cents portion of the amount drives the outcome automatically in the sandbox:
| Amount ends in | Outcome when customer clicks Pay |
|---|---|
.00 (e.g. 500.00) | Automatic success |
.01 (e.g. 500.01) | Automatic failure |
.99 (e.g. 500.99) | Checkout expires without action |
| Any other cents | Manual — use Dev controls or the Pay button |
Best for unit / integration tests — you can deterministically test success, failure, and expiry paths without any UI interaction.
curl -X POST https://nexuspayph.com/v1/payments \
-H "Authorization: Bearer sk_test_..." \
-H "Idempotency-Key: $(uuidgen)" \
-d '{ "amount": 100.01, "currency": "PHP", "method": "gcash_qr" }'3. MagiaWallet demo (for end-to-end pitches)
MagiaWallet is a simulated ewallet (phone-framed purple UI, ₱12,450.75 starting balance, fake recent transactions). In demos:
- Create a test payment as usual. You get a
pay_xxxid and acheckout_url. - Open /demo-wallet in another tab.
- Tap Scan QR, paste the payment id or full checkout URL.
- Review the branded confirmation card (merchant name, amount, before/after balance).
- Tap Pay → enter demo PIN
1234→ green checkmark animation. - Webhook fires on your merchant backend. Balance deducts in the wallet. Full loop in ~10 seconds.
Best for live client demos — it makes the complete flow visible: merchant creates payment → customer scans + confirms → merchant gets webhook.
Test cards for the card method
The sandbox card form is pre-filled with a test card. Any expiry / CVC values work.
| Card number | Outcome |
|---|---|
| 4242 4242 4242 4242 | Always succeeds |
| 4000 0000 0000 0002 | Always declined (card_declined) |
| 4000 0000 0000 9995 | Insufficient funds |
Real card numbers can't be charged in test mode — they'd be treated the same as the test card. No PCI risk in sandbox.
Test keys never move money
- All test ledger entries are tagged
environment=test. Your live balance is physically isolated — the database enforces the split. - You can generate unlimited test transactions. No rate limits on the test ledger itself (standard per-key API rate limits still apply — 120 req/min).
- Test and live webhooks go to separate endpoints. Register one endpoint per environment in the dashboard to avoid cross-contamination.
- Test-mode payments use the NexusPay sandbox as their provider, never DirectPay or PayGram. So no provider-side fees, no real wallet authorisations, no partial chargebacks.
How do I flip from test to live?
In order:
- Complete KYB + activation from the merchant dashboard.
- Receive your
sk_live_*keys (shown once on activation). - Register a separate webhook endpoint for
environment: livefrom your dashboard. - Swap the API key your server uses. Everything else in your integration stays identical.
Because the API and webhook shapes are identical, there's no code change between test and live beyond the API key. Your sandbox-passing integration will work in production.
FAQ
Will my test customer actually get charged?
No. Test-mode payments never reach DirectPay, GCash, Maya, or any real provider. No charge is possible.
Can I share a test checkout link with a co-worker?
Yes — the sandbox checkout at /sandbox/checkout/pay_xxx is unauthenticated (the payment id is the access token). Only test-mode pay_ ids work there.
Are test webhooks signed the same as live?
Yes. X-NexusPay-Signature HMAC-SHA256 is identical in test and live. Each environment has its own signing_secret though — register separate webhook endpoints.
What's the difference between the Dev Controls and the MagiaWallet demo?
Dev Controls skip the customer flow — they force the payment state directly for fast testing. MagiaWallet simulates the whole customer-side experience (scan QR → confirm → PIN → success) so you can show stakeholders what the end-to-end flow feels like.
Do refunds work in test mode?
Yes. Refund any succeeded test payment — the ledger debit applies immediately. See the Refunds guide.
Can I test with a real GCash or Maya wallet?
Not in sandbox — we don't send test-mode payments to GCash or Maya servers. You can test by using the demo wallet, the dev controls, or deterministic amounts. Real GCash / Maya scans only work on sk_live_ keys, where the charge is real.
Summary
In test mode: no real bank, no real wallet, no real card, no money moves. Three ways to drive outcomes: Dev Controls, deterministic amounts, or MagiaWallet demo.
In live mode: DirectPay (GCash / InstaPay) + whatever other providers you have enabled. Real customers, real money, real webhooks.