Testing in sandbox: best practices
Updated a week ago
Sandbox lets you build and test your Billplz integration without processing real payments or moving real money. This article covers the practices that help you catch integration issues early, so the switch to production goes smoothly.
Before you begin
- A Billplz sandbox account. See Create a sandbox account.
- Your sandbox Secret key. See Get your Billplz Secret key.
- A Collection ID from your sandbox dashboard. See Create a Collection ID.
Keep sandbox and production completely separate
Sandbox and production are separate Billplz accounts with separate credentials. Every key, Collection ID, and endpoint URL is environment-specific:
Item | Sandbox | Production |
|---|---|---|
Base URL |
| |
Secret key | From sandbox dashboard | From production dashboard |
X Signature key | From sandbox dashboard | From production dashboard |
Collection IDs | Created in sandbox | Created in production |
Never hard-code credentials. Store your Secret key, X Signature key, and base URL as environment variables or in a configuration file so you can switch environments without changing code:
# .env.sandbox BILLPLZ_BASE_URL=https://www.billplz-sandbox.com/api/ BILLPLZ_SECRET_KEY=your_sandbox_secret_key # .env.production BILLPLZ_BASE_URL=https://www.billplz.com/api/ BILLPLZ_SECRET_KEY=your_production_secret_key
Using a sandbox key against the production endpoint (or vice versa) returns a 401 Unauthorized error. If you see this during testing, confirm your key matches the endpoint. See Common API error codes.
Use the correct test bank codes
Sandbox provides test bank codes that simulate payment flows without connecting to real banks. The test codes vary by product and payment method.
FPX test banks
Select any of the following test banks when completing a payment on the sandbox bill payment page:
Bank code | Name |
|---|---|
| Affin Bank |
| Bank of China |
| UOB Bank |
| Test 0001 |
| Test 0002 |
| Test 0003 |
| Test 0004 |
| Test 0021 |
| Test 0022 |
| Test 0023 |
| Billplz Simulator |
| SBI Bank A |
| SBI Bank B |
| SBI Bank C |
If you use the Bypass Billplz Bill Page feature to skip the payment selection page, set reference_1_label to "Bank Code" and reference_1 to the bank code in your Create a Bill request.
Payment Order
Use DUMMYBANKVERIFIED as the bank_code when creating a Payment Order in sandbox. Any other bank code results in a failed transaction.
Test callbacks with a publicly accessible URL
Billplz sends callbacks via server-to-server POST requests. Your callback_url must be reachable from the internet — localhost URLs do not work because Billplz's servers cannot reach your local machine.
Two approaches:
Tunnelling service (e.g., ngrok) — Exposes your local development server through a public URL. This lets you test your actual callback-handling code end to end.
ngrok http 3000 # Use the generated https://xxxx.ngrok.io URL as your callback_url
Webhook testing service (e.g., webhook.site) — Provides a temporary public URL that captures and displays incoming requests. Use this to inspect the exact payload Billplz sends without writing any server code.
Both approaches work for testing callbacks and redirects.
Verify X Signature before going live
Enable your X Signature key in your sandbox dashboard and verify signatures on every callback and redirect during testing. This ensures your signature verification logic is correct before you handle real payments.
When verifying, confirm that:
- You are using your X Signature key (not your Secret key) for the HMAC-SHA256 computation.
- You exclude the
x_signatureparameter itself from the source string. - You sort key-value pairs in ascending order (case-insensitive) and join them with
|(pipe) characters.
For V5 endpoints (e.g., Payment Order), the checksum uses HMAC-SHA512 — not HMAC-SHA256. Do not mix up the two algorithms. See Authentication overview for the full breakdown.
Test the complete payment flow
Run through the full cycle at least once in sandbox before going live:
- Create a Collection (via dashboard or API).
- Create a bill with both
callback_urlandredirect_url. - Open the bill URL in your browser and complete payment using a test bank.
- Confirm your server receives the callback POST and processes it correctly.
- Confirm the redirect returns the customer to your site with the correct query parameters.
- Call the Get a Bill endpoint to verify the bill status shows
"paid": true.
Test error handling
Intentionally trigger error conditions to confirm your integration handles them gracefully:
- 401 Unauthorized — Send a request with an incorrect Secret key.
- 422 Unprocessable Entity — Omit a required parameter (e.g.,
callback_url) or pass an invalidamount(e.g.,0or a negative number). - 404 Not Found — Request a bill using a non-existent Bill ID.
- Failed payment — Use a real (non-test) bank code in sandbox; the transaction will fail, allowing you to test your failure-handling logic.
Your integration should log errors, return meaningful responses to customers, and avoid exposing raw API error messages in your UI.
Go-live checklist
When your sandbox testing is complete, switch to production by updating three things:
- Base URL — Change from
https://www.billplz-sandbox.com/api/tohttps://www.billplz.com/api/. - Secret key — Replace your sandbox Secret key with your production Secret key from your production dashboard.
- Collection IDs — Create new collections in your production account and update the IDs in your code. Sandbox Collection IDs do not exist in production.
Also confirm:
- Your
callback_urlpoints to your production server (not a tunnelling or testing URL). - X Signature verification is enabled and working with your production X Signature key.
- All API requests use HTTPS. Plain HTTP requests fail.
- Your system handles the
callback_urlandredirect_urlindependently, as their execution order is not guaranteed.
Common issues
Was this article helpful?