Skip to content
MultigateAPI
Support Staff

Get started

Sandbox vs production

The sandbox runs the same API as production, with the same endpoints, fields, statuses, webhooks and error formats. But a few behaviours are deliberately different, and a few checks are switched off in the sandbox. Read this page before you test. It will save you from a test suite that passes in the sandbox and then fails on your first day in production.

Five things that pass in the sandbox and fail in production
  1. Converting without funds. In the sandbox, an FX lock (accepting a quoted exchange rate so the currency conversion goes ahead) succeeds even when the source account can't cover it. Production refuses it with 402.
  2. Saving an invalid Nigerian account. In the sandbox, any NGN account number can be saved as a beneficiary. Production refuses an account the bank doesn't recognise with 400 "Invalid beneficiary account number".
  3. Disposable email addresses. In the sandbox, addresses like test@yopmail.com or x@mailinator.com are accepted. Production refuses them with "Email domain is not allowed".
  4. Simulated inflows. Simulate an inflow funds sandbox accounts. In production it answers success but does nothing: no money arrives and no webhook follows.
  5. Speed. Payout results, customer reviews and some beneficiary checks are much slower in the sandbox (minutes to days, not seconds). Don't size your production timeouts on sandbox timings.

At a glance

Area Production Sandbox What to do
FX: balance check on lock Refused with 402 "Insufficient balance" if the source account can't cover the conversion. 402 "The settlement has failed…" if the debit fails. Not checked. The lock succeeds without funds and the conversion goes ahead. Check the balance yourself before locking, and handle 402.
NGN beneficiary account check Saving refuses an account the bank can't find: 400 "Invalid beneficiary account number". Any account number is accepted when saving or updating. Run Validate a beneficiary account (NGN) first in both environments.
Name enquiry results The account holder's real name, from their bank. From test banks. The name may be a fixed test name that doesn't match your input. Don't assert specific names in tests.
Email addresses Disposable domains (yopmail.com, mailinator.com, temp-mail.org, guerrillamail.com, 10minutemail.com and others) are refused. Accepted. Use real domains in test data.
Funding accounts and inflows Real bank transfers to your virtual accounts. The simulate endpoint does nothing. Only Simulate an inflow. Sandbox account numbers can't receive real transfers. Never call the simulate endpoint from production code.
Payout status updates Usually seconds after the bank answers. Can take 15 minutes or more. Wait for the webhook; poll at most every few minutes.
Payout outcomes The bank's real answer. From test banks and simulated partners. Some outcomes are random (completed or failed for the same input). Test that you handle every outcome, not that you get one.
Customer onboarding review Results arrive within minutes of compliance completing. A customer can stay processing for days. Ask your Multigate contact to complete a sandbox review.
International payout-channel registrations Finalised within minutes. Can stay processing for up to a week, and the transfer waits. Don't block sandbox tests on these; ask your contact if needed.
Webhook delivery Dedicated delivery service. Shared test infrastructure: occasionally delayed or briefly unavailable. Retries work the same. Keep the status fallback you need in production anyway.
Emails Sent to the addresses you entered. Also real emails to the addresses you entered, with links to the sandbox web app. Use addresses you control.
Bank codes on some virtual accounts Real bank codes. Can show test values such as test-bank, and some non-NGN test accounts show NGN-style details. Never hard-code bank codes or names; read them from the API.
Charges Your agreed pricing. May record per-payout charge entries that production doesn't. Don't build reconciliation rules on sandbox fee amounts.
Capacity and releases Scaled for production traffic. Smaller, and can run a newer or older release than production for a while. Don't load test the sandbox. Ignore fields you don't recognise.

How to think about it

Your code should be identical in both environments. Only the base URL, the credentials (API key and client secret) and the webhook URL change. What sits behind the API is different:

flowchart LR
    A["Your server<br/>(same code)"] -->|"MG_BASE_URL"| S["Sandbox API"]
    A -->|"MG_BASE_URL"| P["Production API"]
    S --> SB["Test banks and simulated partners<br/>Simulated inflows<br/>Some checks off, slower jobs"]
    P --> PB["Real banks and partners<br/>Real inflows<br/>All checks on"]
