{
  "info": {
    "name": "Bullion customer trading API",
    "description": "Test and production trading with an API key. Pick the matching environment file, paste your key into api_key (never commit it). See the Bullionwale API documentation. Every request is guarded by an allow-list in the collection pre-request script (needs Postman 10+ / newman 6.1+; older runners ignore skipRequest and would NOT skip): a booking outside the Production folder runs only when env_path is under /api/trading/test/ AND api_key is a bwk_test. key; the Production folder's booking runs only on /api/trading/v1 with a bwk_live. key AND the variable confirm_production_orders set to I-UNDERSTAND-REAL-ORDERS; reads run only when the key's environment matches the folder. Every request, reads included, is also skipped unless base_url is just scheme + host[:port] (an optional trailing slash; no path, query or fragment). The Production 'Place order' sends Idempotency-Key {{prod_idem_key}}: set when empty, kept after a 5xx, a timeout or no response (a resend replays that order), cleared only after 200, 201, 202, 409 (not booking_conflict) or 422.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "apikey",
    "apikey": [
      {
        "key": "key",
        "value": "X-API-Key",
        "type": "string"
      },
      {
        "key": "value",
        "value": "{{api_key}}",
        "type": "string"
      },
      {
        "key": "in",
        "value": "header",
        "type": "string"
      }
    ]
  },
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "type": "text/javascript",
        "exec": [
          "// Allow-list for every request, computed once. A request runs only when its kind is 'yes'.",
          "// Needs Postman 10+ / newman 6.1+ for pm.execution.skipRequest(); older runners ignore it.",
          "var norm = String(pm.variables.get('env_path') || '').trim().toLowerCase().replace(/\\/+$/, '');",
          "var key = String(pm.variables.get('api_key') || '').trim();",
          "var raw = String(pm.variables.get('env_path') || '').toLowerCase();",
          "var traversal = raw.indexOf('..') >= 0 || raw.indexOf('/./') >= 0 || raw.indexOf('%2e') >= 0 || /\\/\\.$/.test(norm) || raw.indexOf('{') >= 0;",
          "// base_url must be scheme + host[:port] only, optional trailing slash: a path, query or",
          "// fragment there (or a nested {{variable}}, or a backslash) could re-point a request at",
          "// another path, e.g. a test request at production orders. Otherwise every flag is 'no'.",
          "var baseOk = /^https?:\\/\\/[^\\/?#\\\\\\s{}]+\\/?$/.test(String(pm.variables.get('base_url') || ''));",
          "var isTestKey = key.indexOf('bwk_test.') === 0;",
          "var isLiveKey = key.indexOf('bwk_live.') === 0;",
          "var isTestPath = norm.indexOf('/api/trading/test/') === 0;",
          "var isProdPath = norm === '/api/trading/v1';",
          "var confirmed = pm.variables.get('confirm_production_orders') === 'I-UNDERSTAND-REAL-ORDERS';",
          "pm.variables.set('__allow_test_book', isTestPath && isTestKey && !traversal && baseOk ? 'yes' : 'no');",
          "pm.variables.set('__allow_test_read', isTestPath && isTestKey && !traversal && baseOk ? 'yes' : 'no');",
          "pm.variables.set('__allow_prod_book', isProdPath && isLiveKey && confirmed && !traversal && baseOk ? 'yes' : 'no');",
          "pm.variables.set('__allow_prod_read', isLiveKey && !traversal && baseOk ? 'yes' : 'no');",
          "// A fresh Idempotency-Key per run for the requests that share {{idem_key}}.",
          "if (!pm.variables.get('idem_key')) { pm.collectionVariables.set('idem_key', pm.variables.replaceIn('{{$guid}}')); }"
        ]
      }
    }
  ],
  "variable": [
    {
      "key": "base_url",
      "value": "https://api.bullionwale.com"
    },
    {
      "key": "api_key",
      "value": ""
    },
    {
      "key": "env_path",
      "value": "/api/trading/test/v1"
    },
    {
      "key": "idem_key",
      "value": ""
    },
    {
      "key": "prod_idem_key",
      "value": ""
    },
    {
      "key": "order_id",
      "value": ""
    },
    {
      "key": "new_api_key",
      "value": ""
    },
    {
      "key": "wrong_env_api_key",
      "value": ""
    },
    {
      "key": "read_only_api_key",
      "value": ""
    }
  ],
  "item": [
    {
      "name": "Test environment",
      "item": [
        {
          "name": "Who am I",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/trading/test/v1/me",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "trading",
                "test",
                "v1",
                "me"
              ]
            }
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'test_read' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_test_read') !== 'yes') { pm.execution.skipRequest(); }"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 200', function () { pm.expect(pm.response.code === 200).to.be.true; });",
                  "pm.test('environment', function () { pm.expect(pm.response.json().environment).to.eql('test'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "Place order",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/trading/test/v1/orders",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "trading",
                "test",
                "v1",
                "orders"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"symbol_code\": \"GOLD_TRADE_999\",\n  \"trade_type\": \"buy\",\n  \"quantity\": 1,\n  \"client_order_id\": \"my-ref-1\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "A simulated order. 201 first time."
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'test_book' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_test_book') !== 'yes') { pm.execution.skipRequest(); }"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 201', function () { pm.expect(pm.response.code === 201).to.be.true; });",
                  "if (pm.response.code < 300) { pm.collectionVariables.set('order_id', pm.response.json().id); }"
                ]
              }
            }
          ]
        },
        {
          "name": "List orders",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/trading/test/v1/orders?limit=20",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "trading",
                "test",
                "v1",
                "orders"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "20"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'test_read' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_test_read') !== 'yes') { pm.execution.skipRequest(); }"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 200', function () { pm.expect(pm.response.code === 200).to.be.true; });"
                ]
              }
            }
          ]
        },
        {
          "name": "Get order",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/trading/test/v1/orders/{{order_id}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "trading",
                "test",
                "v1",
                "orders",
                "{{order_id}}"
              ]
            },
            "description": "Run Place order first (it saves order_id). A pending production order moves to open or rejected."
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'test_read' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_test_read') !== 'yes') { pm.execution.skipRequest(); }"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 200', function () { pm.expect(pm.response.code === 200).to.be.true; });"
                ]
              }
            }
          ]
        },
        {
          "name": "Positions",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/trading/test/v1/positions",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "trading",
                "test",
                "v1",
                "positions"
              ]
            }
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'test_read' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_test_read') !== 'yes') { pm.execution.skipRequest(); }"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 200', function () { pm.expect(pm.response.code === 200).to.be.true; });"
                ]
              }
            }
          ]
        }
      ],
      "description": "Test API only. Every request here runs only with a bwk_test. key and a /api/trading/test/ path; otherwise it is skipped."
    },
    {
      "name": "Production",
      "item": [
        {
          "name": "Who am I",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/trading/v1/me",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "trading",
                "v1",
                "me"
              ]
            }
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'prod_read' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_prod_read') !== 'yes') { pm.execution.skipRequest(); }"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 200', function () { pm.expect(pm.response.code === 200).to.be.true; });",
                  "pm.test('environment', function () { pm.expect(pm.response.json().environment).to.eql('production'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "Place order",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{prod_idem_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/trading/v1/orders",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "trading",
                "v1",
                "orders"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"symbol_code\": \"GOLD_TRADE_999\",\n  \"trade_type\": \"buy\",\n  \"quantity\": 1,\n  \"client_order_id\": \"my-ref-1\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "A REAL market order. 201 open, 202 pending (poll Get order), 409 order_rejected. Needs a production key, the three switches on and orders:write. Idempotency-Key is {{prod_idem_key}}: the pre-request sets it to a fresh id ONLY when it is empty, and the test script clears it ONLY after a definitive answer (200, 201, 202, 409, 422; not 409 booking_conflict, which asks for a same-key retry). After a 5xx, a timeout or no response it is KEPT, so sending again replays the same order (200 + Idempotent-Replayed: true, or its 202/409) instead of booking a second one. Clear prod_idem_key yourself only when you mean a NEW order."
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'prod_book' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_prod_book') !== 'yes') { pm.execution.skipRequest(); }",
                  "// One key per order, kept until a definitive answer (see the test script): a resend",
                  "// after a timeout or a 5xx replays this order instead of booking a second one.",
                  "if (pm.variables.get('__allow_prod_book') === 'yes' && !pm.variables.get('prod_idem_key')) { pm.collectionVariables.set('prod_idem_key', pm.variables.replaceIn('{{$guid}}')); }"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Clear prod_idem_key ONLY on a definitive answer, so the next send is a new order.",
                  "// A 5xx, a timeout or no response keeps it: resend to learn THIS order's outcome.",
                  "var code = pm.response ? pm.response.code : 0;",
                  "// 409 booking_conflict is the one 409 that says 'retry with the same key': kept too.",
                  "var errCode = ''; try { errCode = pm.response.json().detail.code; } catch (e) { errCode = ''; }",
                  "var definitive = [200, 201, 202, 422].indexOf(code) >= 0 || (code === 409 && errCode !== 'booking_conflict');",
                  "if (definitive) { pm.collectionVariables.set('prod_idem_key', ''); }",
                  "pm.test('status is 200, 201 or 202', function () { pm.expect(code === 200 || code === 201 || code === 202).to.be.true; });",
                  "if (code >= 200 && code < 300) { pm.collectionVariables.set('order_id', pm.response.json().id); }"
                ]
              }
            }
          ]
        },
        {
          "name": "List orders",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/trading/v1/orders?limit=20&status=all",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "trading",
                "v1",
                "orders"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "20"
                },
                {
                  "key": "status",
                  "value": "all"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'prod_read' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_prod_read') !== 'yes') { pm.execution.skipRequest(); }"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 200', function () { pm.expect(pm.response.code === 200).to.be.true; });"
                ]
              }
            }
          ]
        },
        {
          "name": "Get order",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/trading/v1/orders/{{order_id}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "trading",
                "v1",
                "orders",
                "{{order_id}}"
              ]
            },
            "description": "Run Place order first (it saves order_id). A pending production order moves to open or rejected."
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'prod_read' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_prod_read') !== 'yes') { pm.execution.skipRequest(); }"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 200', function () { pm.expect(pm.response.code === 200).to.be.true; });"
                ]
              }
            }
          ]
        },
        {
          "name": "Positions",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/trading/v1/positions",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "trading",
                "v1",
                "positions"
              ]
            }
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'prod_read' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_prod_read') !== 'yes') { pm.execution.skipRequest(); }"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 200', function () { pm.expect(pm.response.code === 200).to.be.true; });"
                ]
              }
            }
          ]
        }
      ],
      "description": "Real orders. Reads run only with a bwk_live. key. Place order runs only when env_path is /api/trading/v1, api_key is a bwk_live. key AND you set the variable confirm_production_orders to I-UNDERSTAND-REAL-ORDERS (it is in neither environment file on purpose). Otherwise it is skipped. Needs Postman 10+ / newman 6.1+."
    },
    {
      "name": "Errors",
      "description": "Each request is built to fail with the status and code its test asserts. The one exception, 'Place the order the next request reuses', books a 1 g test order so 'Reused Idempotency-Key' is self-contained. Variables: wrong_env_api_key (a bwk_live. key; it is only ever sent to the TEST API), read_only_api_key (a key without orders:write). Test API only: every request here is guarded by the collection allow-list (bwk_test. key, an env_path under /api/trading/test/ AND a base_url of scheme + host only), otherwise it is SKIPPED, so a run under the production environment or a live key never places an order from this folder. Needs Postman 10+ / newman 6.1+. Use the Production folder for real orders.",
      "item": [
        {
          "name": "No key",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}{{env_path}}/orders",
              "host": [
                "{{base_url}}{{env_path}}"
              ],
              "path": [
                "orders"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"symbol_code\": \"GOLD_TRADE_999\",\n  \"trade_type\": \"buy\",\n  \"quantity\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "auth": {
              "type": "noauth"
            }
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'test_book' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_test_book') !== 'yes') { pm.execution.skipRequest(); }"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 401', function () { pm.expect(pm.response.code === 401).to.be.true; });",
                  "pm.test('error code missing_credential', function () { pm.expect(pm.response.json().detail.code).to.eql('missing_credential'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "Wrong environment",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}{{env_path}}/orders",
              "host": [
                "{{base_url}}{{env_path}}"
              ],
              "path": [
                "orders"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"symbol_code\": \"GOLD_TRADE_999\",\n  \"trade_type\": \"buy\",\n  \"quantity\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{wrong_env_api_key}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            },
            "description": "Set wrong_env_api_key to a production (bwk_live.) key: it is sent to the TEST API, which refuses it 401 wrong_environment. Like every request outside Production it runs only in test mode (bwk_test. api_key, a test env_path and a plain base_url), so it never reaches the production API."
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'test_book' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_test_book') !== 'yes') { pm.execution.skipRequest(); }"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 401', function () { pm.expect(pm.response.code === 401).to.be.true; });",
                  "pm.test('error code wrong_environment', function () { pm.expect(pm.response.json().detail.code).to.eql('wrong_environment'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "Place the order the next request reuses",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{idem_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}{{env_path}}/orders",
              "host": [
                "{{base_url}}{{env_path}}"
              ],
              "path": [
                "orders"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"symbol_code\": \"GOLD_TRADE_999\",\n  \"trade_type\": \"buy\",\n  \"quantity\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Places a 1 g test order under a FRESH {{idem_key}} (set here, every run), so 'Reused Idempotency-Key' below is refused 422 whatever ran before it. Needs at least 1 g of free gold limit on the test book. Skipped on the production API."
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'test_book' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_test_book') !== 'yes') { pm.execution.skipRequest(); }",
                  "// A fresh key every run, so a rerun never collides with an earlier order.",
                  "pm.collectionVariables.set('idem_key', pm.variables.replaceIn('{{$guid}}'));"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 201 or 202 or 200', function () { pm.expect(pm.response.code === 201 || pm.response.code === 202 || pm.response.code === 200).to.be.true; });"
                ]
              }
            }
          ]
        },
        {
          "name": "Reused Idempotency-Key",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{idem_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}{{env_path}}/orders",
              "host": [
                "{{base_url}}{{env_path}}"
              ],
              "path": [
                "orders"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"symbol_code\": \"GOLD_TRADE_999\",\n  \"trade_type\": \"buy\",\n  \"quantity\": 2\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Self-contained: the request before it placed an order with {{idem_key}} and quantity 1; this one sends the same key with quantity 2, so it is refused 422 idempotency_key_reused and nothing is booked. Skipped on the production API."
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'test_book' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_test_book') !== 'yes') { pm.execution.skipRequest(); }"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 422', function () { pm.expect(pm.response.code === 422).to.be.true; });",
                  "pm.test('error code idempotency_key_reused', function () { pm.expect(pm.response.json().detail.code).to.eql('idempotency_key_reused'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "Insufficient scope",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}{{env_path}}/orders",
              "host": [
                "{{base_url}}{{env_path}}"
              ],
              "path": [
                "orders"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"symbol_code\": \"GOLD_TRADE_999\",\n  \"trade_type\": \"buy\",\n  \"quantity\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{read_only_api_key}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'test_book' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_test_book') !== 'yes') { pm.execution.skipRequest(); }"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 403', function () { pm.expect(pm.response.code === 403).to.be.true; });",
                  "pm.test('error code insufficient_scope', function () { pm.expect(pm.response.json().detail.code).to.eql('insufficient_scope'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "Unknown symbol",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}{{env_path}}/orders",
              "host": [
                "{{base_url}}{{env_path}}"
              ],
              "path": [
                "orders"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"symbol_code\": \"NO_SUCH_SYMBOL\",\n  \"trade_type\": \"buy\",\n  \"quantity\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'test_book' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_test_book') !== 'yes') { pm.execution.skipRequest(); }"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 404', function () { pm.expect(pm.response.code === 404).to.be.true; });",
                  "pm.test('error code unknown_symbol', function () { pm.expect(pm.response.json().detail.code).to.eql('unknown_symbol'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "Limit exceeded",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}{{env_path}}/orders",
              "host": [
                "{{base_url}}{{env_path}}"
              ],
              "path": [
                "orders"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"symbol_code\": \"GOLD_TRADE_999\",\n  \"trade_type\": \"buy\",\n  \"quantity\": 1000000\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "quantity 1000000 is the largest the request schema accepts (1,000,000 g = 1,000 kg of gold). No valid quantity can exceed EVERY possible limit (Bullionwale can set a gold limit up to about 10^12 g), so this assumes the test account's free gold limit is below 1,000,000 g — true of any realistic account — and that the trade adds exposure (a buy with no large open sell). The pre-trade rules may answer first with another 400 (e.g. quantity_rule). Skipped on the production API."
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'test_book' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_test_book') !== 'yes') { pm.execution.skipRequest(); }"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 400', function () { pm.expect(pm.response.code === 400).to.be.true; });",
                  "pm.test('error code limit_exceeded', function () { pm.expect(pm.response.json().detail.code).to.eql('limit_exceeded'); });"
                ]
              }
            }
          ]
        },
        {
          "name": "Missing Idempotency-Key",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}{{env_path}}/orders",
              "host": [
                "{{base_url}}{{env_path}}"
              ],
              "path": [
                "orders"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"symbol_code\": \"GOLD_TRADE_999\",\n  \"trade_type\": \"buy\",\n  \"quantity\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'test_book' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_test_book') !== 'yes') { pm.execution.skipRequest(); }"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 400', function () { pm.expect(pm.response.code === 400).to.be.true; });",
                  "pm.test('error code idempotency_key_required', function () { pm.expect(pm.response.json().detail.code).to.eql('idempotency_key_required'); });"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Limits",
      "item": [
        {
          "name": "Burst runner note",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}{{env_path}}/me",
              "host": [
                "{{base_url}}{{env_path}}"
              ],
              "path": [
                "me"
              ]
            },
            "description": "To see the order limits, run the folder's 'Rate limit example' with the Collection Runner: iterations 80, delay 0. Each key has a 10 s burst budget and a per-minute budget, and in production the account has its own per-minute budget shared by all its keys. Over budget answers 429 rate_limited with a Retry-After header. Reads have a separate, larger budget."
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'test_read' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_test_read') !== 'yes') { pm.execution.skipRequest(); }"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 200', function () { pm.expect(pm.response.code === 200).to.be.true; });"
                ]
              }
            }
          ]
        },
        {
          "name": "Rate limit example",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}{{env_path}}/orders",
              "host": [
                "{{base_url}}{{env_path}}"
              ],
              "path": [
                "orders"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"symbol_code\": \"GOLD_TRADE_999\",\n  \"trade_type\": \"buy\",\n  \"quantity\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Use with the Runner against the TEST API. A 429 carries Retry-After (seconds). Skipped on the production API, where it would place a real order per iteration."
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'test_book' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_test_book') !== 'yes') { pm.execution.skipRequest(); }"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 201 or 202 or 200 or 429 or 400 or 403 or 409', function () { pm.expect(pm.response.code === 201 || pm.response.code === 202 || pm.response.code === 200 || pm.response.code === 429 || pm.response.code === 400 || pm.response.code === 403 || pm.response.code === 409).to.be.true; });",
                  "if (pm.response.code === 429) { pm.test('Retry-After present', function () { pm.expect(pm.response.headers.has('Retry-After')).to.be.true; }); }"
                ]
              }
            }
          ]
        }
      ],
      "description": "Test API only: every request here is guarded by the collection allow-list (bwk_test. key, an env_path under /api/trading/test/ AND a base_url of scheme + host only), otherwise it is SKIPPED, so a run under the production environment or a live key never places an order from this folder. Needs Postman 10+ / newman 6.1+. Use the Production folder for real orders."
    },
    {
      "name": "Rotation",
      "description": "Overlap: after Bullionwale rotates a key, the old key keeps working for the overlap period, so both are valid. Idempotency is per ACCOUNT, so a retry sent with the new key replays the order the old key placed. Test API only: every request here is guarded by the collection allow-list (bwk_test. key, an env_path under /api/trading/test/ AND a base_url of scheme + host only), otherwise it is SKIPPED, so a run under the production environment or a live key never places an order from this folder. Needs Postman 10+ / newman 6.1+. Use the Production folder for real orders.",
      "item": [
        {
          "name": "Replay with the same key",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{idem_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}{{env_path}}/orders",
              "host": [
                "{{base_url}}{{env_path}}"
              ],
              "path": [
                "orders"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"symbol_code\": \"GOLD_TRADE_999\",\n  \"trade_type\": \"buy\",\n  \"quantity\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Send twice. The second answer is 200 with Idempotent-Replayed: true. Skipped on the production API."
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'test_book' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_test_book') !== 'yes') { pm.execution.skipRequest(); }"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 200 or 201 or 202', function () { pm.expect(pm.response.code === 200 || pm.response.code === 201 || pm.response.code === 202).to.be.true; });"
                ]
              }
            }
          ]
        },
        {
          "name": "1. Place with the old key",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{idem_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}{{env_path}}/orders",
              "host": [
                "{{base_url}}{{env_path}}"
              ],
              "path": [
                "orders"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"symbol_code\": \"GOLD_TRADE_999\",\n  \"trade_type\": \"buy\",\n  \"quantity\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Set api_key to the OLD key. {{idem_key}} is filled with a fresh value per run; set it yourself to replay a specific earlier order. Skipped on the production API."
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'test_book' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_test_book') !== 'yes') { pm.execution.skipRequest(); }"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 201 or 202 or 200', function () { pm.expect(pm.response.code === 201 || pm.response.code === 202 || pm.response.code === 200).to.be.true; });"
                ]
              }
            }
          ]
        },
        {
          "name": "2. Replay with the new key",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{idem_key}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}{{env_path}}/orders",
              "host": [
                "{{base_url}}{{env_path}}"
              ],
              "path": [
                "orders"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"symbol_code\": \"GOLD_TRADE_999\",\n  \"trade_type\": \"buy\",\n  \"quantity\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{new_api_key}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            },
            "description": "Set new_api_key to the rotated key. Same Idempotency-Key and same body: 200 with Idempotent-Replayed: true, nothing booked twice. Skipped on the production API."
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Guard: runs only when the 'test_book' allow-list in the collection pre-request says yes.",
                  "if (pm.variables.get('__allow_test_book') !== 'yes') { pm.execution.skipRequest(); }"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status is 200', function () { pm.expect(pm.response.code === 200).to.be.true; });",
                  "pm.test('replay header', function () { pm.expect(pm.response.headers.get('Idempotent-Replayed')).to.eql('true'); });"
                ]
              }
            }
          ]
        }
      ]
    }
  ]
}
