{
  "info": {
    "name": "KiiOn API",
    "description": "KiiOn public API — login, device list, unlock and token rotation. Set BASE_URL, phoneNumber and password in a Postman ENVIRONMENT with an empty initial value so credentials never travel with an exported collection. Docs: https://developers.kiion.io/docs/quickstart",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "variable": [
    {
      "key": "BASE_URL",
      "value": "https://staging.zesec.com/api",
      "type": "string"
    },
    {
      "key": "phoneNumber",
      "value": "",
      "type": "string"
    },
    {
      "key": "password",
      "value": "",
      "type": "string"
    },
    {
      "key": "AccessToken",
      "value": "",
      "type": "string"
    },
    {
      "key": "RefreshToken",
      "value": "",
      "type": "string"
    },
    {
      "key": "deviceId",
      "value": "",
      "type": "string"
    }
  ],
  "item": [
    {
      "name": "1. Login by phone",
      "request": {
        "method": "POST",
        "description": "Log in server-side once and reuse the token. One active session per account: a new login kills the previous one.",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"phoneNumber\": \"{{phoneNumber}}\",\n  \"password\": \"{{password}}\"\n}"
        },
        "url": {
          "raw": "{{BASE_URL}}/auth/login-by-phone",
          "host": [
            "{{BASE_URL}}"
          ],
          "path": [
            "auth",
            "login-by-phone"
          ]
        }
      },
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const body = pm.response.json();",
              "// Both values rotate on refresh. Saving only one loses the session (see /docs/authentication).",
              "pm.collectionVariables.set(\"AccessToken\", body.AccessToken ?? body.accessToken ?? \"\");",
              "pm.collectionVariables.set(\"RefreshToken\", body.RefreshToken ?? body.refreshToken ?? \"\");",
              "pm.test(\"tokens received\", () => pm.expect(pm.collectionVariables.get(\"AccessToken\")).to.not.eql(\"\"));"
            ]
          }
        }
      ]
    },
    {
      "name": "2. List devices",
      "request": {
        "method": "GET",
        "description": "The `id` of each entry is the {deviceId} the unlock call needs. Cache this mapping.",
        "header": [
          {
            "key": "Authorization",
            "value": "Bearer {{AccessToken}}"
          }
        ],
        "url": {
          "raw": "{{BASE_URL}}/user/device",
          "host": [
            "{{BASE_URL}}"
          ],
          "path": [
            "user",
            "device"
          ]
        }
      },
      "event": []
    },
    {
      "name": "3. Unlock device",
      "request": {
        "method": "PUT",
        "description": "200 means the command was accepted and forwarded — not that the door physically opened. Never auto-retry.",
        "header": [
          {
            "key": "Authorization",
            "value": "Bearer {{AccessToken}}"
          }
        ],
        "url": {
          "raw": "{{BASE_URL}}/device/{{deviceId}}/unlock",
          "host": [
            "{{BASE_URL}}"
          ],
          "path": [
            "device",
            "{{deviceId}}",
            "unlock"
          ]
        }
      },
      "event": []
    },
    {
      "name": "4. Refresh session",
      "request": {
        "method": "POST",
        "description": "Rotating and single-use. Run it proactively every 36 hours, not on failure.",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"refreshToken\": \"{{RefreshToken}}\"\n}"
        },
        "url": {
          "raw": "{{BASE_URL}}/auth/refresh",
          "host": [
            "{{BASE_URL}}"
          ],
          "path": [
            "auth",
            "refresh"
          ]
        }
      },
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const body = pm.response.json();",
              "// Both values rotate on refresh. Saving only one loses the session (see /docs/authentication).",
              "pm.collectionVariables.set(\"AccessToken\", body.AccessToken ?? body.accessToken ?? \"\");",
              "pm.collectionVariables.set(\"RefreshToken\", body.RefreshToken ?? body.refreshToken ?? \"\");",
              "pm.test(\"tokens received\", () => pm.expect(pm.collectionVariables.get(\"AccessToken\")).to.not.eql(\"\"));"
            ]
          }
        }
      ]
    },
    {
      "name": "5. Logout",
      "request": {
        "method": "POST",
        "description": "Releases the account's single active session.",
        "header": [
          {
            "key": "Authorization",
            "value": "Bearer {{AccessToken}}"
          }
        ],
        "url": {
          "raw": "{{BASE_URL}}/auth/logout",
          "host": [
            "{{BASE_URL}}"
          ],
          "path": [
            "auth",
            "logout"
          ]
        }
      },
      "event": []
    }
  ]
}