magricambi/webhook/magricambi-ricerca-prezzi.json

232 lines
8.2 KiB
JSON
Raw Normal View History

{
"name": "MagRicambi - Ricerca prezzi articolo",
"nodes": [
{
"parameters": {
2026-06-07 18:34:46 +02:00
"content": "## MagRicambi — Ricerca prezzi v3 (solo Tavily)\n\n**Affidabile, senza LLM.** Estrae i prezzi dagli snippet web di Tavily.\n\n**Setup:**\n1. Credenziale Header Auth sul Webhook (`X-Webhook-Secret`)\n2. Credenziale Tavily (header `Authorization: Bearer tvly-...`)\n3. **Attiva** il workflow (toggle verde)\n4. Copia **Production URL** in `N8N_PRICE_SEARCH_WEBHOOK_URL`\n\n**Flusso:** Webhook → Tavily → Estrai prezzi → Respond OK\n\nRisponde **sempre** JSON valido per MagRicambi.",
"height": 340,
"width": 440
},
"id": "sticky-note-setup",
"name": "Note Setup",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
2026-06-07 18:34:46 +02:00
"position": [-80, 60]
},
{
"parameters": {
"httpMethod": "POST",
"path": "magricambi-ricerca-prezzi",
"responseMode": "responseNode",
"authentication": "headerAuth",
"options": {}
},
"id": "webhook-magricambi",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [240, 300],
"webhookId": "magricambi-ricerca-prezzi",
"credentials": {
"httpHeaderAuth": {
"id": "REPLACE_WITH_CREDENTIAL_ID",
"name": "MagRicambi Webhook Secret"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "cond-descrizione-not-empty",
"leftValue": "={{ ($json.body?.descrizione ?? $json.descrizione ?? '').toString().trim() }}",
"rightValue": "",
"operator": {
"type": "string",
"operation": "notEmpty",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "if-descrizione-valida",
"name": "IF Descrizione valida",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [480, 300]
},
{
"parameters": {
"jsCode": "const item = $input.first().json;\nconst body = item.body ?? item;\n\nconst descrizione = String(body.descrizione ?? '').trim();\nconst barcode = String(body.barcode ?? '').trim();\nconst codice = String(body.codice ?? '').trim();\n\nconst parts = [];\nif (barcode) parts.push(barcode);\nif (codice) parts.push(codice);\nif (descrizione) parts.push(descrizione);\nparts.push('prezzo acquisto ricambio industriale Italia EUR');\n\nreturn [{\n json: {\n descrizione,\n barcode: barcode || null,\n codice: codice || null,\n quantita: body.quantita ?? null,\n query: parts.join(' '),\n meta: body.meta ?? {},\n },\n}];"
},
"id": "code-build-query",
"name": "Build Query",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [720, 200]
},
{
"parameters": {
"method": "POST",
"url": "https://api.tavily.com/search",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"query\": {{ JSON.stringify($json.query) }},\n \"search_depth\": \"basic\",\n \"max_results\": 8,\n \"include_answer\": false\n}",
"options": {
"timeout": 20000
}
},
"id": "http-tavily-search",
"name": "Tavily Search",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [960, 200],
2026-06-07 18:34:46 +02:00
"onError": "continueRegularOutput",
"credentials": {
"httpHeaderAuth": {
"id": "REPLACE_WITH_CREDENTIAL_ID",
"name": "Tavily API"
}
}
},
{
"parameters": {
2026-06-07 18:34:46 +02:00
"jsCode": "const query = $('Build Query').first().json.query;\nconst descrizione = $('Build Query').first().json.descrizione;\n\nconst DISCLAIMER =\n \"Prezzi indicativi da fonti web: verificare su ordine fornitore prima dell'acquisto.\";\nconst TAVILY_ERROR_DISCLAIMER =\n DISCLAIMER + \" Ricerca web non disponibile al momento: riprovare tra poco.\";\n\nfunction hostnameFromUrl(url) {\n try {\n return new URL(url).hostname.replace(/^www\\./, '');\n } catch {\n return 'Sconosciuto';\n }\n}\n\nfunction extractPriceFromText(text) {\n const patterns = [\n /(?:€|EUR)\\s*(\\d{1,6}[.,]\\d{2})/i,\n /(\\d{1,6}[.,]\\d{2})\\s*(?:€|EUR)/i,\n ];\n for (const re of patterns) {\n const m = text.match(re);\n if (m) {\n const n = Number(m[1].replace(',', '.'));\n if (Number.isFinite(n) && n > 0 && n < 100000) return n;\n }\n }\n return null;\n}\n\nconst tavilyItem = $input.first().json;\nconst tavilyFailed = Boolean(tavilyItem?.error);\nconst results = Array.isArray(tavilyItem?.results) ? tavilyItem.results : [];\n\nconst offers = [];\nconst seenUrls = new Set();\n\nfor (const r of results) {\n const url = String(r.url ?? '').trim();\n if (!url || url === '#' || seenUrls.has(url)) continue;\n\n const text = `${r.title ?? ''} ${r.content ?? ''}`;\n const price = extractPriceFromText(text);\n if (price === null) continue;\n\n seenUrls.add(url);\n offers.push({\n vendor: hostnameFromUrl(url).slice(0, 120),\n title: String(r.title ?? descrizione).slice(0, 200),\n price,\n currency: 'EUR',\n url,\n confidence: 'medium',\n source: 'snippet',\n });\n\n if (offers.length >= 8) break;\n}\n\nreturn [{\n json: {\n query,\n searchedAt: new Date().toISOString(),\n offers,\n disclaimer: tavilyFailed && offers.length === 0 ? TAVILY_ERROR_DISCLAIMER : DISCLAIMER,\n source: 'tavily',\n },\n}];"
},
2026-06-07 18:34:46 +02:00
"id": "code-extract-prices",
"name": "Estrai Prezzi",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
2026-06-07 18:34:46 +02:00
"position": [1200, 200]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ $json }}",
"options": {
"responseCode": 200
}
},
"id": "respond-ok",
"name": "Respond OK",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
2026-06-07 18:34:46 +02:00
"position": [1440, 200]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ { \"error\": \"descrizione obbligatoria\" } }}",
"options": {
"responseCode": 400
}
},
"id": "respond-errore-400",
"name": "Respond Errore 400",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [720, 420]
}
],
"connections": {
"Webhook": {
"main": [
[
{
"node": "IF Descrizione valida",
"type": "main",
"index": 0
}
]
]
},
"IF Descrizione valida": {
"main": [
[
{
"node": "Build Query",
"type": "main",
"index": 0
}
],
[
{
"node": "Respond Errore 400",
"type": "main",
"index": 0
}
]
]
},
"Build Query": {
"main": [
[
{
"node": "Tavily Search",
"type": "main",
"index": 0
}
]
]
},
"Tavily Search": {
"main": [
[
{
2026-06-07 18:34:46 +02:00
"node": "Estrai Prezzi",
"type": "main",
"index": 0
}
]
]
},
2026-06-07 18:34:46 +02:00
"Estrai Prezzi": {
"main": [
[
{
"node": "Respond OK",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {},
"settings": {
"executionOrder": "v1",
"saveManualExecutions": true,
"callerPolicy": "workflowsFromSameOwner",
"errorWorkflow": ""
},
"staticData": null,
"tags": [
{
"name": "magricambi"
},
{
"name": "ricerca-prezzi"
}
],
"triggerCount": 1,
2026-06-07 18:34:46 +02:00
"updatedAt": "2026-06-07T18:00:00.000Z",
"versionId": "magricambi-ricerca-prezzi-v3-tavily",
"meta": {
"templateCredsSetupCompleted": false,
"instanceId": "magricambi-local"
},
"active": false
2026-06-07 18:34:46 +02:00
}