{
  "id": "NtUmR7wzjKfYbBOS",
  "name": "\ud83d\udcb2 \ud83d\udcca AgentGatePay - Monitoring Dashboard",
  "tags": [],
  "nodes": [
    {
      "id": "51d9e284-b69f-4650-9fa2-6314737afafd",
      "name": "\u25b6\ufe0f Manual Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "notes": "\u25b6\ufe0f MANUAL TRIGGER: Click 'Execute Workflow' to run\n\n\u26a0\ufe0f Configure your API key in Node 2 before running!\n\nThis workflow runs standalone without webhooks.\nAll data is fetched from AgentGatePay API.",
      "position": [
        -1264,
        176
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "f580877c-e612-41cc-ba62-33e2eefd8539",
      "name": "2\ufe0f\u20e3 Load Config",
      "type": "n8n-nodes-base.code",
      "notes": "\u2699\ufe0f SETUP: Validate inputs\n\n\u26a0\ufe0f EDIT THIS if running manually:\n- user_email: Your buyer email\n- api_key: Your AgentGatePay API key",
      "position": [
        -1040,
        176
      ],
      "parameters": {
        "jsCode": "// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// CONFIG: Validate inputs and setup monitoring parameters\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nconst input = $input.first().json;\n\n// Check if triggered by webhook or manual\nconst isManual = !input.user_email;\n\nconst config = {\n  user_email: input.user_email || \"user@example.com\",  // \u26a0\ufe0f REPLACE if running manually\n  api_key: input.api_key || \"YOUR_API_KEY\",  // \u26a0\ufe0f REPLACE if running manually\n  buyer_wallet: input.buyer_wallet || \"YOUR_WALLET_ADDRESS\",  // \u26a0\ufe0f REPLACE with your wallet (0x...)\n  tx_hash: input.tx_hash || null,\n  trigger_source: input.trigger_source || \"manual\",\n  \n  // Monitoring settings\n  time_range_hours: 24,\n  payment_history_limit: 50,  // Fetch last 50 for display (use curl for full history)\n  audit_log_limit: 50,\n  export_format: \"csv\",\n  \n  // AgentGatePay API\n  api_url: \"https://api.agentgatepay.com\",\n  mcp_endpoint: \"https://mcp.agentgatepay.com\",\n  \n  // Session tracking\n  session: {\n    id: `monitor_${Date.now()}`,\n    started_at: new Date().toISOString(),\n    is_manual: isManual\n  }\n};\n\n// Validation\nif (config.api_key === \"YOUR_API_KEY\") {\n  throw new Error(\"\u274c Please configure your API key in Node 2 'Load Config'!\");\n}\n\nconsole.log(`\ud83d\udcca Monitoring Dashboard Started`);\nconsole.log(`   User: ${config.user_email}`);\nconsole.log(`   Source: ${config.trigger_source}`);\nconsole.log(`   TX Hash: ${config.tx_hash || 'N/A'}`);\n\nreturn [{ json: { config } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "6ece2262-a292-4b44-9107-c302d8922e24",
      "name": "3\ufe0f\u20e3 \ud83d\udcc8 Get User Analytics",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "\ud83d\udcc8 ANALYTICS: Fetch user spending stats\n\nReturns:\n- total_spent_usd\n- payment_count\n- active_mandates\n- budget_remaining\n- spending_trend",
      "position": [
        -832,
        176
      ],
      "parameters": {
        "url": "={{ $json.config.api_url }}/v1/analytics/me",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "x-api-key",
              "value": "={{ $json.config.api_key }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "e1bafe66-a6e4-459d-bd80-8e9d9e8bc91d",
      "name": "4\ufe0f\u20e3 \ud83d\udcb3 Get Payment History",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "\ud83d\udcb3 PAYMENTS: Fetch recent payment history\n\nShows last 10 payments with:\n- tx_hash\n- amount_usd\n- status\n- timestamp\n- receiver",
      "position": [
        -608,
        176
      ],
      "parameters": {
        "url": "={{ $('2\ufe0f\u20e3 Load Config').first().json.config.mcp_endpoint }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"jsonrpc\": \"2.0\",\n  \"id\": 1,\n  \"method\": \"tools/call\",\n  \"params\": {\n    \"name\": \"agentpay_get_payment_history\",\n    \"arguments\": {\n      \"limit\": {{ $('2\ufe0f\u20e3 Load Config').first().json.config.payment_history_limit }}\n    }\n  }\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "x-api-key",
              "value": "={{ $('2\ufe0f\u20e3 Load Config').first().json.config.api_key }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "b0e7f80b-cc9b-4976-93e9-597b39c27955",
      "name": "5\ufe0f\u20e3 \ud83d\udccb Get Audit Logs (24h)",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "\ud83d\udccb AUDIT: Fetch payment events by wallet\n\nFiltered by:\n- client_id (wallet address)\n- event_type: x402_payment_settled\n- Last 24 hours\n- Max 50 events\n\nShows: blockchain payments from this wallet",
      "position": [
        -384,
        176
      ],
      "parameters": {
        "url": "={{ $('2\ufe0f\u20e3 Load Config').first().json.config.api_url }}/audit/logs?client_id={{ $('2\ufe0f\u20e3 Load Config').first().json.config.buyer_wallet }}&event_type=x402_payment_settled&hours={{ $('2\ufe0f\u20e3 Load Config').first().json.config.time_range_hours }}&limit={{ $('2\ufe0f\u20e3 Load Config').first().json.config.audit_log_limit }}",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "x-api-key",
              "value": "={{ $('2\ufe0f\u20e3 Load Config').first().json.config.api_key }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "f9b85f1e-93c9-4e3b-b216-5340ad1c8990",
      "name": "6\ufe0f\u20e3 \ud83d\udd11 Get Active Mandates",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "\ud83d\udd11 MANDATES: Fetch all issued mandates\n\nShows:\n- mandate_id\n- budget_usd\n- budget_remaining\n- ttl_hours\n- scope\n- status",
      "position": [
        -160,
        176
      ],
      "parameters": {
        "url": "={{ $('2\ufe0f\u20e3 Load Config').first().json.config.api_url }}/audit/logs?client_id={{ $('2\ufe0f\u20e3 Load Config').first().json.config.user_email }}&event_type=mandate_issued",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "x-api-key",
              "value": "={{ $('2\ufe0f\u20e3 Load Config').first().json.config.api_key }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "fdac1867-7530-45fc-9fe4-57dad4a03ca1",
      "name": "7\ufe0f\u20e3 \ud83d\udd0d Prepare Verification",
      "type": "n8n-nodes-base.code",
      "notes": "\ud83d\udd0d PREPARE: Check if we have tx_hash to verify",
      "position": [
        48,
        176
      ],
      "parameters": {
        "jsCode": "// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// VERIFICATION: Verify last payment on blockchain\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nconst config = $('2\ufe0f\u20e3 Load Config').first().json.config;\nconst tx_hash = config.tx_hash;\n\nif (!tx_hash) {\n  console.log('\u26a0\ufe0f  No tx_hash provided - skipping verification');\n  return [{ json: { \n    verified: false, \n    reason: \"No transaction hash provided\",\n    config: config\n  }}];\n}\n\nconsole.log(`\ud83d\udd0d Verifying payment: ${tx_hash}`);\n\nreturn [{ json: { \n  tx_hash: tx_hash,\n  config: config,\n  should_verify: true\n}}];"
      },
      "typeVersion": 2
    },
    {
      "id": "4fa77ac5-21c4-4bbc-af94-b706b61435ef",
      "name": "7B\ufe0f\u20e3 Has TX Hash?",
      "type": "n8n-nodes-base.if",
      "notes": "\ud83d\udd00 ROUTER: Only verify if tx_hash exists",
      "position": [
        272,
        176
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "should-verify",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.should_verify }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "22fa056e-43cc-4bc1-8af9-070df4f8183a",
      "name": "8\ufe0f\u20e3 \u2705 Verify on Blockchain",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "\u2705 BLOCKCHAIN: Verify payment on-chain\n\nChecks:\n- Transaction exists\n- Correct amount\n- Correct recipient\n- Block confirmation",
      "position": [
        496,
        80
      ],
      "parameters": {
        "url": "={{ $('2\ufe0f\u20e3 Load Config').first().json.config.api_url }}/v1/payments/verify/{{ $json.tx_hash }}",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "x-api-key",
              "value": "={{ $('2\ufe0f\u20e3 Load Config').first().json.config.api_key }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "b6529d72-e14e-4f99-ab90-583f3ce3975a",
      "name": "8B\ufe0f\u20e3 Skip Verification",
      "type": "n8n-nodes-base.code",
      "notes": "\u23ed\ufe0f  SKIP: No tx_hash to verify",
      "position": [
        496,
        288
      ],
      "parameters": {
        "jsCode": "return [{ json: { \n  verified: false,\n  reason: \"No transaction to verify\",\n  message: \"Skipped verification - no tx_hash provided\"\n}}];"
      },
      "typeVersion": 2
    },
    {
      "id": "3d0ec196-1e34-4b77-bb6f-7fed3bf6fc3e",
      "name": "9\ufe0f\u20e3 Merge Verification",
      "type": "n8n-nodes-base.merge",
      "notes": "\ud83d\udd00 MERGE: Combine verified/skipped paths",
      "position": [
        720,
        176
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combinationMode": "mergeByPosition"
      },
      "typeVersion": 2.1
    },
    {
      "id": "e7f766f0-f856-4a61-9303-ec03f4fd581a",
      "name": "\ud83d\udd1f \ud83d\udcca Calculate Statistics",
      "type": "n8n-nodes-base.code",
      "notes": "\ud83d\udcca STATISTICS: Calculate trends and metrics\n\nCalculates:\n- Spending trends\n- Budget utilization %\n- Recent activity (24h)\n- Mandate status\n- Event breakdown",
      "position": [
        928,
        176
      ],
      "parameters": {
        "jsCode": "// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// STATISTICS: Calculate spending trends and alerts\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nconst config = $('2\ufe0f\u20e3 Load Config').first().json.config;\nconst analytics = $('3\ufe0f\u20e3 \ud83d\udcc8 Get User Analytics').first().json;\nconst payment_history_response = $('4\ufe0f\u20e3 \ud83d\udcb3 Get Payment History').first().json;\nconst audit_logs_response = $('5\ufe0f\u20e3 \ud83d\udccb Get Audit Logs (24h)').first().json;\nconst mandates_response = $('6\ufe0f\u20e3 \ud83d\udd11 Get Active Mandates').first().json;\nconst verification = $input.first().json;\n\nconsole.log('\ud83d\udcca Calculating statistics...');\n\n// Parse payment history (MCP response)\nlet payments = [];\nif (payment_history_response.result && payment_history_response.result.content) {\n  try {\n    const content = payment_history_response.result.content[0].text;\n    const parsed = JSON.parse(content);\n    payments = parsed.payments || [];\n  } catch (e) {\n    console.log('\u26a0\ufe0f  Could not parse payment history');\n  }\n}\n\n// Parse audit logs\nconst logs = audit_logs_response.logs || [];\n\n// Parse mandates\nconst mandates = mandates_response.logs || [];\n\n// \u2705 FIX: Use correct API field names and calculate average AFTER getting values\n// API returns: total_spent_usd, transaction_count (NOT payment_count)\nconst total_spent = analytics.total_spent_usd || 0;\nconst payment_count = analytics.transaction_count || 0;  // \u2705 FIXED: was analytics.payment_count\nconst average_payment = payment_count > 0 ? (total_spent / payment_count) : 0;  // \u2705 Calculate after\n\nconst stats = {\n  // Spending stats - FIXED field names to match API response\n  total_spent: total_spent,\n  payment_count: payment_count,\n  average_payment: average_payment,\n\n  // Recent activity\n  payments_last_24h: payments.filter(p => {\n    const paymentTime = new Date(p.timestamp || p.created_at);\n    const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);\n    return paymentTime > oneDayAgo;\n  }).length,\n\n  spent_last_24h: payments.filter(p => {\n    const paymentTime = new Date(p.timestamp || p.created_at);\n    const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);\n    return paymentTime > oneDayAgo;\n  }).reduce((sum, p) => sum + parseFloat(p.amount_usd || 0), 0),\n\n  // Mandate stats\n  active_mandates: mandates.filter(m => {\n    const details = typeof m.details === 'string' ? JSON.parse(m.details) : m.details;\n    return details.status === 'active' || details.status === 'issued';\n  }).length,\n\n  total_budget: mandates.reduce((sum, m) => {\n    const details = typeof m.details === 'string' ? JSON.parse(m.details) : m.details;\n    return sum + parseFloat(details.budget_usd || 0);\n  }, 0),\n\n  budget_remaining: mandates.reduce((sum, m) => {\n    const details = typeof m.details === 'string' ? JSON.parse(m.details) : m.details;\n    return sum + parseFloat(details.budget_remaining || 0);\n  }, 0),\n\n  // Audit log stats\n  total_events_24h: logs.length,\n  payment_events: logs.filter(l => l.event_type && l.event_type.includes('payment')).length,\n  mandate_events: logs.filter(l => l.event_type && l.event_type.includes('mandate')).length,\n  aif_events: logs.filter(l => l.event_type && l.event_type.includes('aif')).length,\n\n  // Most recent payment\n  last_payment: payments.length > 0 ? payments[0] : null,\n\n  // Verification status\n  last_payment_verified: verification.verified || false\n};\n\n// Calculate budget utilization\nstats.budget_utilization_pct = stats.total_budget > 0\n  ? ((stats.total_budget - stats.budget_remaining) / stats.total_budget * 100).toFixed(2)\n  : 0;\n\n// Spending trend (compare last 24h to average)\nstats.spending_trend = stats.payment_count > 0\n  ? (stats.spent_last_24h > stats.average_payment ? 'increasing' : 'stable')\n  : 'no_activity';\n\nconsole.log(`   Total Spent: $${stats.total_spent}`);\nconsole.log(`   Payments (24h): ${stats.payments_last_24h}`);\nconsole.log(`   Budget Remaining: $${stats.budget_remaining}`);\nconsole.log(`   Budget Utilization: ${stats.budget_utilization_pct}%`);\n\nreturn [{ json: { config, analytics, stats, payments, logs, mandates, verification } }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "37d17b89-9df7-473d-9a55-2710f48d69b7",
      "name": "1\ufe0f\u20e31\ufe0f\u20e3 \ud83d\udea8 Check Alerts",
      "type": "n8n-nodes-base.code",
      "notes": "\ud83d\udea8 ALERTS: Check for warnings\n\nChecks:\n- Budget < 10% remaining\n- Mandate expires < 24h\n- Failed payments\n- High spending rate\n- No activity in 24h",
      "position": [
        1152,
        176
      ],
      "parameters": {
        "jsCode": "// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// ALERTS: Check for warnings and important notifications\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nconst data = $input.first().json;\nconst { stats, mandates, payments } = data;\n\nconst alerts = [];\n\n// Alert 1: Low budget warning\nif (stats.budget_remaining > 0 && stats.budget_utilization_pct > 90) {\n  alerts.push({\n    severity: 'high',\n    type: 'budget_low',\n    message: `\u26a0\ufe0f  BUDGET WARNING: Only $${stats.budget_remaining.toFixed(2)} remaining (${stats.budget_utilization_pct}% used)`,\n    action: 'Issue new mandate or reduce spending'\n  });\n} else if (stats.budget_remaining > 0 && stats.budget_utilization_pct > 75) {\n  alerts.push({\n    severity: 'medium',\n    type: 'budget_warning',\n    message: `\u2139\ufe0f  Budget Notice: $${stats.budget_remaining.toFixed(2)} remaining (${stats.budget_utilization_pct}% used)`,\n    action: 'Monitor spending'\n  });\n}\n\n// Alert 2: Mandate expiration warning\nmandates.forEach(m => {\n  const details = typeof m.details === 'string' ? JSON.parse(m.details) : m.details;\n  if (details.ttl_remaining_hours && details.ttl_remaining_hours < 24) {\n    alerts.push({\n      severity: 'high',\n      type: 'mandate_expiring',\n      message: `\u23f0 MANDATE EXPIRING: ${details.mandate_id} expires in ${details.ttl_remaining_hours} hours`,\n      action: 'Renew mandate before expiration'\n    });\n  }\n});\n\n// Alert 3: No recent activity\nif (stats.payments_last_24h === 0 && stats.payment_count > 0) {\n  alerts.push({\n    severity: 'low',\n    type: 'no_activity',\n    message: '\u2139\ufe0f  No payments in last 24 hours',\n    action: 'Normal - no action needed'\n  });\n}\n\n// Alert 4: Failed payments\nconst failed_payments = payments.filter(p => p.status === 'failed');\nif (failed_payments.length > 0) {\n  alerts.push({\n    severity: 'high',\n    type: 'payment_failures',\n    message: `\u274c FAILED PAYMENTS: ${failed_payments.length} payment(s) failed`,\n    action: 'Review failed transactions',\n    failed_txs: failed_payments.map(p => p.tx_hash)\n  });\n}\n\n// Alert 5: High spending rate\nif (stats.spent_last_24h > stats.average_payment * 10 && stats.payment_count > 10) {\n  alerts.push({\n    severity: 'medium',\n    type: 'high_spending',\n    message: `\ud83d\udcc8 High Spending: $${stats.spent_last_24h.toFixed(2)} spent in 24h (10x average)`,\n    action: 'Verify spending is intentional'\n  });\n}\n\n// Alert 6: Verification failure\nif (data.verification && !data.verification.verified && data.config.tx_hash) {\n  alerts.push({\n    severity: 'medium',\n    type: 'verification_failed',\n    message: `\u26a0\ufe0f  Payment verification issue: ${data.verification.reason || 'Unknown'}`,\n    action: 'Check transaction on blockchain explorer'\n  });\n}\n\nconsole.log(`\ud83d\udea8 Alerts: ${alerts.length} alert(s)`);\nalerts.forEach((a, i) => {\n  console.log(`   ${i+1}. [${a.severity.toUpperCase()}] ${a.message}`);\n});\n\nreturn [{ json: { ...data, alerts } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "d346a783-2709-43ff-a8f5-be4122426660",
      "name": "1\ufe0f\u20e32\ufe0f\u20e3 \ud83d\udcf1 Format Dashboard",
      "type": "n8n-nodes-base.code",
      "notes": "\ud83d\udcf1 DASHBOARD: Format metrics for display\n\nCreates:\n- Key metrics cards\n- Alert summary\n- Quick stats\n- Links to full dashboard\n- Export options",
      "position": [
        1376,
        176
      ],
      "parameters": {
        "jsCode": "// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// DASHBOARD DATA: Format metrics for hybrid display\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nconst data = $input.first().json;\nconst { config, analytics, stats, alerts } = data;\n\n// Create dashboard-ready data structure\nconst dashboard = {\n  // Header\n  title: \"\ud83d\udcca Buyer Monitoring Dashboard\",\n  user: config.user_email,\n  generated_at: new Date().toISOString(),\n  session_id: config.session.id,\n  \n  // Key metrics (shown in N8N)\n  metrics: {\n    total_spent: {\n      value: `$${stats.total_spent.toFixed(2)}`,\n      label: \"Total Spent\",\n      icon: \"\ud83d\udcb0\"\n    },\n    payment_count: {\n      value: stats.payment_count,\n      label: \"Total Payments\",\n      icon: \"\ud83d\udcb3\"\n    },\n    budget_remaining: {\n      value: `$${stats.budget_remaining.toFixed(2)}`,\n      label: \"Budget Remaining\",\n      icon: \"\ud83d\udd11\",\n      percentage: `${stats.budget_utilization_pct}% used`\n    },\n    active_mandates: {\n      value: stats.active_mandates,\n      label: \"Active Mandates\",\n      icon: \"\ud83c\udfab\"\n    },\n    payments_24h: {\n      value: stats.payments_last_24h,\n      label: \"Payments (24h)\",\n      icon: \"\ud83d\udcc8\",\n      amount: `$${stats.spent_last_24h.toFixed(2)}`\n    },\n    events_24h: {\n      value: stats.total_events_24h,\n      label: \"Events Logged (24h)\",\n      icon: \"\ud83d\udccb\"\n    }\n  },\n  \n  // Alerts summary\n  alerts_summary: {\n    count: alerts.length,\n    high: alerts.filter(a => a.severity === 'high').length,\n    medium: alerts.filter(a => a.severity === 'medium').length,\n    low: alerts.filter(a => a.severity === 'low').length,\n    items: alerts\n  },\n  \n  // Quick stats\n  quick_stats: {\n    average_payment: `$${stats.average_payment.toFixed(2)}`,\n    spending_trend: stats.spending_trend,\n    budget_utilization: `${stats.budget_utilization_pct}%`,\n    last_payment_verified: stats.last_payment_verified ? '\u2705 Verified' : '\u23f3 Pending'\n  },\n  \n  // Links\n  links: {\n    user_analytics: `${config.api_url}/v1/analytics/me`,\n    audit_logs: `${config.api_url}/audit/logs?client_id=${config.user_email}`,\n    payment_history: `${config.api_url}/v1/payments/list`\n  },\n  \n  // Export options\n  export: {\n    csv_available: true,\n    json_available: true,\n    pdf_available: false\n  }\n};\n\nconsole.log('\ud83d\udcca Dashboard data prepared');\nconsole.log(`   Metrics: ${Object.keys(dashboard.metrics).length}`);\nconsole.log(`   Alerts: ${dashboard.alerts_summary.count}`);\n\nreturn [{ json: { ...data, dashboard } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "0a268443-15a8-4d1e-9acf-ba99eabe6173",
      "name": "1\ufe0f\u20e33\ufe0f\u20e3 \ud83d\udcc4 Generate CSV Export",
      "type": "n8n-nodes-base.code",
      "notes": "\ud83d\udcc4 EXPORT: Generate CSV report\n\nIncludes:\n- Summary metrics\n- Alerts\n- Payment history (last 10)\n- Active mandates\n- Event summary\n\nCopy csv_export field to save",
      "position": [
        1600,
        176
      ],
      "parameters": {
        "jsCode": "// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// CSV EXPORT: Generate downloadable CSV report\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nconst data = $input.first().json;\nconst { config, stats, payments, logs, mandates, alerts } = data;\n\n// CSV Header\nlet csv = \"AgentGatePay Buyer Monitoring Report\\n\";\ncsv += `Generated: ${new Date().toISOString()}\\n`;\ncsv += `User: ${config.user_email}\\n`;\ncsv += `\\n`;\n\n// Summary section\ncsv += \"SUMMARY\\n\";\ncsv += \"Metric,Value\\n\";\ncsv += `Total Spent,$${stats.total_spent}\\n`;\ncsv += `Payment Count,${stats.payment_count}\\n`;\ncsv += `Average Payment,$${stats.average_payment}\\n`;\ncsv += `Budget Remaining,$${stats.budget_remaining}\\n`;\ncsv += `Budget Utilization,${stats.budget_utilization_pct}%\\n`;\ncsv += `Active Mandates,${stats.active_mandates}\\n`;\ncsv += `Payments (24h),${stats.payments_last_24h}\\n`;\ncsv += `Spent (24h),$${stats.spent_last_24h}\\n`;\ncsv += `\\n`;\n\n// Alerts section\nif (alerts.length > 0) {\n  csv += \"ALERTS\\n\";\n  csv += \"Severity,Type,Message,Action\\n\";\n  alerts.forEach(a => {\n    csv += `${a.severity},${a.type},\"${a.message}\",\"${a.action}\"\\n`;\n  });\n  csv += `\\n`;\n}\n\n// Payment history - MERCHANT PAYMENTS\ncsv += \"MERCHANT PAYMENTS (Last 20)\\n\";\ncsv += \"Timestamp,TX Hash,Amount USD,Status,Merchant Address\\n\";\nconst merchant_logs = logs.filter(log => log.event_type === 'x402_payment_settled');\nmerchant_logs.slice(0, 20).forEach(log => {\n  const details = log.details;\n  csv += `${new Date(details.timestamp * 1000).toISOString()},${details.tx_hash},$${details.amount_usd},${details.status || 'completed'},${details.receiver_address}\\n`;\n});\ncsv += `\\n`;\n\n// COMMISSION PAYMENTS\ncsv += \"COMMISSION PAYMENTS (Last 20)\\n\";\ncsv += \"Timestamp,TX Hash,Amount USD,Status,Gateway Address\\n\";\nconst commission_logs = logs.filter(log => log.event_type === 'x402_payment_settled' && log.details.commission_tx_hash);\ncommission_logs.slice(0, 20).forEach(log => {\n  const details = log.details;\n  csv += `${new Date(details.timestamp * 1000).toISOString()},${details.commission_tx_hash},$${details.commission_amount_usd || 0},${details.status || 'completed'},${details.commission_address}\\n`;\n});\ncsv += `\\n`;\n\n// Mandate summary\nif (mandates.length > 0) {\n  csv += \"ACTIVE MANDATES\\n\";\n  csv += \"Mandate ID,Budget USD,Remaining USD,TTL Hours,Status\\n\";\n  mandates.forEach(m => {\n    const details = typeof m.details === 'string' ? JSON.parse(m.details) : m.details;\n    csv += `${details.mandate_id || 'N/A'},$${details.budget_usd || 0},$${details.budget_remaining || 0},${details.ttl_remaining_hours || 'N/A'},${details.status || 'N/A'}\\n`;\n  });\n  csv += `\\n`;\n}\n\n// Event summary\ncsv += \"EVENT SUMMARY (24h)\\n\";\ncsv += \"Category,Count\\n\";\ncsv += `Total Events,${stats.total_events_24h}\\n`;\ncsv += `Payment Events,${stats.payment_events}\\n`;\ncsv += `Mandate Events,${stats.mandate_events}\\n`;\ncsv += `AIF Security Events,${stats.aif_events}\\n`;\n\nconsole.log('\ud83d\udcc4 CSV export generated');\nconsole.log(`   Size: ${csv.length} characters`);\n\nreturn [{ json: { ...data, csv_export: csv } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "9256806d-83ef-44c9-8480-e950a9a3b08f",
      "name": "1\ufe0f\u20e34\ufe0f\u20e3 \ud83d\udccb Final Report",
      "type": "n8n-nodes-base.code",
      "notes": "\ud83d\udccb FINAL REPORT: Complete formatted output\n\nIncludes:\n- Key metrics summary\n- Alerts and warnings\n- Spending analysis\n- Recent payments\n- Active mandates\n- Event activity\n- Dashboard links (hybrid)\n- Export options\n\n\u2705 This is the final output!",
      "position": [
        1808,
        176
      ],
      "parameters": {
        "jsCode": "// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// FINAL REPORT: Beautiful formatted output with CORRECT calculations\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nconst data = $input.first().json;\nconst { config, stats, alerts, logs, mandates } = data;\n\n// \u2705 FIX: Extract ALL payment events from audit logs\nconst payment_logs = logs.filter(log =>\n  log.event_type === 'x402_payment_settled' ||\n  log.event_type === 'x402_commission_collected'\n);\n\n// \u2705 FIX: Extract commission data EMBEDDED within payment_settled events\n// Commission info is in same event as merchant payment, not separate events\nconst commission_payments = logs\n  .filter(log => log.event_type === 'x402_payment_settled' && log.details.commission_tx_hash)\n  .map(log => ({\n    timestamp: new Date(log.details.timestamp * 1000).toISOString(),\n    amount_usd: log.details.commission_amount_usd || 0,\n    status: log.details.status || 'completed',\n    tx_hash: log.details.commission_tx_hash,\n    type: 'commission',\n    receiver: log.details.commission_address,\n    payer: log.details.payer_address || log.details.sender_address,\n    explorer: log.details.commission_explorer_url || `https://basescan.org/tx/${log.details.commission_tx_hash}`\n  }));\n\nconst merchant_payments = logs\n  .filter(log => log.event_type === 'x402_payment_settled' && log.details.merchant_tx_hash)\n  .map(log => ({\n    timestamp: new Date(log.details.timestamp * 1000).toISOString(),\n    amount_usd: log.details.merchant_amount_usd || log.details.amount_usd,\n    status: log.details.status || 'completed',\n    tx_hash: log.details.merchant_tx_hash || log.details.tx_hash,\n    type: 'merchant',\n    receiver: log.details.merchant_address || log.details.receiver_address,\n    payer: log.details.payer_address || log.details.sender_address,\n    explorer: log.details.merchant_explorer_url || log.details.explorer_url || `https://basescan.org/tx/${log.details.merchant_tx_hash || log.details.tx_hash}`\n  }));\n\n// Calculate REAL total spent (commission / 0.005 to get original amount)\n// If commission is $0.00995 and rate is 0.5%, original payment was $0.00995 / 0.005 = $1.99\nconst commission_rate = 0.005; // 0.5%\nconst total_commission = commission_payments.reduce((sum, p) => sum + p.amount_usd, 0);\nconst total_merchant = merchant_payments.reduce((sum, p) => sum + p.amount_usd, 0);\n\n// Total spent = commission + merchant payments (or commission / rate if merchant data missing)\nlet total_spent;\nif (merchant_payments.length > 0) {\n  total_spent = total_commission + total_merchant;\n} else {\n  // Calculate from commission only\n  total_spent = total_commission / commission_rate;\n}\n\nconst payment_count = Math.max(commission_payments.length, merchant_payments.length);\nconst average_payment = payment_count > 0 ? total_spent / payment_count : 0;\n\n// Calculate last 24h activity\nconst oneDayAgo = Date.now() - 24 * 60 * 60 * 1000;\nconst recent_commissions = commission_payments.filter(p => new Date(p.timestamp).getTime() > oneDayAgo);\nconst recent_merchants = merchant_payments.filter(p => new Date(p.timestamp).getTime() > oneDayAgo);\nconst payments_24h_count = Math.max(recent_commissions.length, recent_merchants.length);\nconst spent_24h = (recent_commissions.reduce((sum, p) => sum + p.amount_usd, 0) +\n                   recent_merchants.reduce((sum, p) => sum + p.amount_usd, 0)) ||\n                   (recent_commissions.reduce((sum, p) => sum + p.amount_usd, 0) / commission_rate);\n\n// \u2705 FIX: Calculate CORRECT budget remaining\n// Get total budget from mandates\nconst total_budget = mandates && mandates.length > 0\n  ? mandates.reduce((sum, m) => {\n      const details = typeof m.details === 'string' ? JSON.parse(m.details) : m.details;\n      return sum + (parseFloat(details.budget_usd) || 0);\n    }, 0)\n  : 100; // Default if no mandates\n\nconst budget_remaining = total_budget - total_spent;\nconst budget_utilization_pct = total_budget > 0 ? ((total_spent / total_budget) * 100).toFixed(2) : 0;\n\n// Combine payments for display (grouped by transaction)\nconst all_payments = [];\nconst processed_timestamps = new Set();\n\ncommission_payments.forEach(comm => {\n  const merch = merchant_payments.find(m =>\n    Math.abs(new Date(m.timestamp).getTime() - new Date(comm.timestamp).getTime()) < 5000\n  );\n\n  if (!processed_timestamps.has(comm.timestamp)) {\n    all_payments.push({\n      timestamp: comm.timestamp,\n      total_amount: merch ? comm.amount_usd + merch.amount_usd : comm.amount_usd / commission_rate,\n      commission: comm.amount_usd,\n      merchant_amount: merch ? merch.amount_usd : (comm.amount_usd / commission_rate) - comm.amount_usd,\n      commission_tx: comm.tx_hash,\n      merchant_tx: merch ? merch.tx_hash : 'N/A',\n      status: comm.status,\n      merchant_address: merch ? merch.receiver : 'N/A'\n    });\n    processed_timestamps.add(comm.timestamp);\n  }\n});\n\n// Build dashboard object with CORRECT values\nconst dashboard = {\n  metrics: {\n    total_spent: {\n      value: `$${total_spent.toFixed(2)}`,\n      label: \"Total Spent\",\n      icon: \"\ud83d\udcb0\"\n    },\n    payment_count: {\n      value: payment_count,\n      label: \"Total Payments\",\n      icon: \"\ud83d\udcb3\"\n    },\n    budget_remaining: {\n      value: `$${budget_remaining.toFixed(2)}`,\n      label: \"Budget Remaining\",\n      icon: \"\ud83d\udd11\",\n      percentage: `${budget_utilization_pct}% used`\n    },\n    active_mandates: {\n      value: stats.active_mandates,\n      label: \"Active Mandates\",\n      icon: \"\ud83c\udfab\"\n    },\n    payments_24h: {\n      value: payments_24h_count,\n      label: \"Payments (24h)\",\n      icon: \"\ud83d\udcc8\",\n      amount: `$${spent_24h.toFixed(2)}`\n    },\n    events_24h: {\n      value: stats.total_events_24h,\n      label: \"Events Logged (24h)\",\n      icon: \"\ud83d\udccb\"\n    }\n  },\n  alerts_summary: {\n    count: alerts.length,\n    high: alerts.filter(a => a.severity === 'high').length,\n    medium: alerts.filter(a => a.severity === 'medium').length,\n    low: alerts.filter(a => a.severity === 'low').length,\n    items: alerts\n  },\n  quick_stats: {\n    average_payment: `$${average_payment.toFixed(2)}`,\n    spending_trend: spent_24h > average_payment ? 'increasing' : 'stable',\n    budget_utilization: `${budget_utilization_pct}%`,\n    last_payment_verified: \"\u2705 Verified\"\n  },\n  links: {\n    user_analytics: `${config.api_url}/v1/analytics/me`,\n    audit_logs: `${config.api_url}/audit/logs?client_id=${config.buyer_wallet || config.user_email}`,\n    payment_history: `${config.api_url}/v1/payments/list`\n  }\n};\n\n// Update stats with CORRECT values\nstats.total_spent = total_spent;\nstats.payment_count = payment_count;\nstats.average_payment = average_payment;\nstats.payments_last_24h = payments_24h_count;\nstats.spent_last_24h = spent_24h;\nstats.budget_remaining = budget_remaining;\nstats.budget_utilization_pct = budget_utilization_pct;\nstats.spending_trend = dashboard.quick_stats.spending_trend;\n\n// Build formatted report (ORIGINAL FORMAT)\nconst report = {\n  // Header\n  \"\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\": \"\",\n  \"\ud83c\udfaf AGENTGATEPAY BUYER MONITORING DASHBOARD\": \"\",\n  \"\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550_\": \"\",\n\n  user: config.user_email,\n  generated: new Date().toISOString(),\n  session_id: config.session?.id || 'N/A',\n  trigger_source: config.trigger_source || 'manual',\n\n  \"\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\": \"\",\n  \"\ud83d\udcca KEY METRICS\": \"\",\n  \"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501_\": \"\",\n\n  metrics: dashboard.metrics,\n\n  \"\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501__\": \"\",\n  \"\ud83d\udea8 ALERTS & WARNINGS\": \"\",\n  \"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501___\": \"\",\n\n  alerts_count: `${alerts.length} alert(s) - ${dashboard.alerts_summary.high} high, ${dashboard.alerts_summary.medium} medium, ${dashboard.alerts_summary.low} low`,\n  alerts: alerts.length > 0 ? alerts : [{ message: \"\u2705 No alerts - all systems normal\" }],\n\n  \"\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501____\": \"\",\n  \"\ud83d\udcc8 SPENDING ANALYSIS\": \"\",\n  \"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501_____\": \"\",\n\n  spending_analysis: {\n    total_spent: `$${stats.total_spent.toFixed(2)} USD`,\n    payments_count: stats.payment_count,\n    average_payment: `$${stats.average_payment.toFixed(2)} USD`,\n    last_24h: `${stats.payments_last_24h} payments ($${stats.spent_last_24h.toFixed(2)} USD)`,\n    trend: stats.spending_trend,\n    budget_utilization: `${stats.budget_utilization_pct}% used`,\n    budget_remaining: `$${stats.budget_remaining.toFixed(2)} USD`\n  },\n\n  \"\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501______\": \"\",\n  \"\ud83d\udcb3 PAYMENTS TO MERCHANTS/AGENTS (Last 20)\": \"\",\n  \"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501_______\": \"\",\n\n  merchant_payments: merchant_payments.slice(0, 20).map(p => ({\n    timestamp: p.timestamp,\n    amount_paid: `$${p.amount_usd.toFixed(4)} USD`,\n    merchant_address: p.receiver,\n    tx_hash: p.tx_hash,\n    status: p.status,\n    explorer: p.explorer || `https://basescan.org/tx/${p.tx_hash}`\n  })),\n\n  \"\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501________\": \"\",\n  \"\ud83d\udcb0 GATEWAY COMMISSION PAYMENTS (Last 20)\": \"\",\n  \"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501_________\": \"\",\n\n  commission_payments_list: commission_payments.slice(0, 20).map(p => ({\n    timestamp: p.timestamp,\n    commission: `$${p.amount_usd.toFixed(4)} USD (0.5%)`,\n    gateway_address: p.receiver,\n    tx_hash: p.tx_hash,\n    status: p.status,\n    explorer: p.explorer || `https://basescan.org/tx/${p.tx_hash}`\n  })),\n\n  \"\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501________\": \"\",\n  \"\ud83d\udd11 ACTIVE MANDATES\": \"\",\n  \"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501_________\": \"\",\n\n  mandates_summary: mandates && mandates.length > 0 ? mandates.map(m => {\n    const details = typeof m.details === 'string' ? JSON.parse(m.details) : m.details;\n\n    // \u2705 FIX: Calculate TTL and remaining budget correctly\n    let ttl_hours = details.ttl_remaining_hours;\n    if (!ttl_hours && details.expires_at) {\n      const now = Math.floor(Date.now() / 1000);\n      const expires = details.expires_at;\n      ttl_hours = Math.max(0, Math.floor((expires - now) / 3600));\n    }\n\n    // Calculate this mandate's remaining budget\n    const mandate_budget = parseFloat(details.budget_usd) || 0;\n    const mandate_spent = total_spent; // Simplified - assumes one mandate\n    const mandate_remaining = mandate_budget - mandate_spent;\n\n    return {\n      mandate_id: details.mandate_id,\n      budget: `$${mandate_budget.toFixed(2)} USD ($${mandate_remaining.toFixed(2)} USD remaining)`,\n      ttl: ttl_hours ? `${ttl_hours} hours` : 'expired',\n      status: details.status\n    };\n  }) : [{ message: \"No active mandates\" }],\n\n  \"\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501__________\": \"\",\n  \"\ud83d\udcca EVENT ACTIVITY (24h)\": \"\",\n  \"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501___________\": \"\",\n\n  event_activity: {\n    total_events: stats.total_events_24h,\n    payment_events: stats.payment_events,\n    commission_events: commission_payments.length,\n    mandate_events: stats.mandate_events,\n    aif_security_events: stats.aif_events\n  },\n\n  \"\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501____________\": \"\",\n  \"\ud83d\udd0d SEARCH YOUR LOGS - COPY & PASTE CURL COMMANDS\": \"\",\n  \"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501_____________\": \"\",\n\n  search_commands: {\n    \"\ud83d\udcc5 Last 24 hours\": `curl '${config.api_url}/audit/logs?client_id=${config.buyer_wallet || config.user_email}&hours=24' -H 'x-api-key: ${config.api_key}'`,\n\n    \"\ud83d\udcc5 Last 7 days\": `curl '${config.api_url}/audit/logs?client_id=${config.buyer_wallet || config.user_email}&hours=168' -H 'x-api-key: ${config.api_key}'`,\n\n    \"\ud83d\udcb3 Payment events\": `curl '${config.api_url}/audit/logs?client_id=${config.buyer_wallet || config.user_email}&event_type=x402_payment_settled' -H 'x-api-key: ${config.api_key}'`,\n\n    \"\ud83d\udcb0 Commission events\": `curl '${config.api_url}/audit/logs?client_id=${config.buyer_wallet || config.user_email}&event_type=x402_commission_collected' -H 'x-api-key: ${config.api_key}'`,\n\n    \"\ud83d\udd11 Mandate events\": `curl '${config.api_url}/audit/logs?client_id=${config.buyer_wallet || config.user_email}&event_type=mandate_issued' -H 'x-api-key: ${config.api_key}'`,\n\n    \"\ud83d\udcca Analytics\": `curl '${config.api_url}/v1/analytics/me' -H 'x-api-key: ${config.api_key}'`\n  },\n\n  \"\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501______________\": \"\",\n  \"\ud83d\udd17 API ENDPOINTS\": \"\",\n  \"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501_______________\": \"\",\n\n  api_endpoints: {\n    \"\ud83d\udcca User Analytics\": dashboard.links.user_analytics,\n    \"\ud83d\udccb Audit Logs\": dashboard.links.audit_logs,\n    \"\ud83d\udcb3 Payment History\": dashboard.links.payment_history,\n    \"\ud83d\udca1 How to use\": \"Add header: x-api-key: \" + config.api_key\n  },\n\n  \"\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501________________\": \"\",\n  \"\ud83d\udce5 EXPORT OPTIONS\": \"\",\n  \"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501_________________\": \"\",\n\n  export_options: {\n    \"\ud83d\udcc4 CSV Export\": \"See 'csv_export' field in raw_data\",\n    \"\ud83d\udce6 JSON Export\": \"This complete JSON output\",\n    \"\ud83d\udcca How to View\": \"Use curl commands above to fetch your data\"\n  },\n\n  \"\\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550__________________\": \"\",\n  \"\u2705 MONITORING COMPLETE\": \"\",\n  \"\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550___________________\": \"\",\n\n  summary: `Monitored ${stats.payment_count} payments, $${stats.total_spent.toFixed(2)} USD spent (incl. $${total_commission.toFixed(4)} commission), ${alerts.length} alert(s), ${stats.active_mandates} active mandate(s)`,\n\n  next_steps: alerts.length > 0\n    ? \"\u26a0\ufe0f  Review alerts above and take recommended actions\"\n    : \"\u2705 All systems normal - no action required\"\n};\n\nconsole.log('\u2705 Final report generated');\nconsole.log(`   Total Spent: $${stats.total_spent.toFixed(2)} USD`);\nconsole.log(`   Commission: $${total_commission.toFixed(4)} USD`);\nconsole.log(`   To Merchants: $${total_merchant > 0 ? total_merchant.toFixed(4) : (total_spent - total_commission).toFixed(4)} USD`);\nconsole.log(`   Payments: ${stats.payment_count}`);\nconsole.log(`   Budget Remaining: $${stats.budget_remaining.toFixed(2)} USD`);\n\n// Remove duplicate dashboard from raw_data (already shown in report metrics)\ndelete data.dashboard;\n\nreturn [{ json: { report, raw_data: data } }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "8b215841-6522-41fd-953c-0e3bf9c6c11f",
      "name": "START HERE",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1840,
        16
      ],
      "parameters": {
        "color": 4,
        "width": 500,
        "height": 640,
        "content": "# Buyer Monitoring Dashboard\n\n**What it does:** Shows your spending, payment history, mandates, and alerts.\n\n**Quick start:**\n1. Edit Node 2: Add your wallet address, email and API key\n2. Click Execute Workflow\n3. Check Node 14 for the full report\n\n**What you'll see:**\n- Total spent and payment count\n- Budget remaining from active mandates\n- Recent payments (last 50)\n- Alerts (low budget, failed payments, etc.)\n- Transaction verification status\n\n**Run it:** Manually anytime, or trigger from payment workflows for auto-monitoring\n\n**Export:** Node 13 has CSV data you can copy and save"
      },
      "typeVersion": 1
    },
    {
      "id": "884c3663-dc9a-443a-a486-57f5ab80968c",
      "name": "Sticky Note 1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1312,
        16
      ],
      "parameters": {
        "color": 7,
        "width": 1280,
        "height": 424,
        "content": "## Data Collection\n\nFetches analytics, payment history, audit logs, and active mandates from AgentGatePay API. All data filtered by your wallet address."
      },
      "typeVersion": 1
    },
    {
      "id": "043b6ca6-3821-4d50-a9e3-d0c8d65a270f",
      "name": "Sticky Note 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 860,
        "height": 440,
        "content": "## Blockchain Verification\n\nIf you provide a tx_hash, verifies the payment on-chain. Otherwise skips and merges empty result. Helps confirm your latest transaction went through."
      },
      "typeVersion": 1
    },
    {
      "id": "fc1d6874-d725-4042-9a5d-82c5211540b3",
      "name": "Sticky Note 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        880,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 404,
        "height": 440,
        "content": "## Analysis & Alerts\n\nCalculates spending trends, budget utilization, and checks for issues. Alerts trigger when budget drops below 10% or mandates expire soon."
      },
      "typeVersion": 1
    },
    {
      "id": "3b6bdb16-9d3f-46d9-bfc4-4436fd4e4aa2",
      "name": "Sticky Note 4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1296,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 680,
        "height": 440,
        "content": "## Output Generation\n\nFormats dashboard with key metrics, generates CSV export for spreadsheets, and creates the final report. Node 14 is your main output."
      },
      "typeVersion": 1
    },
    {
      "id": "7a70ac2e-0512-406f-993c-aab97e252e3e",
      "name": "3\ufe0f\u20e3 \ud83d\udcb0 Get Merchant Revenue",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "\ud83d\udcb0 REVENUE: Fetch merchant revenue stats\n\nReturns:\n- total_usd\n- count\n- average_usd\n- by_chain\n- by_token",
      "position": [
        -848,
        1040
      ],
      "parameters": {
        "url": "={{ $json.config.api_url }}/v1/merchant/revenue?wallet={{ $json.config.merchant_wallet }}",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "x-api-key",
              "value": "={{ $json.config.api_key }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "6168ab41-1222-41bf-9180-2e3258b82ccd",
      "name": "4\ufe0f\u20e3 \ud83d\udcb3 Get Payment List",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "\ud83d\udcb3 PAYMENTS: Fetch payments TO this merchant\n\nShows last 10 payments received:\n- tx_hash\n- amount_usd\n- status\n- timestamp\n- sender",
      "position": [
        -624,
        1040
      ],
      "parameters": {
        "url": "={{ $('2\ufe0f\u20e3 Load Config1').first().json.config.api_url }}/v1/payments/list?wallet={{ $('2\ufe0f\u20e3 Load Config1').first().json.config.merchant_wallet }}&limit={{ $('2\ufe0f\u20e3 Load Config1').first().json.config.payment_history_limit }}",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "x-api-key",
              "value": "={{ $('2\ufe0f\u20e3 Load Config1').first().json.config.api_key }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "7b552971-de04-43a2-b4cd-6702fe777ff6",
      "name": "5\ufe0f\u20e3 \ud83d\udd17 Get Webhooks",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "\ud83d\udd17 WEBHOOKS: Fetch configured webhooks\n\nShows:\n- webhook_id\n- url\n- events\n- status\n- delivery_count\n- failure_count",
      "position": [
        -400,
        1040
      ],
      "parameters": {
        "url": "={{ $('2\ufe0f\u20e3 Load Config1').first().json.config.api_url }}/v1/webhooks/list",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "x-api-key",
              "value": "={{ $('2\ufe0f\u20e3 Load Config1').first().json.config.api_key }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "14e2d4c3-8e9d-4899-9f50-bb18c719cefe",
      "name": "6\ufe0f\u20e3 \ud83d\udccb Get Audit Logs (24h)",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "\ud83d\udccb AUDIT: Fetch payment events (24h)\n\nFiltered by:\n- event_type: x402_payment_settled\n- Last 24 hours\n- Max 50 events\n\nShows: payments received",
      "position": [
        -176,
        1040
      ],
      "parameters": {
        "url": "={{ $('2\ufe0f\u20e3 Load Config1').first().json.config.api_url }}/audit/logs?event_type=x402_payment_settled&hours={{ $('2\ufe0f\u20e3 Load Config1').first().json.config.time_range_hours }}&limit={{ $('2\ufe0f\u20e3 Load Config1').first().json.config.audit_log_limit }}",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "x-api-key",
              "value": "={{ $('2\ufe0f\u20e3 Load Config1').first().json.config.api_key }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "6b7ff7a9-9f5c-40d2-9042-fabdefe9ac1a",
      "name": "2\ufe0f\u20e3 Load Config1",
      "type": "n8n-nodes-base.code",
      "notes": "\u2699\ufe0f SETUP: Validate inputs\n\n\u26a0\ufe0f EDIT THIS if running manually:\n- merchant_wallet: Your wallet address\n- api_key: Your AgentGatePay API key",
      "position": [
        -1056,
        1040
      ],
      "parameters": {
        "jsCode": "// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// CONFIG: Validate inputs and setup monitoring parameters\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nconst input = $input.first().json;\n\n// Check if triggered by webhook or manual\nconst isManual = !input.merchant_wallet;\n\nconst config = {\n  merchant_wallet: input.merchant_wallet || \"0xYOUR_WALLET_ADDRESS\",  // \u26a0\ufe0f REPLACE if running manually\n  api_key: input.api_key || \"YOUR_API_KEY\",  // \u26a0\ufe0f REPLACE if running manually\n  tx_hash: input.tx_hash || null,\n  trigger_source: input.trigger_source || \"manual\",\n  \n  // Monitoring settings\n  time_range_hours: 24,\n  payment_history_limit: 50,  // Fetch last 50 for display (use curl for full history)\n  audit_log_limit: 50,\n  export_format: \"csv\",\n  \n  // AgentGatePay API\n  api_url: \"https://api.agentgatepay.com\",\n  mcp_endpoint: \"https://mcp.agentgatepay.com\",\n  \n  // Session tracking\n  session: {\n    id: `monitor_${Date.now()}`,\n    started_at: new Date().toISOString(),\n    is_manual: isManual\n  }\n};\n\n// Validation\nif (config.api_key === \"YOUR_API_KEY\") {\n  throw new Error(\"\u274c Please configure your API key in Node 2 'Load Config'!\");\n}\n\nif (config.merchant_wallet === \"0xYOUR_WALLET_ADDRESS\") {\n  throw new Error(\"\u274c Please configure your merchant wallet in Node 2 'Load Config'!\");\n}\n\nconsole.log(`\ud83d\udcb2 Seller Monitoring Dashboard Started`);\nconsole.log(`   Wallet: ${config.merchant_wallet}`);\nconsole.log(`   Source: ${config.trigger_source}`);\nconsole.log(`   TX Hash: ${config.tx_hash || 'N/A'}`);\n\nreturn [{ json: { config } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "f457f21f-644b-44c3-8586-f10696414046",
      "name": "7\ufe0f\u20e3 \ud83d\udd0d Prepare Verification1",
      "type": "n8n-nodes-base.code",
      "notes": "\ud83d\udd0d PREPARE: Check if we have tx_hash to verify",
      "position": [
        32,
        1040
      ],
      "parameters": {
        "jsCode": "// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// VERIFICATION: Verify last payment received on blockchain\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nconst config = $('2\ufe0f\u20e3 Load Config1').first().json.config;\nconst tx_hash = config.tx_hash;\n\nif (!tx_hash) {\n  console.log('\u26a0\ufe0f  No tx_hash provided - skipping verification');\n  return [{ json: { \n    verified: false, \n    reason: \"No transaction hash provided\",\n    config: config\n  }}];\n}\n\nconsole.log(`\ud83d\udd0d Verifying payment received: ${tx_hash}`);\n\nreturn [{ json: { \n  tx_hash: tx_hash,\n  config: config,\n  should_verify: true\n}}];"
      },
      "typeVersion": 2
    },
    {
      "id": "9477db90-b1ab-47f5-b726-683c4780d47d",
      "name": "7B\ufe0f\u20e3 Has TX Hash?1",
      "type": "n8n-nodes-base.if",
      "notes": "\ud83d\udd00 ROUTER: Only verify if tx_hash exists",
      "position": [
        256,
        1040
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "should-verify",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.should_verify }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "cc493fa7-86a8-4a63-8d46-aebbbb8e3de7",
      "name": "8\ufe0f\u20e3 \u2705 Verify on Blockchain1",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "\u2705 BLOCKCHAIN: Verify payment received\n\nChecks:\n- Transaction exists\n- Correct amount\n- Correct recipient\n- Block confirmation",
      "position": [
        480,
        944
      ],
      "parameters": {
        "url": "={{ $('2\ufe0f\u20e3 Load Config1').first().json.config.api_url }}/v1/payments/verify/{{ $json.tx_hash }}",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "x-api-key",
              "value": "={{ $('2\ufe0f\u20e3 Load Config1').first().json.config.api_key }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "e49e02db-39ad-433f-a9bd-ab484be229ae",
      "name": "8B\ufe0f\u20e3 Skip Verification1",
      "type": "n8n-nodes-base.code",
      "notes": "\u23ed\ufe0f  SKIP: No tx_hash to verify",
      "position": [
        480,
        1152
      ],
      "parameters": {
        "jsCode": "return [{ json: { \n  verified: false,\n  reason: \"No transaction to verify\",\n  message: \"Skipped verification - no tx_hash provided\"\n}}];"
      },
      "typeVersion": 2
    },
    {
      "id": "4406aca5-08e8-40eb-a074-77d12c0d02c9",
      "name": "9\ufe0f\u20e3 Merge Verification1",
      "type": "n8n-nodes-base.merge",
      "notes": "\ud83d\udd00 MERGE: Combine verified/skipped paths",
      "position": [
        704,
        1040
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combinationMode": "mergeByPosition"
      },
      "typeVersion": 2.1
    },
    {
      "id": "76cf6de5-8aee-489e-830f-7ea0f5d44adf",
      "name": "\ud83d\udd1f \ud83d\udcca Calculate Statistics1",
      "type": "n8n-nodes-base.code",
      "notes": "\ud83d\udcca STATISTICS: Calculate merchant metrics\n\nCalculates:\n- Revenue trends\n- Payment success rate\n- Webhook delivery rate\n- Top buyers\n- Recent activity (24h)",
      "position": [
        912,
        1040
      ],
      "parameters": {
        "jsCode": "// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// STATISTICS: Calculate revenue trends and merchant metrics\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nconst config = $('2\ufe0f\u20e3 Load Config1').first().json.config;\nconst revenue = $('3\ufe0f\u20e3 \ud83d\udcb0 Get Merchant Revenue').first().json;\nconst payments_response = $('4\ufe0f\u20e3 \ud83d\udcb3 Get Payment List').first().json;\nconst webhooks_response = $('5\ufe0f\u20e3 \ud83d\udd17 Get Webhooks').first().json;\nconst audit_logs_response = $('6\ufe0f\u20e3 \ud83d\udccb Get Audit Logs (24h)').first().json;\nconst verification = $input.first().json;\n\nconsole.log('\ud83d\udcca Calculating merchant statistics...');\n\n// Parse payments\nconst payment_list = payments_response.payments || [];\n\n// Parse webhooks\nconst webhook_list = webhooks_response.webhooks || [];\n\n// Parse audit logs\nconst logs = audit_logs_response.logs || [];\n\n// \u2705 FIX: Use correct API field names from merchant revenue response\n// API returns: total_usd, count, average_usd (NOT total_revenue_usd, payment_count, average_payment_usd)\nconst total_revenue = revenue.total_usd || 0;\nconst payment_count = revenue.count || 0;  // \u2705 FIXED: use 'count' not 'payment_count'\nconst average_payment = payment_count > 0 ? (total_revenue / payment_count) : (revenue.average_usd || 0);\n\nconst stats = {\n  // Revenue stats - FIXED field names to match API response\n  total_revenue: total_revenue,\n  payment_count: payment_count,\n  average_payment: average_payment,\n  revenue_this_month: revenue.revenue_this_month || 0,\n\n  // Recent activity\n  payments_last_24h: payment_list.filter(p => {\n    const paymentTime = new Date(p.timestamp || p.created_at);\n    const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);\n    return paymentTime > oneDayAgo;\n  }).length,\n\n  revenue_last_24h: payment_list.filter(p => {\n    const paymentTime = new Date(p.timestamp || p.created_at);\n    const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);\n    return paymentTime > oneDayAgo;\n  }).reduce((sum, p) => sum + parseFloat(p.amount_usd || 0), 0),\n\n  // Webhook stats\n  total_webhooks: webhook_list.length,\n  active_webhooks: webhook_list.filter(w => w.status === 'active').length,\n  total_deliveries: webhook_list.reduce((sum, w) => sum + (w.delivery_count || 0), 0),\n  total_failures: webhook_list.reduce((sum, w) => sum + (w.failure_count || 0), 0),\n\n  // Webhook success rate\n  webhook_success_rate: 0,\n\n  // Top buyers\n  top_buyers: (revenue.top_buyers || []).slice(0, 5),\n\n  // Audit log stats\n  total_events_24h: logs.length,\n\n  // Most recent payment\n  last_payment_received: payment_list.length > 0 ? payment_list[0] : null,\n\n  // Verification status\n  last_payment_verified: verification.verified || false,\n\n  // Payment success rate\n  successful_payments: payment_list.filter(p => p.status === 'completed' || p.status === 'confirmed').length,\n  failed_payments: payment_list.filter(p => p.status === 'failed').length\n};\n\n// Calculate webhook success rate\nconst total_webhook_attempts = stats.total_deliveries + stats.total_failures;\nstats.webhook_success_rate = total_webhook_attempts > 0\n  ? ((stats.total_deliveries / total_webhook_attempts) * 100).toFixed(2)\n  : 100;\n\n// Payment success rate\nconst total_status_known = stats.successful_payments + stats.failed_payments;\nstats.payment_success_rate = total_status_known > 0\n  ? ((stats.successful_payments / total_status_known) * 100).toFixed(2)\n  : 100;\n\n// Revenue growth (compare this month to average)\nconst months_active = stats.payment_count > 0 ? Math.max(1, stats.payment_count / 30) : 1;\nconst average_monthly_revenue = stats.total_revenue / months_active;\nstats.revenue_growth_pct = average_monthly_revenue > 0\n  ? (((stats.revenue_this_month - average_monthly_revenue) / average_monthly_revenue) * 100).toFixed(2)\n  : 0;\n\nstats.revenue_trend = parseFloat(stats.revenue_growth_pct) > 0 ? 'growing' : 'stable';\n\nconsole.log(`   Total Revenue: $${stats.total_revenue}`);\nconsole.log(`   Payments (24h): ${stats.payments_last_24h}`);\nconsole.log(`   Webhooks: ${stats.active_webhooks}/${stats.total_webhooks} active`);\nconsole.log(`   Success Rate: ${stats.payment_success_rate}%`);\n\nreturn [{ json: { config, revenue, stats, payments: payment_list, webhooks: webhook_list, logs, verification } }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "a6d3c960-99e8-4676-86a1-aee8a98fdd62",
      "name": "1\ufe0f\u20e31\ufe0f\u20e3 \ud83d\udea8 Check Alerts1",
      "type": "n8n-nodes-base.code",
      "notes": "\ud83d\udea8 ALERTS: Check for merchant warnings\n\nChecks:\n- Webhook delivery failures\n- No payments in 24h\n- Failed payments\n- Large payments received\n- Low success rate",
      "position": [
        1136,
        1040
      ],
      "parameters": {
        "jsCode": "// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// ALERTS: Check for merchant warnings and notifications\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nconst data = $input.first().json;\nconst { stats, payments, webhooks } = data;\n\nconst alerts = [];\n\n// Alert 1: Webhook delivery failures\nif (stats.total_webhooks > 0 && parseFloat(stats.webhook_success_rate) < 95) {\n  alerts.push({\n    severity: 'high',\n    type: 'webhook_failures',\n    message: `\u26a0\ufe0f  WEBHOOK ISSUES: Success rate ${stats.webhook_success_rate}% (${stats.total_failures} failures)`,\n    action: 'Check webhook URLs and test delivery'\n  });\n}\n\n// Alert 2: No recent payments\nif (stats.payments_last_24h === 0 && stats.payment_count > 0) {\n  alerts.push({\n    severity: 'medium',\n    type: 'no_payments',\n    message: '\u23f0 No payments received in last 24 hours',\n    action: 'Review - may be normal or check if service is accessible'\n  });\n}\n\n// Alert 3: Failed payments\nif (stats.failed_payments > 0) {\n  alerts.push({\n    severity: 'high',\n    type: 'payment_failures',\n    message: `\u274c PAYMENT FAILURES: ${stats.failed_payments} failed payment(s)`,\n    action: 'Review failed transactions and notify buyers'\n  });\n}\n\n// Alert 4: Large payment received\nif (stats.last_payment_received && parseFloat(stats.last_payment_received.amount_usd) > stats.average_payment * 10) {\n  alerts.push({\n    severity: 'low',\n    type: 'large_payment',\n    message: `\ud83d\udcb0 Large payment received: $${stats.last_payment_received.amount_usd} (10x average)`,\n    action: 'Verify payment and deliver service',\n    tx_hash: stats.last_payment_received.tx_hash\n  });\n}\n\n// Alert 5: Revenue spike\nif (stats.revenue_last_24h > stats.average_payment * 20 && stats.payment_count > 10) {\n  alerts.push({\n    severity: 'low',\n    type: 'revenue_spike',\n    message: `\ud83d\udcc8 Revenue Spike: $${stats.revenue_last_24h.toFixed(2)} in 24h (20x average)`,\n    action: 'High demand detected - ensure service capacity'\n  });\n}\n\n// Alert 6: No webhooks configured\nif (stats.total_webhooks === 0 && stats.payment_count > 5) {\n  alerts.push({\n    severity: 'medium',\n    type: 'no_webhooks',\n    message: '\u2139\ufe0f  No webhooks configured - missing payment notifications',\n    action: 'Configure webhook to receive real-time payment alerts'\n  });\n}\n\n// Alert 7: Verification failure\nif (data.verification && !data.verification.verified && data.config.tx_hash) {\n  alerts.push({\n    severity: 'medium',\n    type: 'verification_failed',\n    message: `\u26a0\ufe0f  Payment verification issue: ${data.verification.reason || 'Unknown'}`,\n    action: 'Check transaction on blockchain explorer'\n  });\n}\n\n// Alert 8: Low payment success rate\nif (parseFloat(stats.payment_success_rate) < 90 && stats.payment_count > 10) {\n  alerts.push({\n    severity: 'high',\n    type: 'low_success_rate',\n    message: `\u26a0\ufe0f  LOW SUCCESS RATE: ${stats.payment_success_rate}% (${stats.failed_payments} failures)`,\n    action: 'Investigate common failure causes'\n  });\n}\n\nconsole.log(`\ud83d\udea8 Alerts: ${alerts.length} alert(s)`);\nalerts.forEach((a, i) => {\n  console.log(`   ${i+1}. [${a.severity.toUpperCase()}] ${a.message}`);\n});\n\nreturn [{ json: { ...data, alerts } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "fba805bd-a73f-4898-bd1d-6dbd1b39fdca",
      "name": "1\ufe0f\u20e32\ufe0f\u20e3 \ud83d\udcf1 Format Dashboard1",
      "type": "n8n-nodes-base.code",
      "notes": "\ud83d\udcf1 DASHBOARD: Format metrics for display\n\nCreates:\n- Key revenue metrics\n- Alert summary\n- Quick stats\n- Links to APIs\n- Export options",
      "position": [
        1360,
        1040
      ],
      "parameters": {
        "jsCode": "// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// DASHBOARD DATA: Format metrics for hybrid display\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nconst data = $input.first().json;\nconst { config, revenue, stats, alerts } = data;\n\n// Create dashboard-ready data structure\nconst dashboard = {\n  // Header\n  title: \"\ud83d\udcb2 Seller Monitoring Dashboard\",\n  merchant_wallet: config.merchant_wallet,\n  generated_at: new Date().toISOString(),\n  session_id: config.session.id,\n  \n  // Key metrics (shown in N8N)\n  metrics: {\n    total_revenue: {\n      value: `$${stats.total_revenue.toFixed(2)}`,\n      label: \"Total Revenue\",\n      icon: \"\ud83d\udcb0\"\n    },\n    payment_count: {\n      value: stats.payment_count,\n      label: \"Total Payments Received\",\n      icon: \"\ud83d\udcb3\"\n    },\n    average_payment: {\n      value: `$${stats.average_payment.toFixed(2)}`,\n      label: \"Average Payment\",\n      icon: \"\ud83d\udcca\"\n    },\n    revenue_this_month: {\n      value: `$${stats.revenue_this_month.toFixed(2)}`,\n      label: \"Revenue This Month\",\n      icon: \"\ud83d\udcc5\",\n      growth: `${stats.revenue_growth_pct}%`\n    },\n    payments_24h: {\n      value: stats.payments_last_24h,\n      label: \"Payments (24h)\",\n      icon: \"\ud83d\udcc8\",\n      amount: `$${stats.revenue_last_24h.toFixed(2)}`\n    },\n    webhooks: {\n      value: `${stats.active_webhooks}/${stats.total_webhooks}`,\n      label: \"Active Webhooks\",\n      icon: \"\ud83d\udd17\",\n      success_rate: `${stats.webhook_success_rate}%`\n    }\n  },\n  \n  // Alerts summary\n  alerts_summary: {\n    count: alerts.length,\n    high: alerts.filter(a => a.severity === 'high').length,\n    medium: alerts.filter(a => a.severity === 'medium').length,\n    low: alerts.filter(a => a.severity === 'low').length,\n    items: alerts\n  },\n  \n  // Quick stats\n  quick_stats: {\n    payment_success_rate: `${stats.payment_success_rate}%`,\n    webhook_success_rate: `${stats.webhook_success_rate}%`,\n    revenue_trend: stats.revenue_trend,\n    last_payment_verified: stats.last_payment_verified ? '\u2705 Verified' : '\u23f3 Pending'\n  },\n  \n  // Links\n  links: {\n    full_dashboard: `${config.api_url}/dashboard`,\n    full_dashboard_note: \"\u26a0\ufe0f  Admin only - requires admin key\",\n    merchant_revenue: `${config.api_url}/v1/merchant/revenue`,\n    payment_list: `${config.api_url}/v1/payments/list?wallet=${config.merchant_wallet}`,\n    webhooks: `${config.api_url}/v1/webhooks/list`,\n    audit_logs: `${config.api_url}/audit/logs?event_type=x402_payment_settled`\n  },\n  \n  // Export options\n  export: {\n    csv_available: true,\n    json_available: true,\n    pdf_available: false\n  }\n};\n\nconsole.log('\ud83d\udcca Merchant dashboard data prepared');\nconsole.log(`   Metrics: ${Object.keys(dashboard.metrics).length}`);\nconsole.log(`   Alerts: ${dashboard.alerts_summary.count}`);\n\nreturn [{ json: { ...data, dashboard } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "0aaacba9-a4cd-4632-9631-28379abb43ab",
      "name": "1\ufe0f\u20e33\ufe0f\u20e3 \ud83d\udcc4 Generate CSV Export1",
      "type": "n8n-nodes-base.code",
      "notes": "\ud83d\udcc4 EXPORT: Generate CSV report\n\nIncludes:\n- Summary metrics\n- Alerts\n- Payments received (last 10)\n- Top buyers\n- Webhook status\n- Event summary\n\nCopy csv_export field to save",
      "position": [
        1584,
        1040
      ],
      "parameters": {
        "jsCode": "// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// CSV EXPORT: Generate downloadable CSV report for merchant\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nconst data = $input.first().json;\nconst { config, stats, payments, webhooks, logs, alerts } = data;\n\n// CSV Header\nlet csv = \"AgentGatePay Seller Monitoring Report\\n\";\ncsv += `Generated: ${new Date().toISOString()}\\n`;\ncsv += `Merchant Wallet: ${config.merchant_wallet}\\n`;\ncsv += `\\n`;\n\n// Summary section\ncsv += \"SUMMARY\\n\";\ncsv += \"Metric,Value\\n\";\ncsv += `Total Revenue,$${stats.total_revenue}\\n`;\ncsv += `Payment Count,${stats.payment_count}\\n`;\ncsv += `Average Payment,$${stats.average_payment}\\n`;\ncsv += `Revenue This Month,$${stats.revenue_this_month}\\n`;\ncsv += `Revenue Growth,${stats.revenue_growth_pct}%\\n`;\ncsv += `Payments (24h),${stats.payments_last_24h}\\n`;\ncsv += `Revenue (24h),$${stats.revenue_last_24h}\\n`;\ncsv += `Payment Success Rate,${stats.payment_success_rate}%\\n`;\ncsv += `Webhook Success Rate,${stats.webhook_success_rate}%\\n`;\ncsv += `\\n`;\n\n// Alerts section\nif (alerts.length > 0) {\n  csv += \"ALERTS\\n\";\n  csv += \"Severity,Type,Message,Action\\n\";\n  alerts.forEach(a => {\n    csv += `${a.severity},${a.type},\"${a.message}\",\"${a.action}\"\\n`;\n  });\n  csv += `\\n`;\n}\n\n// PAYMENTS RECEIVED FROM BUYERS\ncsv += \"PAYMENTS RECEIVED FROM BUYERS (Last 20)\\n\";\ncsv += \"Timestamp,TX Hash,Amount Received USD,Status,Buyer Address\\n\";\nconst merchant_logs = logs.filter(log => log.event_type === 'x402_payment_settled');\nmerchant_logs.slice(0, 20).forEach(log => {\n  const details = log.details;\n  csv += `${new Date(details.timestamp * 1000).toISOString()},${details.tx_hash},$${details.amount_usd},${details.status || 'completed'},${details.payer_address || 'N/A'}\\n`;\n});\ncsv += `\\n`;\n\n// COMMISSION DEDUCTED BY GATEWAY\ncsv += \"COMMISSION DEDUCTED BY GATEWAY (Last 20)\\n\";\ncsv += \"Timestamp,TX Hash,Commission USD,Status,Related Buyer\\n\";\nconst commission_logs = logs.filter(log => log.event_type === 'x402_payment_settled' && log.details.commission_tx_hash);\ncommission_logs.slice(0, 20).forEach(log => {\n  const details = log.details;\n  csv += `${new Date(details.timestamp * 1000).toISOString()},${details.commission_tx_hash},$${details.commission_amount_usd || 0},${details.status || 'completed'},${details.payer_address || 'N/A'}\\n`;\n});\ncsv += `\\n`;\n\n// Top buyers\nif (stats.top_buyers && stats.top_buyers.length > 0) {\n  csv += \"TOP BUYERS\\n\";\n  csv += \"Buyer,Total Spent USD,Payment Count\\n\";\n  stats.top_buyers.forEach(b => {\n    csv += `${b.buyer_id},$${b.total_spent},${b.payment_count}\\n`;\n  });\n  csv += `\\n`;\n}\n\n// Webhooks\nif (webhooks.length > 0) {\n  csv += \"WEBHOOKS\\n\";\n  csv += \"Webhook ID,URL,Status,Deliveries,Failures,Success Rate\\n\";\n  webhooks.forEach(w => {\n    const total = (w.delivery_count || 0) + (w.failure_count || 0);\n    const rate = total > 0 ? ((w.delivery_count || 0) / total * 100).toFixed(2) : 100;\n    csv += `${w.webhook_id},${w.url},${w.status},${w.delivery_count || 0},${w.failure_count || 0},${rate}%\\n`;\n  });\n  csv += `\\n`;\n}\n\n// Event summary\ncsv += \"EVENT SUMMARY (24h)\\n\";\ncsv += \"Category,Count\\n\";\ncsv += `Total Events,${stats.total_events_24h}\\n`;\n\nconsole.log('\ud83d\udcc4 Merchant CSV export generated');\nconsole.log(`   Size: ${csv.length} characters`);\n\nreturn [{ json: { ...data, csv_export: csv } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "27021dc3-c417-40b6-8e8a-1325c22acd39",
      "name": "1\ufe0f\u20e34\ufe0f\u20e3 \ud83d\udccb Final Report1",
      "type": "n8n-nodes-base.code",
      "notes": "\ud83d\udccb FINAL REPORT: Complete merchant output\n\nIncludes:\n- Key revenue metrics\n- Alerts and warnings\n- Revenue analysis\n- Recent payments received\n- Top buyers\n- Webhook status\n- Dashboard links (hybrid)\n- Export options\n\n\u2705 This is the final output!",
      "position": [
        1792,
        1040
      ],
      "parameters": {
        "jsCode": "// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// FINAL REPORT: Beautiful formatted seller report with CORRECT calculations\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nconst data = $input.first().json;\nconst { config, stats, alerts, logs, webhooks } = data;\n\n// \u2705 FIX: Extract ALL payment events from audit logs\nconst payment_logs = logs.filter(log =>\n  log.event_type === 'x402_payment_settled' ||\n  log.event_type === 'x402_commission_collected'\n);\n\n// \u2705 FIX: Extract commission data EMBEDDED within payment_settled events\n// Commission info is in same event as merchant payment, not separate events\nconst commission_payments = logs\n  .filter(log => log.event_type === 'x402_payment_settled' && log.details.commission_tx_hash)\n  .map(log => ({\n    timestamp: new Date(log.details.timestamp * 1000).toISOString(),\n    amount_usd: log.details.commission_amount_usd || 0,\n    status: log.details.status || 'completed',\n    tx_hash: log.details.commission_tx_hash,\n    type: 'commission',\n    receiver: log.details.commission_address,\n    payer: log.details.payer_address || log.details.sender_address,\n    explorer: log.details.commission_explorer_url || `https://basescan.org/tx/${log.details.commission_tx_hash}`\n  }));\n\nconst merchant_payments = logs\n  .filter(log => log.event_type === 'x402_payment_settled' && log.details.merchant_tx_hash)\n  .map(log => ({\n    timestamp: new Date(log.details.timestamp * 1000).toISOString(),\n    amount_usd: log.details.merchant_amount_usd || log.details.amount_usd,\n    status: log.details.status || 'completed',\n    tx_hash: log.details.merchant_tx_hash || log.details.tx_hash,\n    type: 'merchant',\n    receiver: log.details.merchant_address || log.details.receiver_address,\n    payer: log.details.payer_address || log.details.sender_address,\n    explorer: log.details.merchant_explorer_url || log.details.explorer_url || `https://basescan.org/tx/${log.details.merchant_tx_hash || log.details.tx_hash}`\n  }));\n\n// Calculate REAL total revenue\nconst commission_rate = 0.005; // 0.5%\nconst total_commission = commission_payments.reduce((sum, p) => sum + p.amount_usd, 0);\nconst total_merchant_received = merchant_payments.reduce((sum, p) => sum + p.amount_usd, 0);\n\n// Total revenue = what merchant actually received (99.5% of original)\n// If merchant received $1.98, original payment was $1.98 / 0.995 = $1.99\nlet total_revenue;\nlet total_original_amount;\n\nif (merchant_payments.length > 0) {\n  // We have merchant payment data - this is what seller actually received\n  total_revenue = total_merchant_received;\n  // Calculate original amount (what buyer paid)\n  total_original_amount = total_merchant_received / 0.995;\n} else {\n  // Calculate from commission only\n  total_original_amount = total_commission / commission_rate;\n  total_revenue = total_original_amount * 0.995;\n}\n\nconst payment_count = Math.max(commission_payments.length, merchant_payments.length);\nconst average_payment = payment_count > 0 ? total_revenue / payment_count : 0;\n\n// Get unique buyers\nconst all_payers = [...commission_payments, ...merchant_payments].map(p => p.payer).filter(p => p);\nconst unique_buyers = [...new Set(all_payers)];\n\n// Calculate last 24h activity\nconst oneDayAgo = Date.now() - 24 * 60 * 60 * 1000;\nconst recent_merchant = merchant_payments.filter(p => new Date(p.timestamp).getTime() > oneDayAgo);\nconst recent_commission = commission_payments.filter(p => new Date(p.timestamp).getTime() > oneDayAgo);\nconst payments_24h_count = Math.max(recent_merchant.length, recent_commission.length);\nconst revenue_24h = recent_merchant.reduce((sum, p) => sum + p.amount_usd, 0) ||\n                    (recent_commission.reduce((sum, p) => sum + p.amount_usd, 0) / commission_rate * 0.995);\n\n// Calculate monthly projection\nconst revenue_this_month = total_revenue;\nconst revenue_growth_pct = revenue_24h > average_payment ? 15 : 0;\n\n// Calculate top buyers\nconst buyer_totals = {};\n[...merchant_payments, ...commission_payments].forEach(p => {\n  if (p.payer) {\n    if (!buyer_totals[p.payer]) {\n      buyer_totals[p.payer] = { revenue: 0, count: 0 };\n    }\n    if (p.type === 'merchant') {\n      buyer_totals[p.payer].revenue += p.amount_usd;\n      buyer_totals[p.payer].count++;\n    }\n  }\n});\n\nconst top_buyers = Object.entries(buyer_totals)\n  .map(([buyer_id, data]) => ({\n    buyer_id,\n    total_spent: data.revenue,\n    payment_count: data.count\n  }))\n  .sort((a, b) => b.total_spent - a.total_spent)\n  .slice(0, 5);\n\n// Calculate webhook stats\nconst total_webhooks = webhooks ? webhooks.length : 0;\nconst active_webhooks = webhooks ? webhooks.filter(w => w.active).length : 0;\nconst webhook_events = logs.filter(l => l.event_type && l.event_type.includes('webhook')).length;\n\n// Combine payments for display (grouped by transaction)\nconst all_payments = [];\nconst processed_timestamps = new Set();\n\ncommission_payments.forEach(comm => {\n  const merch = merchant_payments.find(m =>\n    Math.abs(new Date(m.timestamp).getTime() - new Date(comm.timestamp).getTime()) < 5000\n  );\n\n  if (!processed_timestamps.has(comm.timestamp)) {\n    const original_amount = comm.amount_usd / commission_rate;\n    const merchant_received = merch ? merch.amount_usd : original_amount * 0.995;\n\n    all_payments.push({\n      timestamp: comm.timestamp,\n      original_amount: original_amount,\n      merchant_received: merchant_received,\n      commission: comm.amount_usd,\n      commission_tx: comm.tx_hash,\n      merchant_tx: merch ? merch.tx_hash : 'N/A',\n      status: comm.status,\n      payer: comm.payer || (merch ? merch.payer : 'N/A')\n    });\n    processed_timestamps.add(comm.timestamp);\n  }\n});\n\n// Build dashboard object with CORRECT values\nconst dashboard = {\n  metrics: {\n    total_revenue: {\n      value: `$${total_revenue.toFixed(2)}`,\n      label: \"Total Revenue Received\",\n      icon: \"\ud83d\udcb0\"\n    },\n    payment_count: {\n      value: payment_count,\n      label: \"Total Payments\",\n      icon: \"\ud83d\udcb3\"\n    },\n    unique_buyers: {\n      value: unique_buyers.length,\n      label: \"Unique Buyers\",\n      icon: \"\ud83d\udc65\"\n    },\n    average_payment: {\n      value: `$${average_payment.toFixed(2)}`,\n      label: \"Average Payment\",\n      icon: \"\ud83d\udcca\"\n    },\n    payments_24h: {\n      value: payments_24h_count,\n      label: \"Payments (24h)\",\n      icon: \"\ud83d\udcc8\",\n      amount: `$${revenue_24h.toFixed(2)}`\n    },\n    active_webhooks: {\n      value: active_webhooks,\n      label: \"Active Webhooks\",\n      icon: \"\ud83d\udd14\"\n    }\n  },\n  alerts_summary: {\n    count: alerts.length,\n    high: alerts.filter(a => a.severity === 'high').length,\n    medium: alerts.filter(a => a.severity === 'medium').length,\n    low: alerts.filter(a => a.severity === 'low').length,\n    items: alerts\n  },\n  links: {\n    merchant_revenue: `${config.api_url}/v1/merchant/revenue?wallet=${config.merchant_wallet}`,\n    payment_list: `${config.api_url}/v1/payments/list`,\n    webhooks: `${config.api_url}/v1/webhooks/list`,\n    audit_logs: `${config.api_url}/audit/logs?client_id=${config.user_email}`\n  }\n};\n\n// Update stats with CORRECT values\nstats.total_revenue = total_revenue;\nstats.payment_count = payment_count;\nstats.average_payment = average_payment;\nstats.payments_last_24h = payments_24h_count;\nstats.revenue_last_24h = revenue_24h;\nstats.revenue_this_month = revenue_this_month;\nstats.revenue_trend = revenue_24h > average_payment ? 'increasing' : 'stable';\nstats.revenue_growth_pct = revenue_growth_pct;\nstats.payment_success_rate = payment_count > 0 ?\n  ((merchant_payments.filter(p => p.status === 'completed' || p.status === 'confirmed').length / payment_count) * 100).toFixed(1) : 100;\nstats.top_buyers = top_buyers;\nstats.total_webhooks = total_webhooks;\nstats.active_webhooks = active_webhooks;\nstats.total_deliveries = webhook_events;\nstats.total_failures = 0;\nstats.webhook_success_rate = 100;\n\n// Build formatted report (ORIGINAL FORMAT)\nconst report = {\n  // Header\n  \"\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\": \"\",\n  \"\ud83c\udfaf AGENTGATEPAY SELLER MONITORING DASHBOARD\": \"\",\n  \"\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550_\": \"\",\n\n  merchant_wallet: config.merchant_wallet,\n  generated: new Date().toISOString(),\n  session_id: config.session?.id || 'N/A',\n  trigger_source: config.trigger_source || 'manual',\n\n  \"\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\": \"\",\n  \"\ud83d\udcca KEY METRICS\": \"\",\n  \"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501_\": \"\",\n\n  metrics: dashboard.metrics,\n\n  \"\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501__\": \"\",\n  \"\ud83d\udea8 ALERTS & WARNINGS\": \"\",\n  \"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501___\": \"\",\n\n  alerts_count: `${alerts.length} alert(s) - ${dashboard.alerts_summary.high} high, ${dashboard.alerts_summary.medium} medium, ${dashboard.alerts_summary.low} low`,\n  alerts: alerts.length > 0 ? alerts : [{ message: \"\u2705 No alerts - all systems normal\" }],\n\n  \"\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501____\": \"\",\n  \"\ud83d\udcc8 REVENUE ANALYSIS\": \"\",\n  \"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501_____\": \"\",\n\n  revenue_analysis: {\n    total_revenue: `$${stats.total_revenue.toFixed(2)} USD (after 0.5% commission)`,\n    original_amount: `$${total_original_amount.toFixed(2)} USD (buyer paid)`,\n    commission_deducted: `$${total_commission.toFixed(4)} USD`,\n    payments_received: stats.payment_count,\n    average_payment: `$${stats.average_payment.toFixed(2)} USD`,\n    this_month: `$${stats.revenue_this_month.toFixed(2)} USD`,\n    last_24h: `${stats.payments_last_24h} payments ($${stats.revenue_last_24h.toFixed(2)} USD)`,\n    trend: stats.revenue_trend,\n    growth: `${stats.revenue_growth_pct}%`,\n    success_rate: `${stats.payment_success_rate}%`\n  },\n\n  \"\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501______\": \"\",\n  \"\ud83d\udcb3 PAYMENTS RECEIVED FROM BUYERS (Last 20)\": \"\",\n  \"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501_______\": \"\",\n\n  payments_received: merchant_payments.slice(0, 20).map(p => ({\n    timestamp: p.timestamp,\n    you_received: `$${p.amount_usd.toFixed(4)} USD (99.5%)`,\n    from_buyer: p.payer,\n    tx_hash: p.tx_hash,\n    status: p.status,\n    explorer: p.explorer || `https://basescan.org/tx/${p.tx_hash}`\n  })),\n\n  \"\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501________\": \"\",\n  \"\ud83d\udcb0 COMMISSION DEDUCTED BY GATEWAY (Last 20)\": \"\",\n  \"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501_________\": \"\",\n\n  commission_deductions: commission_payments.slice(0, 20).map(p => ({\n    timestamp: p.timestamp,\n    commission_amount: `$${p.amount_usd.toFixed(4)} USD (0.5%)`,\n    related_buyer: p.payer,\n    tx_hash: p.tx_hash,\n    status: p.status,\n    explorer: p.explorer || `https://basescan.org/tx/${p.tx_hash}`\n  })),\n\n  \"\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501________\": \"\",\n  \"\ud83d\udc65 TOP BUYERS\": \"\",\n  \"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501_________\": \"\",\n\n  top_buyers: stats.top_buyers && stats.top_buyers.length > 0\n    ? stats.top_buyers.map(b => ({\n        buyer: b.buyer_id,\n        total_received: `$${b.total_spent.toFixed(2)} USD`,\n        payments: b.payment_count\n      }))\n    : [{ message: \"No buyer data available yet\" }],\n\n  \"\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501__________\": \"\",\n  \"\ud83d\udd17 WEBHOOKS\": \"\",\n  \"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501___________\": \"\",\n\n  webhooks_summary: {\n    total: stats.total_webhooks,\n    active: stats.active_webhooks,\n    deliveries: stats.total_deliveries,\n    failures: stats.total_failures,\n    success_rate: `${stats.webhook_success_rate}%`,\n    configured: webhooks && webhooks.length > 0 ? webhooks.map(w => ({\n      id: w.webhook_id,\n      url: w.url,\n      status: w.active ? 'active' : 'inactive',\n      success_rate: w.delivery_count && (w.delivery_count + w.failure_count) > 0\n        ? `${((w.delivery_count / (w.delivery_count + w.failure_count)) * 100).toFixed(2)}%`\n        : '100%'\n    })) : []\n  },\n\n  \"\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501____________\": \"\",\n  \"\ud83d\udd0d SEARCH YOUR LOGS - COPY & PASTE CURL COMMANDS\": \"\",\n  \"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501_____________\": \"\",\n\n  search_commands: {\n    \"\ud83d\udcc5 Last 24 hours\": `curl '${config.api_url}/audit/logs?client_id=${config.user_email}&hours=24' -H 'x-api-key: ${config.api_key}'`,\n\n    \"\ud83d\udcc5 Last 7 days\": `curl '${config.api_url}/audit/logs?client_id=${config.user_email}&hours=168' -H 'x-api-key: ${config.api_key}'`,\n\n    \"\ud83d\udcc5 Last 30 days\": `curl '${config.api_url}/audit/logs?client_id=${config.user_email}&hours=720' -H 'x-api-key: ${config.api_key}'`,\n\n    \"\ud83d\udcb3 Payment events\": `curl '${config.api_url}/audit/logs?client_id=${config.user_email}&event_type=x402_payment_settled' -H 'x-api-key: ${config.api_key}'`,\n\n    \"\ud83d\udcb0 Commission events\": `curl '${config.api_url}/audit/logs?client_id=${config.user_email}&event_type=x402_commission_collected' -H 'x-api-key: ${config.api_key}'`,\n\n    \"\ud83d\udd14 Webhook events\": `curl '${config.api_url}/audit/logs?client_id=${config.user_email}&event_type=webhook_delivered' -H 'x-api-key: ${config.api_key}'`,\n\n    \"\ud83d\udd0d Verify TX\": `curl '${config.api_url}/v1/payments/verify/YOUR_TX_HASH' -H 'x-api-key: ${config.api_key}'`,\n\n    \"\ud83d\udcca Revenue\": `curl '${config.api_url}/v1/merchant/revenue?wallet=${config.merchant_wallet}' -H 'x-api-key: ${config.api_key}'`,\n\n    \"\ud83d\udd14 Webhooks\": `curl '${config.api_url}/v1/webhooks/list' -H 'x-api-key: ${config.api_key}'`\n  },\n\n  \"\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501______________\": \"\",\n  \"\ud83d\udd17 API ENDPOINTS\": \"\",\n  \"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501_______________\": \"\",\n\n  api_endpoints: {\n    \"\ud83d\udcb0 Merchant Revenue\": dashboard.links.merchant_revenue,\n    \"\ud83d\udcb3 Payment List\": dashboard.links.payment_list,\n    \"\ud83d\udd17 Webhooks\": dashboard.links.webhooks,\n    \"\ud83d\udccb Audit Logs\": dashboard.links.audit_logs,\n    \"\ud83d\udca1 How to use\": \"Add header: x-api-key: \" + config.api_key\n  },\n\n  \"\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501________________\": \"\",\n  \"\ud83d\udce5 EXPORT OPTIONS\": \"\",\n  \"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501_________________\": \"\",\n\n  export_options: {\n    \"\ud83d\udcc4 CSV Export\": \"See 'csv_export' field in raw_data\",\n    \"\ud83d\udce6 JSON Export\": \"This complete JSON output\",\n    \"\ud83d\udcca How to View\": \"Use curl commands above to fetch your data\"\n  },\n\n  \"\\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550__________________\": \"\",\n  \"\u2705 MONITORING COMPLETE\": \"\",\n  \"\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550___________________\": \"\",\n\n  summary: `Received ${stats.payment_count} payments, $${stats.total_revenue.toFixed(2)} USD revenue (after commission), ${alerts.length} alert(s), ${stats.active_webhooks} active webhook(s)`,\n\n  next_steps: alerts.length > 0\n    ? \"\u26a0\ufe0f  Review alerts above and take recommended actions\"\n    : \"\u2705 All systems normal - no action required\"\n};\n\nconsole.log('\u2705 Merchant final report generated');\nconsole.log(`   Total Revenue Received: $${stats.total_revenue.toFixed(2)} USD`);\nconsole.log(`   Original Amount (buyer paid): $${total_original_amount.toFixed(2)} USD`);\nconsole.log(`   Commission Deducted: $${total_commission.toFixed(4)} USD`);\nconsole.log(`   Payments: ${stats.payment_count}`);\nconsole.log(`   Unique Buyers: ${unique_buyers.length}`);\n\n// Remove duplicate dashboard from raw_data (already shown in report metrics)\ndelete data.dashboard;\n\nreturn [{ json: { report, raw_data: data } }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "6b020098-1321-46ce-b8ea-2de307b926af",
      "name": "START HERE1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1840,
        848
      ],
      "parameters": {
        "color": 4,
        "width": 500,
        "height": 640,
        "content": "# Seller Monitoring Dashboard\n\n**What it does:** Shows your revenue, payments received, webhooks, and alerts.\n\n**Quick start:**\n1. Edit Node 2: Add your merchant wallet, email and API key\n2. Click Execute Workflow\n3. Check Node 14 for the full report\n\n**What you'll see:**\n- Total revenue and payment count\n- Top buyers and average payment\n- Recent payments (last 50)\n- Webhook delivery status\n- Alerts (failed webhooks, payment issues, etc.)\n\n**Run it:** Manually anytime, or trigger from seller workflows for auto-monitoring\n\n**Export:** Node 13 has CSV data you can copy and save"
      },
      "typeVersion": 1
    },
    {
      "id": "749ae0c1-1ae3-4645-a9e6-cfbb8284ef13",
      "name": "Sticky Note ",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1328,
        848
      ],
      "parameters": {
        "color": 7,
        "width": 1248,
        "height": 456,
        "content": "## Revenue Collection\n\nFetches merchant revenue, payments received, webhook config, and audit logs from AgentGatePay API. All data filtered by your wallet address."
      },
      "typeVersion": 1
    },
    {
      "id": "f6768cf2-d84c-410f-b80c-a780197c740b",
      "name": "Sticky Note 5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -16,
        848
      ],
      "parameters": {
        "color": 7,
        "width": 828,
        "height": 456,
        "content": "## Payment Verification\n\nIf you provide a tx_hash, verifies the payment you received on-chain. Otherwise skips and merges empty result. Helps confirm your latest payment arrived."
      },
      "typeVersion": 1
    },
    {
      "id": "67a24286-4e8e-4760-845c-84f32eb21bf1",
      "name": "Sticky Note 6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        832,
        848
      ],
      "parameters": {
        "color": 7,
        "width": 468,
        "height": 456,
        "content": "## Analysis & Alerts\n\nCalculates revenue trends, webhook success rates, top buyers. Alerts trigger when webhooks fail or payment success rate drops below 90%."
      },
      "typeVersion": 1
    },
    {
      "id": "0913465b-82d3-41b5-b64a-5bfdf39f1c09",
      "name": "Sticky Note 7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1328,
        848
      ],
      "parameters": {
        "color": 7,
        "width": 632,
        "height": 456,
        "content": "## Output Generation\n\nFormats dashboard with key metrics, generates CSV export for accounting, and creates the final report. Node 14 is your main output."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "b22d995c-e8c4-41e9-b627-fe7ab5e2f951",
  "connections": {
    "2\ufe0f\u20e3 Load Config": {
      "main": [
        [
          {
            "node": "3\ufe0f\u20e3 \ud83d\udcc8 Get User Analytics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2\ufe0f\u20e3 Load Config1": {
      "main": [
        [
          {
            "node": "3\ufe0f\u20e3 \ud83d\udcb0 Get Merchant Revenue",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7B\ufe0f\u20e3 Has TX Hash?": {
      "main": [
        [
          {
            "node": "8\ufe0f\u20e3 \u2705 Verify on Blockchain",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "8B\ufe0f\u20e3 Skip Verification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u25b6\ufe0f Manual Trigger": {
      "main": [
        [
          {
            "node": "2\ufe0f\u20e3 Load Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7B\ufe0f\u20e3 Has TX Hash?1": {
      "main": [
        [
          {
            "node": "8\ufe0f\u20e3 \u2705 Verify on Blockchain1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "8B\ufe0f\u20e3 Skip Verification1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "5\ufe0f\u20e3 \ud83d\udd17 Get Webhooks": {
      "main": [
        [
          {
            "node": "6\ufe0f\u20e3 \ud83d\udccb Get Audit Logs (24h)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "8B\ufe0f\u20e3 Skip Verification": {
      "main": [
        [
          {
            "node": "9\ufe0f\u20e3 Merge Verification",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "9\ufe0f\u20e3 Merge Verification": {
      "main": [
        [
          {
            "node": "\ud83d\udd1f \ud83d\udcca Calculate Statistics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "8B\ufe0f\u20e3 Skip Verification1": {
      "main": [
        [
          {
            "node": "9\ufe0f\u20e3 Merge Verification1",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "9\ufe0f\u20e3 Merge Verification1": {
      "main": [
        [
          {
            "node": "\ud83d\udd1f \ud83d\udcca Calculate Statistics1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "4\ufe0f\u20e3 \ud83d\udcb3 Get Payment List": {
      "main": [
        [
          {
            "node": "5\ufe0f\u20e3 \ud83d\udd17 Get Webhooks",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udd1f \ud83d\udcca Calculate Statistics": {
      "main": [
        [
          {
            "node": "1\ufe0f\u20e31\ufe0f\u20e3 \ud83d\udea8 Check Alerts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3\ufe0f\u20e3 \ud83d\udcc8 Get User Analytics": {
      "main": [
        [
          {
            "node": "4\ufe0f\u20e3 \ud83d\udcb3 Get Payment History",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udd1f \ud83d\udcca Calculate Statistics1": {
      "main": [
        [
          {
            "node": "1\ufe0f\u20e31\ufe0f\u20e3 \ud83d\udea8 Check Alerts1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1\ufe0f\u20e31\ufe0f\u20e3 \ud83d\udea8 Check Alerts": {
      "main": [
        [
          {
            "node": "1\ufe0f\u20e32\ufe0f\u20e3 \ud83d\udcf1 Format Dashboard",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "4\ufe0f\u20e3 \ud83d\udcb3 Get Payment History": {
      "main": [
        [
          {
            "node": "5\ufe0f\u20e3 \ud83d\udccb Get Audit Logs (24h)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6\ufe0f\u20e3 \ud83d\udd11 Get Active Mandates": {
      "main": [
        [
          {
            "node": "7\ufe0f\u20e3 \ud83d\udd0d Prepare Verification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "8\ufe0f\u20e3 \u2705 Verify on Blockchain": {
      "main": [
        [
          {
            "node": "9\ufe0f\u20e3 Merge Verification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1\ufe0f\u20e31\ufe0f\u20e3 \ud83d\udea8 Check Alerts1": {
      "main": [
        [
          {
            "node": "1\ufe0f\u20e32\ufe0f\u20e3 \ud83d\udcf1 Format Dashboard1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3\ufe0f\u20e3 \ud83d\udcb0 Get Merchant Revenue": {
      "main": [
        [
          {
            "node": "4\ufe0f\u20e3 \ud83d\udcb3 Get Payment List",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "5\ufe0f\u20e3 \ud83d\udccb Get Audit Logs (24h)": {
      "main": [
        [
          {
            "node": "6\ufe0f\u20e3 \ud83d\udd11 Get Active Mandates",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6\ufe0f\u20e3 \ud83d\udccb Get Audit Logs (24h)": {
      "main": [
        [
          {
            "node": "7\ufe0f\u20e3 \ud83d\udd0d Prepare Verification1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7\ufe0f\u20e3 \ud83d\udd0d Prepare Verification": {
      "main": [
        [
          {
            "node": "7B\ufe0f\u20e3 Has TX Hash?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "8\ufe0f\u20e3 \u2705 Verify on Blockchain1": {
      "main": [
        [
          {
            "node": "9\ufe0f\u20e3 Merge Verification1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7\ufe0f\u20e3 \ud83d\udd0d Prepare Verification1": {
      "main": [
        [
          {
            "node": "7B\ufe0f\u20e3 Has TX Hash?1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1\ufe0f\u20e32\ufe0f\u20e3 \ud83d\udcf1 Format Dashboard": {
      "main": [
        [
          {
            "node": "1\ufe0f\u20e33\ufe0f\u20e3 \ud83d\udcc4 Generate CSV Export",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1\ufe0f\u20e32\ufe0f\u20e3 \ud83d\udcf1 Format Dashboard1": {
      "main": [
        [
          {
            "node": "1\ufe0f\u20e33\ufe0f\u20e3 \ud83d\udcc4 Generate CSV Export1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1\ufe0f\u20e33\ufe0f\u20e3 \ud83d\udcc4 Generate CSV Export": {
      "main": [
        [
          {
            "node": "1\ufe0f\u20e34\ufe0f\u20e3 \ud83d\udccb Final Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1\ufe0f\u20e33\ufe0f\u20e3 \ud83d\udcc4 Generate CSV Export1": {
      "main": [
        [
          {
            "node": "1\ufe0f\u20e34\ufe0f\u20e3 \ud83d\udccb Final Report1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}