Don't branch on environment

Avoid if (sandbox) … else … in your integration, apart from configuration. The one exception is a test-only helper that calls Simulate an inflow. Keep it out of your production code paths entirely.

FX conversions

Production: when you lock a quote, Multigate checks that the source account can cover the conversion (unless your business is post-funded: allowed by agreement to pay for conversions afterwards), then debits it.

  • Not enough available balance: 402 "Insufficient balance". Nothing is booked.
  • The debit fails: 402 "The settlement has failed due to an issue with our banking partners." No conversion is recorded. Usually nothing was debited, but check the balance before retrying: a debit that timed out inside Multigate can still complete.

Sandbox: neither check stops the conversion. A lock on an empty account succeeds, and the conversion moves on to processing and completed as if it had been funded.

What to do:

  • Fetch the source account's balance (Get an account balance) before you lock, and stop if it's short.
  • Handle 402 from the lock as "not converted": tell your user, fund the account, then lock again (the quote stays usable until endTime) or request a new quote.
  • Don't rely on a sandbox test to prove your insufficient-funds handling. Unit-test it with the 402 response shown above.

See FX conversions.

Beneficiaries and name enquiry

Production: when you save an NGN beneficiary (a person or business you pay), Multigate asks the beneficiary's bank whether the account exists. This lookup is called a name enquiry. If the bank can't find it, the request fails with 400 "Invalid beneficiary account number". The check doesn't compare the name you send, and updating a beneficiary doesn't repeat it.

Sandbox: if the bank lookup fails, the beneficiary is saved anyway. A typo'd or made-up account number goes through.

Validate a beneficiary account (NGN) and Look up an account name behave the same in both environments; for example, a failed validation returns 200 with nameEnquiryResponse: null. In the sandbox, though, the answers come from test banks, so the returned name can be a fixed test value that doesn't match the account number you sent.

What to do:

  • Always validate before saving or paying a new NGN account, and treat nameEnquiryResponse: null as "not verified".
  • Show the returned name to your user to confirm. Don't compare it automatically against expected names in sandbox tests.
  • Expect production to refuse account numbers that the sandbox accepted.

See Beneficiaries.

Email addresses

Production refuses email addresses at disposable or throwaway domains, such as yopmail.com, mailinator.com, temp-mail.org, guerrillamail.com, throwawaymail.com, maildrop.cc and 10minutemail.com. The error is a 400 validation error, "Email domain is not allowed", on the email field.

It applies wherever you send an email address: customers and their shareholders, account requests, beneficiaries, linking requests and users.

Sandbox accepts them.

What to do: use real domains you control in test data (for example addresses on your own domain). Then the same payloads work in production, and you can read the emails Multigate sends.

Inflows and virtual accounts

Sandbox:

  • The only way money arrives is Simulate an inflow. It runs the real inflow pipeline (screening, ledger credit, inflow webhook, "Payment Received" email).
  • A simulated inflow's sender name is the receiving account's own name and its sender account number is null. Its paymentReference/sessionId is a generated ID that the simulate call doesn't return, and its narration looks like MULTIGATE-<account name>-<masked account number>. Make sure your inflow handler copes with null sender fields.
  • For some NGN and GHS accounts, the simulated amount is read as minor units (kobo or pesewas) and credited at one hundredth of what you sent. Check amount in the webhook.
  • Virtual account numbers come from bank test systems, and some are mock responses. Real bank transfers to them never arrive.
  • Some sandbox virtual accounts show test bank codes such as test-bank, and some non-NGN test accounts carry NGN-style details.

Production:

  • Money arrives from payers' banks, with the real sender details.
  • Simulate an inflow returns 200 "inflow initiated" but does nothing.

What to do: read bank names and codes from the API rather than hard-coding them, and treat sender fields as optional.

See Collections and Accounts.

Payout results and timing

Sandbox:

  • Multigate checks pending payouts with the bank only every 15 minutes, so a payout can sit in processing for 15 minutes or more before transfer_completed or transfer_failed arrives.
  • Payouts go to test banks and simulated partners. Some simulated partners pick the outcome at random, so the same request can complete once and fail the next time. Others can stay processing.

