Get started
Environments and sandbox
Multigate has two environments. Build and test everything in the sandbox, then switch the base URL and credentials to go live.
| Sandbox | Production | |
|---|---|---|
| Base URL | https://api-gateway-uat. |
https://api-gateway. |
| Dashboard | uat.multigate.app | multigate.app |
| Money | Simulated. Nothing reaches a real bank account. | Real. |
| Credentials | Sandbox API key and client secret (from the sandbox dashboard) | Production API key and client secret (from the production dashboard) |
| IP allow-list | Its own list, enforced | Its own list, enforced |
| Webhook URL | Registered in the sandbox | Registered in production |
| Funding your accounts | Simulate an inflow | Real bank transfers to your virtual accounts |
Every path in these docs is relative to the base URL. For example, getting the current user in the sandbox is:
GET https://api-gateway-uat.mmacs.io/platform/user-service/api/v1/users/current-user
mp-api-key: <your sandbox API key>
A key works only in the environment whose dashboard generated it, and its start tells you which one: sandbox keys start with mgk_sandbox_ and production keys with mgk_live_.
Read the base URL and credentials from configuration, for example the environment variables MG_BASE_URL, MG_API_KEY and MG_ used throughout these docs (set up in the Quickstart). Going live is then a configuration change, not a code change.
How the sandbox differs from production
The sandbox doesn't behave exactly like production. A few checks are off (FX balance checks, NGN beneficiary account checks, disposable email domains), some jobs are much slower (payout results, customer reviews), and payout outcomes come from test banks, sometimes at random.
Every difference, with what to do about it, is on Sandbox vs production.
| Sandbox | Production | |
|---|---|---|
| Incoming payments | Only through Simulate an inflow. | From payers' banks. The simulate endpoint does nothing. |
| Payouts | Full flow (validation, screening, approvals) against test banks and simulated partners. Results can take 15 minutes or more. | Paid to real accounts, usually within seconds of the bank answering. |
| Checks that are off | FX balance check on lock, NGN account check when saving a beneficiary, disposable email domains. | All on. |
| Webhooks and emails | Sent, with the same format and signing. Emails go to real addresses. | Sent. |
| IP allow-list | Enforced (its own list). | Enforced (its own list). |
| Data | Separate from production. Nothing carries over when you go live. |
Simulate an inflow
Fund a sandbox account, or test your inflow handling, by pretending a payer sent money to one of your virtual accounts.
Use List accounts and pick an account whose status is active. Use one of its virtual account numbers from funding (the numbers payers would send to). The account must belong to your business or one of your active customers. The Quickstart stores it in MG_.
curl -s -X POST "$MG_BASE_URL/client-service/api/v1/webHook/publishInflow" \
-H "mp-api-key: $MG_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"accountNumber\":\"$MG_VIRTUAL_ACCOUNT_NUMBER\",\"amount\":1000000,\"currency\":\"NGN\"}"
{ "message": "inflow initiated" }
amount is in major units (1000000 is 1,000,000.00 NGN). currency is required but ignored: the credit always uses the account's own currency. The response contains no reference.
The response only means the inflow was queued. It is then screened (checked against Multigate's compliance rules) and credited like a real one. In the sandbox this usually takes a few minutes; there is no fixed time. Then:
- your webhook receives
account/inflow; - your business contact receives a "Payment Received" email;
- the balance (Get an account balance) and statement of the account show the credit, minus any collection fee (a fee on money received) configured for your business.
A simulated inflow has no sender bank or sender account number (null in the webhook), and its payment/sessionId is a generated ID the call doesn't return. The sender name is the account's own name, and the narration looks like MULTIGATE-<account name>-<masked account number>.
If the account isn't active yet, the endpoint still answers 200, but with an error body: [{"errors":{"message":"account has not been approved"}}]. Wait for the account_ webhook before simulating inflows into a new account.
For some NGN and GHS sandbox accounts, depending on the partner bank behind them, the simulated amount is read as minor units (kobo or pesewas) and credited at one hundredth: 1000000 credits 10,000.00. Compare amount in the webhook with what you sent, and send 100 times the amount if needed.
In production the endpoint answers 200 but does nothing, so keep it out of your production code paths entirely.
Test checklist
Before you ask for production access, run each of these in the sandbox:
- Call the API with your sandbox API key, rotate it to a second key without errors, and handle a
401from a revoked key (Authentication). - Fund an account with a simulated inflow and process the
inflowwebhook (Collections). - Create a payout, and process
transfer_andcompleted transfer_(Payouts).failed - Retry a payout with the same
uniqueand confirm nothing is paid twice (Idempotency).Request Id - Trigger and handle errors: insufficient balance, invalid account, unknown bank (Errors).
- Reject a webhook with a tampered body (Verifying signatures).
Then read Sandbox vs production and work through the go-live checklist.