{
  "info": {
    "_postman_id": "47054592-f2c7-4eef-9147-1a8845780caf",
    "name": "SwApp API - Mobile Money and Float",
    "description": "Import this collection to test the SwApp APIs. Set the collection variables first, run the token request for the folder you want to test, then run the remaining requests. The requests follow the OpenAPI contracts served by the website.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "item": [
    {
      "name": "Mobile Money",
      "description": "Mobile money token, validation, collections, payouts, status, balance, flat, MoMo, and bulk validation APIs.",
      "auth": {
        "type": "bearer",
        "bearer": [
          {
            "key": "token",
            "value": "{{mobile_money_access_token}}",
            "type": "string"
          }
        ]
      },
      "item": [
        {
          "name": "Create Mobile Money Token",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Swapp-Client-ID",
                "value": "{{client_id}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/mobile-money/token",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "mobile-money",
                "token"
              ]
            },
            "description": "Creates a bearer token for mobile money requests. Fill api_key, api_secret, and client_id before running.",
            "auth": {
              "type": "basic",
              "basic": [
                {
                  "key": "username",
                  "value": "{{api_key}}",
                  "type": "string"
                },
                {
                  "key": "password",
                  "value": "{{api_secret}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [

          ],
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Status code is documented\", function () {",
                  "  pm.expect([200, 202, 400, 401, 403, 404, 408, 409, 412, 429]).to.include(pm.response.code);",
                  "});",
                  "",
                  "pm.test(\"Response is JSON\", function () {",
                  "  pm.response.to.have.header(\"Content-Type\");",
                  "  pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(\"application/json\");",
                  "});",
                  "",
                  "var json = {};",
                  "try { json = pm.response.json(); } catch (e) {}",
                  "",
                  "pm.test(\"Response envelope has numeric code and status\", function () {",
                  "  pm.expect(json).to.have.property(\"code\");",
                  "  pm.expect(json.code).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"status\");",
                  "  pm.expect(json.status).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"message\");",
                  "});",
                  "if (pm.response.code === 200 && json.data && json.data.accessToken) {",
                  "  pm.collectionVariables.set(\"mobile_money_access_token\", json.data.accessToken);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Validate Mobile Money Account",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Swapp-Client-ID",
                "value": "{{client_id}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/mobile-money/accounts/validate",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "mobile-money",
                "accounts",
                "validate"
              ]
            },
            "description": "Validates a customer or payee mobile money account before collection or payout.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{mobile_money_access_token}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"account\": \"{{customer_account}}\",\n  \"amount\": {{amount}},\n  \"type\": \"collect\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [

          ],
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Status code is documented\", function () {",
                  "  pm.expect([200, 202, 400, 401, 403, 404, 408, 409, 412, 429]).to.include(pm.response.code);",
                  "});",
                  "",
                  "pm.test(\"Response is JSON\", function () {",
                  "  pm.response.to.have.header(\"Content-Type\");",
                  "  pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(\"application/json\");",
                  "});",
                  "",
                  "var json = {};",
                  "try { json = pm.response.json(); } catch (e) {}",
                  "",
                  "pm.test(\"Response envelope has numeric code and status\", function () {",
                  "  pm.expect(json).to.have.property(\"code\");",
                  "  pm.expect(json.code).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"status\");",
                  "  pm.expect(json.status).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"message\");",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "Create Mobile Money Collection",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Swapp-Client-ID",
                "value": "{{client_id}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/mobile-money/collections",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "mobile-money",
                "collections"
              ]
            },
            "description": "Collects funds from a customer mobile money account.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{mobile_money_access_token}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"account\": \"{{customer_account}}\",\n  \"amount\": {{amount}},\n  \"requestId\": \"{{request_id}}\",\n  \"callback_url\": \"{{callback_url}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [

          ],
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if (pm.collectionVariables.get(\"reuse_request_id\") !== \"true\") {",
                  "  pm.collectionVariables.set(\"request_id\", crypto.randomUUID());",
                  "  pm.collectionVariables.set(\"bank_reference\", \"BANK-\" + Date.now());",
                  "}",
                  "pm.collectionVariables.set(\"swapp_timestamp\", Math.floor(Date.now() / 1000).toString());",
                  "pm.collectionVariables.set(\"swapp_nonce\", crypto.randomUUID().replace(/-/g, \"\"));"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Status code is documented\", function () {",
                  "  pm.expect([200, 202, 400, 401, 403, 404, 408, 409, 412, 429]).to.include(pm.response.code);",
                  "});",
                  "",
                  "pm.test(\"Response is JSON\", function () {",
                  "  pm.response.to.have.header(\"Content-Type\");",
                  "  pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(\"application/json\");",
                  "});",
                  "",
                  "var json = {};",
                  "try { json = pm.response.json(); } catch (e) {}",
                  "",
                  "pm.test(\"Response envelope has numeric code and status\", function () {",
                  "  pm.expect(json).to.have.property(\"code\");",
                  "  pm.expect(json.code).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"status\");",
                  "  pm.expect(json.status).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"message\");",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "Create Mobile Money Payout",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Swapp-Client-ID",
                "value": "{{client_id}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/mobile-money/payouts",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "mobile-money",
                "payouts"
              ]
            },
            "description": "Sends funds to a customer mobile money account.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{mobile_money_access_token}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"account\": \"{{customer_account}}\",\n  \"amount\": {{amount}},\n  \"requestId\": \"{{request_id}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [

          ],
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if (pm.collectionVariables.get(\"reuse_request_id\") !== \"true\") {",
                  "  pm.collectionVariables.set(\"request_id\", crypto.randomUUID());",
                  "  pm.collectionVariables.set(\"bank_reference\", \"BANK-\" + Date.now());",
                  "}",
                  "pm.collectionVariables.set(\"swapp_timestamp\", Math.floor(Date.now() / 1000).toString());",
                  "pm.collectionVariables.set(\"swapp_nonce\", crypto.randomUUID().replace(/-/g, \"\"));"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Status code is documented\", function () {",
                  "  pm.expect([200, 202, 400, 401, 403, 404, 408, 409, 412, 429]).to.include(pm.response.code);",
                  "});",
                  "",
                  "pm.test(\"Response is JSON\", function () {",
                  "  pm.response.to.have.header(\"Content-Type\");",
                  "  pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(\"application/json\");",
                  "});",
                  "",
                  "var json = {};",
                  "try { json = pm.response.json(); } catch (e) {}",
                  "",
                  "pm.test(\"Response envelope has numeric code and status\", function () {",
                  "  pm.expect(json).to.have.property(\"code\");",
                  "  pm.expect(json.code).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"status\");",
                  "  pm.expect(json.status).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"message\");",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "Validate Flat Mobile Money Account",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Swapp-Client-ID",
                "value": "{{client_id}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/mobile-money/flat/accounts/validate",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "mobile-money",
                "flat",
                "accounts",
                "validate"
              ]
            },
            "description": "Validates a flat mobile money account with an amount.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{mobile_money_access_token}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"account\": \"{{customer_account}}\",\n  \"amount\": {{amount}},\n  \"type\": \"payout\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [

          ],
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Status code is documented\", function () {",
                  "  pm.expect([200, 202, 400, 401, 403, 404, 408, 409, 412, 429]).to.include(pm.response.code);",
                  "});",
                  "",
                  "pm.test(\"Response is JSON\", function () {",
                  "  pm.response.to.have.header(\"Content-Type\");",
                  "  pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(\"application/json\");",
                  "});",
                  "",
                  "var json = {};",
                  "try { json = pm.response.json(); } catch (e) {}",
                  "",
                  "pm.test(\"Response envelope has numeric code and status\", function () {",
                  "  pm.expect(json).to.have.property(\"code\");",
                  "  pm.expect(json.code).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"status\");",
                  "  pm.expect(json.status).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"message\");",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "Create Flat Mobile Money Payout",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Swapp-Client-ID",
                "value": "{{client_id}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/mobile-money/flat/payouts",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "mobile-money",
                "flat",
                "payouts"
              ]
            },
            "description": "Creates a flat mobile money payout.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{mobile_money_access_token}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"account\": \"{{customer_account}}\",\n  \"amount\": {{amount}},\n  \"requestId\": \"{{request_id}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [

          ],
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.collectionVariables.set(\"request_id\", crypto.randomUUID());",
                  "pm.collectionVariables.set(\"bank_reference\", \"BANK-\" + Date.now());",
                  "pm.collectionVariables.set(\"swapp_timestamp\", Math.floor(Date.now() / 1000).toString());",
                  "pm.collectionVariables.set(\"swapp_nonce\", crypto.randomUUID().replace(/-/g, \"\"));"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Status code is documented\", function () {",
                  "  pm.expect([200, 202, 400, 401, 403, 404, 408, 409, 412, 429]).to.include(pm.response.code);",
                  "});",
                  "",
                  "pm.test(\"Response is JSON\", function () {",
                  "  pm.response.to.have.header(\"Content-Type\");",
                  "  pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(\"application/json\");",
                  "});",
                  "",
                  "var json = {};",
                  "try { json = pm.response.json(); } catch (e) {}",
                  "",
                  "pm.test(\"Response envelope has numeric code and status\", function () {",
                  "  pm.expect(json).to.have.property(\"code\");",
                  "  pm.expect(json.code).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"status\");",
                  "  pm.expect(json.status).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"message\");",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "Validate MoMo Account",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Swapp-Client-ID",
                "value": "{{client_id}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/mobile-money/momo/accounts/validate",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "mobile-money",
                "momo",
                "accounts",
                "validate"
              ]
            },
            "description": "Validates a MoMo account with an amount.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{mobile_money_access_token}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"account\": \"{{customer_account}}\",\n  \"amount\": {{amount}},\n  \"type\": \"deposit\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [

          ],
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Status code is documented\", function () {",
                  "  pm.expect([200, 202, 400, 401, 403, 404, 408, 409, 412, 429]).to.include(pm.response.code);",
                  "});",
                  "",
                  "pm.test(\"Response is JSON\", function () {",
                  "  pm.response.to.have.header(\"Content-Type\");",
                  "  pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(\"application/json\");",
                  "});",
                  "",
                  "var json = {};",
                  "try { json = pm.response.json(); } catch (e) {}",
                  "",
                  "pm.test(\"Response envelope has numeric code and status\", function () {",
                  "  pm.expect(json).to.have.property(\"code\");",
                  "  pm.expect(json.code).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"status\");",
                  "  pm.expect(json.status).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"message\");",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "Create MoMo Deposit",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Swapp-Client-ID",
                "value": "{{client_id}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/mobile-money/momo/deposits",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "mobile-money",
                "momo",
                "deposits"
              ]
            },
            "description": "Creates a MoMo deposit request.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{mobile_money_access_token}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"account\": \"{{customer_account}}\",\n  \"amount\": {{amount}},\n  \"requestId\": \"{{request_id}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [

          ],
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.collectionVariables.set(\"request_id\", crypto.randomUUID());",
                  "pm.collectionVariables.set(\"bank_reference\", \"BANK-\" + Date.now());",
                  "pm.collectionVariables.set(\"swapp_timestamp\", Math.floor(Date.now() / 1000).toString());",
                  "pm.collectionVariables.set(\"swapp_nonce\", crypto.randomUUID().replace(/-/g, \"\"));"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Status code is documented\", function () {",
                  "  pm.expect([200, 202, 400, 401, 403, 404, 408, 409, 412, 429]).to.include(pm.response.code);",
                  "});",
                  "",
                  "pm.test(\"Response is JSON\", function () {",
                  "  pm.response.to.have.header(\"Content-Type\");",
                  "  pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(\"application/json\");",
                  "});",
                  "",
                  "var json = {};",
                  "try { json = pm.response.json(); } catch (e) {}",
                  "",
                  "pm.test(\"Response envelope has numeric code and status\", function () {",
                  "  pm.expect(json).to.have.property(\"code\");",
                  "  pm.expect(json.code).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"status\");",
                  "  pm.expect(json.status).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"message\");",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "Get Mobile Money Balance",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Swapp-Client-ID",
                "value": "{{client_id}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/mobile-money/balance",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "mobile-money",
                "balance"
              ]
            },
            "description": "Returns the API client mobile money balance.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{mobile_money_access_token}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [

          ],
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Status code is documented\", function () {",
                  "  pm.expect([200, 202, 400, 401, 403, 404, 408, 409, 412, 429]).to.include(pm.response.code);",
                  "});",
                  "",
                  "pm.test(\"Response is JSON\", function () {",
                  "  pm.response.to.have.header(\"Content-Type\");",
                  "  pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(\"application/json\");",
                  "});",
                  "",
                  "var json = {};",
                  "try { json = pm.response.json(); } catch (e) {}",
                  "",
                  "pm.test(\"Response envelope has numeric code and status\", function () {",
                  "  pm.expect(json).to.have.property(\"code\");",
                  "  pm.expect(json.code).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"status\");",
                  "  pm.expect(json.status).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"message\");",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "Get Mobile Money Status",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Swapp-Client-ID",
                "value": "{{client_id}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/mobile-money/status",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "mobile-money",
                "status"
              ]
            },
            "description": "Checks a mobile money transaction by requestId.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{mobile_money_access_token}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"requestId\": \"{{request_id}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [

          ],
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Status code is documented\", function () {",
                  "  pm.expect([200, 202, 400, 401, 403, 404, 408, 409, 412, 429]).to.include(pm.response.code);",
                  "});",
                  "",
                  "pm.test(\"Response is JSON\", function () {",
                  "  pm.response.to.have.header(\"Content-Type\");",
                  "  pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(\"application/json\");",
                  "});",
                  "",
                  "var json = {};",
                  "try { json = pm.response.json(); } catch (e) {}",
                  "",
                  "pm.test(\"Response envelope has numeric code and status\", function () {",
                  "  pm.expect(json).to.have.property(\"code\");",
                  "  pm.expect(json.code).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"status\");",
                  "  pm.expect(json.status).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"message\");",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "Bulk Validate Mobile Money Accounts",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Swapp-Client-ID",
                "value": "{{client_id}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/mobile-money/bulk/accounts/validate",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "mobile-money",
                "bulk",
                "accounts",
                "validate"
              ]
            },
            "description": "Validates multiple mobile money accounts using the cleaned request body.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{mobile_money_access_token}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"accounts\": [\n    \"{{customer_account}}\",\n    \"{{second_customer_account}}\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [

          ],
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Status code is documented\", function () {",
                  "  pm.expect([200, 202, 400, 401, 403, 404, 408, 409, 412, 429]).to.include(pm.response.code);",
                  "});",
                  "",
                  "pm.test(\"Response is JSON\", function () {",
                  "  pm.response.to.have.header(\"Content-Type\");",
                  "  pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(\"application/json\");",
                  "});",
                  "",
                  "var json = {};",
                  "try { json = pm.response.json(); } catch (e) {}",
                  "",
                  "pm.test(\"Response envelope has numeric code and status\", function () {",
                  "  pm.expect(json).to.have.property(\"code\");",
                  "  pm.expect(json.code).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"status\");",
                  "  pm.expect(json.status).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"message\");",
                  "});"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Float",
      "description": "Agent float token, validation, top-up, withdrawal, and status APIs.",
      "auth": {
        "type": "bearer",
        "bearer": [
          {
            "key": "token",
            "value": "{{float_access_token}}",
            "type": "string"
          }
        ]
      },
      "item": [
        {
          "name": "Create Float Token",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Swapp-Client-ID",
                "value": "{{client_id}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/float/token",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "float",
                "token"
              ]
            },
            "description": "Creates a bearer token for float requests. Fill api_key, api_secret, and client_id before running.",
            "auth": {
              "type": "basic",
              "basic": [
                {
                  "key": "username",
                  "value": "{{api_key}}",
                  "type": "string"
                },
                {
                  "key": "password",
                  "value": "{{api_secret}}",
                  "type": "string"
                }
              ]
            }
          },
          "response": [

          ],
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Status code is documented\", function () {",
                  "  pm.expect([200, 202, 400, 401, 403, 404, 408, 409, 412, 429]).to.include(pm.response.code);",
                  "});",
                  "",
                  "pm.test(\"Response is JSON\", function () {",
                  "  pm.response.to.have.header(\"Content-Type\");",
                  "  pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(\"application/json\");",
                  "});",
                  "",
                  "var json = {};",
                  "try { json = pm.response.json(); } catch (e) {}",
                  "",
                  "pm.test(\"Response envelope has numeric code and status\", function () {",
                  "  pm.expect(json).to.have.property(\"code\");",
                  "  pm.expect(json.code).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"status\");",
                  "  pm.expect(json.status).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"message\");",
                  "});",
                  "if (pm.response.code === 200 && json.data && json.data.accessToken) {",
                  "  pm.collectionVariables.set(\"float_access_token\", json.data.accessToken);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Validate Agent Float Top-up",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Swapp-Client-ID",
                "value": "{{client_id}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/float/agents/validate",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "float",
                "agents",
                "validate"
              ]
            },
            "description": "Validates an active SwApp agent account.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{float_access_token}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"agentNumber\": \"{{agent_number}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [

          ],
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Status code is documented\", function () {",
                  "  pm.expect([200, 202, 400, 401, 403, 404, 408, 409, 412, 429]).to.include(pm.response.code);",
                  "});",
                  "",
                  "pm.test(\"Response is JSON\", function () {",
                  "  pm.response.to.have.header(\"Content-Type\");",
                  "  pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(\"application/json\");",
                  "});",
                  "",
                  "var json = {};",
                  "try { json = pm.response.json(); } catch (e) {}",
                  "",
                  "pm.test(\"Response envelope has numeric code and status\", function () {",
                  "  pm.expect(json).to.have.property(\"code\");",
                  "  pm.expect(json.code).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"status\");",
                  "  pm.expect(json.status).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"message\");",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "Create Agent Float Top-Up",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Swapp-Client-ID",
                "value": "{{client_id}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/float/top-ups",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "float",
                "top-ups"
              ]
            },
            "description": "Credits agent float after a bank-side deposit. The pre-request script creates the Swapp-Transaction value and an RFC 9421 ECDSA P-256 signature. Set signature_key_id and the local-only signature_private_key variable before sending this request.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{float_access_token}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"agentNumber\": \"{{agent_number}}\",\n  \"amount\": {{amount}},\n  \"requestId\": \"{{request_id}}\",\n  \"bankReference\": \"{{bank_reference}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [

          ],
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if (pm.collectionVariables.get(\"reuse_request_id\") !== \"true\") {",
                  "  pm.collectionVariables.set(\"request_id\", crypto.randomUUID());",
                  "  pm.collectionVariables.set(\"bank_reference\", \"BANK-\" + Date.now());",
                  "}",
                  "const signatureHeaders = [\"Swapp-Transaction\", \"Signature-Input\", \"Signature\"];",
                  "signatureHeaders.forEach(function (name) { pm.request.headers.remove(name); });",
                  "const clientId = String(pm.collectionVariables.get(\"client_id\") || \"\").trim();",
                  "const keyId = String(pm.variables.get(\"signature_key_id\") || \"\").trim();",
                  "const privateKeyPem = String(pm.variables.get(\"signature_private_key\") || \"\").replace(/\\\\n/g, \"\\n\").trim();",
                  "if (!clientId || !keyId || !privateKeyPem) { throw new Error(\"client_id, signature_key_id, and signature_private_key are required\"); }",
                  "if (!privateKeyPem.includes(\"BEGIN PRIVATE KEY\")) { throw new Error(\"signature_private_key must be an unencrypted PKCS#8 PEM key\"); }",
                  "const created = Math.floor(Date.now() / 1000);",
                  "const expires = created + Number(pm.collectionVariables.get(\"signature_duration_seconds\") || 300);",
                  "const nonce = crypto.randomUUID();",
                  "const bodyText = pm.variables.replaceIn(pm.request.body.raw || \"\");",
                  "pm.request.body.raw = bodyText;",
                  "const body = JSON.parse(bodyText);",
                  "const amount = Number(body.amount);",
                  "if (!Number.isSafeInteger(amount) || amount <= 0) { throw new Error(\"amount must be a positive integer\"); }",
                  "function encodeComponent(value) {",
                  "  return encodeURIComponent(String(value).trim()).replace(/[!'()*]/g, function (character) {",
                  "    return \"%\" + character.charCodeAt(0).toString(16).toUpperCase();",
                  "  });",
                  "}",
                  "const transaction = [",
                  "  \"agent-id=\" + encodeComponent(body.agentNumber),",
                  "  \"amount=\" + String(amount),",
                  "  \"request-id=\" + encodeComponent(body.requestId),",
                  "  \"bank-reference=\" + encodeComponent(body.bankReference)",
                  "].join(\",\");",
                  "const baseUrl = pm.variables.replaceIn(String(pm.collectionVariables.get(\"base_url\") || \"\")).replace(/\\/+$/, \"\");",
                  "const withoutScheme = baseUrl.replace(/^[a-z][a-z0-9+.-]*:\\/\\//i, \"\");",
                  "const firstSlash = withoutScheme.indexOf(\"/\");",
                  "const authority = (firstSlash === -1 ? withoutScheme : withoutScheme.slice(0, firstSlash)).toLowerCase();",
                  "const basePath = firstSlash === -1 ? \"\" : withoutScheme.slice(firstSlash);",
                  "const path = (basePath + \"/float/top-ups\").replace(/\\/{2,}/g, \"/\");",
                  "const components = \"(\\\"@method\\\" \\\"@authority\\\" \\\"@path\\\" \\\"swapp-client-id\\\" \\\"swapp-transaction\\\")\";",
                  "const parameters = components + \";created=\" + created + \";expires=\" + expires + \";nonce=\\\"\" + nonce + \"\\\";keyid=\\\"\" + keyId + \"\\\";alg=\\\"ecdsa-p256-sha256\\\"\";",
                  "const signatureBase = [",
                  "  \"\\\"@method\\\": \" + pm.request.method.toUpperCase(),",
                  "  \"\\\"@authority\\\": \" + authority,",
                  "  \"\\\"@path\\\": \" + path,",
                  "  \"\\\"swapp-client-id\\\": \" + clientId,",
                  "  \"\\\"swapp-transaction\\\": \" + transaction,",
                  "  \"\\\"@signature-params\\\": \" + parameters",
                  "].join(\"\\n\");",
                  "const pemBody = privateKeyPem.replace(/-----BEGIN PRIVATE KEY-----|-----END PRIVATE KEY-----|\\s/g, \"\");",
                  "const keyBytes = Uint8Array.from(atob(pemBody), function (character) { return character.charCodeAt(0); });",
                  "const privateKey = await crypto.subtle.importKey(\"pkcs8\", keyBytes, { name: \"ECDSA\", namedCurve: \"P-256\" }, false, [\"sign\"]);",
                  "const signatureBytes = new Uint8Array(await crypto.subtle.sign({ name: \"ECDSA\", hash: \"SHA-256\" }, privateKey, new TextEncoder().encode(signatureBase)));",
                  "if (signatureBytes.length !== 64) { throw new Error(\"Postman did not produce the required 64-byte ECDSA signature\"); }",
                  "let signatureBinary = \"\";",
                  "signatureBytes.forEach(function (value) { signatureBinary += String.fromCharCode(value); });",
                  "const signature = btoa(signatureBinary);",
                  "pm.request.headers.upsert({ key: \"Swapp-Transaction\", value: transaction });",
                  "pm.request.headers.upsert({ key: \"Signature-Input\", value: \"swapp=\" + parameters });",
                  "pm.request.headers.upsert({ key: \"Signature\", value: \"swapp=:\" + signature + \":\" });"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Status code is documented\", function () {",
                  "  pm.expect([200, 202, 400, 401, 403, 404, 408, 409, 412, 429]).to.include(pm.response.code);",
                  "});",
                  "",
                  "pm.test(\"Response is JSON\", function () {",
                  "  pm.response.to.have.header(\"Content-Type\");",
                  "  pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(\"application/json\");",
                  "});",
                  "",
                  "var json = {};",
                  "try { json = pm.response.json(); } catch (e) {}",
                  "",
                  "pm.test(\"Response envelope has numeric code and status\", function () {",
                  "  pm.expect(json).to.have.property(\"code\");",
                  "  pm.expect(json.code).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"status\");",
                  "  pm.expect(json.status).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"message\");",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "Validate Float Withdrawal",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Swapp-Client-ID",
                "value": "{{client_id}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/float/withdrawals/validate",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "float",
                "withdrawals",
                "validate"
              ]
            },
            "description": "Validates an agent withdrawal request before app approval is created.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{float_access_token}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"agentNumber\": \"{{agent_number}}\",\n  \"amount\": {{amount}},\n  \"channel\": \"{{channel}}\",\n  \"wallet\": \"{{wallet}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [

          ],
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Status code is documented\", function () {",
                  "  pm.expect([200, 202, 400, 401, 403, 404, 408, 409, 412, 429]).to.include(pm.response.code);",
                  "});",
                  "",
                  "pm.test(\"Response is JSON\", function () {",
                  "  pm.response.to.have.header(\"Content-Type\");",
                  "  pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(\"application/json\");",
                  "});",
                  "",
                  "var json = {};",
                  "try { json = pm.response.json(); } catch (e) {}",
                  "",
                  "pm.test(\"Response envelope has numeric code and status\", function () {",
                  "  pm.expect(json).to.have.property(\"code\");",
                  "  pm.expect(json.code).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"status\");",
                  "  pm.expect(json.status).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"message\");",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "Create Float Withdrawal",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Swapp-Client-ID",
                "value": "{{client_id}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/float/withdrawals",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "float",
                "withdrawals"
              ]
            },
            "description": "Creates an agent withdrawal request requiring app approval.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{float_access_token}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"agentNumber\": \"{{agent_number}}\",\n  \"amount\": {{amount}},\n  \"requestId\": \"{{request_id}}\",\n  \"channel\": \"{{channel}}\",\n  \"reference\": \"{{bank_reference}}\",\n  \"narration\": \"Float withdrawal test\",\n  \"timeout\": 60,\n  \"wallet\": \"{{wallet}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [

          ],
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.collectionVariables.set(\"request_id\", crypto.randomUUID());",
                  "pm.collectionVariables.set(\"bank_reference\", \"BANK-\" + Date.now());",
                  "pm.collectionVariables.set(\"swapp_timestamp\", Math.floor(Date.now() / 1000).toString());",
                  "pm.collectionVariables.set(\"swapp_nonce\", crypto.randomUUID().replace(/-/g, \"\"));"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Status code is documented\", function () {",
                  "  pm.expect([200, 202, 400, 401, 403, 404, 408, 409, 412, 429]).to.include(pm.response.code);",
                  "});",
                  "",
                  "pm.test(\"Response is JSON\", function () {",
                  "  pm.response.to.have.header(\"Content-Type\");",
                  "  pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(\"application/json\");",
                  "});",
                  "",
                  "var json = {};",
                  "try { json = pm.response.json(); } catch (e) {}",
                  "",
                  "pm.test(\"Response envelope has numeric code and status\", function () {",
                  "  pm.expect(json).to.have.property(\"code\");",
                  "  pm.expect(json.code).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"status\");",
                  "  pm.expect(json.status).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"message\");",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "Get Float Status",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Swapp-Client-ID",
                "value": "{{client_id}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/float/status",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "float",
                "status"
              ]
            },
            "description": "Checks float top-up or withdrawal status by requestId.",
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{float_access_token}}",
                  "type": "string"
                }
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"requestId\": \"{{request_id}}\",\n  \"agentNumber\": \"{{agent_number}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [

          ],
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"Status code is documented\", function () {",
                  "  pm.expect([200, 202, 400, 401, 403, 404, 408, 409, 412, 429]).to.include(pm.response.code);",
                  "});",
                  "",
                  "pm.test(\"Response is JSON\", function () {",
                  "  pm.response.to.have.header(\"Content-Type\");",
                  "  pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(\"application/json\");",
                  "});",
                  "",
                  "var json = {};",
                  "try { json = pm.response.json(); } catch (e) {}",
                  "",
                  "pm.test(\"Response envelope has numeric code and status\", function () {",
                  "  pm.expect(json).to.have.property(\"code\");",
                  "  pm.expect(json.code).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"status\");",
                  "  pm.expect(json.status).to.be.a(\"number\");",
                  "  pm.expect(json).to.have.property(\"message\");",
                  "});"
                ]
              }
            }
          ]
        }
      ]
    }
  ],
  "variable": [
    {
      "key": "base_url",
      "value": "https://swapp.co.ug/apitest/v2",
      "type": "string"
    },
    {
      "key": "client_id",
      "value": "",
      "type": "string"
    },
    {
      "key": "api_key",
      "value": "",
      "type": "string"
    },
    {
      "key": "api_secret",
      "value": "",
      "type": "string"
    },
    {
      "key": "mobile_money_access_token",
      "value": "",
      "type": "string"
    },
    {
      "key": "float_access_token",
      "value": "",
      "type": "string"
    },
    {
      "key": "customer_account",
      "value": "772112233",
      "type": "string"
    },
    {
      "key": "second_customer_account",
      "value": "772112234",
      "type": "string"
    },
    {
      "key": "agent_number",
      "value": "37291",
      "type": "string"
    },
    {
      "key": "amount",
      "value": "5000",
      "type": "string"
    },
    {
      "key": "callback_url",
      "value": "https://example.com/swapp/callback",
      "type": "string"
    },
    {
      "key": "request_id",
      "value": "d96dec4b-8a9f-4640-8249-fa140ec02c7f",
      "type": "string"
    },
    {
      "key": "bank_reference",
      "value": "BANK-TEST-001",
      "type": "string"
    },
    {
      "key": "reuse_request_id",
      "value": "false",
      "type": "string"
    },
    {
      "key": "channel",
      "value": "mtn",
      "type": "string"
    },
    {
      "key": "wallet",
      "value": "mtn_wallet",
      "type": "string"
    },
    {
      "key": "signature_key_id",
      "value": "",
      "type": "string"
    },
    {
      "key": "signature_private_key",
      "value": "",
      "type": "string"
    },
    {
      "key": "signature_duration_seconds",
      "value": "300",
      "type": "string"
    }
  ]
}
