{
  "info": {
    "_postman_id": "4567ac8b-5d14-4598-91ce-39b93c2336bf",
    "name": "XY Sense API Examples",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "_exporter_id": "9767789",
    "description": "Runnable examples for the XY Sense external GraphQL API. Run 'Getting started' first: it stores your bearer token and sandbox floor in the environment. Setup steps and prerequisites: https://docs.xysense.io/docs/graphql-api/postman"
  },
  "item": [
    {
      "name": "Getting started",
      "item": [
        {
          "name": "Fetch Auth Token",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": ["var jsonData = JSON.parse(responseBody);", "postman.setEnvironmentVariable(\"coreApiAuthToken\", jsonData.idToken);"],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "name": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\r\n    \"ApiKey\": \"{{coreApiKey}}\",\r\n    \"ApiSecret\": \"{{coreApiSecret}}\"\r\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{coreApiAuthUrl}}",
              "host": ["{{coreApiAuthUrl}}"]
            },
            "description": "Authenticates then updates the 'coreApiAuthToken' env var with the token returned by the auth endpoint."
          },
          "response": []
        },
        {
          "name": "Fetch Space Data",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"set devFloor environment variable\", function () {\r",
                  "    var jsonData = JSON.parse(responseBody);\r",
                  "    var testFloor = jsonData.data.floors.find(floor => floor.name === \"API Test Floor\");\r",
                  "    pm.expect(testFloor, \"No floor named 'API Test Floor' found\").to.not.be.undefined;\r",
                  "    if(testFloor)\r",
                  "        postman.setEnvironmentVariable(\"devFloor\", testFloor.id);\r",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "type": "text",
                "value": "Bearer {{coreApiAuthToken}}"
              }
            ],
            "body": {
              "mode": "graphql",
              "graphql": {
                "query": "query SpaceData {\r\n  floors {\r\n    id\r\n    name\r\n    location {\r\n      id \r\n      name\r\n    }\r\n    floorSpaces {\r\n      id\r\n      name\r\n      capacity\r\n      spaceType {\r\n        name\r\n      }\r\n    }\r\n  }\r\n}",
                "variables": ""
              }
            },
            "url": {
              "raw": "{{coreApiQueryUrl}}",
              "host": ["{{coreApiQueryUrl}}"]
            },
            "description": "Loads floor space info including current occupancy status, all the info needed to initiate a polling integration."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Occupancy",
      "item": [
        {
          "name": "Generate Occupancy Changes",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "type": "text",
                "value": "Bearer {{coreApiAuthToken}}"
              }
            ],
            "body": {
              "mode": "graphql",
              "graphql": {
                "query": "mutation GenerateOccupancy($floorId:ID!) {\r\n  generateOccupancyEvents(floorId:$floorId, count:5 )\r\n  {\r\n    floorSpaceId\r\n  }\r\n}",
                "variables": "{\r\n    \"floorId\": \"{{devFloor}}\"\r\n}"
              }
            },
            "url": {
              "raw": "{{coreApiQueryUrl}}",
              "host": ["{{coreApiQueryUrl}}"]
            },
            "description": "Generates Occupancy changes for spaces on the test floor."
          },
          "response": []
        },
        {
          "name": "Fetch Latest Occupancy",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 200\", function () { \r",
                  "    pm.response.to.have.status(200); \r",
                  "});\r",
                  "\r",
                  "var jsonData = JSON.parse(responseBody);\r",
                  "var nextFrom = jsonData.data.occupancyChanges.nextFrom;\r",
                  "var from = jsonData.data.occupancyChanges.from;\r",
                  "var occupancyChanges = jsonData.data.occupancyChanges.data;\r",
                  "\r",
                  "console.log('Changes Received', occupancyChanges.length);\r",
                  "console.log('From', from);\r",
                  "console.log('Next From', nextFrom);\r",
                  "\r",
                  "postman.setEnvironmentVariable(\"fromDateTime\", nextFrom);"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "type": "text",
                "value": "Bearer {{coreApiAuthToken}}"
              }
            ],
            "body": {
              "mode": "graphql",
              "graphql": {
                "query": "query LatestOccupancy {  \r\n  occupancyChanges {\r\n    nextFrom\r\n    data {\r\n      floorSpaceId\r\n      occupancyStatus\r\n      headcount\r\n      collectedDate\r\n    }\r\n  }\r\n}",
                "variables": ""
              }
            },
            "url": {
              "raw": "{{coreApiQueryUrl}}",
              "host": ["{{coreApiQueryUrl}}"]
            },
            "description": "Loads floor space info including current occupancy status, all the info needed to initiate a polling integration."
          },
          "response": []
        },
        {
          "name": "Fetch Occupancy Changes (moving 'fromDateTime')",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 200\", function () { ",
                  "    pm.response.to.have.status(200); ",
                  "});",
                  "",
                  "var jsonData = JSON.parse(responseBody);",
                  "var nextFrom = jsonData.data.occupancyChanges.nextFrom;",
                  "var from = jsonData.data.occupancyChanges.from;",
                  "var occupancyChanges = jsonData.data.occupancyChanges.data;",
                  "",
                  "console.log('Changes Received', occupancyChanges.length);",
                  "console.log('From', from);",
                  "console.log('Next From', nextFrom);",
                  "",
                  "postman.setEnvironmentVariable(\"fromDateTime\", nextFrom);"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "type": "text",
                "value": "Bearer {{coreApiAuthToken}}"
              }
            ],
            "body": {
              "mode": "graphql",
              "graphql": {
                "query": "query Occupancy {\r\n  occupancyChanges(from: \"{{fromDateTime}}\")\r\n  {\r\n      from\r\n      nextFrom\r\n      data\r\n      {\r\n        floorSpaceId\r\n        occupancyStatus\r\n        headcount\r\n        collectedDate\r\n      }\r\n  }\r\n}",
                "variables": ""
              }
            },
            "url": {
              "raw": "{{coreApiQueryUrl}}",
              "host": ["{{coreApiQueryUrl}}"]
            },
            "description": "Uses 'fromDateTime' env var and updates it based on the changes received, so that the next batch is new changes only. This simulates how a polling integration should behave."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Analytics",
      "item": [
        {
          "name": "Fetch Occupancy Per Hour (paged)",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{coreApiAuthToken}}",
                "type": "text"
              }
            ],
            "body": {
              "mode": "graphql",
              "graphql": {
                "query": "query OccupancyPerHour($from: Date!, $to: Date!, $skip: Int, $take: Int) {\n  occupancyPerHour(from: $from, to: $to, skip: $skip, take: $take) {\n    totalItems\n    hasNextPage\n    items {\n      floorSpaceId\n      date\n      hour\n      avgOccupants\n      maxOccupants\n      occupiedSeconds\n    }\n  }\n}",
                "variables": "{\n    \"from\": \"{{analyticsFrom}}\",\n    \"to\": \"{{analyticsTo}}\",\n    \"skip\": {{analyticsSkip}},\n    \"take\": 1000\n}"
              }
            },
            "url": {
              "raw": "{{coreApiQueryUrl}}",
              "host": ["{{coreApiQueryUrl}}"]
            }
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "exec": [
                  "// Default to yesterday (UTC) so the request is runnable without editing.",
                  "if (!pm.environment.get('analyticsFrom')) {",
                  "    const now = new Date();",
                  "    const to = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));",
                  "    const from = new Date(to.getTime() - 24 * 60 * 60 * 1000);",
                  "    pm.environment.set('analyticsFrom', from.toISOString());",
                  "    pm.environment.set('analyticsTo', to.toISOString());",
                  "}",
                  "if (!pm.environment.get('analyticsSkip')) {",
                  "    pm.environment.set('analyticsSkip', '0');",
                  "}"
                ],
                "type": "text/javascript"
              }
            },
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test('Status code is 200', function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "",
                  "var jsonData = JSON.parse(responseBody);",
                  "var page = jsonData.data.occupancyPerHour;",
                  "console.log('Items in page', page.items.length);",
                  "console.log('Total items', page.totalItems);",
                  "console.log('Has next page', page.hasNextPage);",
                  "",
                  "// Advance skip so re-running the request pages through the results.",
                  "if (page.hasNextPage) {",
                  "    pm.environment.set('analyticsSkip', String(Number(pm.environment.get('analyticsSkip')) + page.items.length));",
                  "} else {",
                  "    pm.environment.set('analyticsSkip', '0');",
                  "}"
                ],
                "type": "text/javascript"
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Space sensors",
      "item": [
        {
          "name": "Fetch Sensor Capabilities",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{coreApiAuthToken}}",
                "type": "text"
              }
            ],
            "body": {
              "mode": "graphql",
              "graphql": {
                "query": "query SpaceSensorCapabilities {\n  spaceSensorCapabilities {\n    name\n    unit\n    description\n    types {\n      name\n    }\n  }\n}",
                "variables": ""
              }
            },
            "url": {
              "raw": "{{coreApiQueryUrl}}",
              "host": ["{{coreApiQueryUrl}}"]
            }
          }
        },
        {
          "name": "Fetch Latest Space Sensor Readings",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{coreApiAuthToken}}",
                "type": "text"
              }
            ],
            "body": {
              "mode": "graphql",
              "graphql": {
                "query": "query LatestSpaceSensorReadings {\n  spaceSensorReadings(includeLatest: true, comfortOnly: false) {\n    nextFrom\n    data {\n      spaceSensorId\n      capabilityName\n      value\n      collectedAt\n    }\n  }\n}",
                "variables": ""
              }
            },
            "url": {
              "raw": "{{coreApiQueryUrl}}",
              "host": ["{{coreApiQueryUrl}}"]
            }
          }
        }
      ]
    },
    {
      "name": "Sensor health",
      "item": [
        {
          "name": "Fetch Area Sensor Connection Status",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{coreApiAuthToken}}",
                "type": "text"
              }
            ],
            "body": {
              "mode": "graphql",
              "graphql": {
                "query": "query AreaSensorConnectionStatus {\n  areaSensorInstallations(isActive: true) {\n    id\n    name\n    areaSensor {\n      serialNumber\n      connection {\n        isOnline\n        isOnlineChangeDate\n        source\n      }\n    }\n  }\n}",
                "variables": ""
              }
            },
            "url": {
              "raw": "{{coreApiQueryUrl}}",
              "host": ["{{coreApiQueryUrl}}"]
            }
          }
        }
      ]
    },
    {
      "name": "Webhooks",
      "item": [
        {
          "name": "List Webhooks",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{coreApiAuthToken}}",
                "type": "text"
              }
            ],
            "body": {
              "mode": "graphql",
              "graphql": {
                "query": "query Webhooks {\n  webhooks {\n    id\n    name\n    webhookType\n    enabled\n    endpoint\n    maxBatchSize\n    maxBatchDelayMs\n    created\n    updated\n  }\n}",
                "variables": ""
              }
            },
            "url": {
              "raw": "{{coreApiQueryUrl}}",
              "host": ["{{coreApiQueryUrl}}"]
            }
          }
        }
      ]
    }
  ],
  "auth": {
    "type": "apikey",
    "apikey": [
      {
        "key": "key",
        "value": "Authorization",
        "type": "string"
      },
      {
        "key": "value",
        "value": "Bearer {{coreApiAuthToken}}",
        "type": "string"
      }
    ]
  },
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "type": "text/javascript",
        "exec": [""]
      }
    },
    {
      "listen": "test",
      "script": {
        "type": "text/javascript",
        "exec": [""]
      }
    }
  ]
}
