{
  "info": {
    "name": "OlympusPay — Africa's Talking",
    "description": "Africa's Talking API calls routed through OlympusPay Supabase edge functions.\nAll outbound functions require a valid USER_ACCESS_TOKEN (obtain via the OlympusPay Auth/Login request).\nThe USSD endpoint is called by Africa's Talking servers — test it manually using the AT USSD Simulator.\n\nSetup:\n1. Import OlympusPay.postman_environment.json and fill AT_* variables.\n2. Run Auth/Login from the main collection first to populate USER_ACCESS_TOKEN.\n3. Set AT_PHONE_NUMBER to a valid test number in international format.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [{ "key": "token", "value": "{{USER_ACCESS_TOKEN}}", "type": "string" }]
  },
  "item": [
    {
      "name": "SMS",
      "item": [
        {
          "name": "Send SMS (single)",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test('Status 200', () => pm.response.to.have.status(200));",
                  "pm.test('Has recipients', () => {",
                  "  const json = pm.response.json();",
                  "  pm.expect(json.recipients).to.be.an('array');",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"to\": \"{{AT_PHONE_NUMBER}}\",\n  \"message\": \"Hello from OlympusPay! Your test SMS via Africa's Talking.\"\n}"
            },
            "url": {
              "raw": "{{FUNCTIONS_BASE_URL}}/at-sms",
              "host": ["{{FUNCTIONS_BASE_URL}}"],
              "path": ["at-sms"]
            },
            "description": "Send a single SMS to a phone number. Requires USER_ACCESS_TOKEN."
          }
        },
        {
          "name": "Send SMS (bulk)",
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"to\": [\"{{AT_PHONE_NUMBER}}\", \"+26772000001\"],\n  \"message\": \"Bulk SMS test from OlympusPay via Africa's Talking.\"\n}"
            },
            "url": {
              "raw": "{{FUNCTIONS_BASE_URL}}/at-sms",
              "host": ["{{FUNCTIONS_BASE_URL}}"],
              "path": ["at-sms"]
            },
            "description": "Send SMS to multiple recipients in a single call."
          }
        },
        {
          "name": "Send Transaction Alert SMS",
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"to\": \"{{AT_PHONE_NUMBER}}\",\n  \"message\": \"OlympusPay: BWP 500.00 sent to Test Recipient. Ref: INV-001. New balance: BWP 1,500.00. Not you? Call +267 XXX XXX.\"\n}"
            },
            "url": {
              "raw": "{{FUNCTIONS_BASE_URL}}/at-sms",
              "host": ["{{FUNCTIONS_BASE_URL}}"],
              "path": ["at-sms"]
            },
            "description": "Example: post-transaction SMS alert."
          }
        }
      ]
    },
    {
      "name": "WhatsApp",
      "item": [
        {
          "name": "Send WhatsApp Text",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test('Status 200', () => pm.response.to.have.status(200));",
                  "pm.test('success flag', () => {",
                  "  const json = pm.response.json();",
                  "  pm.expect(json.success).to.be.true;",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"to\": \"{{AT_PHONE_NUMBER}}\",\n  \"type\": \"text\",\n  \"message\": \"Hello from OlympusPay! Your payment of BWP 500.00 was sent successfully. 🎉\"\n}"
            },
            "url": {
              "raw": "{{FUNCTIONS_BASE_URL}}/at-whatsapp",
              "host": ["{{FUNCTIONS_BASE_URL}}"],
              "path": ["at-whatsapp"]
            },
            "description": "Send a plain text WhatsApp message. Requires AT WhatsApp Business account."
          }
        },
        {
          "name": "Send Payment Receipt (WhatsApp)",
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"to\": \"{{AT_PHONE_NUMBER}}\",\n  \"type\": \"text\",\n  \"message\": \"✅ *Payment Sent*\\n\\nYou sent *BWP 1,200.00* to *Acme Supplies Ltd*.\\nReference: INV-2025-001\\n\\nTrack your payment in the OlympusPay app.\"\n}"
            },
            "url": {
              "raw": "{{FUNCTIONS_BASE_URL}}/at-whatsapp",
              "host": ["{{FUNCTIONS_BASE_URL}}"],
              "path": ["at-whatsapp"]
            },
            "description": "Rich payment receipt template using WhatsApp markdown formatting."
          }
        },
        {
          "name": "Send OTP via WhatsApp",
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"to\": \"{{AT_PHONE_NUMBER}}\",\n  \"type\": \"text\",\n  \"message\": \"🔐 *OlympusPay Verification*\\n\\nYour one-time code is: *847291*\\n\\nExpires in 10 minutes. Do not share this code with anyone.\"\n}"
            },
            "url": {
              "raw": "{{FUNCTIONS_BASE_URL}}/at-whatsapp",
              "host": ["{{FUNCTIONS_BASE_URL}}"],
              "path": ["at-whatsapp"]
            },
            "description": "OTP delivery via WhatsApp for enhanced security flows."
          }
        }
      ]
    },
    {
      "name": "Airtime",
      "item": [
        {
          "name": "Send Airtime (BWP)",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test('Status 200', () => pm.response.to.have.status(200));",
                  "pm.test('numSent >= 1', () => {",
                  "  const json = pm.response.json();",
                  "  pm.expect(json.numSent).to.be.at.least(1);",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"phoneNumber\": \"{{AT_PHONE_NUMBER}}\",\n  \"amount\": 10,\n  \"currency\": \"BWP\"\n}"
            },
            "url": {
              "raw": "{{FUNCTIONS_BASE_URL}}/at-airtime",
              "host": ["{{FUNCTIONS_BASE_URL}}"],
              "path": ["at-airtime"]
            },
            "description": "Send BWP 10 airtime to a phone number. Deducted from user's OlympusPay balance."
          }
        },
        {
          "name": "Send Airtime (KES)",
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"phoneNumber\": \"{{AT_PHONE_NUMBER}}\",\n  \"amount\": 100,\n  \"currency\": \"KES\"\n}"
            },
            "url": {
              "raw": "{{FUNCTIONS_BASE_URL}}/at-airtime",
              "host": ["{{FUNCTIONS_BASE_URL}}"],
              "path": ["at-airtime"]
            },
            "description": "Send KES 100 airtime — useful for cross-border staff payments."
          }
        },
        {
          "name": "Insufficient Funds (expect 422)",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test('Returns 422 for insufficient funds', () => pm.response.to.have.status(422));"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"phoneNumber\": \"{{AT_PHONE_NUMBER}}\",\n  \"amount\": 9999999,\n  \"currency\": \"BWP\"\n}"
            },
            "url": {
              "raw": "{{FUNCTIONS_BASE_URL}}/at-airtime",
              "host": ["{{FUNCTIONS_BASE_URL}}"],
              "path": ["at-airtime"]
            },
            "description": "Negative test: amount exceeds balance — should return 422."
          }
        }
      ]
    },
    {
      "name": "USSD (Simulator)",
      "item": [
        {
          "name": "Dial — Main Menu",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test('Status 200', () => pm.response.to.have.status(200));",
                  "pm.test('Starts with CON', () => {",
                  "  pm.expect(pm.response.text()).to.match(/^CON/);",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "auth": { "type": "noauth" },
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/x-www-form-urlencoded" }],
            "body": {
              "mode": "urlencoded",
              "urlencoded": [
                { "key": "sessionId",   "value": "AT-POSTMAN-{{$randomUUID}}", "type": "text" },
                { "key": "phoneNumber", "value": "{{AT_PHONE_NUMBER}}",        "type": "text" },
                { "key": "networkCode", "value": "99999",                      "type": "text" },
                { "key": "serviceCode", "value": "*384*OLYMPUS#",              "type": "text" },
                { "key": "text",        "value": "",                           "type": "text" }
              ]
            },
            "url": {
              "raw": "{{FUNCTIONS_BASE_URL}}/at-ussd?secret={{AT_USSD_SECRET}}",
              "host": ["{{FUNCTIONS_BASE_URL}}"],
              "path": ["at-ussd"],
              "query": [{ "key": "secret", "value": "{{AT_USSD_SECRET}}" }]
            },
            "description": "Simulates a user dialling the USSD code. text='' means first interaction.\nExpect: CON with the main menu."
          }
        },
        {
          "name": "Select Balance (1)",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test('Status 200', () => pm.response.to.have.status(200));",
                  "pm.test('Starts with END', () => {",
                  "  pm.expect(pm.response.text()).to.match(/^END/);",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "auth": { "type": "noauth" },
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/x-www-form-urlencoded" }],
            "body": {
              "mode": "urlencoded",
              "urlencoded": [
                { "key": "sessionId",   "value": "AT-POSTMAN-BAL-001", "type": "text" },
                { "key": "phoneNumber", "value": "{{AT_PHONE_NUMBER}}", "type": "text" },
                { "key": "networkCode", "value": "99999",               "type": "text" },
                { "key": "serviceCode", "value": "*384*OLYMPUS#",       "type": "text" },
                { "key": "text",        "value": "1",                   "type": "text" }
              ]
            },
            "url": {
              "raw": "{{FUNCTIONS_BASE_URL}}/at-ussd?secret={{AT_USSD_SECRET}}",
              "host": ["{{FUNCTIONS_BASE_URL}}"],
              "path": ["at-ussd"],
              "query": [{ "key": "secret", "value": "{{AT_USSD_SECRET}}" }]
            },
            "description": "Simulates pressing 1 (Balance). Expect: END with balance."
          }
        },
        {
          "name": "Send Money — Step 1 (enter phone)",
          "request": {
            "auth": { "type": "noauth" },
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/x-www-form-urlencoded" }],
            "body": {
              "mode": "urlencoded",
              "urlencoded": [
                { "key": "sessionId",   "value": "AT-POSTMAN-SEND-001", "type": "text" },
                { "key": "phoneNumber", "value": "{{AT_PHONE_NUMBER}}",  "type": "text" },
                { "key": "networkCode", "value": "99999",                "type": "text" },
                { "key": "serviceCode", "value": "*384*OLYMPUS#",        "type": "text" },
                { "key": "text",        "value": "2",                    "type": "text" }
              ]
            },
            "url": {
              "raw": "{{FUNCTIONS_BASE_URL}}/at-ussd?secret={{AT_USSD_SECRET}}",
              "host": ["{{FUNCTIONS_BASE_URL}}"],
              "path": ["at-ussd"],
              "query": [{ "key": "secret", "value": "{{AT_USSD_SECRET}}" }]
            },
            "description": "Step 1 of Send Money: user selects option 2. Expect: CON asking for recipient phone."
          }
        },
        {
          "name": "Unregistered Number (expect END)",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test('Unregistered user gets END', () => {",
                  "  pm.expect(pm.response.text()).to.match(/^END/);",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "auth": { "type": "noauth" },
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/x-www-form-urlencoded" }],
            "body": {
              "mode": "urlencoded",
              "urlencoded": [
                { "key": "sessionId",   "value": "AT-POSTMAN-UNREG-001", "type": "text" },
                { "key": "phoneNumber", "value": "+00000000000",          "type": "text" },
                { "key": "networkCode", "value": "99999",                 "type": "text" },
                { "key": "serviceCode", "value": "*384*OLYMPUS#",         "type": "text" },
                { "key": "text",        "value": "",                      "type": "text" }
              ]
            },
            "url": {
              "raw": "{{FUNCTIONS_BASE_URL}}/at-ussd?secret={{AT_USSD_SECRET}}",
              "host": ["{{FUNCTIONS_BASE_URL}}"],
              "path": ["at-ussd"],
              "query": [{ "key": "secret", "value": "{{AT_USSD_SECRET}}" }]
            },
            "description": "Negative test: phone not registered. Expect END with registration prompt."
          }
        },
        {
          "name": "Invalid Secret (expect 403)",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test('Returns 403 for bad secret', () => pm.response.to.have.status(403));"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "auth": { "type": "noauth" },
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/x-www-form-urlencoded" }],
            "body": {
              "mode": "urlencoded",
              "urlencoded": [
                { "key": "sessionId",   "value": "FAKE-001",            "type": "text" },
                { "key": "phoneNumber", "value": "{{AT_PHONE_NUMBER}}", "type": "text" },
                { "key": "networkCode", "value": "99999",               "type": "text" },
                { "key": "serviceCode", "value": "*384*OLYMPUS#",       "type": "text" },
                { "key": "text",        "value": "",                    "type": "text" }
              ]
            },
            "url": {
              "raw": "{{FUNCTIONS_BASE_URL}}/at-ussd?secret=WRONG_SECRET",
              "host": ["{{FUNCTIONS_BASE_URL}}"],
              "path": ["at-ussd"],
              "query": [{ "key": "secret", "value": "WRONG_SECRET" }]
            },
            "description": "Security test: wrong shared secret. Expect 403 Forbidden."
          }
        }
      ]
    }
  ]
}
