{
  "name": "REVOPS-LI-007 | 05 | Reply intake and owner notification",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "revops-li-007-reply",
        "authentication": "headerAuth",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "17b04d12-d55f-4e2a-abe7-7f8bbcf6f656",
      "name": "Reply Event Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        0
      ],
      "webhookId": "01b45604-6000-4fe4-bcdb-b4c49cc00840",
      "credentials": {
        "httpHeaderAuth": {
          "id": "REPLACE_REPLY_SECRET_CREDENTIAL",
          "name": "Proposal Reply Secret"
        }
      }
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const b=$input.first().json.body||{},e=[];if(!/^[0-9a-f-]{36}$/i.test(String(b.event_id||'')))e.push('event_id UUID required');if(!/^\\d+$/.test(String(b.deal_id||'')))e.push('numeric deal_id required');if(!/^\\d+$/.test(String(b.contact_id||'')))e.push('numeric contact_id required');if(!b.reply_at||!Number.isFinite(Date.parse(b.reply_at)))e.push('reply_at ISO timestamp required');if(!['email','crm email','sms','whatsapp','linkedin','manual'].includes(String(b.channel||'').toLowerCase()))e.push('supported channel required');if(typeof b.summary!=='string'||!b.summary.trim()||b.summary.length>4000)e.push('summary required, max 4000 chars');return [{json:{valid:!e.length,errors:e,b}}];"
      },
      "id": "d74f935e-0d42-46b8-b201-fa1949120bc6",
      "name": "Validate Reply Event",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        270,
        0
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "ff411d14-9a60-4edd-a911-d82a39c4e6b9",
              "leftValue": "={{ $json.valid === true }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "df36a391-30a6-48c3-8922-7d7daea9fa31",
      "name": "Reply Valid?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        540,
        0
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT ghosted_proposal.capture_reply($1::uuid,$2::jsonb) AS result;",
        "options": {
          "queryReplacement": "={{ [$json.b.event_id,JSON.stringify($json.b)] }}"
        }
      },
      "id": "5decd8d8-1946-4dc5-9d76-220ad2270e39",
      "name": "Capture Reply Idempotently",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        810,
        0
      ],
      "credentials": {
        "postgres": {
          "id": "REPLACE_POSTGRES_CREDENTIAL",
          "name": "ATTRIBUTION Postgres"
        }
      }
    },
    {
      "parameters": {
        "method": "GET",
        "url": "={{ 'https://api.hubapi.com/crm/v3/objects/deals/'+$('Validate Reply Event').first().json.b.deal_id+'?properties=dealname,amount,hubspot_owner_id,revops_proposal_sent_at,revops_followup_sent_at&associations=contacts,companies' }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "options": {
          "timeout": 30000,
          "response": {
            "response": {
              "fullResponse": true,
              "neverError": true,
              "responseFormat": "json"
            }
          }
        }
      },
      "id": "d867d976-6071-4cc5-902e-b70e3b94aa57",
      "name": "Read Reply Deal",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1080,
        0
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "REPLACE_HUBSPOT_CREDENTIAL",
          "name": "ATTRIBUTION HubSpot"
        }
      }
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const b=$('Validate Reply Event').first().json.b,r=$input.first().json;if(r.statusCode!==200)throw new Error('Deal read failed');const d=r.body,p=d.properties||{},now=new Date(b.reply_at).toISOString(),esc=s=>String(s||'').replace(/[&<>]/g,ch=>({'&':'&amp;','<':'&lt;','>':'&gt;'}[ch]));const patch={properties:{revops_ghosting_status:'RE_ENGAGED',revops_reply_detected:'true',revops_reply_detected_at:now,revops_last_reply_at:now,revops_manual_action_required:'true',revops_followup_status:'REPLIED',revops_reply_summary:b.summary}};const note={properties:{hs_timestamp:now,hs_note_body:'Proposal follow-up reply ('+esc(b.channel)+'): '+esc(b.summary)},associations:[{to:{id:b.deal_id},types:[{associationCategory:'HUBSPOT_DEFINED',associationTypeId:214}]},{to:{id:b.contact_id},types:[{associationCategory:'HUBSPOT_DEFINED',associationTypeId:202}]}]};const task={properties:{hs_task_subject:'Respond to re-engaged proposal lead',hs_task_body:['Deal: '+(p.dealname||b.deal_id),'Value: '+(p.amount||''),'Reply: '+b.summary].join('\\n'),hs_timestamp:new Date(Date.now()+3600000).toISOString(),hs_task_status:'NOT_STARTED',hs_task_priority:'HIGH',hs_task_type:'TODO',...(p.hubspot_owner_id?{hubspot_owner_id:p.hubspot_owner_id}:{})},associations:[{to:{id:b.deal_id},types:[{associationCategory:'HUBSPOT_DEFINED',associationTypeId:216}]},{to:{id:b.contact_id},types:[{associationCategory:'HUBSPOT_DEFINED',associationTypeId:204}]}]};return [{json:{event_id:b.event_id,deal_id:b.deal_id,patch,note,task}}];"
      },
      "id": "5093b339-6967-4f1f-b1b9-a0766af0faf3",
      "name": "Build Re-Engagement Updates",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1350,
        0
      ]
    },
    {
      "parameters": {
        "method": "PATCH",
        "url": "={{ 'https://api.hubapi.com/crm/v3/objects/deals/'+$json.deal_id }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "contentType": "json",
        "specifyBody": "json",
        "jsonBody": "={{ $json.patch }}",
        "options": {
          "timeout": 30000
        }
      },
      "id": "9188edc3-e164-4ddb-a022-a30d7caf90dc",
      "name": "Mark Deal Re-Engaged",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1620,
        0
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "REPLACE_HUBSPOT_CREDENTIAL",
          "name": "ATTRIBUTION HubSpot"
        }
      },
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 2000
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.hubapi.com/crm/v3/objects/notes",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "contentType": "json",
        "specifyBody": "json",
        "jsonBody": "={{ $('Build Re-Engagement Updates').first().json.note }}",
        "options": {
          "timeout": 30000
        }
      },
      "id": "10c7f3c9-ef19-465d-96e3-a3d326ac80a6",
      "name": "Log Reply Note",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1890,
        0
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "REPLACE_HUBSPOT_CREDENTIAL",
          "name": "ATTRIBUTION HubSpot"
        }
      },
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 2000
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.hubapi.com/crm/v3/objects/tasks",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "contentType": "json",
        "specifyBody": "json",
        "jsonBody": "={{ $('Build Re-Engagement Updates').first().json.task }}",
        "options": {
          "timeout": 30000
        }
      },
      "id": "c70e06ad-6bf6-4449-a828-341096385efb",
      "name": "Notify Owner With Task",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        0,
        300
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "REPLACE_HUBSPOT_CREDENTIAL",
          "name": "ATTRIBUTION HubSpot"
        }
      },
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 2000
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT ghosted_proposal.complete_reply($1::uuid,$2::text,$3::text);",
        "options": {
          "queryReplacement": "={{ [$('Build Re-Engagement Updates').first().json.event_id,$json.id,$('Log Reply Note').first().json.id] }}"
        }
      },
      "id": "ed6075cd-dc93-4ed1-8067-d6fcc7fc8a5b",
      "name": "Complete Reply Audit",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        270,
        300
      ],
      "credentials": {
        "postgres": {
          "id": "REPLACE_POSTGRES_CREDENTIAL",
          "name": "ATTRIBUTION Postgres"
        }
      }
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ {accepted:true,event_id:$('Build Re-Engagement Updates').first().json.event_id} }}",
        "options": {
          "responseCode": 200
        }
      },
      "id": "52c896b5-cc1f-4feb-a583-03b10e64d8c1",
      "name": "Reply Accepted",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        540,
        300
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ {accepted:false,errors:$json.errors} }}",
        "options": {
          "responseCode": 400
        }
      },
      "id": "acd98023-4550-4925-9fbf-5f2ab3c21948",
      "name": "Reply Rejected",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        810,
        300
      ]
    },
    {
      "parameters": {
        "content": "## Reply monitoring adapter\nConnect an inbound email/channel parser or a HubSpot workflow to this authenticated webhook. It accepts a stable event UUID, deal/contact IDs, channel, timestamp and summary.\nThe reply is logged, the deal becomes RE_ENGAGED, and a high-priority task is assigned to the HubSpot deal owner. Raw email bodies are not required.",
        "width": 700,
        "height": 220
      },
      "id": "63e71d5c-20fb-4d45-9a51-452b4b1a1530",
      "name": "Workflow Guide",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        0,
        -270
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "050975d1-59d8-4478-a687-f66f7b60ce7e",
              "leftValue": "={{ $json.result.duplicate === false }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "c91908a3-9ac0-43f1-a0d4-b30484c2bab8",
      "name": "New Reply Event?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1350,
        300
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ {accepted:true,duplicate:true,event_id:$json.result.event_id} }}",
        "options": {
          "responseCode": 200
        }
      },
      "id": "a96d8445-d24a-4a06-8a3b-e50846e479eb",
      "name": "Acknowledge Duplicate Reply",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        1620,
        300
      ]
    }
  ],
  "connections": {
    "Reply Event Webhook": {
      "main": [
        [
          {
            "node": "Validate Reply Event",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Reply Event": {
      "main": [
        [
          {
            "node": "Reply Valid?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Reply Valid?": {
      "main": [
        [
          {
            "node": "Capture Reply Idempotently",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Reply Rejected",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Reply Deal": {
      "main": [
        [
          {
            "node": "Build Re-Engagement Updates",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Re-Engagement Updates": {
      "main": [
        [
          {
            "node": "Mark Deal Re-Engaged",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark Deal Re-Engaged": {
      "main": [
        [
          {
            "node": "Log Reply Note",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Reply Note": {
      "main": [
        [
          {
            "node": "Notify Owner With Task",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Notify Owner With Task": {
      "main": [
        [
          {
            "node": "Complete Reply Audit",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Complete Reply Audit": {
      "main": [
        [
          {
            "node": "Reply Accepted",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Capture Reply Idempotently": {
      "main": [
        [
          {
            "node": "New Reply Event?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "New Reply Event?": {
      "main": [
        [
          {
            "node": "Read Reply Deal",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Acknowledge Duplicate Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "timezone": "Asia/Tbilisi",
    "saveExecutionProgress": true
  },
  "active": false,
  "pinData": {},
  "tags": []
}
