> ## Documentation Index
> Fetch the complete documentation index at: https://docs.matambaintelligence.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Sandbox

> How the sandbox behaves, the requests that rehearse each error, the test values that show rare outcomes, and what it can't show.

The sandbox has the live API's endpoints, with test money and a broker we run, so you can make most outcomes happen before you go live. The last table on this page lists what it can't show, and why.

## How the sandbox behaves

|                 |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Symbols         | Four symbols are available: `DANGCEM` at ₦475.00, `MTNN` at ₦250.00, `ZENITHBANK` at ₦38.50, and `STANBICETF30` (an ETF) at ₦120.50.                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| Fills           | An order that crosses the listed price fills at once, in full, at that price. A market order always crosses, a limit buy crosses at or above the listed price, and a limit sell at or below it. A sell fills only if the account holds every share it sells: if it holds fewer, none of the order fills.                                                                                                                                                                                                                                                                                                     |
| Unfilled orders | An `ioc` or `fok` order that doesn't fill at once expires at once. Any other stays open: a `day` order until midnight, West Africa Time (WAT), when it expires, and a `gtc` order until you cancel it. Only a limit order can be cancelled, so an unfilled `gtc` market sell stays open.                                                                                                                                                                                                                                                                                                                     |
| Market hours    | The sandbox market never closes, so you can test at any time.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| Balance         | Every account starts with ₦1,000,000.00, except the account ending in `99`, which starts with ₦0.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| Wallet          | Your sandbox wallet opens with ₦10,000,000.00 of test money when we set up your access, credited once. For more, [ask us](/support#what-to-send-for-each-request). See [Fund an account](/funding).                                                                                                                                                                                                                                                                                                                                                                                                          |
| Price limits    | 10% either side of the listed price. A market buy is priced at the upper limit and a market sell at the lower limit.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| Fees            | The sandbox charges a flat 1.5%. Live fees are set by the broker: for its fee schedule, [ask us](/support).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| Reset           | A restart of the sandbox, such as for a new release, resets its broker: every account's balance and positions start again, and an order still open there ends `expired` within 30 seconds. Your keys, your webhook endpoint and our records of your orders, applications, allocations, events and wallet stay. Your wallet isn't reset, so money allocated before a restart stays in `allocated_kobo` but is no longer in the accounts' balances. The sandbox's broker never gives a number twice, so an `exchange_order_id`, an application's `reference` or a new account is never one you've seen before. |

## Test your error handling

Before you go live, send these requests to check that your integration handles each error.

[generated: sandbox-errors]: #

| Request                                                                                                       | Response                                                                                                                                                                     |
| ------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| A request to any endpoint without the `Authorization` header                                                  | `401 unauthorized`.                                                                                                                                                          |
| A request with any key starting `mgw_live_`                                                                   | `401 unauthorized`, with a message that it's a live key and this is the sandbox.                                                                                             |
| `GET /v1/nothing`                                                                                             | `404 not_found`.                                                                                                                                                             |
| `PUT /v1/accounts`                                                                                            | `405 method_not_allowed`, with an `Allow` header.                                                                                                                            |
| `POST /v1/orders` with `Content-Type: text/plain`                                                             | `415 unsupported_media_type`.                                                                                                                                                |
| A request body over 16 KiB                                                                                    | `413 request_too_large`.                                                                                                                                                     |
| An order with `"quantity": "10"`, a number in quotes                                                          | `400 invalid_request`. Send numbers as JSON numbers.                                                                                                                         |
| An order without `symbol`                                                                                     | `400 missing_required_field`, with `param` set to `symbol`.                                                                                                                  |
| An order for an account that isn't yours                                                                      | `400 unknown_account`.                                                                                                                                                       |
| `GET /v1/accounts/0000000000`                                                                                 | `404 account_not_found`.                                                                                                                                                     |
| `GET /v1/orders/ord_doesnotexist22222222`                                                                     | `404 order_not_found`.                                                                                                                                                       |
| `GET /v1/applications/app_doesnotexist22222222`                                                               | `404 application_not_found`.                                                                                                                                                 |
| `GET /v1/allocations/alc_doesnotexist22222222`                                                                | `404 allocation_not_found`.                                                                                                                                                  |
| Buy on the account ending in `99`                                                                             | `422 order_rejected` with `reject_reason: insufficient_funds`, because the account has a zero balance.                                                                       |
| Place a limit order on `DANGCEM`                                                                              | `422 order_rejected` with `reject_reason: limit_orders_etf_only`. Limit orders are accepted only for ETFs.                                                                   |
| Place a market order for a symbol that isn't listed above                                                     | `422 unknown_symbol`. The order isn't stored, so you can reuse the idempotency key.                                                                                          |
| Place a limit buy for a symbol that isn't listed above                                                        | `422 order_rejected` with `reject_reason: unknown_symbol`. Only a market order or a sell is checked before we store it, so a limit buy reaches the broker, which rejects it. |
| Reuse an `Idempotency-Key` with a different order, such as step 3's key with `quantity` 11                    | `409 duplicate_order`, with `order` naming the order that owns the key.                                                                                                      |
| More than 40 requests sent together, such as 80 `GET /v1/accounts`                                            | `429 rate_limited`, with a `Retry-After: 1` header.                                                                                                                          |
| A market buy of 20,000 `DANGCEM`                                                                              | `422 limit_exceeded`: counted at the day's upper price limit, it's more than the default day's order value. Nothing is stored.                                               |
| Cancel a market order                                                                                         | `409 order_not_cancelable`. Only a limit order can be cancelled.                                                                                                             |
| While an order for 2,222 shares is `uncertain` (see Test values), send another identical order with a new key | `409 similar_order_unresolved`, with `order` naming the uncertain order. Nothing is stored.                                                                                  |
| An allocation of more than your sandbox wallet holds, within the day's allocation limit                       | `422 wallet_too_low`. Nothing is stored.                                                                                                                                     |
| An allocation of ₦60,000,000                                                                                  | `422 limit_exceeded`: it's more than the default day's allocations. Nothing is stored.                                                                                       |
| Reuse an application's `Idempotency-Key` with a different form                                                | `409 duplicate_application`, with `application` naming the application that owns the key.                                                                                    |
| Reuse an allocation's `Idempotency-Key` with a different amount                                               | `409 duplicate_allocation`, with `allocation` naming the allocation that owns the key.                                                                                       |

[end generated: sandbox-errors]: #

## Test values

Each row shows one outcome on demand, only in the sandbox. For the order quantities, use a limit buy of `STANBICETF30` below ₦120.50, such as `price_kobo` `12000`, so the order stays open.

[generated: sandbox-values]: #

| Send                                                                                               | What happens                                                                                                                                                                                                                                                                                                                                    |
| -------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| A market order                                                                                     | `201` `pending`. Within 30 seconds it becomes `filled`, with an `order.filled` event.                                                                                                                                                                                                                                                           |
| An order for exactly 1,111 shares                                                                  | `201` `pending`. 444 shares fill at once at your price and the rest stays open, so within 30 seconds you receive `order.partially_filled`.                                                                                                                                                                                                      |
| An order for exactly 2,222 shares                                                                  | `201` `uncertain`: the sandbox withholds the broker's response to the order. Within about two minutes, reconciliation finds it at the broker and it becomes `pending`, with an `order.pending` event.                                                                                                                                           |
| A cancel of an open limit order                                                                    | `202`. Within 30 seconds the order becomes `cancelled`.                                                                                                                                                                                                                                                                                         |
| A cancel of an open order of exactly 3,333 shares                                                  | `503 cancel_unconfirmed`: the cancel reaches the broker, and the sandbox withholds its response. Within 30 seconds the order becomes `cancelled`.                                                                                                                                                                                               |
| A limit `ioc` or `fok` order that doesn't cross the listed price                                   | `201` `pending`. It expires at once, and within 30 seconds it becomes `expired`.                                                                                                                                                                                                                                                                |
| An account ending in `98`                                                                          | The broker is settling the day's trades for it. Its balance: `503 settlement_lockout` with `Retry-After: 60`. An estimate or an order: `422 order_rejected` with `reject_reason: settlement_lockout`. Its positions, trades and contract notes read as usual, and an allocation to it is booked. [Ask us](/support) to add one to your sandbox. |
| An application                                                                                     | `201` `submitted`. The sandbox's broker opens it, and within 30 seconds it becomes `opened`, with an `application.opened` event that carries the new `account`.                                                                                                                                                                                 |
| An application with `bvn` `00000000000`                                                            | `422 application_rejected` with `reject_reason: rejected_by_broker`. Nothing reaches the sandbox's broker, so you can send it again. In live, [contact us](/support) before you send it again.                                                                                                                                                  |
| A second application with a `bvn` or an `email` the sandbox has already accepted, from any partner | `422 application_rejected` with `reject_reason: already_at_broker`. Use a new BVN and email for each application.                                                                                                                                                                                                                               |
| An application with an `email` without an `@`                                                      | `422 application_rejected` with `reject_reason: invalid_field` and `param` set to `email`. Correct it and send it with a new key.                                                                                                                                                                                                               |
| An allocation to one of your accounts                                                              | `201` `booked`, with an `allocation.booked` event.                                                                                                                                                                                                                                                                                              |

What the sandbox can't show you, and why:

| Outcome                                           | Why                                                                                                                                          |
| ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| An order in `refused`                             | Only an order we could not send to the broker at all.                                                                                        |
| An order in `sending`                             | An order is `sending` only while its request is in progress, or after it if its outcome was not recorded. No test value causes either.       |
| An order rejected with `account_not_at_broker`    | The sandbox's broker opens any ten-digit account the first time it's used.                                                                   |
| An order rejected with `market_closed`            | The sandbox market never closes.                                                                                                             |
| An order rejected with `rejected_by_exchange`     | Only when the broker can't accept an order as we sent it, rejects an order after accepting it, or our operations team records a rejection.   |
| An order rejected with `symbol_not_tradable`      | Every symbol the sandbox lists can be traded.                                                                                                |
| An application in `refused`                       | Only an application we could not send to the broker at all.                                                                                  |
| An application in `sending`                       | An application is `sending` only while its request is in progress, or after it if its outcome was not recorded. No test value causes either. |
| An application in `uncertain`                     | No test value withholds the broker's response to an application.                                                                             |
| An application in `unplaced`                      | Only our operations team records that the broker does not hold an application.                                                               |
| An application rejected with `declined_by_broker` | Only our operations team records that the broker declined an application after accepting it.                                                 |
| An allocation in `refused`                        | Only an allocation we could not send to the broker at all.                                                                                   |
| An allocation in `rejected`                       | No test value makes the sandbox's broker refuse a deposit, so no allocation reject reason can be shown.                                      |
| An allocation in `sending`                        | An allocation is `sending` only while its request is in progress, or after it if its outcome was not recorded. No test value causes either.  |
| An allocation in `uncertain`                      | No test value withholds the broker's response to an allocation.                                                                              |
| The limit on requests in progress at once         | Not on demand: the sandbox's broker answers at once, so your requests are rarely in progress together.                                       |
| `account_not_at_broker`                           | The sandbox's broker opens any ten-digit account the first time it's used.                                                                   |
| `allocation_not_sent`                             | Only an allocation we could not send to the broker at all.                                                                                   |
| `allocation_rejected`                             | No test value makes the sandbox's broker refuse a deposit.                                                                                   |
| `application_not_sent`                            | Only an application we could not send to the broker at all.                                                                                  |
| `exchange_error`                                  | Only when the broker's response can't be processed.                                                                                          |
| `exchange_unavailable`                            | Only while we can't reach the broker.                                                                                                        |
| `feature_not_enabled`                             | Account opening and deposits are enabled on the sandbox for every partner.                                                                   |
| `insufficient_scope`                              | Only with a key that lacks a scope. [Ask us](/support) for one to test with.                                                                 |
| `internal_error`                                  | Only on an internal gateway error.                                                                                                           |
| `order_not_sent`                                  | Only an order we could not send to the broker at all.                                                                                        |
| `outcome_not_recorded`                            | Only when the outcome of a new order, application or allocation was not recorded. No test value causes it.                                   |
| `service_unavailable`                             | Only when the gateway is temporarily unable to process the request.                                                                          |
| `similar_allocation_unresolved`                   | Only while an allocation is unresolved, and no test value withholds the broker's response to an allocation.                                  |
| `trading_paused`                                  | Only while our operations team has paused trading.                                                                                           |
| A live key from an unregistered address           | Sandbox keys work from any address.                                                                                                          |
| Linking a customer the broker already knows       | Our operations team does it with the broker, outside the API.                                                                                |

[end generated: sandbox-values]: #
