Sandbox testing
How the sandbox behaves, how to drive a transaction to each terminal state, and what differs from production.
The sandbox at https://sandbox-api.omicloud.io is a full copy of the API wired to each gateway's own sandbox. Use omi_test_ keys. No real funds move.
What is the same as production
- Every endpoint, every field, every error code.
- Routing, limits and fees — taken from the same configuration.
- Webhook signing, retries and the deliveries log.
- Idempotency behaviour.
What is different
| Sandbox | Production | |
|---|---|---|
| Gateways | Each gateway's sandbox (for DCE: api.dcepay.dev, testnets such as TRX_SHASTA) | Live gateway accounts |
| Settlement | Real testnet transfers, or forced with the simulate endpoint below | Real on-chain / gateway confirmation |
| Limits | May be lower than production for some gateways — read GET /v1/routes rather than assuming | — |
| Data retention | Transactions older than 90 days are purged | Retained |
| Extra endpoint | POST /v1/sandbox/transactions/{reference}/simulate | Does not exist (404) |
Forcing an outcome
Any non-terminal sandbox transaction — a deposit whose session is open, or a payout in processing — can be pushed to a terminal state without touching a chain:
curl -X POST https://sandbox-api.omicloud.io/v1/sandbox/transactions/txn_8f3a1c9e02b4/simulate \
-H "Authorization: Bearer omi_test_…" \
-H "Content-Type: application/json" \
-d '{"outcome":"settle"}'outcome | Transaction becomes | Event sent |
|---|---|---|
settle | settled | transaction.settled |
decline | declined, declineReason: gateway_rejected | transaction.declined |
expire (deposits only) | declined, declineReason: session_expired | session.expired |
reverse (settled deposits only) | reversed | transaction.reversed |
The response is the updated transaction. Webhooks fire exactly as they would in production, so this is the fastest way to exercise a receiver end to end. Simulating goes through the same state machine as a real gateway callback — an illegal transition (e.g. settle on a declined transaction) returns 409.
If you would rather exercise a real transfer, send testnet USDT to deposit.address on the testnet network the route reports, or create a payout to a testnet address you control. Confirmation follows the real chain, so allow a few minutes. Sessions expire 15 minutes after creation in both environments.
Testing webhooks without a public URL
POST /v1/webhook-endpoints/{id}/testsends awebhook.testevent and returns the delivery record including your server's response status.GET /v1/webhook-endpoints/{id}/deliveriesshows every attempt, so you can see exactly what OmiCloud sent and what came back.- For local development, a tunnel (ngrok, Cloudflare Tunnel) is the fastest path.
Testing error handling
| To get | Do |
|---|---|
AMOUNT_TOO_LOW / AMOUNT_TOO_HIGH | send an amount outside the route's limits |
ROUTE_NOT_SUPPORTED | request a currency/network no gateway offers |
IDEMPOTENCY_KEY_REUSED | reuse an Idempotency-Key with a different body within 24 h |
GATEWAY_ERROR | set operatorReference to simulate:gateway_error on a sandbox session or payout |
QUOTE_TIMEOUT | set endUserId to simulate:quote_timeout on a sandbox quote |
GATEWAY_NOT_CONNECTED | pass a gateway id from the catalog you are not connected to |
Updated about 2 months ago