{
  "info": {
    "_postman_id": "65b18d06-b55c-4d60-b195-ctech-sms-gateway",
    "name": "CTech SMS Gateway API v1",
    "description": "Production-ready requests for authentication, SMS submission, idempotency checks, and status tracking. Configure client_id, client_secret and test_phone before use.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "variable": [
    { "key": "base_url", "value": "https://sms-gateway-api.ctechapp.com/api/v1", "type": "string" },
    { "key": "client_id", "value": "", "type": "string" },
    { "key": "client_secret", "value": "", "type": "string" },
    { "key": "access_token", "value": "", "type": "string" },
    { "key": "test_phone", "value": "0991234567", "type": "string" },
    { "key": "sender_id", "value": "YOUR_APPROVED_SENDER_ID", "type": "string" },
    { "key": "idempotency_key", "value": "manual-test-v1", "type": "string" },
    { "key": "request_id", "value": "", "type": "string" }
  ],
  "item": [
    {
      "name": "1. Authentication",
      "item": [
        {
          "name": "Generate access token",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test('Status is 200', () => pm.response.to.have.status(200));",
                  "const body = pm.response.json();",
                  "pm.test('Access token returned', () => pm.expect(body.access_token).to.be.a('string').and.not.empty);",
                  "if (body.access_token) pm.collectionVariables.set('access_token', body.access_token);"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              { "key": "Accept", "value": "application/json" },
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"client_id\": \"{{client_id}}\",\n  \"client_secret\": \"{{client_secret}}\"\n}",
              "options": { "raw": { "language": "json" } }
            },
            "url": "{{base_url}}/auth/token"
          }
        },
        {
          "name": "Reject incorrect credentials",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": ["pm.test('Status is 401', () => pm.response.to.have.status(401));"],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              { "key": "Accept", "value": "application/json" },
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"client_id\": \"{{client_id}}\",\n  \"client_secret\": \"intentionally-wrong\"\n}",
              "options": { "raw": { "language": "json" } }
            },
            "url": "{{base_url}}/auth/token"
          }
        }
      ]
    },
    {
      "name": "2. SMS requests",
      "item": [
        {
          "name": "Send single SMS",
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "exec": [
                  "if (!pm.collectionVariables.get('idempotency_key')) {",
                  "  pm.collectionVariables.set('idempotency_key', `postman-${Date.now()}`);",
                  "}"
                ],
                "type": "text/javascript"
              }
            },
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test('Accepted or existing', () => pm.expect([200, 202]).to.include(pm.response.code));",
                  "const body = pm.response.json();",
                  "pm.test('Request ID returned', () => pm.expect(body.request_id).to.be.a('string').and.not.empty);",
                  "if (body.request_id) pm.collectionVariables.set('request_id', body.request_id);"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "auth": { "type": "bearer", "bearer": [{ "key": "token", "value": "{{access_token}}", "type": "string" }] },
            "method": "POST",
            "header": [
              { "key": "Accept", "value": "application/json" },
              { "key": "Content-Type", "value": "application/json" },
              { "key": "Idempotency-Key", "value": "{{idempotency_key}}" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"recipients\": [\n    {\n      \"phone\": \"{{test_phone}}\",\n      \"external_reference\": \"postman-live-test\"\n    }\n  ],\n  \"message\": \"CTech SMS Gateway integration test. No action is required.\",\n  \"sender_id\": \"{{sender_id}}\",\n  \"metadata\": {\n    \"source\": \"postman\",\n    \"purpose\": \"integration-test\"\n  }\n}",
              "options": { "raw": { "language": "json" } }
            },
            "url": "{{base_url}}/sms/requests",
            "description": "This request sends a real SMS and may consume provider balance. Set test_phone and sender_id first. Reusing the same idempotency_key with this identical body will not send a duplicate."
          }
        },
        {
          "name": "Send shared bulk SMS",
          "request": {
            "auth": { "type": "bearer", "bearer": [{ "key": "token", "value": "{{access_token}}", "type": "string" }] },
            "method": "POST",
            "header": [
              { "key": "Accept", "value": "application/json" },
              { "key": "Content-Type", "value": "application/json" },
              { "key": "Idempotency-Key", "value": "replace-with-a-new-bulk-key" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"recipients\": [\n    { \"phone\": \"0991234567\", \"external_reference\": \"user-1001\" },\n    { \"phone\": \"0881234567\", \"external_reference\": \"user-1002\" }\n  ],\n  \"message\": \"This is a shared bulk message.\",\n  \"sender_id\": \"{{sender_id}}\",\n  \"metadata\": { \"source\": \"postman\", \"batch\": \"bulk-test\" }\n}",
              "options": { "raw": { "language": "json" } }
            },
            "url": "{{base_url}}/sms/requests"
          }
        },
        {
          "name": "Send personalised bulk SMS",
          "request": {
            "auth": { "type": "bearer", "bearer": [{ "key": "token", "value": "{{access_token}}", "type": "string" }] },
            "method": "POST",
            "header": [
              { "key": "Accept", "value": "application/json" },
              { "key": "Content-Type", "value": "application/json" },
              { "key": "Idempotency-Key", "value": "replace-with-a-new-personalised-key" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"recipients\": [\n    {\n      \"phone\": \"0991234567\",\n      \"external_reference\": \"appointment-1001\",\n      \"message\": \"Hello Mary, your appointment is at 09:00.\"\n    },\n    {\n      \"phone\": \"0881234567\",\n      \"external_reference\": \"appointment-1002\",\n      \"message\": \"Hello James, your appointment is at 10:30.\"\n    }\n  ],\n  \"sender_id\": \"{{sender_id}}\",\n  \"metadata\": { \"source\": \"postman\", \"batch\": \"personalised-test\" }\n}",
              "options": { "raw": { "language": "json" } }
            },
            "url": "{{base_url}}/sms/requests"
          }
        }
      ]
    },
    {
      "name": "3. Status",
      "item": [
        {
          "name": "Get request status",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test('Status is 200', () => pm.response.to.have.status(200));",
                  "pm.test('Summary returned', () => pm.expect(pm.response.json().data.request_id).to.eql(pm.collectionVariables.get('request_id')));"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "auth": { "type": "bearer", "bearer": [{ "key": "token", "value": "{{access_token}}", "type": "string" }] },
            "method": "GET",
            "header": [{ "key": "Accept", "value": "application/json" }],
            "url": "{{base_url}}/sms/requests/{{request_id}}"
          }
        },
        {
          "name": "Get recipient statuses",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test('Status is 200', () => pm.response.to.have.status(200));",
                  "pm.test('Recipient data returned', () => pm.expect(pm.response.json().data).to.be.an('array'));"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "auth": { "type": "bearer", "bearer": [{ "key": "token", "value": "{{access_token}}", "type": "string" }] },
            "method": "GET",
            "header": [{ "key": "Accept", "value": "application/json" }],
            "url": "{{base_url}}/sms/requests/{{request_id}}/recipients?page=1"
          }
        }
      ]
    }
  ]
}
