{
  "name": "Souqly \u2014 Automatisation DMs Instagram",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "instagram-webhook",
        "authentication": "none",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "b1c2d3e4-0001-0001-0001-b1c2d3e40001",
      "name": "Webhook \u2014 DM Instagram entrant",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        240,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// Gestion de la v\u00e9rification webhook Meta (GET) + messages entrants (POST)\nconst req = $input.first().json;\n\n// V\u00e9rification initiale Meta (requ\u00eate GET lors de la config)\nif (req.query && req.query['hub.mode'] === 'subscribe') {\n  const VERIFY_TOKEN = $vars.META_WEBHOOK_VERIFY_TOKEN;\n  if (req.query['hub.verify_token'] === VERIFY_TOKEN) {\n    return [{ json: { type: 'verification', challenge: req.query['hub.challenge'] } }];\n  } else {\n    throw new Error('Token de v\u00e9rification invalide');\n  }\n}\n\n// Traitement des messages entrants\nconst body = req.body;\nif (!body || !body.entry) {\n  return [{ json: { type: 'ignored', reason: 'Pas de body valide' } }];\n}\n\nconst messages = [];\n\nfor (const entry of body.entry) {\n  for (const messaging of (entry.messaging || [])) {\n    // Ignorer les messages envoy\u00e9s par nous-m\u00eames\n    if (messaging.message && !messaging.message.is_echo) {\n      messages.push({\n        json: {\n          type: 'dm',\n          sender_id: messaging.sender.id,\n          recipient_id: messaging.recipient.id,\n          timestamp: messaging.timestamp,\n          message_text: messaging.message.text || '',\n          message_id: messaging.message.mid,\n          attachments: messaging.message.attachments || []\n        }\n      });\n    }\n  }\n}\n\nif (messages.length === 0) {\n  return [{ json: { type: 'ignored', reason: 'Aucun DM textuel' } }];\n}\n\nreturn messages;"
      },
      "id": "b1c2d3e4-0002-0002-0002-b1c2d3e40002",
      "name": "Extraire le DM",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        460,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "cond-001",
              "leftValue": "={{ $json.type }}",
              "rightValue": "dm",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ]
        },
        "options": {}
      },
      "id": "b1c2d3e4-0003-0003-0003-b1c2d3e40003",
      "name": "Est un vrai DM ?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        680,
        300
      ]
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "OK",
        "options": {}
      },
      "id": "b1c2d3e4-0004-0004-0004-b1c2d3e40004",
      "name": "R\u00e9pondre OK \u00e0 Meta",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        900,
        460
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.anthropic.com/v1/messages",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "anthropic-version",
              "value": "2023-06-01"
            },
            {
              "name": "content-type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"model\": \"claude-sonnet-4-6\",\n  \"max_tokens\": 1024,\n  \"system\": \"Tu es l'assistant DM Instagram de Souqly, un SaaS catalogue pour revendeurs et artisans. Ton r\u00f4le : r\u00e9pondre aux DMs de mani\u00e8re naturelle, courte (2-3 phrases max), en tutoiement, et qualifier les leads.\\n\\nSouqly en bref :\\n- Catalogue produit pro en ligne, prot\u00e9g\u00e9 par code d'acc\u00e8s\\n- Les clients commandent via WhatsApp/Telegram directement\\n- 29\u20ac/mois, 14 jours gratuits SANS carte bancaire\\n- Z\u00e9ro commission sur les ventes\\n- Remplace Yupoo, les PDFs et les partages Instagram manuels\\n- Pr\u00eat en 10 minutes, aucune comp\u00e9tence technique requise\\n- Lien d'inscription : https://souqly.fr/inscription\\n\\nPersonas types :\\n- Revendeuses mode (envoient des PDFs, utilisent WhatsApp)\\n- Grossistes franco-maghr\u00e9bins (utilisent Yupoo)\\n- Revendeurs sneakers/streetwear (cherchent du pro et rapide)\\n- Artisanes diaspora (cosm\u00e9tiques, textile, pas de site)\\n\\nTon style de r\u00e9ponse :\\n- Naturel, pas corporate\\n- Tutoiement syst\u00e9matique\\n- Max 3 lignes\\n- Toujours terminer par un CTA clair (essayer, voir une d\u00e9mo, le lien)\\n- Si la personne est h\u00e9sitante : mettre en avant le trial gratuit sans CB\\n- Si elle mentionne Yupoo : rassurer sur la migration facile\\n\\nTu dois aussi \u00e9valuer le score de qualification du lead (0-10) :\\n- 8-10 : Tr\u00e8s chaud (demande le prix, veut s'inscrire, mentionne un probl\u00e8me concret)\\n- 5-7 : Int\u00e9ress\u00e9 (pose des questions, curieux)\\n- 0-4 : Froid (mauvais contact, spam, hors sujet)\\n\\nR\u00e9ponds TOUJOURS en JSON strict :\\n{\\n  \\\"reponse_dm\\\": \\\"[ta r\u00e9ponse naturelle ici]\\\",\\n  \\\"score_lead\\\": [0-10],\\n  \\\"persona_detecte\\\": \\\"[revendeuse_mode|grossiste|sneakers|artisane|autre]\\\",\\n  \\\"intention\\\": \\\"[curiosite|demande_prix|probleme_concret|inscription|hors_sujet]\\\",\\n  \\\"note_interne\\\": \\\"[observation courte pour le dashboard, pas envoy\u00e9e au lead]\\\"\\n}\",\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"DM re\u00e7u : {{ $json.message_text }}\"\n    }\n  ]\n}",
        "options": {}
      },
      "id": "b1c2d3e4-0005-0005-0005-b1c2d3e40005",
      "name": "Claude \u2014 Analyse et r\u00e9pond",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        900,
        300
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const claudeResponse = $input.first().json;\nconst originalDM = $('Extraire le DM').first().json;\n\n// Parser la r\u00e9ponse Claude\nconst content = claudeResponse.content[0].text;\nlet analysis;\ntry {\n  analysis = JSON.parse(content);\n} catch(e) {\n  const jsonMatch = content.match(/\\{[\\s\\S]*\\}/);\n  analysis = JSON.parse(jsonMatch[0]);\n}\n\nreturn [{\n  json: {\n    // Donn\u00e9es originales du DM\n    sender_id: originalDM.sender_id,\n    message_original: originalDM.message_text,\n    timestamp: originalDM.timestamp,\n    // Analyse Claude\n    reponse_dm: analysis.reponse_dm,\n    score_lead: analysis.score_lead,\n    persona_detecte: analysis.persona_detecte,\n    intention: analysis.intention,\n    note_interne: analysis.note_interne,\n    // Drapeaux\n    lead_chaud: analysis.score_lead >= 7,\n    lead_moyen: analysis.score_lead >= 4 && analysis.score_lead < 7,\n    hors_sujet: analysis.score_lead < 2\n  }\n}];"
      },
      "id": "b1c2d3e4-0006-0006-0006-b1c2d3e40006",
      "name": "Parser r\u00e9ponse Claude",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1120,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "cond-002",
              "leftValue": "={{ $json.hors_sujet }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true"
              }
            }
          ]
        },
        "options": {}
      },
      "id": "b1c2d3e4-0007-0007-0007-b1c2d3e40007",
      "name": "Hors sujet / spam ?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1340,
        300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://graph.facebook.com/v19.0/{{ $vars.INSTAGRAM_PAGE_ID }}/messages",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"recipient\": {\n    \"id\": \"{{ $json.sender_id }}\"\n  },\n  \"message\": {\n    \"text\": \"{{ $json.reponse_dm }}\"\n  },\n  \"messaging_type\": \"RESPONSE\"\n}",
        "options": {}
      },
      "id": "b1c2d3e4-0008-0008-0008-b1c2d3e40008",
      "name": "Envoyer r\u00e9ponse DM",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1560,
        200
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "cond-003",
              "leftValue": "={{ $json.lead_chaud }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true"
              }
            }
          ]
        },
        "options": {}
      },
      "id": "b1c2d3e4-0009-0009-0009-b1c2d3e40009",
      "name": "Lead chaud ?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1780,
        200
      ]
    },
    {
      "parameters": {
        "chatId": "={{ $vars.TELEGRAM_CHAT_ID }}",
        "text": "=\ud83d\udd25 *LEAD CHAUD \u2014 Souqly Instagram*\n\n\ud83d\udc64 Sender ID: `{{ $('Parser r\u00e9ponse Claude').first().json.sender_id }}`\n\ud83d\udcca Score: *{{ $('Parser r\u00e9ponse Claude').first().json.score_lead }}/10*\n\ud83c\udfaf Persona: {{ $('Parser r\u00e9ponse Claude').first().json.persona_detecte }}\n\ud83d\udcac Intention: {{ $('Parser r\u00e9ponse Claude').first().json.intention }}\n\n*Message re\u00e7u :*\n_{{ $('Parser r\u00e9ponse Claude').first().json.message_original }}_\n\n*R\u00e9ponse envoy\u00e9e :*\n_{{ $('Parser r\u00e9ponse Claude').first().json.reponse_dm }}_\n\n\ud83d\udcdd Note: {{ $('Parser r\u00e9ponse Claude').first().json.note_interne }}\n\n\u27a1\ufe0f Relancer manuellement dans 24h si pas de r\u00e9ponse.",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "id": "b1c2d3e4-0010-0010-0010-b1c2d3e40010",
      "name": "Notif Telegram \u2014 Lead chaud",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.1,
      "position": [
        2000,
        160
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "appendOrUpdate",
        "documentId": {
          "__rl": true,
          "value": "={{ $vars.GOOGLE_SHEET_ID }}",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Leads DM",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "date": "={{ new Date($('Parser r\u00e9ponse Claude').first().json.timestamp).toLocaleDateString('fr-FR') }}",
            "sender_id": "={{ $('Parser r\u00e9ponse Claude').first().json.sender_id }}",
            "message": "={{ $('Parser r\u00e9ponse Claude').first().json.message_original }}",
            "reponse": "={{ $('Parser r\u00e9ponse Claude').first().json.reponse_dm }}",
            "score": "={{ $('Parser r\u00e9ponse Claude').first().json.score_lead }}",
            "persona": "={{ $('Parser r\u00e9ponse Claude').first().json.persona_detecte }}",
            "intention": "={{ $('Parser r\u00e9ponse Claude').first().json.intention }}",
            "statut": "R\u00e9pondu"
          }
        },
        "options": {}
      },
      "id": "b1c2d3e4-0011-0011-0011-b1c2d3e40011",
      "name": "Log Google Sheets \u2014 Lead",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4,
      "position": [
        2000,
        340
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "options": {}
      },
      "id": "b1c2d3e4-0012-0012-0012-b1c2d3e40012",
      "name": "Ignorer (hors sujet)",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        1560,
        420
      ]
    },
    {
      "parameters": {
        "options": {}
      },
      "id": "b1c2d3e4-0013-0013-0013-b1c2d3e40013",
      "name": "Fin",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        2220,
        260
      ]
    }
  ],
  "connections": {
    "Webhook \u2014 DM Instagram entrant": {
      "main": [
        [
          {
            "node": "Extraire le DM",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extraire le DM": {
      "main": [
        [
          {
            "node": "Est un vrai DM ?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Est un vrai DM ?": {
      "main": [
        [
          {
            "node": "Claude \u2014 Analyse et r\u00e9pond",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "R\u00e9pondre OK \u00e0 Meta",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Claude \u2014 Analyse et r\u00e9pond": {
      "main": [
        [
          {
            "node": "Parser r\u00e9ponse Claude",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parser r\u00e9ponse Claude": {
      "main": [
        [
          {
            "node": "Hors sujet / spam ?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Hors sujet / spam ?": {
      "main": [
        [
          {
            "node": "Ignorer (hors sujet)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Envoyer r\u00e9ponse DM",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Envoyer r\u00e9ponse DM": {
      "main": [
        [
          {
            "node": "Lead chaud ?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Lead chaud ?": {
      "main": [
        [
          {
            "node": "Notif Telegram \u2014 Lead chaud",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Log Google Sheets \u2014 Lead",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Notif Telegram \u2014 Lead chaud": {
      "main": [
        [
          {
            "node": "Log Google Sheets \u2014 Lead",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Google Sheets \u2014 Lead": {
      "main": [
        [
          {
            "node": "Fin",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true,
    "callerPolicy": "workflowsFromSameOwner",
    "errorWorkflow": ""
  },
  "versionId": "v1-dm-automation",
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "id": "souqly-wf-002",
  "tags": [
    {
      "createdAt": "2026-04-29T00:00:00.000Z",
      "updatedAt": "2026-04-29T00:00:00.000Z",
      "id": "tag-001",
      "name": "Souqly"
    },
    {
      "createdAt": "2026-04-29T00:00:00.000Z",
      "updatedAt": "2026-04-29T00:00:00.000Z",
      "id": "tag-003",
      "name": "DM Automation"
    }
  ]
}