Production: pending payouts are checked every 15 seconds for their first 30 minutes, then every 15 minutes up to 6 hours and every 30 minutes up to 24 hours. Results usually arrive soon after the bank answers. A bank can still take longer, which is why the unknown-outcome rules apply in both environments.

What to do:

  • Build on webhooks. If you also poll Find transfers (filtered by uniqueRequestId), poll no more than every few minutes and stop when the status is final.
  • In automated sandbox tests, assert that your code handles completed, failed and a long processing. Don't assert which one you get.
  • Set production alert thresholds from production experience, not from sandbox timings.

Customers and compliance review

Sandbox: compliance results for customers (the businesses you onboard and act for, called sub-clients in the API) are collected much less often than in production, so a submitted customer can stay processing for days. Registering a beneficiary with an international payout channel (done automatically on the first transfer through that channel) can take up to a week, and the transfer stays processing meanwhile. Until a customer is active, you can't open accounts, pay out or convert for it, so sandbox flows that need a customer wait for the review.

Production: results are collected every few minutes once compliance has decided.

What to do:

  • Don't make sandbox test runs wait for subclient_approved. Ask your Multigate contact to complete the review for your test customers.
  • In your product, show "under review" for processing. In production it can also take a while when compliance needs more information.

See Customers.

API keys and IP allow-list

Production Sandbox
API keys Generated in the production dashboard Generated in the sandbox dashboard
API key format mgk_live_… mgk_sandbox_…
API key header and errors Same Same
IP allow-list Enforced Enforced

Each environment has its own API keys: a sandbox key (mgk_sandbox_…) returns 401 in production, and a production key (mgk_live_…) returns 401 in the sandbox.

The IP allow-list is enforced in both environments. If your business has an allow-list, register your test servers' outbound IP addresses in the sandbox as well as your production addresses in production. Each environment has its own list.

See Authentication.

Webhooks and emails

  • Registration is per environment. Register a sandbox webhook URL in the sandbox and a production URL in production. Signing, payload format, timeout and retry schedule are identical. Use one mode per environment and send webhookUrl on every save: the last saved configuration (any mode) sets the webhook URL and IP allow-list.
  • Sandbox delivery runs on shared test infrastructure. Webhooks can arrive late, or not until a retry, during sandbox maintenance. Your fallback (fetch the status when no final webhook arrives) covers this, and you need that fallback in production too.
  • Sandbox emails are real emails. They go to the addresses on your users, customers and beneficiaries, and their links open the sandbox web app. Use addresses you control.

See Webhooks overview and Email notifications.

Charges and reconciliation

The sandbox can record per-payout charge entries that production doesn't record in the same way. Fee amounts and charge lines on sandbox statements aren't a guide to your production pricing. Use Get a transfer fee in production for the fee you will actually pay, and agree pricing with Multigate.

Capacity and releases

  • The sandbox runs on smaller infrastructure. Don't load test or performance test it. Ask Multigate if you need a performance test.
  • The sandbox and production are released separately, so for short periods the sandbox can run a newer (or older) version. Build your integration to ignore response and webhook fields it doesn't recognise, so new optional fields never break it.

What's the same in both

So you don't have to second-guess everything, these behave identically:

  • Endpoints, request and response fields, statuses, error formats and webhook payloads.
  • API key authentication and IP allow-list enforcement.
  • Validation rules (except disposable email domains, above), including the 1 MB request size limit and page size limits.
  • Idempotency with uniqueRequestId.
  • Approvals (maker-checker) and compliance screening of payouts and inflows.
  • How long an FX quote stays valid before you must lock it.
  • Webhook signing, the 9-second timeout and the retry schedule.

Before go-live: re-test against production rules

Once production is enabled, run these with your production credentials, ideally with small amounts on day one:

  • Call Get the current user with your production API key from each production server (key and IP allow-list).
  • Save a beneficiary with a deliberately wrong NGN account number and confirm you handle the 400.
  • Create a customer or user with your real production email domains.
  • Try an FX lock larger than the available balance and confirm you handle the 402.
  • Receive a real inflow into a virtual account and process the inflow webhook, including the real sender fields.
  • Make a small real payout and process its webhook.

Then finish the go-live checklist.