The simulator is a provider
Not a mock. It implements the full adapter contract, is chosen by the same routing rules as anything else, and signs its callbacks with an HMAC over the raw body that we then verify like any other.
Scripted outcomes
The last three digits of the amount decide what happens. Deterministic, so a test suite can assert on it, and available to you in exactly the same way it is available to our own CI.
| Amount ends in | What happens |
|---|---|
| …000 | Succeeds normally. |
| …001 | Declines with INSUFFICIENT_FUNDS — retryable. |
| …002 | The customer cancels at the prompt. |
| …003 | Nobody answers; the payment reaches EXPIRED, not FAILED. |
| …004 | The provider is unavailable, so the router looks elsewhere. |
| …005 | Succeeds after about thirty seconds — the case your timeout handling is wrong about. |
| …006 | The callback never arrives, and the reconciler has to resolve it. |
# The last three digits of the amount script the outcome in test mode.
# …001 declines for insufficient funds:
curl https://api.idealbox.org/v1/payment_intents \
-H "Authorization: Bearer ib_sk_test_4f2a9c1e8b7d6053" \
-H "Content-Type: application/json" \
-d '{
"amount": "500001",
"currency": "XAF",
"country": "CM",
"methodType": "MOBILE_MONEY",
"providerParams": { "phoneNumber": "+237699000000" }
}'Resetting the sandbox
Developers → Overview has a reset. It clears your test events, deliveries, request logs, customers and — most usefully — your idempotency keys, then seeds a couple of sample customers back in.
Callbacks and the reconciler
Provider callbacks get lost, arrive twice and arrive out of order. A polling reconciler independently asks what happened, and both paths end in the same code, so they cannot disagree.