{
  "name": "Facebook Comments to Chatwoot + Agent Reply to Facebook",
  "nodes": [
    {
      "parameters": {
        "path": "facebook-comments",
        "responseMode": "responseNode",
        "options": {}
      },
      "name": "Meta Verification Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [
        -1200,
        -500
      ],
      "id": "meta-verification-webhook"
    },
    {
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "{{$json.query[\"hub.verify_token\"]}}",
              "value2": "YOUR_META_VERIFY_TOKEN"
            }
          ]
        }
      },
      "name": "Verify Meta Token",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        -960,
        -500
      ],
      "id": "verify-meta-token"
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "{{$json.query[\"hub.challenge\"]}}",
        "options": {
          "responseCode": 200
        }
      },
      "name": "Return Meta Challenge",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        -720,
        -580
      ],
      "id": "return-meta-challenge"
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "Invalid verify token",
        "options": {
          "responseCode": 403
        }
      },
      "name": "Reject Verification",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        -720,
        -420
      ],
      "id": "reject-verification"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "facebook-comments",
        "options": {}
      },
      "name": "Facebook Comment Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [
        -1200,
        100
      ],
      "id": "facebook-comment-webhook"
    },
    {
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "{{$json.body.entry[0].changes[0].value.item}}",
              "value2": "comment"
            }
          ]
        }
      },
      "name": "Only Facebook Comments",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        -960,
        100
      ],
      "id": "only-facebook-comments"
    },
    {
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "{{$json.body.entry[0].changes[0].value.from.id}}",
              "operation": "notEqual",
              "value2": "YOUR_FACEBOOK_PAGE_ID"
            }
          ]
        }
      },
      "name": "Ignore Page Own Comments",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        -720,
        100
      ],
      "id": "ignore-page-own-comments"
    },
    {
      "parameters": {
        "requestMethod": "GET",
        "url": "YOUR_CHATWOOT_BASE_URL/api/v1/accounts/YOUR_CHATWOOT_ACCOUNT_ID/search/contacts?q=fb_{{$node[\"Facebook Comment Webhook\"].json.body.entry[0].changes[0].value.from.id}}&page=1",
        "jsonParameters": true,
        "options": {},
        "headerParametersJson": "{ \"api_access_token\": \"YOUR_CHATWOOT_API_ACCESS_TOKEN\", \"Content-Type\": \"application/json\" }"
      },
      "name": "Search Chatwoot Contact",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 2,
      "position": [
        -480,
        100
      ],
      "id": "search-chatwoot-contact"
    },
    {
      "parameters": {
        "conditions": {
          "number": [
            {
              "value1": "{{($json.payload.contacts || []).length}}",
              "operation": "larger",
              "value2": 0
            }
          ]
        }
      },
      "name": "Contact Exists?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        -240,
        100
      ],
      "id": "contact-exists"
    },
    {
      "parameters": {
        "jsCode": "const contact = ($json.payload.contacts || [])[0];\n\nif (!contact) {\n  throw new Error('No existing contact found in payload.contacts');\n}\n\nreturn [\n  {\n    json: {\n      contact_id: contact.id\n    }\n  }\n];"
      },
      "name": "Use Existing Contact",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        0,
        0
      ],
      "id": "use-existing-contact"
    },
    {
      "parameters": {
        "requestMethod": "POST",
        "url": "YOUR_CHATWOOT_BASE_URL/api/v1/accounts/YOUR_CHATWOOT_ACCOUNT_ID/contacts",
        "jsonParameters": true,
        "options": {},
        "bodyParametersJson": "{\n  \"name\": \"{{$node['Facebook Comment Webhook'].json.body.entry[0].changes[0].value.from.name}}\",\n  \"identifier\": \"fb_{{$node['Facebook Comment Webhook'].json.body.entry[0].changes[0].value.from.id}}\",\n  \"additional_attributes\": {\n    \"social_profiles\": {\n      \"facebook\": \"https://facebook.com/{{$node['Facebook Comment Webhook'].json.body.entry[0].changes[0].value.from.id}}\"\n    }\n  }\n}",
        "headerParametersJson": "{ \"api_access_token\": \"YOUR_CHATWOOT_API_ACCESS_TOKEN\", \"Content-Type\": \"application/json\" }"
      },
      "name": "Create Chatwoot Contact",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 2,
      "position": [
        0,
        220
      ],
      "id": "create-chatwoot-contact"
    },
    {
      "parameters": {
        "jsCode": "const contact = $json.payload.contact;\n\nif (!contact) {\n  throw new Error('No new contact found in payload.contact');\n}\n\nreturn [\n  {\n    json: {\n      contact_id: contact.id\n    }\n  }\n];"
      },
      "name": "Use New Contact",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        240,
        220
      ],
      "id": "use-new-contact"
    },
    {
      "parameters": {
        "jsCode": "const fb = $('Facebook Comment Webhook').first().json.body.entry[0].changes[0].value;\n\nconst contactId = $json.contact_id;\nconst userId = fb.from.id;\nconst postId = fb.post_id;\nconst commentId = fb.comment_id;\nconst threadKey = `fb_post_${postId}_user_${userId}`;\n\nif (!contactId) {\n  throw new Error('No contact_id found before preparing Facebook context');\n}\n\nreturn [\n  {\n    json: {\n      contact_id: contactId,\n      fb_user_id: userId,\n      fb_user_name: fb.from.name,\n      fb_comment: fb.message || '',\n      fb_post_id: postId,\n      fb_comment_id: commentId,\n      fb_thread_key: threadKey\n    }\n  }\n];"
      },
      "name": "Prepare Facebook Context",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        500,
        100
      ],
      "id": "prepare-facebook-context"
    },
    {
      "parameters": {
        "requestMethod": "GET",
        "url": "https://graph.facebook.com/v25.0/{{$json.fb_post_id}}?fields=message,permalink_url,created_time,full_picture,status_type&access_token=YOUR_LONG_LIVED_PAGE_ACCESS_TOKEN",
        "jsonParameters": true,
        "options": {}
      },
      "name": "Get Facebook Post Details",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 2,
      "position": [
        760,
        100
      ],
      "id": "get-facebook-post-details"
    },
    {
      "parameters": {
        "jsCode": "const ctx = $('Prepare Facebook Context').first().json;\n\nreturn [\n  {\n    json: {\n      ...ctx,\n      fb_post_text: $json.message || 'No post text available',\n      fb_post_url: $json.permalink_url || '',\n      fb_post_created_time: $json.created_time || '',\n      fb_post_picture: $json.full_picture || '',\n      fb_post_type: $json.status_type || 'Unknown'\n    }\n  }\n];"
      },
      "name": "Prepare Conversation Payload",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1020,
        100
      ],
      "id": "prepare-conversation-payload"
    },
    {
      "parameters": {
        "requestMethod": "GET",
        "url": "YOUR_CHATWOOT_BASE_URL/api/v1/accounts/YOUR_CHATWOOT_ACCOUNT_ID/search/conversations?q={{$json.fb_thread_key}}&page=1",
        "jsonParameters": true,
        "options": {},
        "headerParametersJson": "{ \"api_access_token\": \"YOUR_CHATWOOT_API_ACCESS_TOKEN\", \"Content-Type\": \"application/json\" }"
      },
      "name": "Search Chatwoot Conversation",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 2,
      "position": [
        1280,
        100
      ],
      "id": "search-chatwoot-conversation"
    },
    {
      "parameters": {
        "conditions": {
          "number": [
            {
              "value1": "{{($json.payload.conversations || []).length}}",
              "operation": "larger",
              "value2": 0
            }
          ]
        }
      },
      "name": "Conversation Exists?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        1520,
        100
      ],
      "id": "conversation-exists"
    },
    {
      "parameters": {
        "jsCode": "const ctx = $('Prepare Conversation Payload').first().json;\nconst conversation = ($json.payload.conversations || [])[0];\n\nif (!conversation) {\n  throw new Error('No existing conversation found in payload.conversations');\n}\n\nreturn [\n  {\n    json: {\n      ...ctx,\n      conversation_id: conversation.id\n    }\n  }\n];"
      },
      "name": "Use Existing Conversation",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1760,
        0
      ],
      "id": "use-existing-conversation"
    },
    {
      "parameters": {
        "requestMethod": "POST",
        "url": "YOUR_CHATWOOT_BASE_URL/api/v1/accounts/YOUR_CHATWOOT_ACCOUNT_ID/conversations",
        "jsonParameters": true,
        "options": {},
        "bodyParametersJson": "{\n  \"source_id\": \"{{$node['Prepare Conversation Payload'].json.fb_thread_key}}\",\n  \"inbox_id\": YOUR_CHATWOOT_INBOX_ID,\n  \"contact_id\": {{$node['Prepare Conversation Payload'].json.contact_id}},\n  \"custom_attributes\": {\n    \"fb_comment_id\": \"{{$node['Prepare Conversation Payload'].json.fb_comment_id}}\",\n    \"fb_post_id\": \"{{$node['Prepare Conversation Payload'].json.fb_post_id}}\",\n    \"fb_user_id\": \"{{$node['Prepare Conversation Payload'].json.fb_user_id}}\",\n    \"fb_post_url\": \"{{$node['Prepare Conversation Payload'].json.fb_post_url}}\",\n    \"fb_thread_key\": \"{{$node['Prepare Conversation Payload'].json.fb_thread_key}}\"\n  }\n}",
        "headerParametersJson": "{ \"api_access_token\": \"YOUR_CHATWOOT_API_ACCESS_TOKEN\", \"Content-Type\": \"application/json\" }"
      },
      "name": "Create Chatwoot Conversation",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 2,
      "position": [
        1760,
        220
      ],
      "id": "create-chatwoot-conversation"
    },
    {
      "parameters": {
        "jsCode": "const ctx = $('Prepare Conversation Payload').first().json;\n\nif (!$json.id) {\n  throw new Error('No conversation id returned from Chatwoot');\n}\n\nreturn [\n  {\n    json: {\n      ...ctx,\n      conversation_id: $json.id\n    }\n  }\n];"
      },
      "name": "Use New Conversation",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2000,
        220
      ],
      "id": "use-new-conversation"
    },
    {
      "parameters": {
        "requestMethod": "POST",
        "url": "YOUR_CHATWOOT_BASE_URL/api/v1/accounts/YOUR_CHATWOOT_ACCOUNT_ID/conversations/{{$json.conversation_id}}/custom_attributes",
        "jsonParameters": true,
        "options": {},
        "bodyParametersJson": "{\n  \"custom_attributes\": {\n    \"fb_comment_id\": \"{{$json.fb_comment_id}}\",\n    \"fb_post_id\": \"{{$json.fb_post_id}}\",\n    \"fb_user_id\": \"{{$json.fb_user_id}}\",\n    \"fb_post_url\": \"{{$json.fb_post_url}}\",\n    \"fb_thread_key\": \"{{$json.fb_thread_key}}\"\n  }\n}",
        "headerParametersJson": "{ \"api_access_token\": \"YOUR_CHATWOOT_API_ACCESS_TOKEN\", \"Content-Type\": \"application/json\" }"
      },
      "name": "Update Conversation Attributes",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 2,
      "position": [
        2240,
        100
      ],
      "id": "update-conversation-attributes"
    },
    {
      "parameters": {
        "jsCode": "let ctx;\n\nif ($('Use Existing Conversation').isExecuted) {\n  ctx = $('Use Existing Conversation').first().json;\n} else if ($('Use New Conversation').isExecuted) {\n  ctx = $('Use New Conversation').first().json;\n} else {\n  throw new Error('No conversation context found');\n}\n\nreturn [\n  {\n    json: ctx\n  }\n];"
      },
      "name": "Restore Conversation Context",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2480,
        100
      ],
      "id": "restore-conversation-context"
    },
    {
      "parameters": {
        "requestMethod": "POST",
        "url": "YOUR_CHATWOOT_BASE_URL/api/v1/accounts/YOUR_CHATWOOT_ACCOUNT_ID/conversations/{{$json.conversation_id}}/messages",
        "jsonParameters": true,
        "options": {},
        "bodyParametersJson": "{\n  \"content\": {{ JSON.stringify(\"## Facebook Comment\\n\\n**Customer:** \" + $json.fb_user_name + \"\\n**Facebook User ID:** \" + $json.fb_user_id + \"\\n\\n**Comment:**\\n> \" + $json.fb_comment + \"\\n\\n---\\n\\n**Post:**\\n\" + ($json.fb_post_text || \"No post text available\") + \"\\n\\n**Post Type:** \" + ($json.fb_post_type || \"Unknown\") + \"\\n**Post Time:** \" + ($json.fb_post_created_time || \"Unknown\") + \"\\n\\n[Open Original Comment](https://facebook.com/\" + $json.fb_comment_id + \")\\n\\n[Open Original Post](\" + $json.fb_post_url + \")\\n\\n---\\n\\n**Internal IDs**\\nThread Key: `\" + $json.fb_thread_key + \"`\\nPost ID: `\" + $json.fb_post_id + \"`\\nComment ID: `\" + $json.fb_comment_id + \"`\") }},\n  \"message_type\": \"incoming\",\n  \"content_type\": \"text\"\n}",
        "headerParametersJson": "{ \"api_access_token\": \"YOUR_CHATWOOT_API_ACCESS_TOKEN\", \"Content-Type\": \"application/json\" }"
      },
      "name": "Add Comment Message",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 2,
      "position": [
        2720,
        100
      ],
      "id": "add-comment-message"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "chatwoot-facebook-reply",
        "options": {}
      },
      "name": "Chatwoot Reply Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [
        -1200,
        640
      ],
      "id": "chatwoot-reply-webhook"
    },
    {
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "{{$json.body.message_type}}",
              "value2": "outgoing"
            }
          ]
        }
      },
      "name": "Only Agent Replies",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        -960,
        640
      ],
      "id": "only-agent-replies"
    },
    {
      "parameters": {
        "jsCode": "const body = $json.body;\n\nconst replyText = body.content || body.message?.content || '';\n\nconst fbCommentId =\n  body.conversation?.custom_attributes?.fb_comment_id ||\n  body.conversation?.additional_attributes?.fb_comment_id ||\n  body.custom_attributes?.fb_comment_id ||\n  '';\n\nif (!replyText) {\n  throw new Error('No Chatwoot agent reply content found.');\n}\n\nif (!fbCommentId) {\n  throw new Error('No fb_comment_id found in Chatwoot conversation custom_attributes.');\n}\n\nreturn [\n  {\n    json: {\n      fb_comment_id: fbCommentId,\n      reply_text: replyText\n    }\n  }\n];"
      },
      "name": "Prepare Facebook Reply",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -720,
        560
      ],
      "id": "prepare-facebook-reply"
    },
    {
      "parameters": {
        "requestMethod": "POST",
        "url": "https://graph.facebook.com/v25.0/{{$json.fb_comment_id}}/comments",
        "jsonParameters": true,
        "options": {},
        "bodyParametersJson": "{\n  \"message\": {{ JSON.stringify($json.reply_text) }},\n  \"access_token\": \"YOUR_LONG_LIVED_PAGE_ACCESS_TOKEN\"\n}"
      },
      "name": "Reply to Facebook Comment",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 2,
      "position": [
        -480,
        560
      ],
      "id": "reply-to-facebook-comment"
    }
  ],
  "connections": {
    "Meta Verification Webhook": {
      "main": [
        [
          {
            "node": "Verify Meta Token",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Verify Meta Token": {
      "main": [
        [
          {
            "node": "Return Meta Challenge",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Reject Verification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Facebook Comment Webhook": {
      "main": [
        [
          {
            "node": "Only Facebook Comments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Only Facebook Comments": {
      "main": [
        [
          {
            "node": "Ignore Page Own Comments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Ignore Page Own Comments": {
      "main": [
        [
          {
            "node": "Search Chatwoot Contact",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Chatwoot Contact": {
      "main": [
        [
          {
            "node": "Contact Exists?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Contact Exists?": {
      "main": [
        [
          {
            "node": "Use Existing Contact",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Create Chatwoot Contact",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Use Existing Contact": {
      "main": [
        [
          {
            "node": "Prepare Facebook Context",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Chatwoot Contact": {
      "main": [
        [
          {
            "node": "Use New Contact",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Use New Contact": {
      "main": [
        [
          {
            "node": "Prepare Facebook Context",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Facebook Context": {
      "main": [
        [
          {
            "node": "Get Facebook Post Details",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Facebook Post Details": {
      "main": [
        [
          {
            "node": "Prepare Conversation Payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Conversation Payload": {
      "main": [
        [
          {
            "node": "Search Chatwoot Conversation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Chatwoot Conversation": {
      "main": [
        [
          {
            "node": "Conversation Exists?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Conversation Exists?": {
      "main": [
        [
          {
            "node": "Use Existing Conversation",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Create Chatwoot Conversation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Use Existing Conversation": {
      "main": [
        [
          {
            "node": "Update Conversation Attributes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Chatwoot Conversation": {
      "main": [
        [
          {
            "node": "Use New Conversation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Use New Conversation": {
      "main": [
        [
          {
            "node": "Update Conversation Attributes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Conversation Attributes": {
      "main": [
        [
          {
            "node": "Restore Conversation Context",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Restore Conversation Context": {
      "main": [
        [
          {
            "node": "Add Comment Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Chatwoot Reply Webhook": {
      "main": [
        [
          {
            "node": "Only Agent Replies",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Only Agent Replies": {
      "main": [
        [
          {
            "node": "Prepare Facebook Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Facebook Reply": {
      "main": [
        [
          {
            "node": "Reply to Facebook Comment",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "active": false
}