A developer sandbox that actually behaves like production.
Real orchestrator, real ledger, real webhooks — only the provider is mocked. Flip 12 named failure scenarios on or off per provider so you can see exactly how your code behaves when a wallet OTP expires, a bank account is frozen, or a network blip eats a response. No real money, no real cards, no real cleanup.
At a glance
- Scenarios seeded
- 12
- Providers covered
- All 5 + mock
- Cost
- Free
- Universal OTP
- 123456
Why a real sandbox matters
Most payment platforms ship a half-built sandbox that only handles the happy path. We seeded twelve named failure scenarios because failure cases are exactly where your integration breaks in production.
Same code path as production
Sandbox is the same gateway, the same orchestrator, and the same ledger — just routed to a mock provider. Your integration code is identical between environments; only the API key changes.
Per-provider scenario overrides
Set the next response from waafi to insufficient_funds, sabapay to otp_expired, cac to provider_timeout — independently. Sticky overrides hold until you clear them; one-shot overrides apply to a single call.
OTP 123456 always works
In sandbox, the universal OTP is 123456. Useful for both manual testing and headless integration tests — no SMS gateway, no real handset.
Reset is free
Every sandbox API key has a Reset action that clears merchants, customers, intents, and ledger entries you generated. No accumulated state to clean up by hand.
Webhook delivery to localhost
Register a webhook with an ngrok URL and we will deliver signed events to it. Or use the dashboard's webhook inspector to view the last 100 deliveries with retry traces.
No rate limits worth caring about
Sandbox is rate-limited per merchant at a level you would have to try hard to hit. Run load tests, integration suites, retry loops — knock yourself out.
The four-step path from signup to confident deploy
- 1
Sign up for a sandbox account
Self-service signup. You receive an environment_default of sandbox on day one; sk_test_* and pk_test_* keys are issued immediately from the merchant portal.
- 2
Pin an API version
Set MerasPay-Version: 2026-05-01 (or any later release date) on your API client. Once you set it on a key, that version is locked for that key forever.
- 3
Optionally apply a scenario override
POST /v1/simulator/overrides {provider: "waafi", scenario: "otp_invalid", sticky: true} — the next Waafi sandbox call (and every subsequent one until you clear it) returns the OTP-invalid response.
- 4
Build, break, repeat
Walk every failure mode, every retry, every weird state. Then flip the merchant to live and watch the same code path do the real thing.
The 12 named scenarios
Each scenario maps to a sentinel error in the gateway. Set it once, watch your code behave; sticky overrides hold until you clear them, one-shot overrides apply to a single call.
| Slug | What it does |
|---|---|
| success | Provider returns a successful response. |
| insufficient_funds | Customer wallet or account does not have enough balance. |
| otp_invalid | Customer entered the wrong OTP — confirm fails. |
| otp_expired | Customer took too long; OTP has expired. |
| request_expired | The payment request itself expired before the customer responded. |
| limit_exceeded | Per-transaction or daily aggregate limit hit. |
| customer_not_found | No account exists for the supplied identifier. |
| frozen_account | Customer account is frozen by the issuing bank. |
| provider_timeout | Provider did not respond within the deadline. |
| network_error | TCP-level failure reaching the provider. |
| duplicate | Provider says this idempotency reference was already processed. |
| fraud_decline | Decision Manager or risk engine declined the payment. |
See it in code
Three calls: set an override, exercise the failure path, clear the override. The same shape you would use from a CI integration test.
# Set Waafi to fail with insufficient funds on the next call.
$ curl -X POST https://api.meraspay.io/v1/simulator/overrides \
-u sk_test_xxx: \
-d provider=waafi \
-d scenario=insufficient_funds \
-d sticky=true
{ "provider": "waafi", "scenario": "insufficient_funds", "sticky": true,
"expires_at": "2026-06-23T15:47:00Z" }
# Now any PaymentIntent against waafi fails with ErrInsufficientFunds.
$ curl -X POST https://api.meraspay.io/v1/payment_intents \
-u sk_test_xxx: \
-H "Idempotency-Key: test-001" \
-d amount=10000 -d currency=DJF \
-d "payment_method[provider]=waafi" \
-d "payment_method[msisdn]=+25377123456"
{ "error": { "type": "insufficient_funds",
"message": "Customer wallet does not have enough balance",
"code": "ErrInsufficientFunds" } }
# Clear the override when you are done.
$ curl -X DELETE https://api.meraspay.io/v1/simulator/overrides/waafi \
-u sk_test_xxx:Frequently asked
Can I move between sandbox and live with the same code?▾
Yes — the only thing that changes between environments is the API key prefix (sk_test_* vs sk_live_*). The endpoints, the resource shapes, and the webhook signatures are byte-identical.
Is there a public test card number?▾
Cybersource CNP test cards are exposed once that adapter ships — the standard 4242 4242 4242 4242 family. Until then, card-not-present scenarios are exercised through the simulator overrides on the mock adapter.
How do I test webhooks locally?▾
Either register an ngrok URL as your webhook endpoint and let us deliver to it, or open the webhook inspector in the merchant portal and replay the most recent events with one click.
Are sandbox transactions visible to anyone else?▾
No. Sandbox state is scoped to the merchant; nothing leaks into production reporting, the admin portal, or partner files. You can also delete a sandbox account and wipe all generated rows.
Can I share a sandbox account with my team?▾
Yes. Sandbox accounts support invited teammates the same way live ones do. Give your QA team owner or developer roles; restrict them out of sensitive operations as needed.
Do you have a Postman collection?▾
Yes — the OpenAPI 3.1 spec is the source of truth and we publish a Postman / Insomnia collection generated from it. Import the collection and every endpoint, every example, and every shape is there.
Ready to integrate?
Get a sandbox account in minutes. Production goes live after a brief KYB review.