{
  "name": "Daily Stuck-Deal Owner Alert",
  "nodes": [
    {
      "parameters": {
        "content": "## Setup\n1. Paste your HubSpot private app token into \"Fetch Deals\".\n2. This posts to one Slack channel with @owner mentions; swap for direct DMs per rep if your Slack workspace supports it.\n\nFrom Chapter 8's decision tree: a deal with no dated next step and no named owner isn't progressing, it's parked. This checks daily instead of waiting for the weekly digest.",
        "height": 280,
        "width": 380
      },
      "id": "d3e4f5a6-3333-4a2b-9c3a-000000000001",
      "name": "Setup Notes",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [-200, 60]
    },
    {
      "parameters": { "rule": { "interval": [{ "field": "days", "triggerAtHour": 9 }] } },
      "id": "d3e4f5a6-3333-4a2b-9c3a-000000000002",
      "name": "Every Morning 9am",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [-200, 400]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "https://api.hubapi.com/crm/v3/objects/deals",
        "sendHeaders": true,
        "headerParameters": { "parameters": [{ "name": "Authorization", "value": "Bearer YOUR_HUBSPOT_PRIVATE_APP_TOKEN" }] },
        "sendQuery": true,
        "queryParameters": { "parameters": [{ "name": "properties", "value": "dealname,dealstage,hubspot_owner_id,next_step,next_step_date" }, { "name": "limit", "value": "100" }] },
        "options": {}
      },
      "id": "d3e4f5a6-3333-4a2b-9c3a-000000000003",
      "name": "Fetch Deals",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [40, 400]
    },
    {
      "parameters": {
        "jsCode": "const deals = $input.first().json.results || [];\nconst stuck = deals.filter(d => !d.properties.next_step || !d.properties.next_step_date || !d.properties.hubspot_owner_id);\nconst lines = stuck.map(d => `${d.properties.dealname || d.id} — missing ${!d.properties.hubspot_owner_id ? 'an owner' : (!d.properties.next_step ? 'a next step' : 'a next step date')}`);\nreturn [{ json: { count: stuck.length, list: lines.length ? lines.join('\\n') : 'None today.' } }];"
      },
      "id": "d3e4f5a6-3333-4a2b-9c3a-000000000004",
      "name": "Find Stuck Deals",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [280, 400]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "YOUR_SLACK_INCOMING_WEBHOOK_URL",
        "sendBody": true,
        "bodyParameters": { "parameters": [{ "name": "text", "value": "=Deals with no owner, no next step, or no next-step date ({{ $json.count }}):\n\n{{ $json.list }}" }] },
        "options": {}
      },
      "id": "d3e4f5a6-3333-4a2b-9c3a-000000000005",
      "name": "Post Alert",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [520, 400]
    }
  ],
  "connections": {
    "Every Morning 9am": { "main": [[{ "node": "Fetch Deals", "type": "main", "index": 0 }]] },
    "Fetch Deals": { "main": [[{ "node": "Find Stuck Deals", "type": "main", "index": 0 }]] },
    "Find Stuck Deals": { "main": [[{ "node": "Post Alert", "type": "main", "index": 0 }]] }
  },
  "active": false,
  "settings": { "executionOrder": "v1" },
  "pinData": {}
}
