{
  "auth": {
    "bearer": [
      {
        "key": "token",
        "value": "{{api_key}}",
        "type": "string"
      }
    ],
    "type": "bearer"
  },
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "type": "text/javascript",
        "exec": [
          "const key = pm.environment.get('api_key') || '';",
          "if (!key.startsWith('mgw_test_')) {",
          "  throw new Error('This collection is for the sandbox, and it places orders. Use a sandbox key (mgw_test_...).');",
          "}"
        ]
      }
    }
  ],
  "info": {
    "_postman_id": "5e0c3a91-7d24-4b8f-a6c1-2f9e8d7b4c10",
    "description": "This collection runs the quickstart in Postman. Import the Matamba Gateway (sandbox) environment beside it and fill in `base_url` (`https://` and your sandbox host), `api_key`, `account` and `account_99`: every request reads them. Send the first folder's requests in order. The third sends a new `Idempotency-Key` each run, and fills in `order_id` for the fourth.\n\n\nThis guide takes you from your API key to a filled order in five requests. The sandbox has the same endpoints as the live API, but it has its own host and keys, uses test money, and doesn't connect to the exchange.\n\n## Before you begin\n\nWhen we set up your [sandbox access](https://docs.matambaintelligence.com/support), we send you the sandbox host, a sandbox API key, and two account codes: one to trade with, and one ending in `99` that has a zero balance, so you can test a rejected order.\n\nThe examples use these placeholders:\n\n| Placeholder | Replace with |\n|---|---|\n| `{{api_key}}` | Your sandbox API key |\n| `{{account}}` | The account you trade with |\n| `{{account_99}}` | The account ending in `99` |\n| `{{order_id}}` | The `id` returned when you place the order in step 3 |\n\nSend every request with the `Authorization: Bearer {{api_key}}` header. Request and response bodies are JSON. Amounts are integers in kobo, so ₦475.00 is `47500`, and a field ending in `_kobo_decimal` is a decimal string of kobo.\n\n## Place your first order\n\n### 1. List your accounts\n\nConfirm that your key works and see which accounts you can trade for.\n\n```http\nGET /v1/accounts\nAuthorization: Bearer {{api_key}}\n```\n\n```http\nHTTP/1.1 200 OK\n\n{\n  \"object\": \"list\",\n  \"has_more\": false,\n  \"next_cursor\": null,\n  \"data\": [\n    {\n      \"object\": \"account\",\n      \"code\": \"{{account}}\",\n      \"application\": null,\n      \"created_at\": \"2026-09-25T06:00:00Z\"\n    },\n    {\n      \"object\": \"account\",\n      \"code\": \"{{account_99}}\",\n      \"application\": null,\n      \"created_at\": \"2026-09-25T06:00:00Z\"\n    }\n  ]\n}\n```\n\n### 2. Estimate the cost\n\nGet an estimate before you place the order. An estimate doesn't place or store anything.\n\n```http\nPOST /v1/orders/estimate\nAuthorization: Bearer {{api_key}}\nContent-Type: application/json\n\n{\n  \"account\": \"{{account}}\",\n  \"symbol\": \"DANGCEM\",\n  \"side\": \"buy\",\n  \"quantity\": 10,\n  \"type\": \"market\",\n  \"time_in_force\": \"day\"\n}\n```\n\n```http\nHTTP/1.1 200 OK\n\n{\n  \"object\": \"order_estimate\",\n  \"account\": \"{{account}}\",\n  \"symbol\": \"DANGCEM\",\n  \"side\": \"buy\",\n  \"quantity\": 10,\n  \"type\": \"market\",\n  \"time_in_force\": \"day\",\n  \"price_kobo\": null,\n  \"estimated_total_kobo\": 530338\n}\n```\n\nA market order is priced at the day's price limit: the upper limit for a buy, the lower limit for a sell. In the sandbox, the limits are 10% either side of the listed price, and charges are a flat 1.5%. This estimate works out as follows:\n\n| | Kobo |\n|---|---|\n| Upper price limit: ₦475.00 plus 10% | `52250` |\n| 10 shares at the upper limit: 10 × 52250 | `522500` |\n| Plus 1.5% charges: 522500 × 1.015 = 530337.5, rounded to the nearest kobo | `530338` |\n\nThe sandbox then fills the order at ₦475.00, so the account pays `482125` kobo: 10 × 47500, plus 1.5%. A sell estimate is priced at the lower limit and is what you'd receive after charges. In live, the estimate is the broker's figure: it includes the consideration, statutory charges and commission, and it's indicative.\n\n### 3. Place the order\n\nUse a unique `Idempotency-Key` for each order. If a request times out, retry it with the same key and you'll get the original order back instead of a duplicate. Each run of this guide needs a new key, such as `my-first-order-2`: sent again, `my-first-order` returns your first order with `200 OK`, and with a different order `409 duplicate_order`.\n```http\nPOST /v1/orders\nAuthorization: Bearer {{api_key}}\nContent-Type: application/json\nIdempotency-Key: {{order_key}}\n\n{\n  \"account\": \"{{account}}\",\n  \"symbol\": \"DANGCEM\",\n  \"side\": \"buy\",\n  \"quantity\": 10,\n  \"type\": \"market\",\n  \"time_in_force\": \"day\"\n}\n```\n\n```http\nHTTP/1.1 201 Created\n\n{\n  \"object\": \"order\",\n  \"id\": \"ord_62jxryztxctob7uopekg\",\n  \"account\": \"{{account}}\",\n  \"symbol\": \"DANGCEM\",\n  \"side\": \"buy\",\n  \"quantity\": 10,\n  \"type\": \"market\",\n  \"time_in_force\": \"day\",\n  \"price_kobo\": null,\n  \"state\": \"pending\",\n  \"exchange_order_id\": \"1790316754123\",\n  \"filled_quantity\": 0,\n  \"reason\": null,\n  \"reject_reason\": null,\n  \"created_at\": \"2026-09-25T06:12:34Z\",\n  \"updated_at\": \"2026-09-25T06:12:34Z\",\n  \"filled_at\": null,\n  \"average_fill_price_kobo_decimal\": null,\n  \"client_reference\": null\n}\n```\n\nThe `pending` state means the order is open at the exchange.\n\nTo see a rejected order, place the same order on `{{account_99}}` with a new key. It returns `422 order_rejected` with `reject_reason` `insufficient_funds`.\n\n### 4. Check the order status\n\nThe sandbox fills market orders immediately. We check the broker for fills about every 30 seconds. If you've registered a webhook endpoint, we send it an `order.filled` [event](https://docs.matambaintelligence.com/webhooks). Either way, the event is in `GET /v1/events`. Wait 30 seconds, then retrieve the order. If it still reads `pending`, retrieve it again a few seconds later.\n\n```http\nGET /v1/orders/{{order_id}}\nAuthorization: Bearer {{api_key}}\n```\n\n```http\nHTTP/1.1 200 OK\n\n{\n  \"object\": \"order\",\n  \"id\": \"ord_62jxryztxctob7uopekg\",\n  \"account\": \"{{account}}\",\n  \"symbol\": \"DANGCEM\",\n  \"side\": \"buy\",\n  \"quantity\": 10,\n  \"type\": \"market\",\n  \"time_in_force\": \"day\",\n  \"price_kobo\": null,\n  \"state\": \"filled\",\n  \"exchange_order_id\": \"1790316754123\",\n  \"filled_quantity\": 10,\n  \"reason\": null,\n  \"reject_reason\": null,\n  \"created_at\": \"2026-09-25T06:12:34Z\",\n  \"updated_at\": \"2026-09-25T06:13:02Z\",\n  \"filled_at\": \"2026-09-25T06:13:02Z\",\n  \"average_fill_price_kobo_decimal\": \"47500\",\n  \"client_reference\": null\n}\n```\n\n### 5. View the position\n\nThe filled order now appears as a position on the account.\n\n```http\nGET /v1/accounts/{{account}}/positions\nAuthorization: Bearer {{api_key}}\n```\n\n```http\nHTTP/1.1 200 OK\n\n{\n  \"object\": \"list\",\n  \"data\": [\n    {\n      \"object\": \"position\",\n      \"symbol\": \"DANGCEM\",\n      \"name\": \"DANGCEM\",\n      \"quantity\": 10,\n      \"average_cost_kobo_decimal\": \"47500\",\n      \"market_price_kobo\": 47500,\n      \"market_value_kobo\": 475000,\n      \"asset_class\": \"Stock\",\n      \"sector\": null,\n      \"industry\": null\n    }\n  ],\n  \"has_more\": false,\n  \"next_cursor\": null\n}\n```\nThe order is filled and the position shows it. Every endpoint is in the API reference, and every error code in the [error reference](https://docs.matambaintelligence.com/errors).\n\n## Rehearse errors and rare outcomes\n\nThe [sandbox reference](https://docs.matambaintelligence.com/sandbox) lists how the sandbox behaves, a request for each error it can show, and the test values that make rare outcomes happen on demand.\n\nThe API reference and the error table are published at https://docs.matambaintelligence.com.\n",
    "name": "Matamba Gateway v1",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "item": [
    {
      "name": "1. Start here: run these in order",
      "item": [
        {
          "name": "1. List your accounts",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200', () => pm.response.to.have.status(200));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": null,
            "url": "{{base_url}}/v1/accounts"
          }
        },
        {
          "name": "2. Estimate the cost",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200', () => pm.response.to.have.status(200));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"account\": \"{{account}}\",\n  \"symbol\": \"DANGCEM\",\n  \"side\": \"buy\",\n  \"quantity\": 10,\n  \"type\": \"market\",\n  \"time_in_force\": \"day\"\n}"
            },
            "url": "{{base_url}}/v1/orders/estimate"
          }
        },
        {
          "name": "3. Place the order",
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.collectionVariables.set('order_key', pm.variables.replaceIn('{{$guid}}'));"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('201', () => pm.response.to.have.status(201));",
                  "pm.collectionVariables.set('order_id', pm.response.json().id);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{order_key}}"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"account\": \"{{account}}\",\n  \"symbol\": \"DANGCEM\",\n  \"side\": \"buy\",\n  \"quantity\": 10,\n  \"type\": \"market\",\n  \"time_in_force\": \"day\"\n}"
            },
            "url": "{{base_url}}/v1/orders"
          }
        },
        {
          "name": "4. Check the order status",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200', () => pm.response.to.have.status(200));",
                  "pm.test('pending or filled', () => pm.expect(pm.response.json().state).to.be.oneOf(['pending', 'filled']));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": null,
            "url": "{{base_url}}/v1/orders/{{order_id}}",
            "description": "Sent immediately after step 3, this usually returns `pending`: we check the broker for fills every 30 seconds. Send it again after 30 seconds to see `filled`."
          }
        },
        {
          "name": "5. View the position",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200', () => pm.response.to.have.status(200));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": null,
            "url": "{{base_url}}/v1/accounts/{{account}}/positions"
          }
        }
      ]
    },
    {
      "name": "2. Sandbox: rehearse errors",
      "item": [
        {
          "name": "A buy on the account ending in 99",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('422', () => pm.response.to.have.status(422));",
                  "pm.test('order_rejected', () => pm.expect(pm.response.json().error.code).to.eql('order_rejected'));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\"account\":\"{{account_99}}\",\"symbol\":\"DANGCEM\",\"side\":\"buy\",\"quantity\":10,\"type\":\"market\",\"time_in_force\":\"day\"}"
            },
            "url": "{{base_url}}/v1/orders"
          }
        },
        {
          "name": "A limit order on DANGCEM",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('422', () => pm.response.to.have.status(422));",
                  "pm.test('order_rejected', () => pm.expect(pm.response.json().error.code).to.eql('order_rejected'));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\"account\":\"{{account}}\",\"symbol\":\"DANGCEM\",\"side\":\"buy\",\"quantity\":10,\"type\":\"limit\",\"time_in_force\":\"day\",\"price_kobo\":47500}"
            },
            "url": "{{base_url}}/v1/orders"
          }
        },
        {
          "name": "A market order on a symbol not listed",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('422', () => pm.response.to.have.status(422));",
                  "pm.test('unknown_symbol', () => pm.expect(pm.response.json().error.code).to.eql('unknown_symbol'));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\"account\":\"{{account}}\",\"symbol\":\"NOTLISTED\",\"side\":\"buy\",\"quantity\":10,\"type\":\"market\",\"time_in_force\":\"day\"}"
            },
            "url": "{{base_url}}/v1/orders"
          }
        },
        {
          "name": "Reuse step 3's key with a different order",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('409', () => pm.response.to.have.status(409));",
                  "pm.test('duplicate_order', () => pm.expect(pm.response.json().error.code).to.eql('duplicate_order'));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{order_key}}"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"account\": \"{{account}}\",\n  \"symbol\": \"DANGCEM\",\n  \"side\": \"buy\",\n  \"quantity\": 11,\n  \"type\": \"market\",\n  \"time_in_force\": \"day\"\n}"
            },
            "url": "{{base_url}}/v1/orders"
          }
        },
        {
          "name": "A market buy of 20,000 DANGCEM",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('422', () => pm.response.to.have.status(422));",
                  "pm.test('limit_exceeded', () => pm.expect(pm.response.json().error.code).to.eql('limit_exceeded'));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\"account\":\"{{account}}\",\"symbol\":\"DANGCEM\",\"side\":\"buy\",\"quantity\":20000,\"type\":\"market\",\"time_in_force\":\"day\"}"
            },
            "url": "{{base_url}}/v1/orders"
          }
        }
      ]
    },
    {
      "name": "3. Open an account",
      "item": [
        {
          "name": "Apply for an account",
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.collectionVariables.set('fresh_bvn', String(10000000000 + Math.floor(Math.random() * 89999999999)));"
                ]
              }
            },
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.collectionVariables.set('fresh_email', 'ada+' + Date.now() + '@example.com');"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('201', () => pm.response.to.have.status(201));",
                  "pm.test('submitted', () => pm.expect(pm.response.json().state).to.be.oneOf(['submitted']));",
                  "pm.collectionVariables.set('application_id', pm.response.json().id);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"first_name\": \"Ada\",\n  \"last_name\": \"Example\",\n  \"gender\": \"F\",\n  \"date_of_birth\": \"1990-01-15\",\n  \"email\": \"{{fresh_email}}\",\n  \"phone\": \"+2348000000000\",\n  \"street\": \"1 Example Street\",\n  \"city\": \"Ikeja\",\n  \"state\": \"LA\",\n  \"postcode\": \"100001\",\n  \"state_of_origin\": \"LA\",\n  \"lga_of_origin\": \"LA-IKJ\",\n  \"next_of_kin_name\": \"Ben Example\",\n  \"next_of_kin_phone\": \"+2348000000001\",\n  \"bank\": \"058\",\n  \"bank_account_name\": \"Ada Example\",\n  \"bank_account_number\": \"0000000000\",\n  \"bank_account_opened\": \"2015-06-01\",\n  \"bvn\": \"{{fresh_bvn}}\"\n}"
            },
            "url": "{{base_url}}/v1/applications"
          }
        },
        {
          "name": "Retrieve the application",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200', () => pm.response.to.have.status(200));",
                  "pm.test('submitted or opened', () => pm.expect(pm.response.json().state).to.be.oneOf(['submitted', 'opened']));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": null,
            "url": "{{base_url}}/v1/applications/{{application_id}}"
          }
        }
      ]
    },
    {
      "name": "4. Fund an account",
      "item": [
        {
          "name": "Read your wallet",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200', () => pm.response.to.have.status(200));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": null,
            "url": "{{base_url}}/v1/wallet"
          }
        },
        {
          "name": "Read your wallet's ledger",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200', () => pm.response.to.have.status(200));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": null,
            "url": "{{base_url}}/v1/wallet/transfers"
          }
        },
        {
          "name": "Allocate from your wallet",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('201', () => pm.response.to.have.status(201));",
                  "pm.test('booked', () => pm.expect(pm.response.json().state).to.be.oneOf(['booked']));",
                  "pm.collectionVariables.set('allocation_id', pm.response.json().id);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"account\": \"{{account}}\",\n  \"amount_kobo\": 5000000\n}"
            },
            "url": "{{base_url}}/v1/allocations"
          }
        },
        {
          "name": "Retrieve the allocation",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200', () => pm.response.to.have.status(200));",
                  "pm.test('booked', () => pm.expect(pm.response.json().state).to.be.oneOf(['booked']));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": null,
            "url": "{{base_url}}/v1/allocations/{{allocation_id}}"
          }
        }
      ]
    },
    {
      "name": "5. Cancel an order",
      "item": [
        {
          "name": "Place a limit buy below the price, so it rests",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('201', () => pm.response.to.have.status(201));",
                  "pm.test('pending', () => pm.expect(pm.response.json().state).to.be.oneOf(['pending']));",
                  "pm.collectionVariables.set('cancel_order_id', pm.response.json().id);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\"account\":\"{{account}}\",\"symbol\":\"STANBICETF30\",\"side\":\"buy\",\"quantity\":10,\"type\":\"limit\",\"time_in_force\":\"day\",\"price_kobo\":12000}"
            },
            "url": "{{base_url}}/v1/orders"
          }
        },
        {
          "name": "Cancel it",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('202', () => pm.response.to.have.status(202));"
                ]
              }
            }
          ],
          "request": {
            "method": "DELETE",
            "header": null,
            "url": "{{base_url}}/v1/orders/{{cancel_order_id}}"
          }
        },
        {
          "name": "Retrieve it",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200', () => pm.response.to.have.status(200));",
                  "pm.test('pending or cancelled', () => pm.expect(pm.response.json().state).to.be.oneOf(['pending', 'cancelled']));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": null,
            "url": "{{base_url}}/v1/orders/{{cancel_order_id}}"
          }
        }
      ]
    },
    {
      "name": "6. Catch up on events",
      "item": [
        {
          "name": "Read your events",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('200', () => pm.response.to.have.status(200));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": null,
            "url": "{{base_url}}/v1/events"
          }
        }
      ]
    },
    {
      "name": "7. Errors to handle",
      "item": [
        {
          "name": "401 (no key)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('401', () => pm.response.to.have.status(401));",
                  "pm.test('unauthorized', () => pm.expect(pm.response.json().error.code).to.eql('unauthorized'));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": null,
            "url": "{{base_url}}/v1/accounts",
            "auth": {
              "type": "noauth"
            }
          }
        },
        {
          "name": "404 (an order ID that does not exist)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('404', () => pm.response.to.have.status(404));",
                  "pm.test('order_not_found', () => pm.expect(pm.response.json().error.code).to.eql('order_not_found'));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": null,
            "url": "{{base_url}}/v1/orders/ord_doesnotexist22222222"
          }
        },
        {
          "name": "405 (a method the path does not accept)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('405', () => pm.response.to.have.status(405));",
                  "pm.test('method_not_allowed', () => pm.expect(pm.response.json().error.code).to.eql('method_not_allowed'));"
                ]
              }
            }
          ],
          "request": {
            "method": "PUT",
            "header": null,
            "url": "{{base_url}}/v1/accounts"
          }
        },
        {
          "name": "415 (not JSON)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('415', () => pm.response.to.have.status(415));",
                  "pm.test('unsupported_media_type', () => pm.expect(pm.response.json().error.code).to.eql('unsupported_media_type'));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "text/plain"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "hello"
            },
            "url": "{{base_url}}/v1/orders"
          }
        },
        {
          "name": "429 (more than 40 requests sent together)",
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const burst = [];",
                  "for (let i = 0; i < 80; i++) {",
                  "  burst.push(pm.sendRequest({ url: pm.variables.replaceIn('{{base_url}}/v1/accounts'), header: { Authorization: 'Bearer ' + pm.environment.get('api_key') } }));",
                  "}",
                  "const answers = await Promise.all(burst);",
                  "pm.collectionVariables.set('refused_in_burst', String(answers.filter((r) => r.code === 429 && r.json().error.code === 'rate_limited').length));"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('429 rate_limited for the requests past the burst', () => pm.expect(Number(pm.collectionVariables.get('refused_in_burst'))).to.be.above(0));",
                  "pm.test('200 or 429', () => pm.expect(pm.response.code).to.be.oneOf([200, 429]));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": null,
            "url": "{{base_url}}/v1/accounts"
          }
        }
      ]
    }
  ],
  "variable": [
    {
      "key": "order_id",
      "value": "",
      "type": "string",
      "description": "Filled in by '3. Place the order'."
    },
    {
      "key": "order_key",
      "value": "",
      "type": "string",
      "description": "The Idempotency-Key '3. Place the order' sends, fresh each run."
    },
    {
      "key": "application_id",
      "value": "",
      "type": "string",
      "description": "Filled in by the application request in '3. Open an account'."
    },
    {
      "key": "allocation_id",
      "value": "",
      "type": "string",
      "description": "Filled in by the allocation request in '4. Fund an account'."
    },
    {
      "key": "cancel_order_id",
      "value": "",
      "type": "string",
      "description": "Filled in by the first request in '5. Cancel an order'."
    },
    {
      "key": "refused_in_burst",
      "value": "",
      "type": "string",
      "description": "How many of the 429 item's burst were refused with rate_limited."
    },
    {
      "key": "fresh_bvn",
      "value": "",
      "type": "string",
      "description": "A new value each run for the application's bvn: the sandbox refuses one it has already seen."
    },
    {
      "key": "fresh_email",
      "value": "",
      "type": "string",
      "description": "A new value each run for the application's email: the sandbox refuses one it has already seen."
    }
  ]
}
