{
  "info": {
    "_postman_id": "wallet-api-v1-collection",
    "name": "MercuryPay Wallet API v1",
    "description": "REST API collection for Customer Management, Cards, Transactions, Rewards & Prepaid.\n\nSet the `baseUrl` variable to your server (e.g. http://localhost:4000) and `token` to a valid Bearer JWT before running.\n\nGet a token via: POST {{baseUrl}}/api/v1/auth/login",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "variable": [
    { "key": "baseUrl",        "value": "http://localhost:4000",    "type": "string" },
    { "key": "token",          "value": "REPLACE_WITH_JWT",          "type": "string" },
    { "key": "user_id",        "value": "usr_REPLACE",               "type": "string" },
    { "key": "card_id",        "value": "card_dev_prepaid_001",      "type": "string" },
    { "key": "transaction_id", "value": "topup_xyz",                 "type": "string" },
    { "key": "offer_id",       "value": "offer_001",                 "type": "string" },
    { "key": "account_id",     "value": "acc_001",                   "type": "string" },
    { "key": "program_id",     "value": "prog_kw_001",               "type": "string" }
  ],
  "auth": {
    "type": "bearer",
    "bearer": [{ "key": "token", "value": "{{token}}", "type": "string" }]
  },
  "item": [

    {
      "name": "Auth",
      "description": "Obtain and refresh Bearer JWTs. Use the token in all subsequent requests.",
      "item": [
        {
          "name": "Login",
          "request": {
            "auth": { "type": "noauth" },
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "url": {
              "raw": "{{baseUrl}}/api/v1/auth/login",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "auth", "login"]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\":    \"admin@mercurypay.dev\",\n  \"password\": \"Admin@123456\"\n}",
              "options": { "raw": { "language": "json" } }
            },
            "description": "Exchange email + password for a Bearer JWT.\n\nDev seed credentials:\n- admin@mercurypay.dev / Admin@123456  (admin)\n- ops@mercurypay.dev  / Ops@123456    (ops_supervisor)\n- agent@mercurypay.dev / Agent@123456  (ops_agent)\n\nResponse: { data: { token, token_type, expires_in, user_id, roles } }"
          },
          "response": []
        },
        {
          "name": "Refresh token",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{baseUrl}}/api/v1/auth/refresh",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "auth", "refresh"]
            },
            "body": { "mode": "raw", "raw": "", "options": { "raw": { "language": "json" } } },
            "description": "Issue a new JWT from an existing valid token (uses Bearer header). Useful before expiry to avoid re-login."
          },
          "response": []
        }
      ]
    },

    {
      "name": "Customer Management  (ops_supervisor+)",
      "description": "Create and manage wallet customers. All endpoints require at minimum ops_supervisor role in the JWT (except GET /customers/:user_id which allows ops_agent+).\n\nTypical onboarding flow:\n1. POST /customers          → creates account, returns user_id\n2. POST /cards              → issue a card for that user_id\n3. POST /prepaid/.../top-up → fund the card\n4. POST /webhooks/...       → simulate network transactions",
      "item": [
        {
          "name": "Create customer",
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "url": {
              "raw": "{{baseUrl}}/api/v1/customers",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "customers"]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\":       \"john.doe@example.com\",\n  \"full_name\":   \"John Doe\",\n  \"phone\":       \"+96550012345\",\n  \"nationality\": \"KW\",\n  \"currency\":    \"KWD\",\n  \"tier\":        \"standard\"\n}",
              "options": { "raw": { "language": "json" } }
            },
            "description": "Onboards a new customer: generates a `user_id`, opens a wallet account in the given currency, and stores profile metadata.\n\nRequired: email, currency.\nOptional: full_name, phone, nationality, tier (standard | premium | business).\n\nReturns: { user_id, account_id, email, currency, tier, status, opened_at, message }\n\nNext step: POST /api/v1/cards to issue a card for this user_id."
          },
          "response": []
        },
        {
          "name": "List customers",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/v1/customers",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "customers"],
              "query": [
                { "key": "status",   "value": "active",   "disabled": true, "description": "pending | active | suspended | frozen | closed" },
                { "key": "tier",     "value": "standard", "disabled": true, "description": "standard | premium | business" },
                { "key": "page",     "value": "1",        "disabled": true },
                { "key": "per_page", "value": "20",       "disabled": true }
              ]
            },
            "description": "Returns all wallet accounts (ETS scan). Filterable by status and tier. Paginated."
          },
          "response": []
        },
        {
          "name": "Get customer",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/v1/customers/{{user_id}}",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "customers", "{{user_id}}"]
            },
            "description": "Returns all wallet accounts for a given user_id. Requires ops_agent or higher role."
          },
          "response": []
        },
        {
          "name": "Update customer",
          "request": {
            "method": "PATCH",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "url": {
              "raw": "{{baseUrl}}/api/v1/customers/{{user_id}}",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "customers", "{{user_id}}"]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"tier\":     \"premium\",\n  \"metadata\": { \"nationality\": \"KW\", \"segment\": \"vip\" }\n}",
              "options": { "raw": { "language": "json" } }
            },
            "description": "Update the primary account's tier and/or merge extra metadata. Requires ops_supervisor+."
          },
          "response": []
        },
        {
          "name": "Activate customer",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{baseUrl}}/api/v1/customers/{{user_id}}/activate",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "customers", "{{user_id}}", "activate"]
            },
            "body": { "mode": "raw", "raw": "", "options": { "raw": { "language": "json" } } },
            "description": "Move a pending account to active. Requires ops_agent+."
          },
          "response": []
        },
        {
          "name": "Suspend customer",
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "url": {
              "raw": "{{baseUrl}}/api/v1/customers/{{user_id}}/suspend",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "customers", "{{user_id}}", "suspend"]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"reason\": \"Pending KYC verification\"\n}",
              "options": { "raw": { "language": "json" } }
            },
            "description": "Temporarily suspend a customer account. Requires ops_supervisor+."
          },
          "response": []
        },
        {
          "name": "Resume customer",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{baseUrl}}/api/v1/customers/{{user_id}}/resume",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "customers", "{{user_id}}", "resume"]
            },
            "body": { "mode": "raw", "raw": "", "options": { "raw": { "language": "json" } } },
            "description": "Resume a suspended account to active. Requires ops_supervisor+."
          },
          "response": []
        }
      ]
    },

    {
      "name": "Webhooks — Card Network Ingestion",
      "description": "Server-to-server endpoints called by the card processor (Visa/Mastercard/BIN sponsor).\n\nAuthentication: HMAC-SHA256 via X-Card-Network-Signature header (NOT Bearer JWT).\nIn dev/test the signature check is skipped when card_network_webhook_secret is not configured.",
      "item": [
        {
          "name": "Card authorization (real-time)",
          "request": {
            "auth": { "type": "noauth" },
            "method": "POST",
            "header": [
              { "key": "Content-Type",               "value": "application/json" },
              { "key": "X-Card-Network-Signature",   "value": "sha256=REPLACE_WITH_HMAC", "description": "sha256=<hex>. Omit in dev (secret not configured = skip)." }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/webhooks/card-authorization",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "webhooks", "card-authorization"]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"card_id\":      \"{{card_id}}\",\n  \"amount\":       \"10.500\",\n  \"currency\":     \"AED\",\n  \"txn_type\":     \"debit\",\n  \"merchant\":     \"McDonald's\",\n  \"category\":     \"Dining\",\n  \"reference_id\": \"AUTH-2026-06-30-001\",\n  \"network_ref\":  \"VIS-840392\",\n  \"status\":       \"authorized\",\n  \"txn_date\":     \"2026-06-30\"\n}",
              "options": { "raw": { "language": "json" } }
            },
            "description": "Called by the card processor when a card is swiped/tapped/used online.\n\nCreates a CardUsageTransaction record and adjusts the prepaid card balance.\n\ntxn_type: debit | credit\nstatus: authorized | settled | reversed | declined"
          },
          "response": []
        },
        {
          "name": "Card settlement (batch row)",
          "request": {
            "auth": { "type": "noauth" },
            "method": "POST",
            "header": [
              { "key": "Content-Type",             "value": "application/json" },
              { "key": "X-Card-Network-Signature", "value": "sha256=REPLACE_WITH_HMAC" }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/webhooks/card-settlement",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "webhooks", "card-settlement"]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"card_id\":      \"{{card_id}}\",\n  \"amount\":       \"10.500\",\n  \"currency\":     \"AED\",\n  \"txn_type\":     \"debit\",\n  \"merchant\":     \"McDonald's\",\n  \"category\":     \"Dining\",\n  \"reference_id\": \"SETTLE-2026-06-30-001\",\n  \"network_ref\":  \"VIS-840392\",\n  \"status\":       \"settled\",\n  \"txn_date\":     \"2026-06-30\"\n}",
              "options": { "raw": { "language": "json" } }
            },
            "description": "Same shape as card-authorization but marks source: settlement. Called once per row during end-of-day settlement file ingestion."
          },
          "response": []
        }
      ]
    },

    {
      "name": "Phase A1 — Cards",
      "description": "Card issuance and lifecycle: issue, list, detail, balance, freeze/unfreeze, block/unblock, reset-PIN.",
      "item": [
        {
          "name": "Issue card (virtual — self-service or ops)",
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cards",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "cards"]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"user_id\":   \"{{user_id}}\",\n  \"card_type\": \"debit\",\n  \"is_virtual\": true,\n  \"is_prepaid\": false,\n  \"network\":   \"Visa\"\n}",
              "options": { "raw": { "language": "json" } }
            },
            "description": "Issue a new virtual debit/credit card.\n\nFields:\n- user_id: target user (ops_supervisor+ can specify any user; a customer gets their own user_id)\n- card_type: debit | credit  (default: debit)\n- is_virtual: true | false  (default: true)\n- is_prepaid: true | false  (default: false)\n- network: Visa | Mastercard  (default: Visa)\n- last_four: override last 4 digits (default: random)\n- expiry: MM/YY  (default: 3 years from now)\n- program_id: required for prepaid cards\n- daily_limit: integer cents (default: 500000)\n- monthly_limit: integer cents (default: 5000000)\n\nReturns: full card object."
          },
          "response": []
        },
        {
          "name": "Issue prepaid card (ops, linked to program)",
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cards",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "cards"]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"user_id\":    \"{{user_id}}\",\n  \"card_type\":  \"debit\",\n  \"is_virtual\": false,\n  \"is_prepaid\": true,\n  \"program_id\": \"{{program_id}}\",\n  \"network\":    \"Visa\",\n  \"last_four\":  \"9001\",\n  \"expiry\":     \"12/28\"\n}",
              "options": { "raw": { "language": "json" } }
            },
            "description": "Issue a physical prepaid card linked to a program. Requires ops_supervisor+. After issuance, fund it via POST /prepaid/cards/:card_id/top-up."
          },
          "response": []
        },
        {
          "name": "List cards",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/v1/cards",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "cards"],
              "query": [
                { "key": "status", "value": "active",  "disabled": true, "description": "active | frozen | blocked | expired" },
                { "key": "type",   "value": "debit",   "disabled": true, "description": "debit | credit" }
              ]
            },
            "description": "Returns all cards for the authenticated user."
          },
          "response": []
        },
        {
          "name": "Get card detail",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/v1/cards/{{card_id}}",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "cards", "{{card_id}}"]
            },
            "description": "Returns full card detail. 404 if not found, 403 if not owned."
          },
          "response": []
        },
        {
          "name": "Get card balance",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/v1/cards/{{card_id}}/balance",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "cards", "{{card_id}}", "balance"]
            },
            "description": "Current balance for a prepaid/debit card."
          },
          "response": []
        },
        {
          "name": "Freeze card",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{baseUrl}}/api/v1/cards/{{card_id}}/freeze",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "cards", "{{card_id}}", "freeze"]
            },
            "body": { "mode": "raw", "raw": "", "options": { "raw": { "language": "json" } } },
            "description": "Freeze an active card. 422 if already frozen or blocked."
          },
          "response": []
        },
        {
          "name": "Unfreeze card",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{baseUrl}}/api/v1/cards/{{card_id}}/unfreeze",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "cards", "{{card_id}}", "unfreeze"]
            },
            "body": { "mode": "raw", "raw": "", "options": { "raw": { "language": "json" } } },
            "description": "Unfreeze a frozen card."
          },
          "response": []
        },
        {
          "name": "Block card",
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "url": {
              "raw": "{{baseUrl}}/api/v1/cards/{{card_id}}/block",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "cards", "{{card_id}}", "block"]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"reason\": \"lost\"\n}",
              "options": { "raw": { "language": "json" } }
            },
            "description": "Permanently block a card (lost/stolen). 422 if already blocked."
          },
          "response": []
        },
        {
          "name": "Unblock card",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{baseUrl}}/api/v1/cards/{{card_id}}/unblock",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "cards", "{{card_id}}", "unblock"]
            },
            "body": { "mode": "raw", "raw": "", "options": { "raw": { "language": "json" } } },
            "description": "Unblock a card (admin/ops use)."
          },
          "response": []
        },
        {
          "name": "Reset card PIN",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{baseUrl}}/api/v1/cards/{{card_id}}/reset-pin",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "cards", "{{card_id}}", "reset-pin"]
            },
            "body": { "mode": "raw", "raw": "", "options": { "raw": { "language": "json" } } },
            "description": "Initiates PIN reset — sends OTP to registered mobile number."
          },
          "response": []
        }
      ]
    },

    {
      "name": "Phase A2 — Transactions & Ledger",
      "description": "Card transaction history, per-user history, per-card statement, and ledger queries.",
      "item": [
        {
          "name": "List all transactions (user)",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/v1/transactions",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "transactions"],
              "query": [
                { "key": "status",   "value": "success",    "disabled": true },
                { "key": "from",     "value": "2026-01-01", "disabled": true },
                { "key": "to",       "value": "2026-06-30", "disabled": true },
                { "key": "page",     "value": "1",          "disabled": true },
                { "key": "per_page", "value": "20",         "disabled": true }
              ]
            },
            "description": "All top-up transactions for the authenticated user across all cards."
          },
          "response": []
        },
        {
          "name": "Get single transaction",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/v1/transactions/{{transaction_id}}",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "transactions", "{{transaction_id}}"]
            },
            "description": "Fetch one top-up transaction by ID."
          },
          "response": []
        },
        {
          "name": "List transactions for card",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/v1/cards/{{card_id}}/transactions",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "cards", "{{card_id}}", "transactions"],
              "query": [
                { "key": "from",     "value": "2026-01-01", "disabled": true },
                { "key": "to",       "value": "2026-06-30", "disabled": true },
                { "key": "page",     "value": "1",          "disabled": true },
                { "key": "per_page", "value": "20",         "disabled": true }
              ]
            },
            "description": "Top-up transactions for a specific card, newest first."
          },
          "response": []
        },
        {
          "name": "List card usage transactions (network spend)",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/v1/cards/{{card_id}}/usage-transactions",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "cards", "{{card_id}}", "usage-transactions"],
              "query": [
                { "key": "period",   "value": "3m",     "disabled": false, "description": "1m | 3m | 6m | all" },
                { "key": "type",     "value": "all",    "disabled": true,  "description": "debit | credit | all" },
                { "key": "search",   "value": "Amazon", "disabled": true },
                { "key": "page",     "value": "1",      "disabled": true },
                { "key": "per_page", "value": "20",     "disabled": true }
              ]
            },
            "description": "Returns real-time card usage transactions from CardUsageTransactionStore (populated by card-authorization webhooks). Falls back to demo data when no real transactions exist."
          },
          "response": []
        },
        {
          "name": "Get card statement",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/v1/cards/{{card_id}}/statement",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "cards", "{{card_id}}", "statement"],
              "query": [
                { "key": "from", "value": "2026-06-01", "disabled": false },
                { "key": "to",   "value": "2026-06-30", "disabled": false }
              ]
            },
            "description": "Statement summary for a date range: total credits, total debits, net, count."
          },
          "response": []
        },
        {
          "name": "Get ledger history",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/v1/accounts/{{account_id}}/ledger",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "accounts", "{{account_id}}", "ledger"],
              "query": [
                { "key": "page",     "value": "1",   "disabled": true },
                { "key": "per_page", "value": "20",  "disabled": true },
                { "key": "currency", "value": "AED", "disabled": true }
              ]
            },
            "description": "Double-entry journal history for an account."
          },
          "response": []
        }
      ]
    },

    {
      "name": "Phase A3 — Rewards & Points",
      "description": "Browse offers, redeem offers, check points balance, view history.\n\nPoints credit/debit endpoints require ops_supervisor+ role.",
      "item": [
        {
          "name": "List active offers",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/v1/rewards/offers",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "rewards", "offers"],
              "query": [
                { "key": "category",   "value": "Groceries", "disabled": true },
                { "key": "merchant",   "value": "Carrefour", "disabled": true },
                { "key": "max_points", "value": "1000",      "disabled": true }
              ]
            },
            "description": "Lists all currently active offers."
          },
          "response": []
        },
        {
          "name": "Get offer detail",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/v1/rewards/offers/{{offer_id}}",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "rewards", "offers", "{{offer_id}}"]
            }
          },
          "response": []
        },
        {
          "name": "Redeem offer",
          "request": {
            "method": "POST",
            "url": {
              "raw": "{{baseUrl}}/api/v1/rewards/offers/{{offer_id}}/redeem",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "rewards", "offers", "{{offer_id}}", "redeem"]
            },
            "body": { "mode": "raw", "raw": "", "options": { "raw": { "language": "json" } } },
            "description": "Redeem an offer using the user's points balance. 422 if insufficient_points or offer_expired."
          },
          "response": []
        },
        {
          "name": "Get points balance",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/v1/rewards/points",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "rewards", "points"]
            },
            "description": "Current points balance for authenticated user. Returns {balance: 0} for new users."
          },
          "response": []
        },
        {
          "name": "Get points history",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/v1/rewards/points/history",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "rewards", "points", "history"],
              "query": [
                { "key": "type",     "value": "earn",       "disabled": true, "description": "earn | redeem" },
                { "key": "from",     "value": "2026-01-01", "disabled": true },
                { "key": "to",       "value": "2026-06-30", "disabled": true },
                { "key": "page",     "value": "1",          "disabled": true },
                { "key": "per_page", "value": "20",         "disabled": true }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Credit points  (ops_supervisor+)",
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "url": {
              "raw": "{{baseUrl}}/api/v1/rewards/points/credit",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "rewards", "points", "credit"]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"user_id\": \"{{user_id}}\",\n  \"amount\":  500,\n  \"reason\":  \"Welcome bonus for new customer\"\n}",
              "options": { "raw": { "language": "json" } }
            },
            "description": "Add points to a user's balance. `amount` must be a positive integer.\n\nReturns: { user_id, operation: 'credit', amount, new_balance, txn_id }\n\nRequires ops_supervisor or admin role."
          },
          "response": []
        },
        {
          "name": "Debit points  (ops_supervisor+)",
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "url": {
              "raw": "{{baseUrl}}/api/v1/rewards/points/debit",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "rewards", "points", "debit"]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"user_id\": \"{{user_id}}\",\n  \"amount\":  200,\n  \"reason\":  \"Points correction — duplicate earn reversed\"\n}",
              "options": { "raw": { "language": "json" } }
            },
            "description": "Deduct points from a user's balance. `amount` must be a positive integer (sign is implicit). 422 if balance would go below zero.\n\nReturns: { user_id, operation: 'debit', amount, new_balance, txn_id }\n\nRequires ops_supervisor or admin role."
          },
          "response": []
        },
        {
          "name": "Adjust points (signed delta)  (ops_supervisor+)",
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "url": {
              "raw": "{{baseUrl}}/api/v1/rewards/points/adjust",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "rewards", "points", "adjust"]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"user_id\": \"{{user_id}}\",\n  \"delta\":   200,\n  \"reason\":  \"Goodwill credit for service disruption\"\n}",
              "options": { "raw": { "language": "json" } }
            },
            "description": "Manually adjust a user's points balance with a signed delta. Positive = credit, negative = debit. Prefer the explicit /credit and /debit endpoints for clarity."
          },
          "response": []
        },
        {
          "name": "Get all reward transactions",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/v1/rewards/transactions",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "rewards", "transactions"],
              "query": [
                { "key": "page",     "value": "1",  "disabled": true },
                { "key": "per_page", "value": "20", "disabled": true }
              ]
            }
          },
          "response": []
        }
      ]
    },

    {
      "name": "Phase A4 — Prepaid Top-Up",
      "description": "Top-up individual prepaid cards, query top-up transactions, and program-level ops queries.",
      "item": [
        {
          "name": "Top-up prepaid card",
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type",    "value": "application/json" },
              { "key": "Idempotency-Key", "value": "idem-{{$randomUUID}}", "description": "Optional: duplicate requests within 24h return the original response." }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/prepaid/cards/{{card_id}}/top-up",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "prepaid", "cards", "{{card_id}}", "top-up"]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": \"100.000\",\n  \"currency\": \"AED\",\n  \"reference\": \"SAL-2026-06-001\"\n}",
              "options": { "raw": { "language": "json" } }
            },
            "description": "Credits a prepaid card with the specified amount. 422 if not_a_prepaid_card, program_mismatch, or amount_must_be_positive."
          },
          "response": []
        },
        {
          "name": "List prepaid card transactions",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/v1/prepaid/cards/{{card_id}}/transactions",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "prepaid", "cards", "{{card_id}}", "transactions"],
              "query": [
                { "key": "status",   "value": "success",    "disabled": true },
                { "key": "from",     "value": "2026-01-01", "disabled": true },
                { "key": "to",       "value": "2026-06-30", "disabled": true },
                { "key": "page",     "value": "1",          "disabled": true },
                { "key": "per_page", "value": "20",         "disabled": true }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Get single prepaid transaction",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/v1/prepaid/transactions/{{transaction_id}}",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "prepaid", "transactions", "{{transaction_id}}"]
            }
          },
          "response": []
        },
        {
          "name": "List program cards  (ops_agent+)",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/v1/prepaid/programs/{{program_id}}/cards",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "prepaid", "programs", "{{program_id}}", "cards"],
              "query": [
                { "key": "status",   "value": "active", "disabled": true },
                { "key": "page",     "value": "1",      "disabled": true },
                { "key": "per_page", "value": "20",     "disabled": true }
              ]
            }
          },
          "response": []
        },
        {
          "name": "List program transactions  (ops_agent+)",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/api/v1/prepaid/programs/{{program_id}}/transactions",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "prepaid", "programs", "{{program_id}}", "transactions"],
              "query": [
                { "key": "from",     "value": "2026-06-01", "disabled": true },
                { "key": "to",       "value": "2026-06-30", "disabled": true },
                { "key": "page",     "value": "1",          "disabled": true },
                { "key": "per_page", "value": "20",         "disabled": true }
              ]
            }
          },
          "response": []
        }
      ]
    }

  ]
}
