{
  "info": {
    "name": "Sentinel Secure ID API",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "description": "Biometric identity & security platform (fingerprint via OpenAFIS, face, plates, cases, wanted persons, activity).\n\n1. Select the \"Sentinel Secure ID (local)\" environment (or set baseUrl).\n2. Run Auth > Login. The token is saved and used by every request (Bearer auth on the collection).\n3. File uploads: pick files from the project `demo/` folder in the form-data rows (Postman needs the file chosen on your machine).\n4. Device / personal API keys: set the `apiKey` variable and use the requests in \"Device & API-key calls\".\n\nEvery request is permission checked. Admins choose each user's permissions and API access in Administration > Users & access, or via \"Admin > Set user access\"."
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{token}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "http://localhost:4000"
    },
    {
      "key": "token",
      "value": ""
    },
    {
      "key": "apiKey",
      "value": ""
    },
    {
      "key": "username",
      "value": "admin"
    },
    {
      "key": "password",
      "value": "Admin@12345"
    },
    {
      "key": "personId",
      "value": ""
    },
    {
      "key": "userId",
      "value": ""
    },
    {
      "key": "caseId",
      "value": ""
    },
    {
      "key": "vehicleId",
      "value": ""
    },
    {
      "key": "fingerprintId",
      "value": ""
    },
    {
      "key": "faceId",
      "value": ""
    },
    {
      "key": "alertId",
      "value": ""
    },
    {
      "key": "scanId",
      "value": ""
    },
    {
      "key": "apiKeyId",
      "value": ""
    },
    {
      "key": "readId",
      "value": ""
    },
    {
      "key": "cameraId",
      "value": ""
    },
    {
      "key": "cameraKey",
      "value": ""
    },
    {
      "key": "approvalId",
      "value": ""
    },
    {
      "key": "deviceId",
      "value": ""
    },
    {
      "key": "plate",
      "value": "APP-456CV"
    }
  ],
  "item": [
    {
      "name": "Auth",
      "item": [
        {
          "name": "Login",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));",
                  "try { const v = pm.response.json().token; if (v) pm.collectionVariables.set(\"token\", v); } catch (e) {}",
                  "try { const v = pm.response.json().user.id; if (v) pm.collectionVariables.set(\"userId\", v); } catch (e) {}",
                  "pm.test(\"token received\", () => pm.expect(pm.response.json().token).to.be.a(\"string\"));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/auth/login",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "auth",
                "login"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"username\": \"{{username}}\",\n  \"password\": \"{{password}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Returns a JWT (valid 12h by default). 5 wrong passwords lock the account for 15 minutes.",
            "auth": {
              "type": "noauth"
            }
          },
          "response": []
        },
        {
          "name": "Me (effective permissions)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/auth/me",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "auth",
                "me"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Change my password",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/auth/change-password",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "auth",
                "change-password"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"currentPassword\": \"{{password}}\",\n  \"newPassword\": \"{{password}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Set newPassword to the new value (it is the same as the current one here so running the whole collection changes nothing). Update the `password` variable afterwards."
          },
          "response": []
        },
        {
          "name": "My API keys (needs API access)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/403\", () => pm.expect([200,403]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/auth/api-keys",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "auth",
                "api-keys"
              ]
            },
            "description": "403 until an admin enables API access for your user."
          },
          "response": []
        },
        {
          "name": "Create my API key",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 201/403\", () => pm.expect([201,403]).to.include(pm.response.code));",
                  "try { const v = pm.response.json().key; if (v) pm.collectionVariables.set(\"apiKey\", v); } catch (e) {}",
                  "try { const v = pm.response.json().id; if (v) pm.collectionVariables.set(\"apiKeyId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/auth/api-keys",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "auth",
                "api-keys"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"Postman\",\n  \"permissions\": [],\n  \"expiresInDays\": 90\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Only works when an admin has enabled API access for your user (403 otherwise). `permissions` may narrow the key further (must be within your API scopes). The key is saved to {{apiKey}}."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Admin",
      "item": [
        {
          "name": "Roles, permissions and groups",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/roles",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "roles"
              ]
            }
          },
          "response": []
        },
        {
          "name": "List users",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/users",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "users"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Create user",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));",
                  "try { const v = pm.response.json().id; if (v) pm.collectionVariables.set(\"userId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/users",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "users"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"username\": \"ada{{$timestamp}}\",\n  \"name\": \"Sgt. Ada Okoro\",\n  \"password\": \"Demo@12345\",\n  \"role\": \"officer\",\n  \"rank\": \"Sergeant\",\n  \"unit\": \"Yaba Division\",\n  \"phone\": \"+234 803 000 2222\",\n  \"expiresAt\": \"2027-12-31\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Every account except the super admin needs expiresAt (YYYY-MM-DD). It is disabled automatically when that day ends."
          },
          "response": []
        },
        {
          "name": "Update user",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "PATCH",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/users/{{userId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "users",
                "{{userId}}"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"unit\": \"Ikeja Division\",\n  \"active\": true\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Set user access (custom permissions + API access)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "PUT",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/users/{{userId}}/access",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "users",
                "{{userId}}",
                "access"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"customPermissions\": true,\n  \"permissions\": [\n    \"persons:read\",\n    \"biometrics:identify\",\n    \"vehicles:read\",\n    \"sightings:read\",\n    \"sightings:write\"\n  ],\n  \"apiAccess\": true,\n  \"apiScopes\": [\n    \"biometrics:identify\",\n    \"vehicles:read\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "customPermissions=false -> the user gets their role defaults; true -> exactly `permissions`.\napiAccess -> may the user call the API with personal keys (X-API-Key)?\napiScopes -> which of their permissions those keys may use ([] = all of them)."
          },
          "response": []
        },
        {
          "name": "List API keys",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/api-keys",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "api-keys"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Create personal API key for a user",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));",
                  "try { const v = pm.response.json().key; if (v) pm.collectionVariables.set(\"apiKey\", v); } catch (e) {}",
                  "try { const v = pm.response.json().id; if (v) pm.collectionVariables.set(\"apiKeyId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/api-keys",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "api-keys"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"Postman - Ada\",\n  \"ownerId\": \"{{userId}}\",\n  \"permissions\": [],\n  \"expiresInDays\": 30\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "The user must have API access. The key acts as that user, limited by their API scopes and by `permissions` here."
          },
          "response": []
        },
        {
          "name": "Create device API key",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));",
                  "try { const v = pm.response.json().key; if (v) pm.collectionVariables.set(\"apiKey\", v); } catch (e) {}",
                  "try { const v = pm.response.json().id; if (v) pm.collectionVariables.set(\"apiKeyId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/api-keys",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "api-keys"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"Lekki toll gate ANPR cam 2\",\n  \"role\": \"device\",\n  \"permissions\": [],\n  \"address\": \"Lekki Toll Gate, Lagos\",\n  \"lat\": 6.44,\n  \"lng\": 3.484\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Device key with the default device permissions (sightings:write, events:write, biometrics:identify). Saved to {{apiKey}} for the \"Device & API-key calls\" folder."
          },
          "response": []
        },
        {
          "name": "Change key scopes",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "PATCH",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/api-keys/{{apiKeyId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "api-keys",
                "{{apiKeyId}}"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"permissions\": [\n    \"sightings:write\",\n    \"events:write\",\n    \"biometrics:identify\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Audit log",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/audit",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "audit"
              ],
              "query": [
                {
                  "key": "action",
                  "value": "identify"
                },
                {
                  "key": "limit",
                  "value": "50"
                },
                {
                  "key": "since",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "user",
                  "value": "",
                  "disabled": true
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Dashboard stats",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/stats",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "stats"
              ]
            }
          },
          "response": []
        }
      ]
    },
    {
      "name": "People",
      "item": [
        {
          "name": "Search people",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));",
                  "try { const v = pm.response.json().items[0]._id; if (v) pm.collectionVariables.set(\"personId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/persons",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "persons"
              ],
              "query": [
                {
                  "key": "q",
                  "value": "okafor"
                },
                {
                  "key": "status",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "wanted",
                  "value": "true",
                  "disabled": true
                },
                {
                  "key": "page",
                  "value": "1"
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Lookup by NIN / licence / phone",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/persons/lookup",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "persons",
                "lookup"
              ],
              "query": [
                {
                  "key": "nin",
                  "value": "12345678901"
                },
                {
                  "key": "license",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "phone",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "passport",
                  "value": "",
                  "disabled": true
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Create person (JSON)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));",
                  "try { const v = pm.response.json().person._id; if (v) pm.collectionVariables.set(\"personId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/persons",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "persons"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"firstName\": \"Chinedu\",\n  \"middleName\": \"Ikenna\",\n  \"lastName\": \"Obi\",\n  \"gender\": \"male\",\n  \"dateOfBirth\": \"1990-04-12\",\n  \"nin\": \"7{{$timestamp}}\",\n  \"phone\": \"+234 803 111 2222\",\n  \"driverLicense\": {\n    \"number\": \"LAG12345AA01\",\n    \"class\": \"B\",\n    \"state\": \"Lagos\",\n    \"expiresAt\": \"2029-01-01\"\n  },\n  \"passportNumber\": \"A12345678\",\n  \"address\": {\n    \"line1\": \"12 Allen Avenue\",\n    \"city\": \"Ikeja\",\n    \"state\": \"Lagos\",\n    \"country\": \"Nigeria\"\n  },\n  \"nextOfKin\": {\n    \"name\": \"Ngozi Obi\",\n    \"phone\": \"+234 805 000 0000\",\n    \"relationship\": \"spouse\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Images can also be sent in this JSON as base64 or data URIs: `photo` (face is enrolled), `faces` [..], `fingerprints` [..] with `fingerPositions` \"1,2\"."
          },
          "response": []
        },
        {
          "name": "Create person (multipart with photo + fingerprints)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));",
                  "try { const v = pm.response.json().person._id; if (v) pm.collectionVariables.set(\"personId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/persons",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "persons"
              ]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "data",
                  "value": "{\"firstName\":\"Halima\",\"lastName\":\"Sani\",\"gender\":\"female\",\"nin\":\"8{{$timestamp}}\",\"fingerPositions\":\"1,2\"}",
                  "type": "text"
                },
                {
                  "key": "photo",
                  "type": "file",
                  "src": "",
                  "description": "face photo"
                },
                {
                  "key": "fingerprints",
                  "type": "file",
                  "src": "",
                  "description": "right thumb image or ISO template"
                },
                {
                  "key": "fingerprints",
                  "type": "file",
                  "src": "",
                  "description": "right index"
                }
              ]
            },
            "description": "Choose a file / paste base64 first; without it the API answers 400 (expected)."
          },
          "response": []
        },
        {
          "name": "Get person profile",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/persons/{{personId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "persons",
                "{{personId}}"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Update person",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "PATCH",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/persons/{{personId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "persons",
                "{{personId}}"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"occupation\": \"Trader\",\n  \"watchlist\": false\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Set photo (enrols face)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/persons/{{personId}}/photo",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "persons",
                "{{personId}}",
                "photo"
              ]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "photo",
                  "type": "file",
                  "src": ""
                }
              ]
            },
            "description": "Choose a file / paste base64 first; without it the API answers 400 (expected)."
          },
          "response": []
        },
        {
          "name": "Timeline (events + sightings)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/persons/{{personId}}/timeline",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "persons",
                "{{personId}}",
                "timeline"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Declare wanted",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/persons/{{personId}}/wanted",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "persons",
                "{{personId}}",
                "wanted"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"reason\": \"Armed robbery\",\n  \"dangerLevel\": \"high\",\n  \"caseId\": \"{{caseId}}\",\n  \"reward\": \"₦500,000\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Clear wanted",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/persons/{{personId}}/wanted",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "persons",
                "{{personId}}",
                "wanted"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"note\": \"Arrested\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Delete person",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/persons/{{personId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "persons",
                "{{personId}}"
              ]
            }
          },
          "response": []
        }
      ]
    },
    {
      "name": "Fingerprints (OpenAFIS)",
      "item": [
        {
          "name": "Enroll fingerprint (file)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));",
                  "try { const v = pm.response.json().id; if (v) pm.collectionVariables.set(\"fingerprintId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/fingerprints/enroll",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "fingerprints",
                "enroll"
              ]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "personId",
                  "value": "{{personId}}",
                  "type": "text"
                },
                {
                  "key": "finger",
                  "value": "1",
                  "type": "text",
                  "description": "ISO position: 1 R thumb, 2 R index ... 6 L thumb ... 10 L little"
                },
                {
                  "key": "image",
                  "type": "file",
                  "src": "",
                  "description": "fingerprint image (demo/fingerprints/*.png)"
                },
                {
                  "key": "template",
                  "type": "file",
                  "src": "",
                  "description": "or an ISO 19794-2 template"
                }
              ]
            },
            "description": "Choose a file / paste base64 first; without it the API answers 400 (expected)."
          },
          "response": []
        },
        {
          "name": "Enroll fingerprint (base64 JSON)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));",
                  "try { const v = pm.response.json().id; if (v) pm.collectionVariables.set(\"fingerprintId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/fingerprints/enroll",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "fingerprints",
                "enroll"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"personId\": \"{{personId}}\",\n  \"finger\": 2,\n  \"image\": \"Paste base64 here (or a data URI: data:image/png;base64,...)\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Choose a file / paste base64 first; without it the API answers 400 (expected)."
          },
          "response": []
        },
        {
          "name": "Identify 1:N (file)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));",
                  "pm.test(\"has matches array\", () => pm.expect(pm.response.json().matches).to.be.an(\"array\"));",
                  "try { const v = pm.response.json().best && pm.response.json().best.personId; if (v) pm.collectionVariables.set(\"personId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/fingerprints/identify",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "fingerprints",
                "identify"
              ]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "image",
                  "type": "file",
                  "src": "",
                  "description": "try demo/fingerprints/01-...-probe.png"
                },
                {
                  "key": "topK",
                  "value": "5",
                  "type": "text"
                },
                {
                  "key": "finger",
                  "value": "",
                  "type": "text",
                  "description": "optional: search only this finger"
                },
                {
                  "key": "lat",
                  "value": "6.5244",
                  "type": "text"
                },
                {
                  "key": "lng",
                  "value": "3.3792",
                  "type": "text"
                },
                {
                  "key": "address",
                  "value": "Checkpoint, Ikeja",
                  "type": "text"
                }
              ]
            },
            "description": "Adding lat/lng/address records a sighting for the matched person (raises an alert if wanted).\n\nChoose a file / paste base64 first; without it the API answers 400 (expected)."
          },
          "response": []
        },
        {
          "name": "Identify 1:N (base64 JSON)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/fingerprints/identify",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "fingerprints",
                "identify"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"image\": \"Paste base64 here (or a data URI: data:image/png;base64,...)\",\n  \"topK\": 5\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Choose a file / paste base64 first; without it the API answers 400 (expected)."
          },
          "response": []
        },
        {
          "name": "Verify 1:1 against a person",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/fingerprints/verify",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "fingerprints",
                "verify"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"personId\": \"{{personId}}\",\n  \"image\": \"Paste base64 here (or a data URI: data:image/png;base64,...)\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Choose a file / paste base64 first; without it the API answers 400 (expected)."
          },
          "response": []
        },
        {
          "name": "Compare two fingerprints",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/fingerprints/compare",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "fingerprints",
                "compare"
              ]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "imageA",
                  "type": "file",
                  "src": ""
                },
                {
                  "key": "imageB",
                  "type": "file",
                  "src": ""
                }
              ]
            },
            "description": "Choose a file / paste base64 first; without it the API answers 400 (expected)."
          },
          "response": []
        },
        {
          "name": "Matcher stats",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/fingerprints/stats",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "fingerprints",
                "stats"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Delete fingerprint",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/fingerprints/{{fingerprintId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "fingerprints",
                "{{fingerprintId}}"
              ]
            }
          },
          "response": []
        }
      ]
    },
    {
      "name": "Faces",
      "item": [
        {
          "name": "Enroll face",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));",
                  "try { const v = pm.response.json().id; if (v) pm.collectionVariables.set(\"faceId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/faces/enroll",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "faces",
                "enroll"
              ]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "personId",
                  "value": "{{personId}}",
                  "type": "text"
                },
                {
                  "key": "image",
                  "type": "file",
                  "src": "",
                  "description": "clear face photo"
                }
              ]
            },
            "description": "Choose a file / paste base64 first; without it the API answers 400 (expected)."
          },
          "response": []
        },
        {
          "name": "Enroll face (base64)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));",
                  "try { const v = pm.response.json().id; if (v) pm.collectionVariables.set(\"faceId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/faces/enroll",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "faces",
                "enroll"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"personId\": \"{{personId}}\",\n  \"image\": \"Paste base64 here (or a data URI: data:image/png;base64,...)\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Choose a file / paste base64 first; without it the API answers 400 (expected)."
          },
          "response": []
        },
        {
          "name": "Identify all faces in a photo",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/faces/identify",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "faces",
                "identify"
              ]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "image",
                  "type": "file",
                  "src": ""
                },
                {
                  "key": "topK",
                  "value": "3",
                  "type": "text"
                },
                {
                  "key": "lat",
                  "value": "6.5244",
                  "type": "text"
                },
                {
                  "key": "lng",
                  "value": "3.3792",
                  "type": "text"
                },
                {
                  "key": "address",
                  "value": "CCTV cam 4",
                  "type": "text"
                }
              ]
            },
            "description": "Choose a file / paste base64 first; without it the API answers 400 (expected)."
          },
          "response": []
        },
        {
          "name": "Identify by descriptor (128 numbers)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/faces/identify",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "faces",
                "identify"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"descriptor\": [\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0\n  ],\n  \"topK\": 3\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "What the live webcam page sends. Replace with a real descriptor from face-api."
          },
          "response": []
        },
        {
          "name": "Verify face against a person",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/faces/verify",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "faces",
                "verify"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"personId\": \"{{personId}}\",\n  \"image\": \"Paste base64 here (or a data URI: data:image/png;base64,...)\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Choose a file / paste base64 first; without it the API answers 400 (expected)."
          },
          "response": []
        },
        {
          "name": "Compare two faces",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/faces/compare",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "faces",
                "compare"
              ]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "imageA",
                  "type": "file",
                  "src": ""
                },
                {
                  "key": "imageB",
                  "type": "file",
                  "src": ""
                }
              ]
            },
            "description": "Choose a file / paste base64 first; without it the API answers 400 (expected)."
          },
          "response": []
        },
        {
          "name": "Face stats",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/faces/stats",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "faces",
                "stats"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Delete face",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/faces/{{faceId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "faces",
                "{{faceId}}"
              ]
            }
          },
          "response": []
        }
      ]
    },
    {
      "name": "Vehicles, plates & sightings",
      "item": [
        {
          "name": "Recognise plate (file)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/plates/recognize",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "plates",
                "recognize"
              ]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "image",
                  "type": "file",
                  "src": "",
                  "description": "demo/plates/images.jpg"
                },
                {
                  "key": "record",
                  "value": "true",
                  "type": "text"
                },
                {
                  "key": "lat",
                  "value": "6.44",
                  "type": "text"
                },
                {
                  "key": "lng",
                  "value": "3.484",
                  "type": "text"
                },
                {
                  "key": "address",
                  "value": "Lekki Toll Gate",
                  "type": "text"
                },
                {
                  "key": "cameraId",
                  "value": "ANPR-LEKKI-01",
                  "type": "text"
                }
              ]
            },
            "description": "Choose a file / paste base64 first; without it the API answers 400 (expected)."
          },
          "response": []
        },
        {
          "name": "Recognise plate (base64)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/plates/recognize",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "plates",
                "recognize"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"image\": \"Paste base64 here (or a data URI: data:image/png;base64,...)\",\n  \"record\": false\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Choose a file / paste base64 first; without it the API answers 400 (expected)."
          },
          "response": []
        },
        {
          "name": "List vehicles",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));",
                  "try { const v = pm.response.json().items[0]._id; if (v) pm.collectionVariables.set(\"vehicleId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles"
              ],
              "query": [
                {
                  "key": "q",
                  "value": ""
                },
                {
                  "key": "status",
                  "value": "",
                  "disabled": true
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Register vehicle",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));",
                  "try { const v = pm.response.json()._id; if (v) pm.collectionVariables.set(\"vehicleId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"plate\": \"KJA-701AB\",\n  \"plateState\": \"Lagos\",\n  \"make\": \"Toyota\",\n  \"model\": \"Camry\",\n  \"color\": \"Black\",\n  \"year\": 2015,\n  \"owner\": \"{{personId}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Vehicle by plate",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles/by-plate/{{plate}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles",
                "by-plate",
                "{{plate}}"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Vehicle details + sightings",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles/{{vehicleId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles",
                "{{vehicleId}}"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Update vehicle",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "PATCH",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles/{{vehicleId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles",
                "{{vehicleId}}"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"color\": \"Silver\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Flag vehicle stolen",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles/{{vehicleId}}/flag",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles",
                "{{vehicleId}}",
                "flag"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"status\": \"stolen\",\n  \"reason\": \"Reported stolen\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Clear vehicle flag",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles/{{vehicleId}}/flag",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles",
                "{{vehicleId}}",
                "flag"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"status\": \"normal\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Record sighting (plate)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/sightings",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "sightings"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"plate\": \"{{plate}}\",\n  \"lat\": 6.5244,\n  \"lng\": 3.3792,\n  \"address\": \"Ikeja, Lagos\",\n  \"cameraId\": \"ANPR-IKEJA-02\",\n  \"direction\": \"northbound\",\n  \"speedKph\": 54\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Record sighting (person)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/sightings",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "sightings"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"personId\": \"{{personId}}\",\n  \"method\": \"manual\",\n  \"lat\": 6.5244,\n  \"lng\": 3.3792,\n  \"address\": \"Ikeja, Lagos\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Where was this plate last seen?",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/sightings/last",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "sightings",
                "last"
              ],
              "query": [
                {
                  "key": "plate",
                  "value": "{{plate}}"
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Sightings history / near a point",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/sightings",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "sightings"
              ],
              "query": [
                {
                  "key": "plate",
                  "value": "{{plate}}"
                },
                {
                  "key": "near",
                  "value": "6.5244,3.3792",
                  "disabled": true
                },
                {
                  "key": "radius",
                  "value": "5000",
                  "disabled": true
                },
                {
                  "key": "since",
                  "value": "",
                  "disabled": true
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Owner & drivers of a plate",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/persons-by-plate/{{plate}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "persons-by-plate",
                "{{plate}}"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Supported countries & plate formats",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/plates/countries",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "plates",
                "countries"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Recent plate reads",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));",
                  "try { const v = pm.response.json().items[0] && pm.response.json().items[0]._id; if (v) pm.collectionVariables.set(\"readId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/plates/reads",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "plates",
                "reads"
              ],
              "query": [
                {
                  "key": "lowConfidence",
                  "value": "true",
                  "disabled": true
                },
                {
                  "key": "corrected",
                  "value": "true",
                  "disabled": true
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Correct a plate read",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/plates/reads/{{readId}}/correct",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "plates",
                "reads",
                "{{readId}}",
                "correct"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"plate\": \"GWA-294NV\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Corrections are exported with `npm run plates:dataset` to fine-tune the plate model on local plates."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Settings & notifications",
      "item": [
        {
          "name": "Get settings",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/settings",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "settings"
              ]
            },
            "description": "Secrets (SMTP password, SMS API keys) come back as {set: true/false}."
          },
          "response": []
        },
        {
          "name": "Set plate country",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "PUT",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/settings",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "settings"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"plate\": {\n    \"country\": \"NG\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Country codes: GET /plates/countries (NG, GH, KE, ZA, GB, US, CA, DE, FR, IN, AE, BR, GLOBAL)."
          },
          "response": []
        },
        {
          "name": "Configure email alerts (SMTP)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "PUT",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/settings",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "settings"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"notifications\": {\n    \"severities\": [\n      \"critical\",\n      \"warning\"\n    ],\n    \"email\": {\n      \"enabled\": false,\n      \"host\": \"smtp.gmail.com\",\n      \"port\": 587,\n      \"secure\": false,\n      \"user\": \"alerts@example.com\",\n      \"pass\": \"app-password\",\n      \"from\": \"Sentinel <alerts@example.com>\",\n      \"to\": [\n        \"duty-officer@example.com\"\n      ]\n    }\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Set enabled to true and fill in your SMTP details."
          },
          "response": []
        },
        {
          "name": "Configure SMS alerts (Termii)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "PUT",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/settings",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "settings"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"notifications\": {\n    \"sms\": {\n      \"enabled\": false,\n      \"provider\": \"termii\",\n      \"to\": [\n        \"+2348030000000\"\n      ],\n      \"termii\": {\n        \"apiKey\": \"your-termii-key\",\n        \"senderId\": \"Sentinel\",\n        \"channel\": \"dnd\"\n      }\n    }\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Set enabled to true and fill in your key. Other providers: twilio {accountSid, authToken, from}, africastalking {username, apiKey, from}, webhook {url, authHeader}."
          },
          "response": []
        },
        {
          "name": "Configure misuse detection",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "PUT",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/settings",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "settings"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"abuse\": {\n    \"enabled\": true,\n    \"windowMinutes\": 60,\n    \"maxIdentifications\": 100,\n    \"maxProfileViews\": 200,\n    \"maxSensitiveLookups\": 30,\n    \"maxFailedLogins\": 10,\n    \"offHours\": {\n      \"enabled\": true,\n      \"from\": \"22:00\",\n      \"to\": \"06:00\"\n    }\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Send test email",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/400\", () => pm.expect([200,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/settings/notifications/test",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "settings",
                "notifications",
                "test"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"channel\": \"email\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "400 until email is configured."
          },
          "response": []
        },
        {
          "name": "Send test SMS",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/400\", () => pm.expect([200,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/settings/notifications/test",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "settings",
                "notifications",
                "test"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"channel\": \"sms\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "400 until SMS is configured."
          },
          "response": []
        },
        {
          "name": "Notifications sent",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/notifications",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "notifications"
              ]
            }
          },
          "response": []
        }
      ]
    },
    {
      "name": "Database (MongoDB or Oracle)",
      "item": [
        {
          "name": "Database in use",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/database",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "database"
              ]
            },
            "description": "Running database, the one saved for the next start, restartNeeded, and copy progress."
          },
          "response": []
        },
        {
          "name": "Test an Oracle connection",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/400\", () => pm.expect([200,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/database/test",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "database",
                "test"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"type\": \"oracle\",\n  \"uri\": \"mongodb://SENTINEL:password@your-adb.adb.eu-frankfurt-1.oraclecloudapps.com:27017/SENTINEL\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Put your Oracle Database API for MongoDB address here. Nothing is changed. 400 = could not connect (message says why)."
          },
          "response": []
        },
        {
          "name": "Copy all data to Oracle",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 202/400\", () => pm.expect([202,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/database/copy",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "database",
                "copy"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"type\": \"oracle\",\n  \"uri\": \"mongodb://SENTINEL:password@your-adb.adb.eu-frankfurt-1.oraclecloudapps.com:27017/SENTINEL\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Runs in the background; watch progress with \"Database in use\". Replaces Sentinel collections in the target."
          },
          "response": []
        },
        {
          "name": "Use Oracle from the next restart",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/400\", () => pm.expect([200,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "PUT",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/database",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "database"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"type\": \"oracle\",\n  \"uri\": \"mongodb://SENTINEL:password@your-adb.adb.eu-frankfurt-1.oraclecloudapps.com:27017/SENTINEL\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Tests the connection first and only saves when it works. Restart the server to switch."
          },
          "response": []
        },
        {
          "name": "Cancel the switch (back to .env)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "PUT",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/database",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "database"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"reset\": true\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        }
      ],
      "description": "See docs/DATABASE.md for preparing Oracle (Autonomous Database or ORDS)."
    },
    {
      "name": "Cameras",
      "item": [
        {
          "name": "List cameras",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));",
                  "try { const v = pm.response.json()[0] && pm.response.json()[0]._id; if (v) pm.collectionVariables.set(\"cameraId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cameras",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "cameras"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Add push camera (gets its own key)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));",
                  "try { const v = pm.response.json().camera._id; if (v) pm.collectionVariables.set(\"cameraId\", v); } catch (e) {}",
                  "try { const v = pm.response.json().apiKey; if (v) pm.collectionVariables.set(\"cameraKey\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cameras",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "cameras"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"Gate 2 ANPR\",\n  \"purpose\": \"plates\",\n  \"mode\": \"push\",\n  \"brand\": \"hikvision\",\n  \"address\": \"Gate 2\",\n  \"lat\": 6.44,\n  \"lng\": 3.48\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Add RTSP camera",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cameras",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "cameras"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"Lobby faces\",\n  \"purpose\": \"faces\",\n  \"mode\": \"rtsp\",\n  \"brand\": \"hikvision\",\n  \"rtspUrl\": \"rtsp://192.168.1.64:554/Streaming/Channels/101\",\n  \"username\": \"admin\",\n  \"password\": \"camera-password\",\n  \"intervalSec\": 2,\n  \"enabled\": false\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Add snapshot camera",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cameras",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "cameras"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"Car park\",\n  \"purpose\": \"both\",\n  \"mode\": \"snapshot\",\n  \"brand\": \"dahua\",\n  \"snapshotUrl\": \"http://192.168.1.65/cgi-bin/snapshot.cgi?channel=1\",\n  \"username\": \"admin\",\n  \"password\": \"camera-password\",\n  \"intervalSec\": 5,\n  \"enabled\": false\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Test camera (grab one frame)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/400\", () => pm.expect([200,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cameras/{{cameraId}}/test",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "cameras",
                "{{cameraId}}",
                "test"
              ]
            },
            "description": "Snapshot / RTSP cameras: grabs a frame. Push cameras: attach an image as form-data \"image\"."
          },
          "response": []
        },
        {
          "name": "Camera sends an image (ingest)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cameras/ingest",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "cameras",
                "ingest"
              ]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "image",
                  "type": "file",
                  "src": "",
                  "description": "snapshot from the camera"
                }
              ]
            },
            "description": "What the camera does. Cameras that only accept a URL can use {{baseUrl}}/api/v1/cameras/ingest?key=<camera key> with a raw image/jpeg body.\n\nChoose a file / paste base64 first; without it the API answers 400 (expected).",
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{cameraKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Latest frame (JPEG)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/204\", () => pm.expect([200,204]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cameras/{{cameraId}}/snapshot.jpg",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "cameras",
                "{{cameraId}}",
                "snapshot.jpg"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Update camera",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "PATCH",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cameras/{{cameraId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "cameras",
                "{{cameraId}}"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"intervalSec\": 3\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "New key for push camera",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));",
                  "try { const v = pm.response.json().apiKey; if (v) pm.collectionVariables.set(\"cameraKey\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cameras/{{cameraId}}/rotate-key",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "cameras",
                "{{cameraId}}",
                "rotate-key"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Delete camera",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cameras/{{cameraId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "cameras",
                "{{cameraId}}"
              ]
            }
          },
          "response": []
        }
      ]
    },
    {
      "name": "Field devices",
      "item": [
        {
          "name": "List devices",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));",
                  "try { const v = pm.response.json()[0] && pm.response.json()[0]._id; if (v) pm.collectionVariables.set(\"deviceId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/devices",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "devices"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Approve device",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/devices/{{deviceId}}/approve",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "devices",
                "{{deviceId}}",
                "approve"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"label\": \"Patrol car 12\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Rename device",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "PATCH",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/devices/{{deviceId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "devices",
                "{{deviceId}}"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"label\": \"Patrol car 12\",\n  \"notes\": \"Issued to Ikeja division\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Request camera view (officer must consent)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 202/400/404\", () => pm.expect([202,400,404]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/devices/{{deviceId}}/view",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "devices",
                "{{deviceId}}",
                "view"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "View status",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/devices/{{deviceId}}/view",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "devices",
                "{{deviceId}}",
                "view"
              ]
            }
          },
          "response": []
        },
        {
          "name": "End camera view",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/devices/{{deviceId}}/view",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "devices",
                "{{deviceId}}",
                "view"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Revoke device",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/devices/{{deviceId}}/revoke",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "devices",
                "{{deviceId}}",
                "revoke"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        }
      ],
      "description": "Phones sign in with headers X-Client: android and X-Device-Id. The live stream is GET {{baseUrl}}/api/v1/devices/{{deviceId}}/live?token={{token}} (MJPEG, after the officer allows it)."
    },
    {
      "name": "Intelligence (offline AI)",
      "item": [
        {
          "name": "Ask a question",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/ai/ask",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "ai",
                "ask"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"question\": \"how many robberies in Ikeja this week\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Plain English, answered from the database on this server (no internet). Try: is Emeka Eze wanted, where was BEN-319HM last seen, tell me about Segun Ogunleye, crime hotspots, what crime should we expect next week, early warnings, vehicles with expired insurance, summary."
          },
          "response": []
        },
        {
          "name": "Person analysis (risk, associates, places, advice)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/ai/person/{{personId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "ai",
                "person",
                "{{personId}}"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Hotspots, forecast and early warnings",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/ai/insights",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "ai",
                "insights"
              ],
              "query": [
                {
                  "key": "weeks",
                  "value": "12"
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Run the early-warning scan now",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/ai/scan",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "ai",
                "scan"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Also runs every hour; new warnings become alerts of type ai-warning."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Records: print & email",
      "item": [
        {
          "name": "Print a person record (HTML)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/records/person/{{personId}}/print",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "records",
                "person",
                "{{personId}}",
                "print"
              ]
            },
            "description": "type: person | case | vehicle | user. Opens a printable page with letterhead and a reference number (DOC-YYYY-NNNNNN); logged in the activity log. In a browser use ?token= instead of the header."
          },
          "response": []
        },
        {
          "name": "Email a case record",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/400/403\", () => pm.expect([200,400,403]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/records/case/{{caseId}}/email",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "records",
                "case",
                "{{caseId}}",
                "email"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"to\": [\n    \"investigator@agency.gov\"\n  ],\n  \"message\": \"For your review.\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Needs records:email and email set up in Settings. Logged with the recipients."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Branding & network access",
      "item": [
        {
          "name": "Branding (public)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/branding",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "branding"
              ]
            },
            "auth": {
              "type": "noauth"
            }
          },
          "response": []
        },
        {
          "name": "Set motto",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "PUT",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/settings",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "settings"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"organisation\": {\n    \"motto\": \"Service with integrity\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Upload logo",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/settings/logo",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "settings",
                "logo"
              ]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "logo",
                  "type": "file",
                  "src": ""
                }
              ]
            },
            "description": "Choose a file / paste base64 first; without it the API answers 400 (expected)."
          },
          "response": []
        },
        {
          "name": "Your address and the local networks",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/settings/network-info",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "settings",
                "network-info"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Restrict access to listed addresses",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/400\", () => pm.expect([200,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "PUT",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/settings",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "settings"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"network\": {\n    \"enabled\": false,\n    \"allowLocal\": true,\n    \"trustProxy\": false,\n    \"allowed\": [\n      \"102.89.4.17\",\n      \"41.58.0.0/16\"\n    ]\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Set enabled to true to apply. Refused if it would block your own address. Emergency: start the server with IP_GUARD=off."
          },
          "response": []
        },
        {
          "name": "Map: Google Maps",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/400\", () => pm.expect([200,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "PUT",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/settings",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "settings"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"map\": {\n    \"provider\": \"google\",\n    \"googleKey\": \"AIza…your key\",\n    \"googleMapId\": \"\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        }
      ]
    },
    {
      "name": "Vehicle papers & licences",
      "item": [
        {
          "name": "Check papers (plate and/or licence)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/documents/check",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "documents",
                "check"
              ],
              "query": [
                {
                  "key": "plate",
                  "value": "BEN-319HM"
                },
                {
                  "key": "licence",
                  "value": "",
                  "disabled": true
                }
              ]
            },
            "description": "Registration, insurance, roadworthiness and driver's licences with valid / expiring / expired, plus warnings (flagged vehicle, wanted owner, deceased person)."
          },
          "response": []
        },
        {
          "name": "Papers of a vehicle",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles/by-plate/BEN-319HM/documents",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles",
                "by-plate",
                "BEN-319HM",
                "documents"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Update papers by plate (licensing authority / insurer)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201\", () => pm.expect([200,201]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "PUT",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles/by-plate/KJA-123AB/documents",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles",
                "by-plate",
                "KJA-123AB",
                "documents"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"make\": \"Toyota\",\n  \"model\": \"Corolla\",\n  \"color\": \"Silver\",\n  \"year\": 2019,\n  \"registration\": {\n    \"number\": \"LAG-2024-55821\",\n    \"authority\": \"Lagos MVAA\",\n    \"issuedAt\": \"2025-11-01\",\n    \"expiresAt\": \"2026-10-31\"\n  },\n  \"insurance\": {\n    \"provider\": \"AXA Mansard\",\n    \"policyNumber\": \"MTR-0099812\",\n    \"type\": \"third-party\",\n    \"expiresAt\": \"2027-03-31\"\n  },\n  \"roadworthiness\": {\n    \"number\": \"RW-77812\",\n    \"expiresAt\": \"2027-01-15\"\n  },\n  \"owner\": {\n    \"nin\": \"\",\n    \"firstName\": \"Kunle\",\n    \"lastName\": \"Adeyemi\",\n    \"phone\": \"+234 803 000 3333\",\n    \"driverLicense\": {\n      \"number\": \"LAG-DL-0098812\",\n      \"class\": \"B\",\n      \"expiresAt\": \"2028-06-30\"\n    }\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Creates the vehicle if it is new. The owner / driver is found by personId, nin or driverLicense.number, or created from firstName + lastName, so every document is linked to a person. Needs documents:write (give an API key only this permission for an authority or insurer)."
          },
          "response": []
        },
        {
          "name": "Vehicles with expired papers",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/vehicles",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "vehicles"
              ],
              "query": [
                {
                  "key": "docs",
                  "value": "expired"
                },
                {
                  "key": "limit",
                  "value": "50"
                }
              ]
            },
            "description": "docs = expired | expiring (30 days) | missing | valid"
          },
          "response": []
        }
      ]
    },
    {
      "name": "Dispatch & officers",
      "item": [
        {
          "name": "Officer directory (search)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));",
                  "try { const v = pm.response.json()[0] && pm.response.json()[0].officer.id; if (v) pm.collectionVariables.set(\"officerId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/officers",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "officers"
              ],
              "query": [
                {
                  "key": "q",
                  "value": ""
                },
                {
                  "key": "near",
                  "value": "6.4541,3.3947",
                  "disabled": true
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Nearest officers to a case",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/400\", () => pm.expect([200,400]).to.include(pm.response.code));",
                  "try { const v = pm.response.json().officers && pm.response.json().officers[0] && pm.response.json().officers[0].officer.id; if (v) pm.collectionVariables.set(\"officerId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/dispatch/nearest",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "dispatch",
                "nearest"
              ],
              "query": [
                {
                  "key": "caseId",
                  "value": "{{caseId}}"
                },
                {
                  "key": "maxAgeMin",
                  "value": "60"
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Nearest officers to a place",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/dispatch/nearest",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "dispatch",
                "nearest"
              ],
              "query": [
                {
                  "key": "lat",
                  "value": "6.4541"
                },
                {
                  "key": "lng",
                  "value": "3.3947"
                },
                {
                  "key": "maxAgeMin",
                  "value": "60"
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Dispatch officers to a case",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 201/400\", () => pm.expect([201,400]).to.include(pm.response.code));",
                  "try { const v = pm.response.json()[0] && pm.response.json()[0]._id; if (v) pm.collectionVariables.set(\"dispatchId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/dispatch",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "dispatch"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"caseId\": \"{{caseId}}\",\n  \"officerIds\": [\n    \"{{officerId}}\"\n  ],\n  \"priority\": \"high\",\n  \"note\": \"Suspect on foot, blue shirt\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Dispatch officers to a place",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 201/400\", () => pm.expect([201,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/dispatch",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "dispatch"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"lat\": 6.4541,\n  \"lng\": 3.3947,\n  \"address\": \"Broad Street, Lagos Island\",\n  \"title\": \"Crowd control\",\n  \"officerIds\": [\n    \"{{officerId}}\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Active dispatches",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/dispatch",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "dispatch"
              ],
              "query": [
                {
                  "key": "active",
                  "value": "true"
                },
                {
                  "key": "q",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "case",
                  "value": "{{caseId}}",
                  "disabled": true
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Officer answers (field app)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/400/403\", () => pm.expect([200,400,403]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/dispatch/{{dispatchId}}/respond",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "dispatch",
                "{{dispatchId}}",
                "respond"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"status\": \"accepted\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Only the dispatched officer: accepted, declined (with note), arrived, completed."
          },
          "response": []
        },
        {
          "name": "Cancel dispatch",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/400/404\", () => pm.expect([200,400,404]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/dispatch/{{dispatchId}}/cancel",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "dispatch",
                "{{dispatchId}}",
                "cancel"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Phone reports its position (field app)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/403\", () => pm.expect([200,403]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/devices/me/location",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "devices",
                "me",
                "location"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"lat\": 6.4541,\n  \"lng\": 3.3947,\n  \"accuracy\": 10\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Sent by the field app in the background. { off: true, reason } when location is switched off raises an alert."
          },
          "response": []
        }
      ],
      "description": "Officer positions come from their approved phones (the field app sends GPS in the background)."
    },
    {
      "name": "Locations",
      "item": [
        {
          "name": "Countries",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/geo/countries",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "geo",
                "countries"
              ]
            }
          },
          "response": []
        },
        {
          "name": "States and local governments of a country",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/geo/countries/NG",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "geo",
                "countries",
                "NG"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Correct a state's local governments (admin)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "PUT",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/geo/countries/NG/states/05",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "geo",
                "countries",
                "NG",
                "states",
                "05"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"lgas\": []\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Send the full list of names; an empty list restores the bundled GeoNames list."
          },
          "response": []
        },
        {
          "name": "Cases in a state / local government",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cases",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "cases"
              ],
              "query": [
                {
                  "key": "state",
                  "value": "Lagos"
                },
                {
                  "key": "lga",
                  "value": "Ikeja",
                  "disabled": true
                }
              ]
            }
          },
          "response": []
        }
      ]
    },
    {
      "name": "Approvals",
      "item": [
        {
          "name": "Requests waiting for review",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));",
                  "try { const v = pm.response.json().items[0] && pm.response.json().items[0]._id; if (v) pm.collectionVariables.set(\"approvalId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/approvals",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "approvals"
              ],
              "query": [
                {
                  "key": "status",
                  "value": "pending"
                },
                {
                  "key": "mine",
                  "value": "true",
                  "disabled": true
                },
                {
                  "key": "q",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "resource",
                  "value": "person",
                  "disabled": true
                },
                {
                  "key": "action",
                  "value": "delete",
                  "disabled": true
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Pending count",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/approvals/count",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "approvals",
                "count"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Bulk approve / reject",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/400/403\", () => pm.expect([200,400,403]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/approvals/bulk",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "approvals",
                "bulk"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"ids\": [\n    \"{{approvalId}}\"\n  ],\n  \"decision\": \"approve\",\n  \"note\": \"checked against source documents\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "decision: approve | reject (a note is required to reject). Each request is decided on its own; the result lists every outcome. Your own requests are skipped."
          },
          "response": []
        },
        {
          "name": "Declare a person deceased",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/202/400\", () => pm.expect([200,202,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/persons/{{personId}}/deceased",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "persons",
                "{{personId}}",
                "deceased"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"date\": \"2026-10-01\",\n  \"place\": \"General Hospital, Ikeja\",\n  \"cause\": \"\",\n  \"certificateNumber\": \"DC-2026-0012\",\n  \"notes\": \"Confirmed by next of kin\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Goes through approval. Afterwards any biometric / document match of this identity raises a possible identity fraud alert."
          },
          "response": []
        },
        {
          "name": "Approve",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/400/403/404\", () => pm.expect([200,400,403,404]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/approvals/{{approvalId}}/approve",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "approvals",
                "{{approvalId}}",
                "approve"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"note\": \"verified against source documents\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Reject",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/400/403/404\", () => pm.expect([200,400,403,404]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/approvals/{{approvalId}}/reject",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "approvals",
                "{{approvalId}}",
                "reject"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"note\": \"not supported by evidence\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Withdraw my request",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/404\", () => pm.expect([200,404]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/approvals/{{approvalId}}/cancel",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "approvals",
                "{{approvalId}}",
                "cancel"
              ]
            }
          },
          "response": []
        }
      ],
      "description": "Edits (PATCH) and deletions (DELETE) of people, vehicles, cases, fingerprints and faces return 202 {approval} and wait here until another reviewer approves them."
    },
    {
      "name": "Activity log (audit)",
      "item": [
        {
          "name": "Activity log",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/audit",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "audit"
              ],
              "query": [
                {
                  "key": "category",
                  "value": "biometric-search",
                  "disabled": true
                },
                {
                  "key": "q",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "status",
                  "value": "denied",
                  "disabled": true
                },
                {
                  "key": "resourceId",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "since",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "until",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "50"
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Activity summary by user (24h)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/audit/summary",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "audit",
                "summary"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Export activity log (CSV)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/audit/export.csv",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "audit",
                "export.csv"
              ],
              "query": [
                {
                  "key": "category",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "since",
                  "value": "",
                  "disabled": true
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Verify log integrity (hash chain)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));",
                  "pm.test(\"log intact\", () => pm.expect(pm.response.json().ok).to.eql(true));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/audit/verify",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "audit",
                "verify"
              ]
            }
          },
          "response": []
        }
      ],
      "description": "Categories: biometric-search, profile-view, sensitive-lookup, data-change, delete, admin-change, login, login-failed, audit-access, read."
    },
    {
      "name": "Activity events",
      "item": [
        {
          "name": "Post event (by personId)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/events",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "events"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"personId\": \"{{personId}}\",\n  \"type\": \"check-in\",\n  \"title\": \"Hotel check-in\",\n  \"lat\": 6.5244,\n  \"lng\": 3.3792,\n  \"address\": \"Ikeja, Lagos\",\n  \"data\": {\n    \"room\": \"402\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Post event (by NIN)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/events",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "events"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"nin\": \"12345678901\",\n  \"type\": \"access-granted\",\n  \"title\": \"HQ main gate\",\n  \"lat\": 6.5244,\n  \"lng\": 3.3792,\n  \"address\": \"Ikeja, Lagos\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Post events in bulk",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/events",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "events"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "[\n  {\n    \"personId\": \"{{personId}}\",\n    \"type\": \"visit\",\n    \"title\": \"Visited station\"\n  },\n  {\n    \"personId\": \"{{personId}}\",\n    \"type\": \"interview\",\n    \"title\": \"Gave statement\"\n  }\n]",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "List events",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/events",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "events"
              ],
              "query": [
                {
                  "key": "q",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "person",
                  "value": "{{personId}}",
                  "disabled": true
                },
                {
                  "key": "type",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "since",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "until",
                  "value": "",
                  "disabled": true
                }
              ]
            }
          },
          "response": []
        }
      ]
    },
    {
      "name": "Cases & complaints",
      "item": [
        {
          "name": "List cases",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));",
                  "try { const v = pm.response.json().items[0]._id; if (v) pm.collectionVariables.set(\"caseId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cases",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "cases"
              ],
              "query": [
                {
                  "key": "q",
                  "value": ""
                },
                {
                  "key": "status",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "mine",
                  "value": "true",
                  "disabled": true
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "File complaint (JSON)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));",
                  "try { const v = pm.response.json()._id; if (v) pm.collectionVariables.set(\"caseId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cases",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "cases"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"title\": \"Phone snatched at bus stop\",\n  \"type\": \"complaint\",\n  \"category\": \"theft\",\n  \"priority\": \"medium\",\n  \"description\": \"Two men on a motorcycle...\",\n  \"lat\": 6.5244,\n  \"lng\": 3.3792,\n  \"address\": \"Ikeja, Lagos\",\n  \"country\": \"NG\",\n  \"state\": \"Lagos\",\n  \"lga\": \"Ikeja\",\n  \"complainant\": {\n    \"firstName\": \"Bisi\",\n    \"lastName\": \"Alade\",\n    \"phone\": \"+234 803 000 1111\",\n    \"nin\": \"\",\n    \"driverLicense\": \"\",\n    \"statement\": \"They rode towards Ketu.\"\n  },\n  \"subjects\": [\n    {\n      \"role\": \"suspect\",\n      \"nin\": \"\",\n      \"driverLicense\": \"\",\n      \"firstName\": \"\",\n      \"lastName\": \"\"\n    }\n  ],\n  \"vehiclePlates\": [\n    \"APP-456CV\"\n  ],\n  \"photos\": []\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "NIN, driver's licence and plate numbers are optional. Registered people / vehicles are linked automatically and returned in `matches`; a wanted person or flagged vehicle raises an alert."
          },
          "response": []
        },
        {
          "name": "File complaint (multipart + photos)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));",
                  "try { const v = pm.response.json()._id; if (v) pm.collectionVariables.set(\"caseId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cases",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "cases"
              ]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "data",
                  "value": "{\"title\":\"Burglary at shop\",\"type\":\"crime\",\"category\":\"burglary\",\"priority\":\"high\"}",
                  "type": "text"
                },
                {
                  "key": "photos",
                  "type": "file",
                  "src": ""
                },
                {
                  "key": "photos",
                  "type": "file",
                  "src": ""
                }
              ]
            },
            "description": "Choose a file / paste base64 first; without it the API answers 400 (expected)."
          },
          "response": []
        },
        {
          "name": "Get case",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cases/{{caseId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "cases",
                "{{caseId}}"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Update case status",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "PATCH",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cases/{{caseId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "cases",
                "{{caseId}}"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"status\": \"investigating\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Add note",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cases/{{caseId}}/notes",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "cases",
                "{{caseId}}",
                "notes"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"text\": \"Suspect identified from CCTV.\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Add evidence (base64)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cases/{{caseId}}/attachments",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "cases",
                "{{caseId}}",
                "attachments"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"attachments\": [\n    \"Paste base64 here (or a data URI: data:image/png;base64,...)\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Choose a file / paste base64 first; without it the API answers 400 (expected)."
          },
          "response": []
        },
        {
          "name": "Link suspect",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cases/{{caseId}}/link",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "cases",
                "{{caseId}}",
                "link"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"role\": \"suspect\",\n  \"personId\": \"{{personId}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Assign officers",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cases/{{caseId}}/assign",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "cases",
                "{{caseId}}",
                "assign"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"userIds\": [\n    \"{{userId}}\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        }
      ]
    },
    {
      "name": "Wanted & alerts",
      "item": [
        {
          "name": "Wanted list",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/wanted",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "wanted"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Alerts",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));",
                  "try { const v = pm.response.json().items[0] && pm.response.json().items[0]._id; if (v) pm.collectionVariables.set(\"alertId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/alerts",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "alerts"
              ],
              "query": [
                {
                  "key": "status",
                  "value": "new"
                },
                {
                  "key": "severity",
                  "value": "critical",
                  "disabled": true
                },
                {
                  "key": "type",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "q",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "since",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "until",
                  "value": "",
                  "disabled": true
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Acknowledge alert",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "PATCH",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/alerts/{{alertId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "alerts",
                "{{alertId}}"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"status\": \"acknowledged\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        }
      ],
      "description": "Live alerts are a Server-Sent Events stream: GET {{baseUrl}}/api/v1/alerts/stream?token={{token}} (open it in a browser or with curl -N)."
    },
    {
      "name": "Airports & passports",
      "item": [
        {
          "name": "Airline check-in (passport)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/travel/events",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "travel",
                "events"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"kind\": \"check-in\",\n  \"airport\": \"LOS\",\n  \"passport\": {\n    \"number\": \"A01234567\",\n    \"country\": \"NG\"\n  },\n  \"traveller\": {\n    \"firstName\": \"Segun\",\n    \"lastName\": \"Ogunleye\",\n    \"dateOfBirth\": \"1988-03-14\"\n  },\n  \"flight\": {\n    \"airline\": \"Air Peace\",\n    \"number\": \"P47500\",\n    \"from\": \"LOS\",\n    \"to\": \"LHR\",\n    \"departsAt\": \"2026-11-02T22:05:00Z\",\n    \"seat\": \"23C\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Usually sent by an airline / airport / immigration system with a `border` API key. A wanted, missing or watched traveller, or a lost / stolen passport, raises an alert."
          },
          "response": []
        },
        {
          "name": "Immigration exit with e-gate photo (multipart)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/travel/events",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "travel",
                "events"
              ]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "data",
                  "value": "{\"kind\":\"immigration-exit\",\"airport\":\"ABV\",\"passport\":{\"number\":\"A01234567\",\"country\":\"NG\"},\"flight\":{\"number\":\"ET910\",\"to\":\"ADD\"}}",
                  "type": "text"
                },
                {
                  "key": "photo",
                  "type": "file",
                  "src": ""
                }
              ]
            },
            "description": "The face in the photo is checked: if it belongs to someone else than the passport holder, a critical alert is raised.\n\nChoose a file / paste base64 first; without it the API answers 400 (expected)."
          },
          "response": []
        },
        {
          "name": "Passport used at a hotel",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/travel/events",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "travel",
                "events"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"kind\": \"passport-scan\",\n  \"passport\": {\n    \"number\": \"A01234567\"\n  },\n  \"place\": {\n    \"type\": \"hotel\",\n    \"name\": \"Eko Hotel\",\n    \"city\": \"Lagos\",\n    \"country\": \"NG\",\n    \"lat\": 6.4253,\n    \"lng\": 3.4296\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Travel history",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/travel/events",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "travel",
                "events"
              ],
              "query": [
                {
                  "key": "person",
                  "value": "{{personId}}",
                  "disabled": true
                },
                {
                  "key": "passport",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "place",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "flight",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "flagged",
                  "value": "true",
                  "disabled": true
                },
                {
                  "key": "q",
                  "value": "",
                  "disabled": true
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Airports",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/travel/airports",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "travel",
                "airports"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Report passport stolen",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/404\", () => pm.expect([200,404]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/travel/passport-status",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "travel",
                "passport-status"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"passportNumber\": \"A01234567\",\n  \"status\": \"stolen\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Tell me when this person travels",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/persons/{{personId}}/travel-watch",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "persons",
                "{{personId}}",
                "travel-watch"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"reason\": \"Suspect in fraud case may try to leave the country\",\n  \"until\": \"2026-12-31\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Stop travel watch",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/persons/{{personId}}/travel-watch",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "persons",
                "{{personId}}",
                "travel-watch"
              ]
            }
          },
          "response": []
        }
      ]
    },
    {
      "name": "Video scan",
      "item": [
        {
          "name": "Scan video (identify everyone)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));",
                  "try { const v = pm.response.json().id; if (v) pm.collectionVariables.set(\"scanId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/video/scan",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "video",
                "scan"
              ]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "video",
                  "type": "file",
                  "src": ""
                },
                {
                  "key": "mode",
                  "value": "identify",
                  "type": "text"
                },
                {
                  "key": "address",
                  "value": "Ikeja City Mall",
                  "type": "text"
                }
              ]
            },
            "description": "Choose a file / paste base64 first; without it the API answers 400 (expected)."
          },
          "response": []
        },
        {
          "name": "Scan video (find specific people)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));",
                  "try { const v = pm.response.json().id; if (v) pm.collectionVariables.set(\"scanId\", v); } catch (e) {}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/video/scan",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "video",
                "scan"
              ]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "video",
                  "type": "file",
                  "src": ""
                },
                {
                  "key": "mode",
                  "value": "find",
                  "type": "text"
                },
                {
                  "key": "personIds",
                  "value": "{{personId}}",
                  "type": "text"
                }
              ]
            },
            "description": "Choose a file / paste base64 first; without it the API answers 400 (expected)."
          },
          "response": []
        },
        {
          "name": "Scan result",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/video/scans/{{scanId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "video",
                "scans",
                "{{scanId}}"
              ]
            }
          },
          "response": []
        },
        {
          "name": "List scans",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/video/scans",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "video",
                "scans"
              ],
              "query": [
                {
                  "key": "q",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "status",
                  "value": "done",
                  "disabled": true
                },
                {
                  "key": "mode",
                  "value": "",
                  "disabled": true
                }
              ]
            }
          },
          "response": []
        }
      ]
    },
    {
      "name": "Device & API-key calls",
      "item": [
        {
          "name": "Who am I (key)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/auth/me",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "auth",
                "me"
              ]
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{apiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Camera: recognise plate",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/201/202/400\", () => pm.expect([200,201,202,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/plates/recognize",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "plates",
                "recognize"
              ]
            },
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "image",
                  "type": "file",
                  "src": "",
                  "description": "demo/plates/images.jpg"
                },
                {
                  "key": "cameraId",
                  "value": "ANPR-LEKKI-01",
                  "type": "text"
                }
              ]
            },
            "description": "Device keys record a sighting automatically (location from the key if not sent).\n\nChoose a file / paste base64 first; without it the API answers 400 (expected).",
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{apiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Camera: post sighting",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/sightings",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "sightings"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"plate\": \"BEN-319HM\",\n  \"lat\": 6.5244,\n  \"lng\": 3.3792,\n  \"address\": \"Ikeja, Lagos\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{apiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Gate: post event by NIN",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/events",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "events"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"nin\": \"12345678901\",\n  \"type\": \"access-granted\",\n  \"title\": \"Gate 2\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{apiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Key: identify fingerprint (base64)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/400\", () => pm.expect([200,400]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/fingerprints/identify",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "fingerprints",
                "identify"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"image\": \"Paste base64 here (or a data URI: data:image/png;base64,...)\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "400 until you paste a real base64 fingerprint image.",
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{apiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Key: people search (403 unless permitted)",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is one of 200/403\", () => pm.expect([200,403]).to.include(pm.response.code));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/persons",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "persons"
              ],
              "query": [
                {
                  "key": "q",
                  "value": "okafor"
                }
              ]
            },
            "description": "Shows access control: a device key without persons:read gets 403.",
            "auth": {
              "type": "apikey",
              "apikey": [
                {
                  "key": "key",
                  "value": "X-API-Key",
                  "type": "string"
                },
                {
                  "key": "value",
                  "value": "{{apiKey}}",
                  "type": "string"
                },
                {
                  "key": "in",
                  "value": "header",
                  "type": "string"
                }
              ]
            }
          },
          "response": []
        }
      ],
      "description": "These use {{apiKey}} in the X-API-Key header instead of the login token."
    },
    {
      "name": "Cleanup (run last)",
      "item": [
        {
          "name": "Revoke API key",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/api-keys/{{apiKeyId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "api-keys",
                "{{apiKeyId}}"
              ]
            }
          },
          "response": []
        },
        {
          "name": "Reset user to role defaults, no API access",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test(\"status is 2xx\", () => pm.expect(pm.response.code).to.be.within(200, 299));"
                ]
              }
            }
          ],
          "request": {
            "method": "PUT",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/users/{{userId}}/access",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "users",
                "{{userId}}",
                "access"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"customPermissions\": false,\n  \"apiAccess\": false,\n  \"apiScopes\": []\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        }
      ]
    }
  ]
}