{
  "info": {
    "_postman_id": "broadcastav-api-collection-unified",
    "name": "BroadcastAV - API Collection",
    "description": "Unified and complete Postman Collection for BroadcastAV API.\n\nModules Included:\n- Auth (Admin & Seller)\n- Profile Management\n- Seller Management (Admin)\n- Category Management\n- Listing & Product Management\n- Quote Management\n- Offer Management\n- Enquiry Management (Questions)\n- Dashboard Management (Stats, Trends & Recent Admin Activity)\n- Admin Notifications (7-day retention feed, mark read, mark all read)",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "http://localhost:3000/v1",
      "type": "string"
    },
    {
      "key": "adminEmail",
      "value": "sky.high142001@gmail.com",
      "type": "string"
    },
    {
      "key": "adminPassword",
      "value": "BroadcastAV@123",
      "type": "string"
    },
    {
      "key": "adminToken",
      "value": "",
      "type": "string"
    },
    {
      "key": "resetSessionToken",
      "value": "",
      "type": "string"
    },
    {
      "key": "sellerEmail",
      "value": "seller@example.com",
      "type": "string"
    },
    {
      "key": "sellerUsername",
      "value": "sellerjane",
      "type": "string"
    },
    {
      "key": "sellerPassword",
      "value": "sellerPassword123",
      "type": "string"
    },
    {
      "key": "sellerToken",
      "value": "",
      "type": "string"
    },
    {
      "key": "categoryId",
      "value": "",
      "type": "string"
    },
    {
      "key": "mainCategoryId",
      "value": "",
      "type": "string"
    },
    {
      "key": "subCategoryId",
      "value": "",
      "type": "string"
    },
    {
      "key": "listingId",
      "value": "",
      "type": "string"
    },
    {
      "key": "sellerId",
      "value": "",
      "type": "string"
    },
    {
      "key": "listingNo",
      "value": "101",
      "type": "string"
    },
    {
      "key": "quoteId",
      "value": "",
      "type": "string"
    },
    {
      "key": "offerId",
      "value": "",
      "type": "string"
    },
    {
      "key": "enquiryId",
      "value": "",
      "type": "string"
    },
    {
      "key": "notificationId",
      "value": "",
      "type": "string"
    },
    {
      "key": "verifyEmailToken",
      "value": "",
      "type": "string"
    }
  ],
  "item": [
    {
      "name": "Unified Login (Admin & Seller)",
      "event": [
        {
          "listen": "test",
          "script": {
            "exec": [
              "pm.test(\"Status code is 200\", function () {",
              "    pm.response.to.have.status(200);",
              "});",
              "var jsonData = pm.response.json();",
              "pm.test(\"Response follows unified format\", function () {",
              "    pm.expect(jsonData.success).to.eql(true);",
              "    pm.expect(jsonData.statusCode).to.eql(200);",
              "    pm.expect(jsonData.meta).to.have.property('timestamp');",
              "});",
              "if (jsonData.data && jsonData.data.tokens && jsonData.data.tokens.access) {",
              "    var token = jsonData.data.tokens.access.token;",
              "    if (jsonData.data.user.role === 'admin') {",
              "        pm.collectionVariables.set(\"adminToken\", token);",
              "        console.log(\"Saved adminToken:\", token);",
              "    } else {",
              "        pm.collectionVariables.set(\"sellerToken\", token);",
              "        console.log(\"Saved sellerToken:\", token);",
              "    }",
              "}"
            ],
            "type": "text/javascript"
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"email\": \"{{adminEmail}}\",\n  \"password\": \"{{adminPassword}}\",\n  \"rememberMe\": true\n}"
        },
        "url": {
          "raw": "{{baseUrl}}/auth/login",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "auth",
            "login"
          ]
        },
        "description": "Unified login endpoint for both Admin and Seller. Accepts email or username. Supports optional `role` parameter ('admin' | 'seller') if strict role enforcement is required. Automatically saves token to either adminToken or sellerToken based on the authenticated user's role."
      },
      "response": []
    },
    {
      "name": "Unified Change Password (Admin & Seller)",
      "request": {
        "auth": {
          "type": "bearer",
          "bearer": [
            {
              "key": "token",
              "value": "{{adminToken}}",
              "type": "string"
            }
          ]
        },
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"currentPassword\": \"BroadcastAV@123\",\n  \"newPassword\": \"BroadcastAV@456\",\n  \"confirmPassword\": \"BroadcastAV@456\"\n}"
        },
        "url": {
          "raw": "{{baseUrl}}/auth/change-password",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "auth",
            "change-password"
          ]
        },
        "description": "Unified change password endpoint for BOTH Admin and Seller. Accepts currentPassword, newPassword, confirmPassword."
      }
    },
    {
      "name": "Admin Auth",
      "item": [
        {
          "name": "1. Admin Login",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 200\", function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "var jsonData = pm.response.json();",
                  "pm.test(\"Response follows unified format\", function () {",
                  "    pm.expect(jsonData.success).to.eql(true);",
                  "    pm.expect(jsonData.statusCode).to.eql(200);",
                  "    pm.expect(jsonData.meta).to.have.property('timestamp');",
                  "});",
                  "if (jsonData.data && jsonData.data.tokens && jsonData.data.tokens.access) {",
                  "    pm.collectionVariables.set(\"adminToken\", jsonData.data.tokens.access.token);",
                  "    console.log(\"Saved adminToken:\", jsonData.data.tokens.access.token);",
                  "}"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\": \"{{adminEmail}}\",\n  \"password\": \"{{adminPassword}}\",\n  \"rememberMe\": true\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/auth/login",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "auth",
                "login"
              ]
            },
            "description": "Log in with an admin account. If rememberMe is true, refresh token expires in 90 days instead of 30 days.\nOn success, the access token is automatically saved into {{adminToken}}."
          },
          "response": []
        },
        {
          "name": "2. Admin Forgot Password (Send OTP)",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 200\", function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "var jsonData = pm.response.json();",
                  "pm.test(\"OTP sent successfully\", function () {",
                  "    pm.expect(jsonData.success).to.eql(true);",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\": \"{{adminEmail}}\"\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/auth/admin/forgot-password",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "auth",
                "admin",
                "forgot-password"
              ]
            },
            "description": "Sends a 6-digit numeric OTP to the admin's email address. The OTP is valid for 10 minutes."
          },
          "response": []
        },
        {
          "name": "3. Admin Resend OTP (15s Cooldown)",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "var jsonData = pm.response.json();",
                  "if (pm.response.code === 200) {",
                  "    pm.test(\"OTP resent successfully\", function () {",
                  "        pm.expect(jsonData.success).to.eql(true);",
                  "    });",
                  "} else if (pm.response.code === 429) {",
                  "    pm.test(\"Cooldown active (HTTP 429)\", function () {",
                  "        pm.expect(jsonData.success).to.eql(false);",
                  "    });",
                  "}"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\": \"{{adminEmail}}\"\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/auth/admin/resend-otp",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "auth",
                "admin",
                "resend-otp"
              ]
            },
            "description": "Resends the OTP if 15 seconds have elapsed since the last generation. Returns HTTP 429 if attempted before cooldown."
          },
          "response": []
        },
        {
          "name": "4. Admin Verify OTP",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 200\", function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "var jsonData = pm.response.json();",
                  "if (jsonData.data && jsonData.data.resetSessionToken) {",
                  "    pm.collectionVariables.set(\"resetSessionToken\", jsonData.data.resetSessionToken);",
                  "    console.log(\"Saved resetSessionToken:\", jsonData.data.resetSessionToken);",
                  "}"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\": \"{{adminEmail}}\",\n  \"otp\": \"123456\"\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/auth/admin/verify-otp",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "auth",
                "admin",
                "verify-otp"
              ]
            },
            "description": "Verifies the 6-digit OTP received via email. Consumes the OTP and returns a 15-minute `resetSessionToken` which is automatically saved to {{resetSessionToken}}."
          },
          "response": []
        },
        {
          "name": "5. Admin Reset Password",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 200\", function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "var jsonData = pm.response.json();",
                  "pm.test(\"Password reset successful\", function () {",
                  "    pm.expect(jsonData.success).to.eql(true);",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"resetSessionToken\": \"{{resetSessionToken}}\",\n  \"newPassword\": \"adminNewPass123\",\n  \"confirmPassword\": \"adminNewPass123\"\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/auth/admin/reset-password",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "auth",
                "admin",
                "reset-password"
              ]
            },
            "description": "Resets the admin's password using the session token obtained from verifying the OTP. Rejects if the new password is the same as the previous password."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Seller Auth",
      "item": [
        {
          "name": "1. Seller Register",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 201\", function () {",
                  "    pm.response.to.have.status(201);",
                  "});",
                  "var jsonData = pm.response.json();",
                  "pm.test(\"Seller registered with email verification required\", function () {",
                  "    pm.expect(jsonData.success).to.eql(true);",
                  "    pm.expect(jsonData.statusCode).to.eql(201);",
                  "    pm.expect(jsonData.data.user.role).to.eql(\"seller\");",
                  "    pm.expect(jsonData.data.user.isEmailVerified).to.eql(false);",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"firstName\": \"Jane\",\n  \"lastName\": \"Seller\",\n  \"email\": \"{{sellerEmail}}\",\n  \"phone\": \"+61400000000\",\n  \"username\": \"{{sellerUsername}}\",\n  \"password\": \"{{sellerPassword}}\",\n  \"confirmPassword\": \"{{sellerPassword}}\",\n  \"city\": \"Sydney\",\n  \"postalCode\": \"2000\",\n  \"country\": \"Australia\",\n  \"recaptchaToken\": \"\"\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/auth/seller/register",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "auth",
                "seller",
                "register"
              ]
            },
            "description": "Registers a new seller on BroadcastAV. A verification link is sent to the seller's email address. The account must be verified before login is allowed.\n\nNote on reCAPTCHA:\n- If RECAPTCHA_SECRET_KEY is configured on the backend, a valid token from the frontend widget must be passed in recaptchaToken.\n- If RECAPTCHA_SECRET_KEY is empty in backend .env, recaptchaToken can be left empty for easy local API testing."
          },
          "response": []
        },
        {
          "name": "2. Seller Verify Email",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 200\", function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "var jsonData = pm.response.json();",
                  "pm.test(\"Email verified successfully\", function () {",
                  "    pm.expect(jsonData.success).to.eql(true);",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"token\": \"{{verifyEmailToken}}\"\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/auth/seller/verify-email",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "auth",
                "seller",
                "verify-email"
              ]
            },
            "description": "Verifies the seller's email using the token received in the verification email. Also supports GET /auth/seller/verify-email?token={{verifyEmailToken}}."
          },
          "response": []
        },
        {
          "name": "3. Seller Resend Verification Email",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 200\", function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "var jsonData = pm.response.json();",
                  "pm.test(\"Verification email resent successfully\", function () {",
                  "    pm.expect(jsonData.success).to.eql(true);",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\": \"{{sellerEmail}}\"\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/auth/seller/resend-verification-email",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "auth",
                "seller",
                "resend-verification-email"
              ]
            },
            "description": "Resends an email verification link to the seller if the previous token expired or was lost. Enforces a 60-second cooldown."
          },
          "response": []
        },
        {
          "name": "4. Seller Login (via Email)",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 200\", function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "var jsonData = pm.response.json();",
                  "pm.test(\"Seller login successful\", function () {",
                  "    pm.expect(jsonData.success).to.eql(true);",
                  "    pm.expect(jsonData.data).to.have.property('mustChangePassword');",
                  "});",
                  "if (jsonData.data && jsonData.data.tokens && jsonData.data.tokens.access) {",
                  "    pm.collectionVariables.set(\"sellerToken\", jsonData.data.tokens.access.token);",
                  "    console.log(\"Saved sellerToken:\", jsonData.data.tokens.access.token);",
                  "}"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\": \"{{sellerEmail}}\",\n  \"password\": \"{{sellerPassword}}\",\n  \"rememberMe\": true\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/auth/login",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "auth",
                "login"
              ]
            },
            "description": "Seller login using email address. Also returns `mustChangePassword` boolean flag."
          },
          "response": []
        },
        {
          "name": "5. Seller Login (via Username)",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 200\", function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "var jsonData = pm.response.json();",
                  "pm.test(\"Seller login via username successful\", function () {",
                  "    pm.expect(jsonData.success).to.eql(true);",
                  "});",
                  "if (jsonData.data && jsonData.data.tokens && jsonData.data.tokens.access) {",
                  "    pm.collectionVariables.set(\"sellerToken\", jsonData.data.tokens.access.token);",
                  "}"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\": \"{{sellerUsername}}\",\n  \"password\": \"{{sellerPassword}}\"\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/auth/login",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "auth",
                "login"
              ]
            },
            "description": "Seller login using username instead of email in the identifier field."
          },
          "response": []
        },
        {
          "name": "6. Seller Lost Username",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 200\", function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "var jsonData = pm.response.json();",
                  "pm.test(\"Lost username email sent\", function () {",
                  "    pm.expect(jsonData.success).to.eql(true);",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\": \"{{sellerEmail}}\"\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/auth/seller/lost-username",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "auth",
                "seller",
                "lost-username"
              ]
            },
            "description": "Sends the registered username to the seller's email address."
          },
          "response": []
        },
        {
          "name": "7. Seller Lost Password",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 200\", function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "var jsonData = pm.response.json();",
                  "pm.test(\"Temporary password sent\", function () {",
                  "    pm.expect(jsonData.success).to.eql(true);",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\": \"{{sellerEmail}}\"\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/auth/seller/lost-password",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "auth",
                "seller",
                "lost-password"
              ]
            },
            "description": "Generates a random secure temporary password and emails it to the seller. Sets `mustChangePassword: true` on the account, requiring a password change upon logging in."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Category Management",
      "description": "Category APIs for admin management of 3-level categories across New and Used product navigations.",
      "item": [
        {
          "name": "1. Navigations",
          "item": [
            {
              "name": "Get Available Navigations",
              "request": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{baseUrl}}/categories/navigations",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "categories",
                    "navigations"
                  ]
                },
                "description": "Returns available navigations: New Products ('new'), Used Products ('used'), and any added navigations."
              },
              "response": []
            },
            {
              "name": "Add Navigation",
              "request": {
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{adminToken}}",
                      "type": "string"
                    }
                  ]
                },
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"name\": \"Refurbished Products\",\n  \"navigation\": \"refurbished\",\n  \"description\": \"Certified refurbished and open-box equipment\"\n}"
                },
                "url": {
                  "raw": "{{baseUrl}}/categories/navigations",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "categories",
                    "navigations"
                  ]
                },
                "description": "Add a new navigation layer directly in the Category collection. The new navigation will immediately be available in Get Navigations and Tree view."
              },
              "response": []
            }
          ]
        },
        {
          "name": "2. Get All Categories",
          "item": [
            {
              "name": "Get Categories (Paginated & Filtered)",
              "request": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{baseUrl}}/categories?navigation=new&level=1&page=1&limit=20",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "categories"
                  ],
                  "query": [
                    {
                      "key": "navigation",
                      "value": "new",
                      "description": "Filter by navigation ('new' or 'used')"
                    },
                    {
                      "key": "level",
                      "value": "1",
                      "description": "Filter by level (1, 2, or 3)"
                    },
                    {
                      "key": "status",
                      "value": "active",
                      "description": "Filter by status ('active', 'inactive', 'removed')",
                      "disabled": true
                    },
                    {
                      "key": "parentId",
                      "value": "{{mainCategoryId}}",
                      "description": "Filter by parent category ID",
                      "disabled": true
                    },
                    {
                      "key": "page",
                      "value": "1"
                    },
                    {
                      "key": "limit",
                      "value": "20"
                    }
                  ]
                },
                "description": "Get flat list of categories with pagination, filtering, navigationLabel and displayName."
              },
              "response": []
            },
            {
              "name": "Get Categories Tree View",
              "request": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{baseUrl}}/categories?tree=true",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "categories"
                  ],
                  "query": [
                    {
                      "key": "tree",
                      "value": "true"
                    }
                  ]
                },
                "description": "Get complete nested hierarchy: Navigation -> Main Category -> Sub Category -> Sub-Sub Category."
              },
              "response": []
            },
            {
              "name": "Search Categories by Name",
              "request": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{baseUrl}}/categories?search=Lenses",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "categories"
                  ],
                  "query": [
                    {
                      "key": "search",
                      "value": "Lenses"
                    }
                  ]
                },
                "description": "Search categories by name."
              },
              "response": []
            },
            {
              "name": "Get Category by ID",
              "request": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{baseUrl}}/categories/{{categoryId}}?navigation=new",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "categories",
                    "{{categoryId}}"
                  ],
                  "query": [
                    {
                      "key": "navigation",
                      "value": "new",
                      "description": "Optional navigation scope ('new' or 'used') when querying by slug or categoryNumber",
                      "disabled": true
                    }
                  ]
                },
                "description": "Get single category details with ancestor breadcrumb hierarchy. Accepts MongoDB ObjectId, numbered slug (e.g. 26-lenses-adaptors), or numeric categoryNumber (e.g. 26). Optional '?navigation=new' or '?navigation=used' can be provided to scope lookups."
              },
              "response": []
            },
            {
              "name": "Get Category by Slug or Number",
              "request": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{baseUrl}}/categories/26-lenses-adaptors?navigation=used",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "categories",
                    "26-lenses-adaptors"
                  ],
                  "query": [
                    {
                      "key": "navigation",
                      "value": "used",
                      "description": "Optional navigation scope ('new' or 'used') when identical slug exists across both navigations"
                    }
                  ]
                },
                "description": "Get category details directly using its auto-generated numbered slug (e.g. 26-lenses-adaptors) or categoryNumber (e.g. 26). Uses ?navigation=used to scope cleanly without needing -used in the slug."
              },
              "response": []
            }
          ]
        },
        {
          "name": "3. Add New Category (3 Levels)",
          "item": [
            {
              "name": "Add Main Category (Level 1 - New Products)",
              "event": [
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      "pm.test(\"Status code is 201\", function () {",
                      "    pm.response.to.have.status(201);",
                      "});",
                      "var jsonData = pm.response.json();",
                      "if (jsonData && jsonData.id) {",
                      "    pm.collectionVariables.set(\"mainCategoryId\", jsonData.id);",
                      "    pm.collectionVariables.set(\"categoryId\", jsonData.id);",
                      "    console.log(\"Saved mainCategoryId:\", jsonData.id);",
                      "}"
                    ],
                    "type": "text/javascript"
                  }
                }
              ],
              "request": {
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{adminToken}}",
                      "type": "string"
                    }
                  ]
                },
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"name\": \"Lenses\",\n  \"type\": \"Main Category\",\n  \"navigation\": \"New Products\",\n  \"description\": \"Professional camera and cinema lenses\",\n  \"categoryThumbnail\": \"http://localhost:4000/uploads/categories/lenses.webp\"\n}"
                },
                "url": {
                  "raw": "{{baseUrl}}/categories",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "categories"
                  ]
                },
                "description": "Create a Level 1 Main Category in 'New Products' navigation. Note: 'categoryNumber' and numbered 'slug' (e.g. 26-lenses) are generated automatically based on navigation. 'categoryThumbnail' is optional (URL string in JSON or binary file via multipart/form-data)."
              },
              "response": []
            },
            {
              "name": "Add Main Category with File Upload (multipart/form-data)",
              "request": {
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{adminToken}}",
                      "type": "string"
                    }
                  ]
                },
                "method": "POST",
                "header": [],
                "body": {
                  "mode": "formdata",
                  "formdata": [
                    {
                      "key": "name",
                      "value": "Cinema Cameras",
                      "type": "text"
                    },
                    {
                      "key": "type",
                      "value": "Main Category",
                      "type": "text"
                    },
                    {
                      "key": "navigation",
                      "value": "New Products",
                      "type": "text"
                    },
                    {
                      "key": "description",
                      "value": "High-end 4K/8K digital cinema cameras",
                      "type": "text"
                    },
                    {
                      "key": "categoryThumbnail",
                      "type": "file",
                      "src": [],
                      "description": "Optional category thumbnail image file. Sharp automatically compresses and converts it to WebP."
                    }
                  ]
                },
                "url": {
                  "raw": "{{baseUrl}}/categories",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "categories"
                  ]
                },
                "description": "Create a category uploading a thumbnail file directly using multipart/form-data. The server optimizes and converts the image to WebP using Sharp and stores the public URL in 'categoryThumbnail' and 'thumbnail'."
              },
              "response": []
            },
            {
              "name": "Add Main Category (Level 1 - Used Products)",
              "request": {
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{adminToken}}",
                      "type": "string"
                    }
                  ]
                },
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"name\": \"Lenses\",\n  \"type\": \"Main Category\",\n  \"navigation\": \"Used Products\",\n  \"description\": \"Pre-owned cinema and broadcast lenses\"\n}"
                },
                "url": {
                  "raw": "{{baseUrl}}/categories",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "categories"
                  ]
                },
                "description": "Create same category name in 'Used Products' navigation. Slugs are scoped per navigation, producing a clean SEO slug (e.g. 26-lenses) identical to New Products without appending '-used'."
              },
              "response": []
            },
            {
              "name": "Add Sub Category (Level 2)",
              "event": [
                {
                  "listen": "test",
                  "script": {
                    "exec": [
                      "pm.test(\"Status code is 201\", function () {",
                      "    pm.response.to.have.status(201);",
                      "});",
                      "var jsonData = pm.response.json();",
                      "if (jsonData && jsonData.id) {",
                      "    pm.collectionVariables.set(\"subCategoryId\", jsonData.id);",
                      "    pm.collectionVariables.set(\"categoryId\", jsonData.id);",
                      "    console.log(\"Saved subCategoryId:\", jsonData.id);",
                      "}"
                    ],
                    "type": "text/javascript"
                  }
                }
              ],
              "request": {
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{adminToken}}",
                      "type": "string"
                    }
                  ]
                },
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"name\": \"Cinema Lenses\",\n  \"type\": \"Sub Category\",\n  \"parentId\": \"{{mainCategoryId}}\",\n  \"description\": \"High-end cinema prime and zoom lenses\"\n}"
                },
                "url": {
                  "raw": "{{baseUrl}}/categories",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "categories"
                  ]
                },
                "description": "Create Level 2 Sub Category. Navigation auto-inherited from parent."
              },
              "response": []
            },
            {
              "name": "Add Sub-Sub Category (Level 3)",
              "request": {
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{adminToken}}",
                      "type": "string"
                    }
                  ]
                },
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"name\": \"Anamorphic Lenses\",\n  \"type\": \"Sub Sub Category\",\n  \"parentId\": \"{{subCategoryId}}\",\n  \"description\": \"Widescreen anamorphic cinema lenses\"\n}"
                },
                "url": {
                  "raw": "{{baseUrl}}/categories",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "categories"
                  ]
                },
                "description": "Create Level 3 Sub-Sub Category. Navigation auto-inherited."
              },
              "response": []
            }
          ]
        },
        {
          "name": "4. Update & Status",
          "item": [
            {
              "name": "Update Category Details",
              "request": {
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{adminToken}}",
                      "type": "string"
                    }
                  ]
                },
                "method": "PATCH",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"name\": \"Broadcast Cinema Lenses\",\n  \"description\": \"Updated description for cinema lenses\",\n  \"categoryThumbnail\": \"http://localhost:4000/uploads/categories/updated-lens.webp\"\n}"
                },
                "url": {
                  "raw": "{{baseUrl}}/categories/{{categoryId}}",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "categories",
                    "{{categoryId}}"
                  ]
                },
                "description": "Update category name, description, or categoryThumbnail URL. Note: If 'name' is updated, its slug (e.g. 26-broadcast-cinema-lenses) is automatically re-generated while preserving its categoryNumber."
              },
              "response": []
            },
            {
              "name": "Update Category Thumbnail (multipart/form-data)",
              "request": {
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{adminToken}}",
                      "type": "string"
                    }
                  ]
                },
                "method": "PATCH",
                "header": [],
                "body": {
                  "mode": "formdata",
                  "formdata": [
                    {
                      "key": "categoryThumbnail",
                      "type": "file",
                      "src": [],
                      "description": "New thumbnail image file. Sharp automatically compresses and converts it to WebP."
                    }
                  ]
                },
                "url": {
                  "raw": "{{baseUrl}}/categories/{{categoryId}}",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "categories",
                    "{{categoryId}}"
                  ]
                },
                "description": "Update an existing category's thumbnail via direct file upload. Server uses Sharp to optimize and convert it to WebP, replacing the previous thumbnail."
              },
              "response": []
            },
            {
              "name": "Change Category Status (active/inactive)",
              "request": {
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{adminToken}}",
                      "type": "string"
                    }
                  ]
                },
                "method": "PATCH",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"status\": \"inactive\"\n}"
                },
                "url": {
                  "raw": "{{baseUrl}}/categories/{{categoryId}}/status",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "categories",
                    "{{categoryId}}",
                    "status"
                  ]
                },
                "description": "Change status to 'active' or 'inactive'. For deletion/removal, use the Remove Category endpoint which sets isRemoved: true."
              },
              "response": []
            }
          ]
        },
        {
          "name": "5. Category Products",
          "item": [
            {
              "name": "Get Products for Category",
              "request": {
                "method": "GET",
                "header": [],
                "url": {
                  "raw": "{{baseUrl}}/categories/{{categoryId}}/products?page=1&limit=10",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "categories",
                    "{{categoryId}}",
                    "products"
                  ],
                  "query": [
                    {
                      "key": "page",
                      "value": "1"
                    },
                    {
                      "key": "limit",
                      "value": "10"
                    }
                  ]
                },
                "description": "Display products under category and descendants with productNo, productName, subSubCategory, subCategory, mainCategory, navigation."
              },
              "response": []
            }
          ]
        },
        {
          "name": "6. Remove Category",
          "item": [
            {
              "name": "Remove Category (Uncategorize Products)",
              "request": {
                "auth": {
                  "type": "bearer",
                  "bearer": [
                    {
                      "key": "token",
                      "value": "{{adminToken}}",
                      "type": "string"
                    }
                  ]
                },
                "method": "DELETE",
                "header": [],
                "url": {
                  "raw": "{{baseUrl}}/categories/{{categoryId}}",
                  "host": [
                    "{{baseUrl}}"
                  ],
                  "path": [
                    "categories",
                    "{{categoryId}}"
                  ]
                },
                "description": "Remove category and mark all attached products as uncategorized (categoryId: null, isUncategorized: true)."
              },
              "response": []
            }
          ]
        }
      ]
    },
    {
      "name": "Listing & Product Management",
      "item": [
        {
          "name": "1. Admin Add New Product (Direct Image Upload & Create)",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 201\", function () {",
                  "    pm.response.to.have.status(201);",
                  "});",
                  "var jsonData = pm.response.json();",
                  "pm.test(\"Response is success\", function () {",
                  "    pm.expect(jsonData.success).to.eql(true);",
                  "    pm.expect(jsonData.data).to.have.property(\"listingNo\");",
                  "    pm.expect(jsonData.data.productType).to.eql(\"new-ads\");",
                  "    pm.expect(jsonData.data.addedBy).to.eql(\"admin\");",
                  "});",
                  "if (jsonData.data && jsonData.data.id) {",
                  "    pm.collectionVariables.set(\"listingId\", jsonData.data.id);",
                  "    console.log(\"Saved listingId:\", jsonData.data.id);",
                  "}"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{adminToken}}",
                  "type": "string"
                }
              ]
            },
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "categoryId",
                  "value": "{{categoryId}}",
                  "type": "text"
                },
                {
                  "key": "title",
                  "value": "Blackmagic ATEM Mini Pro",
                  "type": "text"
                },
                {
                  "key": "manufacturer",
                  "value": "Blackmagic Design",
                  "type": "text"
                },
                {
                  "key": "modelNumber",
                  "value": "ATEM Mini Pro",
                  "type": "text"
                },
                {
                  "key": "price",
                  "value": "1249",
                  "type": "text"
                },
                {
                  "key": "currency",
                  "value": "AUD",
                  "type": "text"
                },
                {
                  "key": "stockUnit",
                  "value": "24",
                  "type": "text"
                },
                {
                  "key": "isPriceNegotiable",
                  "value": "false",
                  "type": "text"
                },
                {
                  "key": "accessoriesIncluded",
                  "value": "Power supply, international socket adapters",
                  "type": "text"
                },
                {
                  "key": "optionalAccessories",
                  "value": "HDMI cables, Carrying case",
                  "type": "text"
                },
                {
                  "key": "detailedNotes",
                  "value": "Brand new in original box, never opened with full manufacturer warranty.",
                  "type": "text"
                },
                {
                  "key": "images",
                  "type": "file",
                  "src": [],
                  "description": "Upload up to 5 image files (JPEG/PNG, max 2MB each)"
                }
              ]
            },
            "url": {
              "raw": "{{baseUrl}}/listings",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "listings"
              ]
            },
            "description": "Admin creates listing and uploads images directly in a single request (multipart/form-data). Files are automatically saved to /uploads/products and stored in listingImages."
          },
          "response": []
        },
        {
          "name": "2. Seller Post an Ad (Direct Image Upload & Create)",
          "event": [
            {
              "listen": "test",
              "script": {
                "exec": [
                  "pm.test(\"Status code is 201\", function () {",
                  "    pm.response.to.have.status(201);",
                  "});",
                  "var jsonData = pm.response.json();",
                  "pm.test(\"Response is success\", function () {",
                  "    pm.expect(jsonData.success).to.eql(true);",
                  "    pm.expect(jsonData.data.productType).to.eql(\"used-product\");",
                  "    pm.expect(jsonData.data.addedBy).to.eql(\"seller\");",
                  "});"
                ],
                "type": "text/javascript"
              }
            }
          ],
          "request": {
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{sellerToken}}",
                  "type": "string"
                }
              ]
            },
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "categoryId",
                  "value": "{{categoryId}}",
                  "type": "text"
                },
                {
                  "key": "contactFirstName",
                  "value": "James",
                  "type": "text"
                },
                {
                  "key": "contactLastName",
                  "value": "Mitchell",
                  "type": "text"
                },
                {
                  "key": "contactEmail",
                  "value": "james.mitchell@broadcastav.com.au",
                  "type": "text"
                },
                {
                  "key": "contactPhone",
                  "value": "+61 412 345 678",
                  "type": "text"
                },
                {
                  "key": "businessName",
                  "value": "Outback Trading Co",
                  "type": "text"
                },
                {
                  "key": "australianABN",
                  "value": "51 824 753 556",
                  "type": "text"
                },
                {
                  "key": "businessAddress",
                  "value": "42 Wallaby Way, Sydney",
                  "type": "text"
                },
                {
                  "key": "businessCity",
                  "value": "Melbourne",
                  "type": "text"
                },
                {
                  "key": "businessState",
                  "value": "Victoria",
                  "type": "text"
                },
                {
                  "key": "businessPostalCode",
                  "value": "3000",
                  "type": "text"
                },
                {
                  "key": "businessCountry",
                  "value": "Australia",
                  "type": "text"
                },
                {
                  "key": "title",
                  "value": "Canon EOS R5 Camera Kit",
                  "type": "text"
                },
                {
                  "key": "manufacturer",
                  "value": "Canon",
                  "type": "text"
                },
                {
                  "key": "modelNumber",
                  "value": "EOS R5",
                  "type": "text"
                },
                {
                  "key": "workingCondition",
                  "value": "good",
                  "type": "text"
                },
                {
                  "key": "physicalCondition",
                  "value": "good",
                  "type": "text"
                },
                {
                  "key": "price",
                  "value": "2500",
                  "type": "text"
                },
                {
                  "key": "currency",
                  "value": "AUD",
                  "type": "text"
                },
                {
                  "key": "isPriceNegotiable",
                  "value": "true",
                  "type": "text"
                },
                {
                  "key": "reasonForSale",
                  "value": "Upgrading studio gear to Cinema series",
                  "type": "text"
                },
                {
                  "key": "accessoriesIncluded",
                  "value": "Original box, 2x batteries, 128GB SD card, lens hood, shoulder strap",
                  "type": "text"
                },
                {
                  "key": "optionalAccessories",
                  "value": "RF 24-70mm lens, EF adapter",
                  "type": "text"
                },
                {
                  "key": "detailedNotes",
                  "value": "Shutter count approx. 12,000. Clean sensor, minor cosmetic scratches on baseplate.",
                  "type": "text"
                },
                {
                  "key": "images",
                  "type": "file",
                  "src": [],
                  "description": "Upload up to 5 image files (JPEG/PNG, max 2MB each)"
                }
              ]
            },
            "url": {
              "raw": "{{baseUrl}}/listings",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "listings"
              ]
            },
            "description": "Seller creates listing and uploads images directly in a single request (multipart/form-data). Files are automatically saved to /uploads/products and stored in listingImages."
          },
          "response": []
        },
        {
          "name": "3. Get All Products (Filtered & Paginated)",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/listings?type=new-ads&status=active&categoryId={{categoryId}}&minPrice=0&maxPrice=10000&minStock=0&maxStock=100&minQuotes=0&maxQuotes=100&minOffers=0&maxOffers=100&search=&sortBy=createdAt:desc&limit=12&page=1",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "listings"
              ],
              "query": [
                {
                  "key": "type",
                  "value": "new-ads",
                  "description": "'new-ads' or 'used-product'"
                },
                {
                  "key": "status",
                  "value": "active",
                  "description": "'active', 'inactive', 'sold_out', 'deal_locked'"
                },
                {
                  "key": "categoryId",
                  "value": "{{categoryId}}",
                  "description": "Category ObjectId to filter products by category and subcategories",
                  "disabled": true
                },
                {
                  "key": "minPrice",
                  "value": "0",
                  "disabled": true
                },
                {
                  "key": "maxPrice",
                  "value": "10000",
                  "disabled": true
                },
                {
                  "key": "minStock",
                  "value": "0",
                  "disabled": true
                },
                {
                  "key": "maxStock",
                  "value": "100",
                  "disabled": true
                },
                {
                  "key": "minQuotes",
                  "value": "0",
                  "disabled": true
                },
                {
                  "key": "maxQuotes",
                  "value": "100",
                  "disabled": true
                },
                {
                  "key": "minOffers",
                  "value": "0",
                  "disabled": true
                },
                {
                  "key": "maxOffers",
                  "value": "100",
                  "disabled": true
                },
                {
                  "key": "search",
                  "value": "",
                  "description": "Search across brand, title, model, or listing number",
                  "disabled": true
                },
                {
                  "key": "sortBy",
                  "value": "newest",
                  "description": "Options: 'newest', 'oldest', 'Price: Low to High' (or price:asc), 'Price: High to Low' (or price:desc), 'Name: A-Z' (or a-z), 'Name: Z-A' (or z-a), 'Most Popular' (popular)"
                },
                {
                  "key": "limit",
                  "value": "12"
                },
                {
                  "key": "page",
                  "value": "1"
                },
                {
                  "key": "sellerId",
                  "value": "",
                  "description": "Filter listings by seller Mongo ID (for Seller profile Ads tab or admin view)",
                  "disabled": true
                }
              ]
            },
            "description": "Combined listing query endpoint. Supports multi-category filtration (main category includes all sub and sub-sub categories, or multiple checkbox IDs), status, price range, stock, quotes, offers, search, sorting (Newest, Oldest, Price Low/High, Name A-Z/Z-A, Most Popular), and pagination."
          },
          "response": []
        },
        {
          "name": "4. Get Product Details (by ID, Listing No, or Slug)",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/listings/{{listingId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "listings",
                "{{listingId}}"
              ]
            },
            "description": "Fetch complete details of a listing using either MongoDB ObjectId ({{listingId}}), numeric listing number (e.g. 506), or SEO slug (e.g. 101-blackmagic-atem-mini-pro)."
          },
          "response": []
        },
        {
          "name": "4b. Get Product by Slug",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/listings/101-blackmagic-atem-mini-pro",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "listings",
                "101-blackmagic-atem-mini-pro"
              ]
            },
            "description": "Fetch complete details of a product directly using its SEO slug ({listingNo}-{product-title-slug}). Used directly in frontend product detail routes."
          },
          "response": []
        },
        {
          "name": "5. Update Listing Details",
          "request": {
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{adminToken}}",
                  "type": "string"
                }
              ]
            },
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"price\": 1199,\n  \"stockUnit\": 15,\n  \"title\": \"Blackmagic ATEM Mini Pro (Updated Price)\"\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/listings/{{listingId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "listings",
                "{{listingId}}"
              ]
            },
            "description": "Update listing fields. If stockUnit is set to 0, status automatically changes to sold_out."
          },
          "response": []
        },
        {
          "name": "6. Change Listing Status (Single & Multiple)",
          "request": {
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{adminToken}}",
                  "type": "string"
                }
              ]
            },
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"ids\": [\n    \"{{listingId}}\"\n  ],\n  \"status\": \"inactive\"\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/listings/status",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "listings",
                "status"
              ]
            },
            "description": "Unified status API: Pass single ID [\"id\"] or multiple IDs [\"id1\", \"id2\"] in the ids array. Admin allowed: active, inactive, sold_out. Seller allowed: active, deal_locked."
          },
          "response": []
        },
        {
          "name": "7. Delete Listing(s) (Single & Multiple)",
          "request": {
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{adminToken}}",
                  "type": "string"
                }
              ]
            },
            "method": "DELETE",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"ids\": [\n    \"{{listingId}}\"\n  ]\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/listings",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "listings"
              ]
            },
            "description": "Unified delete API: Pass single ID [\"id\"] or multiple IDs [\"id1\", \"id2\"] in the ids array for soft deletion."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Profile Management",
      "description": "Endpoints to view and update logged-in Admin and Seller profile details and avatar photo.",
      "item": [
        {
          "name": "1. Get My Profile (Admin / Seller)",
          "request": {
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{adminToken}}",
                  "type": "string"
                }
              ]
            },
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/users/profile",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "users",
                "profile"
              ]
            },
            "description": "Returns authenticated user profile (Admin or Seller) including formattedName, memberSince, views, and contact details."
          }
        },
        {
          "name": "2. Update My Profile (JSON / Details)",
          "request": {
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{adminToken}}",
                  "type": "string"
                }
              ]
            },
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"firstName\": \"Jimmy\",\n  \"lastName\": \"Overton\",\n  \"phone\": \"+61 412 345 678\",\n  \"city\": \"Sydney\",\n  \"country\": \"Australia\",\n  \"postalCode\": \"2000\"\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/users/profile",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "users",
                "profile"
              ]
            },
            "description": "Updates personal/contact details for logged-in Admin or Seller."
          }
        },
        {
          "name": "3. Update My Profile Photo (Multipart / File Upload)",
          "request": {
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "{{adminToken}}",
                  "type": "string"
                }
              ]
            },
            "method": "PATCH",
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "profileImage",
                  "type": "file",
                  "src": "",
                  "description": "Select an image file (JPEG or PNG, max 2MB)"
                },
                {
                  "key": "firstName",
                  "value": "Jimmy",
                  "type": "text"
                }
              ]
            },
            "url": {
              "raw": "{{baseUrl}}/users/profile",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "users",
                "profile"
              ]
            },
            "description": "Uploads and updates avatar profile photo for Admin or Seller."
          }
        }
      ]
    },
    {
      "name": "Seller Management (Admin)",
      "item": [
        {
          "name": "1. Get All Sellers (Admin)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{adminToken}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/sellers?page=1&limit=10",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "sellers"
              ],
              "query": [
                {
                  "key": "page",
                  "value": "1"
                },
                {
                  "key": "limit",
                  "value": "10"
                },
                {
                  "key": "status",
                  "value": "active",
                  "disabled": true,
                  "description": "active | inactive | suspended"
                },
                {
                  "key": "search",
                  "value": "",
                  "disabled": true,
                  "description": "Search company, name, email"
                }
              ]
            },
            "description": "Get paginated list of registered sellers with status and product counts."
          }
        },
        {
          "name": "2. Change Seller Status (Active / Inactive / Suspended) (Admin)",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Authorization",
                "value": "Bearer {{adminToken}}"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"ids\": [\n    \"{{sellerId}}\"\n  ],\n  \"status\": \"active\",\n  \"reason\": \"Verified business documentation\",\n  \"reasonMessage\": \"Showroom and ABN verified.\"\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/sellers/status",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "sellers",
                "status"
              ]
            },
            "description": "Update seller status to active, inactive, or suspended. Triggers an admin activity log entry."
          }
        },
        {
          "name": "3. Get Seller By ID (Admin)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{adminToken}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/sellers/{{sellerId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "sellers",
                "{{sellerId}}"
              ]
            },
            "description": "Get complete seller profile with product counts, views, contact details, and current status."
          }
        }
      ]
    },
    {
      "name": "Quote Management",
      "item": [
        {
          "name": "1. Submit Quote (Buyer / Guest)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"listingNo\": 101,\n  \"firstName\": \"Sarah\",\n  \"lastName\": \"Jenkins\",\n  \"email\": \"sarah.jenkins@example.com\",\n  \"phone\": \"+61 412 345 678\",\n  \"comments\": \"Looking for a formal quote for bulk purchase.\"\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/quotes",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "quotes"
              ]
            },
            "description": "Submit quote request for a listing. Triggers `quote_received` admin notification."
          }
        },
        {
          "name": "2. Get All Quotes (Admin)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{adminToken}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/quotes?page=1&limit=10",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "quotes"
              ],
              "query": [
                {
                  "key": "page",
                  "value": "1"
                },
                {
                  "key": "limit",
                  "value": "10"
                },
                {
                  "key": "status",
                  "value": "pending",
                  "disabled": true,
                  "description": "pending | quote_sent | sold | all"
                },
                {
                  "key": "search",
                  "value": "",
                  "disabled": true
                }
              ]
            },
            "description": "Query all non-deleted quotes with filters."
          }
        },
        {
          "name": "3. Get Quote By ID (Admin)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{adminToken}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/quotes/{{quoteId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "quotes",
                "{{quoteId}}"
              ]
            },
            "description": "Retrieve full details of a quote including populated product and buyer info."
          }
        },
        {
          "name": "4. Change Quotes Status (Admin)",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Authorization",
                "value": "Bearer {{adminToken}}"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"ids\": [\n    \"{{quoteId}}\"\n  ],\n  \"status\": \"quote_sent\"\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/quotes/status",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "quotes",
                "status"
              ]
            },
            "description": "Update quote status to pending, quote_sent, or sold. Logs admin activity."
          }
        },
        {
          "name": "5. Delete Quotes (Admin)",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Authorization",
                "value": "Bearer {{adminToken}}"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"ids\": [\n    \"{{quoteId}}\"\n  ]\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/quotes",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "quotes"
              ]
            },
            "description": "Soft delete quote(s). Logs admin activity."
          }
        }
      ]
    },
    {
      "name": "Offer Management",
      "item": [
        {
          "name": "1. Submit Offer (Buyer / Guest)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"listingNo\": 101,\n  \"firstName\": \"David\",\n  \"lastName\": \"Chen\",\n  \"email\": \"david.chen@example.com\",\n  \"phone\": \"+61 411 999 888\",\n  \"offerPrice\": 18500,\n  \"comments\": \"Offering $18,500 with immediate payment.\"\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/offers",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "offers"
              ]
            },
            "description": "Submit an offer for a product. Triggers `offer_submitted` notification."
          }
        },
        {
          "name": "2. Get All Offers (Admin)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{adminToken}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/offers?page=1&limit=10",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "offers"
              ],
              "query": [
                {
                  "key": "page",
                  "value": "1"
                },
                {
                  "key": "limit",
                  "value": "10"
                },
                {
                  "key": "status",
                  "value": "pending",
                  "disabled": true,
                  "description": "pending | shared | sold | rejected | all"
                },
                {
                  "key": "search",
                  "value": "",
                  "disabled": true
                }
              ]
            },
            "description": "Query all non-deleted offers with filters."
          }
        },
        {
          "name": "3. Get Offer By ID (Admin)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{adminToken}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/offers/{{offerId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "offers",
                "{{offerId}}"
              ]
            },
            "description": "Retrieve full details of an offer."
          }
        },
        {
          "name": "4. Change Offers Status (Admin)",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Authorization",
                "value": "Bearer {{adminToken}}"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"ids\": [\n    \"{{offerId}}\"\n  ],\n  \"status\": \"sold\"\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/offers/status",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "offers",
                "status"
              ]
            },
            "description": "Update status to pending, shared, sold, or rejected. Triggers `offer_accepted` or `offer_declined` notification and logs admin activity."
          }
        },
        {
          "name": "5. Delete Offers (Admin)",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Authorization",
                "value": "Bearer {{adminToken}}"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"ids\": [\n    \"{{offerId}}\"\n  ]\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/offers",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "offers"
              ]
            },
            "description": "Soft delete offer(s). Logs admin activity."
          }
        }
      ]
    },
    {
      "name": "Enquiry Management (Questions)",
      "item": [
        {
          "name": "1. Submit Enquiry (Buyer/Public)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"listingNo\": {{listingNo}},\n  \"firstName\": \"John\",\n  \"lastName\": \"Doe\",\n  \"email\": \"john.doe@example.com\",\n  \"phone\": \"+61 411 222 333\",\n  \"question\": \"Is the camera body still in warranty?\"\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/enquiries",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "enquiries"
              ]
            },
            "description": "Submit a question for a listing. Can pass `listingNo`, `listingId`, or `productId`. Automatically registers or finds the buyer in User table."
          }
        },
        {
          "name": "2. Get All Enquiries (Admin - Pending Only by Default)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{adminToken}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/enquiries?page=1&limit=10",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "enquiries"
              ],
              "query": [
                {
                  "key": "page",
                  "value": "1"
                },
                {
                  "key": "limit",
                  "value": "10"
                },
                {
                  "key": "status",
                  "value": "pending",
                  "description": "Optional: 'pending', 'responded', or 'all' (default is 'pending')",
                  "disabled": true
                },
                {
                  "key": "search",
                  "value": "",
                  "description": "Search by buyer name, email, phone, question, or product name",
                  "disabled": true
                },
                {
                  "key": "listingNo",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "sortBy",
                  "value": "createdAt:desc",
                  "disabled": true
                }
              ]
            },
            "description": "Fetches all enquiries. Defaults to pending queries, excluding responded and deleted queries."
          }
        },
        {
          "name": "3. Get Enquiry By ID (Admin)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{adminToken}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/enquiries/{{enquiryId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "enquiries",
                "{{enquiryId}}"
              ]
            },
            "description": "Fetches complete details of an enquiry including populated product info and buyer info."
          }
        },
        {
          "name": "4. Update Enquiry Status (Single or Bulk) (Admin)",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Authorization",
                "value": "Bearer {{adminToken}}"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"ids\": [\n    \"{{enquiryId}}\"\n  ],\n  \"status\": \"responded\"\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/enquiries/status",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "enquiries",
                "status"
              ]
            },
            "description": "Bulk update status of multiple enquiries to 'responded' or 'pending'."
          }
        },
        {
          "name": "5. Delete Enquiry (Single or Bulk) (Admin)",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Authorization",
                "value": "Bearer {{adminToken}}"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"ids\": [\n    \"{{enquiryId}}\"\n  ]\n}"
            },
            "url": {
              "raw": "{{baseUrl}}/enquiries",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "enquiries"
              ]
            },
            "description": "Soft-deletes one or multiple enquiries via array of IDs or single ID string, and decrements product enquiriesCount."
          }
        }
      ]
    },
    {
      "name": "Dashboard Management (Admin)",
      "item": [
        {
          "name": "1. Get Platform Stats (Admin)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{adminToken}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/dashboard/stats",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "dashboard",
                "stats"
              ]
            },
            "description": "5 metric cards comparing against last month: total sellers, new products, used products, pending quotes, pending offers."
          }
        },
        {
          "name": "2. Get Products Trend (Admin)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{adminToken}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/dashboard/products-trend?interval=monthly&year=2026&month=9",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "dashboard",
                "products-trend"
              ],
              "query": [
                {
                  "key": "interval",
                  "value": "monthly",
                  "description": "yearly | monthly | weekly | daily"
                },
                {
                  "key": "year",
                  "value": "2026"
                },
                {
                  "key": "month",
                  "value": "9"
                }
              ]
            },
            "description": "Trend of new vs used products over specified intervals."
          }
        },
        {
          "name": "3. Get Recent Activity By Admin (recentactivityByAdmin)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{adminToken}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/dashboard/recent-activity?module=all",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "dashboard",
                "recent-activity"
              ],
              "query": [
                {
                  "key": "module",
                  "value": "all",
                  "description": "Filter by module: all | listing | seller | category | quote | offer | enquiry (or questions)"
                }
              ]
            },
            "description": "Returns all admin activities from the past 7 days (auto-deleted after 7 days via TTL index). Includes performing admin info, module, action, target entity name, human-readable description, details, and relative timeAgo."
          }
        }
      ]
    },
    {
      "name": "Admin Notifications",
      "item": [
        {
          "name": "1. Get Admin Notifications (7 Days)",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{adminToken}}"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/notifications",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "notifications"
              ]
            },
            "description": "Returns all admin notifications from the past 7 days in descending order (createdAt: desc). Includes unreadCount, dynamically resolved thumbnail image (product image or seller avatar), and short relative timeAgo (2m, 8m, 1h, 2d). Auto-deleted after 7 days."
          }
        },
        {
          "name": "2. Mark Notification(s) as Read (Single, Multiple, or All)",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Authorization",
                "value": "Bearer {{adminToken}}"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"ids\": [\n    \"{{notificationId}}\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/notifications/read",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "notifications",
                "read"
              ]
            },
            "description": "Unified endpoint to mark notifications as read.\n\nUsage:\n1. Single or Multiple: Pass `\"ids\": [\"<notificationId>\"]` (or single string `\"ids\": \"<notificationId>\"`). Only unread items will be updated.\n2. Mark All as Read: Pass empty body `{}` or `{\"all\": true}`. All unread notifications from the past 7 days will be marked as read.\n\nAlready-read notifications are completely skipped and their timestamps remain unchanged."
          }
        }
      ]
    }
  ]
}