{
  "info": {
    "name": "LoyaltyLoop API",
    "description": "Complete API collection for the LoyaltyLoop loyalty platform.\n\n## Collection Variables (set once)\n| Variable | Default | Description |\n|---|---|---|\n| `base_url` | `https://loyaltyloop.in` | Server URL — change to `http://localhost` for local dev |\n| `api_key` | `ll_YOUR_API_KEY_HERE` | From Settings → API Access |\n\n## Per-Request Path Variables\nRequests with dynamic path segments (customer ID, QR code, webhook ID) use Postman **path variables** (`:variable` syntax). Set them in the **Path Variables** tab of each request — they are scoped to that request only and do not affect other requests.\n\n## Authentication\nAll requests inherit `Authorization: Bearer {{api_key}}` from the collection.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "version": "1.3.0"
  },
  "variable": [
    {
      "key": "base_url",
      "value": "https://loyaltyloop.in",
      "description": "Server URL — no trailing slash. Change to http://localhost for local dev."
    },
    {
      "key": "api_key",
      "value": "ll_YOUR_API_KEY_HERE",
      "description": "Your API key from Settings → API Access"
    }
  ],
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{api_key}}",
        "type": "string"
      }
    ]
  },
  "item": [
    {
      "name": "Customers",
      "description": "Endpoints for managing loyalty program customers.",
      "item": [
        {
          "name": "List Customers",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/customers?page=1&limit=50",
              "host": ["{{base_url}}"],
              "path": ["api", "v1", "customers"],
              "query": [
                {
                  "key": "page",
                  "value": "1",
                  "description": "Page number (default: 1)"
                },
                {
                  "key": "limit",
                  "value": "50",
                  "description": "Results per page (default: 50, max: 100)"
                }
              ]
            },
            "description": "Retrieve a paginated list of all customers in your loyalty program."
          },
          "response": [
            {
              "name": "200 OK",
              "status": "OK",
              "code": 200,
              "header": [{ "key": "Content-Type", "value": "application/json" }],
              "body": "{\n  \"data\": [\n    {\n      \"id\": 1,\n      \"name\": \"John Doe\",\n      \"email\": \"john@example.com\",\n      \"phone\": \"1234567890\",\n      \"qr_code\": \"CUS12AB34CD56EF\",\n      \"current_stamps\": 8,\n      \"current_points\": 0,\n      \"total_visits\": 15,\n      \"rewards_earned\": 2,\n      \"rewards_redeemed\": 1,\n      \"joined_at\": \"2026-01-15 10:30:00\",\n      \"last_visit\": \"2026-03-10 14:20:00\"\n    }\n  ],\n  \"pagination\": {\n    \"page\": 1,\n    \"limit\": 50,\n    \"total\": 150,\n    \"pages\": 3\n  }\n}"
            },
            {
              "name": "401 Unauthorized",
              "status": "Unauthorized",
              "code": 401,
              "header": [{ "key": "Content-Type", "value": "application/json" }],
              "body": "{\n  \"error\": true,\n  \"message\": \"Invalid or disabled API key\"\n}"
            }
          ]
        },
        {
          "name": "Get Customer",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/customers/:customer_id",
              "host": ["{{base_url}}"],
              "path": ["api", "v1", "customers", ":customer_id"],
              "variable": [
                {
                  "key": "customer_id",
                  "value": "1",
                  "description": "Numeric ID of the customer to retrieve"
                }
              ]
            },
            "description": "Get detailed info for a customer, including their last 20 transactions.\n\nSet `:customer_id` in the **Path Variables** tab."
          },
          "response": [
            {
              "name": "200 OK",
              "status": "OK",
              "code": 200,
              "header": [{ "key": "Content-Type", "value": "application/json" }],
              "body": "{\n  \"data\": {\n    \"id\": 1,\n    \"name\": \"John Doe\",\n    \"email\": \"john@example.com\",\n    \"phone\": \"1234567890\",\n    \"qr_code\": \"CUS12AB34CD56EF\",\n    \"current_stamps\": 8,\n    \"current_points\": 0,\n    \"total_visits\": 15,\n    \"rewards_earned\": 2,\n    \"rewards_redeemed\": 1,\n    \"joined_at\": \"2026-01-15 10:30:00\",\n    \"last_visit\": \"2026-03-10 14:20:00\",\n    \"transactions\": [\n      {\n        \"id\": 45,\n        \"transaction_type\": \"stamp_add\",\n        \"stamps_added\": 1,\n        \"points_added\": 0,\n        \"created_at\": \"2026-03-10 14:20:00\"\n      }\n    ]\n  }\n}"
            },
            {
              "name": "404 Not Found",
              "status": "Not Found",
              "code": 404,
              "header": [{ "key": "Content-Type", "value": "application/json" }],
              "body": "{\n  \"error\": true,\n  \"message\": \"Customer not found\"\n}"
            }
          ]
        },
        {
          "name": "Get Customer by QR Code",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/customers/qr/:qr_code",
              "host": ["{{base_url}}"],
              "path": ["api", "v1", "customers", "qr", ":qr_code"],
              "variable": [
                {
                  "key": "qr_code",
                  "value": "CUS12AB34CD56EF",
                  "description": "Customer QR code value scanned from their loyalty card"
                }
              ]
            },
            "description": "Look up a customer by their QR code. Set `:qr_code` in the **Path Variables** tab to the scanned QR value.\n\nUse this before stamping to display the customer's current loyalty status."
          },
          "response": [
            {
              "name": "200 OK",
              "status": "OK",
              "code": 200,
              "header": [{ "key": "Content-Type", "value": "application/json" }],
              "body": "{\n  \"data\": {\n    \"id\": 1,\n    \"name\": \"John Doe\",\n    \"phone\": \"1234567890\",\n    \"email\": \"john@example.com\",\n    \"qr_code\": \"CUS12AB34CD56EF\",\n    \"current_stamps\": 5,\n    \"current_points\": 0,\n    \"rewards_earned\": 1,\n    \"rewards_redeemed\": 1,\n    \"total_visits\": 10,\n    \"is_active\": 1,\n    \"joined_at\": \"2026-01-15 10:30:00\",\n    \"last_visit\": \"2026-03-18 14:00:00\",\n    \"transactions\": [\n      {\n        \"id\": 38,\n        \"transaction_type\": \"stamp_add\",\n        \"stamps_added\": 1,\n        \"created_at\": \"2026-03-18 14:00:00\"\n      }\n    ]\n  }\n}"
            },
            {
              "name": "404 Not Found",
              "status": "Not Found",
              "code": 404,
              "header": [{ "key": "Content-Type", "value": "application/json" }],
              "body": "{\n  \"error\": true,\n  \"message\": \"Customer not found\"\n}"
            }
          ]
        },
        {
          "name": "Add Stamps by QR Code ★ recommended",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"stamps\": 1\n}",
              "options": { "raw": { "language": "json" } }
            },
            "url": {
              "raw": "{{base_url}}/api/v1/customers/qr/:qr_code/stamps",
              "host": ["{{base_url}}"],
              "path": ["api", "v1", "customers", "qr", ":qr_code", "stamps"],
              "variable": [
                {
                  "key": "qr_code",
                  "value": "CUS12AB34CD56EF",
                  "description": "Customer QR code value scanned from their loyalty card"
                }
              ]
            },
            "description": "**Primary scan-and-stamp flow.** Set `:qr_code` in the **Path Variables** tab to the scanned value.\n\nWhen `current_stamps + stamps >= stamps_required` the card resets to 0, `rewards_earned` increments, and `reward_earned: true` is returned.\n\n**Body:** `stamps` — integer 1–10, defaults to 1."
          },
          "response": [
            {
              "name": "200 OK – Stamp Added",
              "status": "OK",
              "code": 200,
              "header": [{ "key": "Content-Type", "value": "application/json" }],
              "body": "{\n  \"data\": {\n    \"id\": 1,\n    \"name\": \"John Doe\",\n    \"qr_code\": \"CUS12AB34CD56EF\",\n    \"current_stamps\": 6,\n    \"current_points\": 0,\n    \"rewards_earned\": 1,\n    \"rewards_redeemed\": 1,\n    \"total_visits\": 11,\n    \"last_visit\": \"2026-03-18 15:00:00\",\n    \"reward_earned\": false,\n    \"stamps_required\": 8,\n    \"reward_description\": \"Free coffee\"\n  }\n}"
            },
            {
              "name": "200 OK – Reward Earned",
              "status": "OK",
              "code": 200,
              "header": [{ "key": "Content-Type", "value": "application/json" }],
              "body": "{\n  \"data\": {\n    \"id\": 1,\n    \"name\": \"John Doe\",\n    \"qr_code\": \"CUS12AB34CD56EF\",\n    \"current_stamps\": 0,\n    \"current_points\": 0,\n    \"rewards_earned\": 2,\n    \"rewards_redeemed\": 1,\n    \"total_visits\": 11,\n    \"last_visit\": \"2026-03-18 15:00:00\",\n    \"reward_earned\": true,\n    \"stamps_required\": 8,\n    \"reward_description\": \"Free coffee\"\n  }\n}"
            }
          ]
        },
        {
          "name": "Add Stamps by Customer ID",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"stamps\": 1\n}",
              "options": { "raw": { "language": "json" } }
            },
            "url": {
              "raw": "{{base_url}}/api/v1/customers/:customer_id/stamps",
              "host": ["{{base_url}}"],
              "path": ["api", "v1", "customers", ":customer_id", "stamps"],
              "variable": [
                {
                  "key": "customer_id",
                  "value": "1",
                  "description": "Numeric ID of the customer to stamp"
                }
              ]
            },
            "description": "Add stamps using the numeric customer ID. Set `:customer_id` in the **Path Variables** tab.\n\nPrefer the QR-based endpoint for POS/scanner integrations.\n\n**Body:** `stamps` — integer 1–10, defaults to 1."
          },
          "response": [
            {
              "name": "200 OK – Stamp Added",
              "status": "OK",
              "code": 200,
              "header": [{ "key": "Content-Type", "value": "application/json" }],
              "body": "{\n  \"data\": {\n    \"id\": 1,\n    \"name\": \"John Doe\",\n    \"current_stamps\": 5,\n    \"current_points\": 0,\n    \"rewards_earned\": 1,\n    \"rewards_redeemed\": 1,\n    \"total_visits\": 16,\n    \"reward_earned\": false,\n    \"last_visit\": \"2026-03-18 15:50:00\"\n  }\n}"
            },
            {
              "name": "200 OK – Reward Earned",
              "status": "OK",
              "code": 200,
              "header": [{ "key": "Content-Type", "value": "application/json" }],
              "body": "{\n  \"data\": {\n    \"id\": 1,\n    \"name\": \"John Doe\",\n    \"current_stamps\": 0,\n    \"current_points\": 0,\n    \"rewards_earned\": 3,\n    \"rewards_redeemed\": 1,\n    \"total_visits\": 16,\n    \"reward_earned\": true,\n    \"last_visit\": \"2026-03-18 15:50:00\"\n  }\n}"
            }
          ]
        },
        {
          "name": "Create Customer",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"Jane Smith\",\n  \"phone\": \"9876543210\",\n  \"email\": \"jane@example.com\"\n}",
              "options": { "raw": { "language": "json" } }
            },
            "url": {
              "raw": "{{base_url}}/api/v1/customers",
              "host": ["{{base_url}}"],
              "path": ["api", "v1", "customers"]
            },
            "description": "Create a new customer and enrol them in the active loyalty program.\n\n**Required:** `name`, `phone`  \n**Optional:** `email`\n\nReturns a unique `qr_code` for the customer's loyalty card."
          },
          "response": [
            {
              "name": "201 Created",
              "status": "Created",
              "code": 201,
              "header": [{ "key": "Content-Type", "value": "application/json" }],
              "body": "{\n  \"data\": {\n    \"id\": 151,\n    \"name\": \"Jane Smith\",\n    \"email\": \"jane@example.com\",\n    \"phone\": \"9876543210\",\n    \"qr_code\": \"CUSAB12CD34EF56GH\",\n    \"current_stamps\": 0,\n    \"current_points\": 0,\n    \"total_visits\": 0,\n    \"rewards_earned\": 0,\n    \"rewards_redeemed\": 0,\n    \"joined_at\": \"2026-03-18 15:45:00\"\n  }\n}"
            },
            {
              "name": "400 Bad Request",
              "status": "Bad Request",
              "code": 400,
              "header": [{ "key": "Content-Type", "value": "application/json" }],
              "body": "{\n  \"error\": true,\n  \"message\": \"Name and phone are required\"\n}"
            },
            {
              "name": "409 Conflict",
              "status": "Conflict",
              "code": 409,
              "header": [{ "key": "Content-Type", "value": "application/json" }],
              "body": "{\n  \"error\": true,\n  \"message\": \"Customer already exists\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Analytics",
      "description": "Endpoints for retrieving loyalty program analytics.",
      "item": [
        {
          "name": "Get Analytics",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/analytics?days=30",
              "host": ["{{base_url}}"],
              "path": ["api", "v1", "analytics"],
              "query": [
                {
                  "key": "days",
                  "value": "30",
                  "description": "Number of days to analyse (default: 30, max: 365)"
                }
              ]
            },
            "description": "Get a summary of your loyalty program for the last N days.\n\nChange the `days` query param to adjust the window (1–365)."
          },
          "response": [
            {
              "name": "200 OK",
              "status": "OK",
              "code": 200,
              "header": [{ "key": "Content-Type", "value": "application/json" }],
              "body": "{\n  \"data\": {\n    \"total_customers\": 150,\n    \"new_customers\": 25,\n    \"active_customers\": 80,\n    \"total_visits\": 450,\n    \"total_stamps\": 900,\n    \"total_redemptions\": 35,\n    \"growth_rate\": 12.5,\n    \"avg_stamps_per_visit\": 2.0,\n    \"period_days\": 30\n  }\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "Webhooks",
      "description": "Endpoints for managing webhook subscriptions.",
      "item": [
        {
          "name": "List Webhooks",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/webhooks",
              "host": ["{{base_url}}"],
              "path": ["api", "v1", "webhooks"]
            },
            "description": "List all registered webhooks for your business."
          },
          "response": [
            {
              "name": "200 OK",
              "status": "OK",
              "code": 200,
              "header": [{ "key": "Content-Type", "value": "application/json" }],
              "body": "{\n  \"data\": [\n    {\n      \"id\": 1,\n      \"url\": \"https://yoursite.com/webhook\",\n      \"events\": [\"customer.created\", \"stamp.added\", \"reward.redeemed\"],\n      \"is_active\": 1,\n      \"created_at\": \"2026-03-01 10:00:00\"\n    }\n  ]\n}"
            }
          ]
        },
        {
          "name": "Create Webhook",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"url\": \"https://yoursite.com/webhook\",\n  \"events\": [\"customer.created\", \"stamp.added\", \"reward.redeemed\", \"customer.updated\"]\n}",
              "options": { "raw": { "language": "json" } }
            },
            "url": {
              "raw": "{{base_url}}/api/v1/webhooks",
              "host": ["{{base_url}}"],
              "path": ["api", "v1", "webhooks"]
            },
            "description": "Register a webhook URL to receive real-time event notifications. Returns a `secret` — store it securely to verify signatures.\n\n**Available events:**\n- `customer.created` – New customer enrolled\n- `stamp.added` – Stamps added to a customer\n- `reward.redeemed` – Customer redeemed a reward\n- `customer.updated` – Customer profile updated"
          },
          "response": [
            {
              "name": "201 Created",
              "status": "Created",
              "code": 201,
              "header": [{ "key": "Content-Type", "value": "application/json" }],
              "body": "{\n  \"success\": true,\n  \"message\": \"Webhook registered successfully\",\n  \"data\": {\n    \"id\": 2,\n    \"url\": \"https://yoursite.com/webhook\",\n    \"events\": [\"customer.created\", \"stamp.added\", \"reward.redeemed\", \"customer.updated\"],\n    \"secret\": \"whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n  }\n}"
            },
            {
              "name": "400 Bad Request",
              "status": "Bad Request",
              "code": 400,
              "header": [{ "key": "Content-Type", "value": "application/json" }],
              "body": "{\n  \"error\": true,\n  \"message\": \"A valid webhook URL is required\"\n}"
            }
          ]
        },
        {
          "name": "Delete Webhook",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/webhooks/:webhook_id",
              "host": ["{{base_url}}"],
              "path": ["api", "v1", "webhooks", ":webhook_id"],
              "variable": [
                {
                  "key": "webhook_id",
                  "value": "1",
                  "description": "ID of the webhook to delete (from List Webhooks or Create Webhook response)"
                }
              ]
            },
            "description": "Delete a webhook. Set `:webhook_id` in the **Path Variables** tab to the webhook ID returned by List Webhooks or Create Webhook."
          },
          "response": [
            {
              "name": "200 OK",
              "status": "OK",
              "code": 200,
              "header": [{ "key": "Content-Type", "value": "application/json" }],
              "body": "{\n  \"success\": true,\n  \"message\": \"Webhook deleted\"\n}"
            },
            {
              "name": "404 Not Found",
              "status": "Not Found",
              "code": 404,
              "header": [{ "key": "Content-Type", "value": "application/json" }],
              "body": "{\n  \"error\": true,\n  \"message\": \"Webhook not found\"\n}"
            }
          ]
        }
      ]
    },
    {
      "name": "API Key",
      "description": "Manage your API key from within the app dashboard.",
      "item": [
        {
          "name": "Regenerate API Key",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/regenerate-key",
              "host": ["{{base_url}}"],
              "path": ["api", "regenerate-key"]
            },
            "description": "Generate a new API key. The old key is immediately invalidated.\n\n⚠️ This endpoint uses **session cookie auth** (not Bearer token) — you must be logged in via the browser/dashboard to call it."
          },
          "response": [
            {
              "name": "200 OK",
              "status": "OK",
              "code": 200,
              "header": [{ "key": "Content-Type", "value": "application/json" }],
              "body": "{\n  \"success\": true,\n  \"api_key\": \"ll_newkeyxxxxxxxxxxxxxxxxxxxxxxxx\"\n}"
            }
          ]
        }
      ]
    }
  ]
}
