{
  "name": "Weekly Pipeline Report — HubSpot → Slack",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 8,
              "triggerAtDay": 1
            }
          ]
        }
      },
      "id": "schedule-trigger",
      "name": "Weekly Monday 8am",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [0, 0]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "https://api.hubapi.com/crm/v3/pipelines/deals",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "hubspotApi",
        "options": {}
      },
      "id": "fetch-stages",
      "name": "Fetch Stages",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [220, 0],
      "credentials": {
        "hubspotApi": {
          "id": "credential-id",
          "name": "HubSpot API"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.hubapi.com/crm/v3/objects/deals/search",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "hubspotApi",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"filterGroups\": [\n    {\n      \"filters\": [\n        {\n          \"propertyName\": \"pipeline\",\n          \"operator\": \"EQ\",\n          \"value\": \"default\"\n        }\n      ]\n    }\n  ],\n  \"properties\": [\n    \"dealname\", \"amount\", \"dealstage\", \"pipeline\",\n    \"closedate\", \"createdate\", \"hubspot_owner_id\",\n    \"hs_lastmodifieddate\"\n  ],\n  \"sorts\": [\n    { \"propertyName\": \"amount\", \"direction\": \"DESCENDING\" }\n  ],\n  \"limit\": 100\n}",
        "options": {}
      },
      "id": "fetch-deals",
      "name": "Fetch Deals",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [440, 0],
      "credentials": {
        "hubspotApi": {
          "id": "credential-id",
          "name": "HubSpot API"
        }
      }
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const deals = $input.all().map(item => item.json);\n\n// Parse the search response\nconst results = deals[0]?.results || deals;\nconst pipelineData = $('Fetch Stages').first().json.results;\n\n// Build stage name lookup\nconst stageMap = {};\nfor (const pipeline of pipelineData) {\n  for (const stage of pipeline.stages) {\n    stageMap[stage.id] = stage.label;\n  }\n}\n\n// Calculate metrics\nlet totalValue = 0;\nconst byStage = {};\nlet staleDeals = [];\n\nfor (const deal of results) {\n  const amount = parseFloat(deal.properties.amount || '0');\n  totalValue += amount;\n\n  const stageId = deal.properties.dealstage;\n  const stageName = stageMap[stageId] || stageId;\n  byStage[stageName] = (byStage[stageName] || 0) + 1;\n\n  // Flag deals with no activity in 14+ days\n  const lastMod = new Date(deal.properties.hs_lastmodifieddate);\n  const daysSinceUpdate = (Date.now() - lastMod) / (1000 * 60 * 60 * 24);\n  if (daysSinceUpdate > 14) {\n    staleDeals.push({\n      name: deal.properties.dealname,\n      amount,\n      daysSinceUpdate: Math.round(daysSinceUpdate),\n    });\n  }\n}\n\nstaleDeals.sort((a, b) => b.daysSinceUpdate - a.daysSinceUpdate);\n\nreturn [{\n  json: {\n    totalValue,\n    dealCount: results.length,\n    byStage,\n    staleDeals: staleDeals.slice(0, 5),\n  }\n}];"
      },
      "id": "calculate-metrics",
      "name": "Calculate Metrics",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [660, 0]
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "sales-reports",
          "mode": "name"
        },
        "messageType": "block",
        "blocksUi": "={\n  \"blocks\": [\n    {\n      \"type\": \"header\",\n      \"text\": {\n        \"type\": \"plain_text\",\n        \"text\": \"📊 Weekly Pipeline Report\"\n      }\n    },\n    {\n      \"type\": \"section\",\n      \"fields\": [\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"*Total Pipeline*\\n$\" + $json.totalValue.toLocaleString()\n        },\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"*Active Deals*\\n\" + $json.dealCount\n        }\n      ]\n    },\n    {\n      \"type\": \"divider\"\n    },\n    {\n      \"type\": \"section\",\n      \"text\": {\n        \"type\": \"mrkdwn\",\n        \"text\": \"*Deals by Stage*\\n\" + Object.entries($json.byStage).map(([stage, count]) => `• ${stage}: ${count}`).join('\\n')\n      }\n    },\n    {\n      \"type\": \"context\",\n      \"elements\": [\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"Report generated \" + new Date().toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' })\n        }\n      ]\n    }\n  ]\n}",
        "otherOptions": {
          "unfurl_links": false
        }
      },
      "id": "post-to-slack",
      "name": "Post to Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.3,
      "position": [880, 0],
      "credentials": {
        "slackApi": {
          "id": "credential-id",
          "name": "Slack API"
        }
      }
    }
  ],
  "connections": {
    "Weekly Monday 8am": {
      "main": [
        [
          {
            "node": "Fetch Stages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Stages": {
      "main": [
        [
          {
            "node": "Fetch Deals",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Deals": {
      "main": [
        [
          {
            "node": "Calculate Metrics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate Metrics": {
      "main": [
        [
          {
            "node": "Post to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "staticData": null,
  "tags": [],
  "triggerCount": 0,
  "active": false,
  "meta": {
    "instanceId": "",
    "templateId": "revi-pipeline-report"
  }
}
