This workflow follows the Discord → HTTP Request recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "BaseLinker Product Automation - Full Sanitized Workflow",
"nodes": [
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "7ca45a22-c386-4f9f-98e4-9a85fe1206a3",
"leftValue": "={{ $('Webhook - Odbierz Produkty').item.json.body.stareSzablony }}",
"rightValue": "true",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
-1552,
3344
],
"id": "cf6ec122-6300-4457-8bf3-117f83f9e6ae",
"name": "Stare szablony"
},
{
"parameters": {
"jsCode": "const state = { ...$input.item.json };\n\n// 1. Sprawd\u017a, czy obraz jest ju\u017c przekazany z poprzedniego w\u0119z\u0142a\nif ($input.item.binary && $input.item.binary.image) {\n return { json: state, binary: { image: $input.item.binary.image } };\n}\n\n// 2. Pobierz dane binarne z Webhooka\nconst wb = $('Webhook - Odbierz Produkty').first().binary || {};\n\n// 3. Pobierz list\u0119 plik\u00f3w przygotowan\u0105 i posortowan\u0105 przez Tw\u00f3j w\u0119ze\u0142 \"Parsuj Nazwy Plik\u00f3w\"\nconst parsedData = $('Parsuj Nazwy Plik\u00f3w1').first().json;\nconst regularEntries = parsedData.regularEntries || [];\n\nif (regularEntries.length === 0) {\n throw new Error('[B\u0141\u0104D] Brak zwyk\u0142ych zdj\u0119\u0107. Nie mo\u017cna pobra\u0107 ostatniego obrazu.');\n}\n\n// 4. \"Parsuj Nazwy Plik\u00f3w\" sortuje pliki rosn\u0105co, wi\u0119c ostatni na li\u015bcie to obraz z najwy\u017cszym numerem\nconst lastEntry = regularEntries[regularEntries.length - 1];\nconst lastKey = lastEntry.key;\n\n// 5. Zwr\u00f3\u0107 plik binarny, kt\u00f3ry odpowiada temu ostatniemu kluczowi\nif (!wb[lastKey]) {\n throw new Error(`[B\u0141\u0104D] Nie znaleziono danych binarnych dla klucza: ${lastKey}`);\n}\n\nreturn { \n json: state, \n binary: { \n image: wb[lastKey] \n } \n};"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-1504,
2416
],
"id": "e077d1a7-1199-4da9-9bb3-12ea75bdb32b",
"name": "Wstrzyknij Ostatni obraz"
},
{
"parameters": {
"resource": "image",
"operation": "analyze",
"modelId": {
"__rl": true,
"value": "models/gemini-2.5-flash-lite",
"mode": "list"
},
"text": "=Jeste\u015b ekspertem od gramatyki polskiej i opis\u00f3w produkt\u00f3w.\n\n{{ $json.descAttempt > 0 ? '\u26a0\ufe0f POPRZEDNIA PR\u00d3BA NR ' + $json.descAttempt + ' ODRZUCONA\\nOdrzucone: \"' + $json.currentDesc + '\"\\nPow\u00f3d: ' + $json.lastDescReason + ($json.lastDescSuggestion ? '\\nSugestia: ' + $json.lastDescSuggestion : '') + '\\n\\nUWZGL\u0118DNIJ uwagi i wygeneruj POPRAWIONY TEKST.\\n' : '' }}\n\nZADANIE: Na podstawie OBRAZU oraz SZABLONU wygeneruj PE\u0141NY szablon odpowiednio dostosowany.\n\nSZABLON:\n{{ $('Inicjalizuj Stan1').item.json.szablon }}\n\nTYTU\u0141 PRODUKTU (TYLKO KONTEKST \u2014 NIE WOLNO GO PRZEPISYWA\u0106 ANI MODYFIKOWA\u0106):\n{{ $('Parsuj Wer T1').item.json.currentTitle }}\n\nINSTRUKCJA:\n1. Zidentyfikuj g\u0142\u00f3wny motyw widoczny na obrazie\n2. Dostosuj opis pod ten konkretny motyw przytoczony w tytule oraz widoczny na zdjeciu\n3. Zwr\u00f3\u0107 CA\u0141Y OPIS w takiej samej postaci jak\u0105 dosta\u0142es ale odpowiednie dostosowany\n4. Dopasuj poprawnie gramatyk\u0119 (przypadek, liczba, rodzaj)\n5. Popraw u\u017cycie \u201ez\u201d / \u201eze\u201d (np. \u201eze zwierz\u0119tami\u201d, \u201ez kotem\u201d, \u201ez motywem\u201d, \"z liskami\", \"z gwiazdami\")\n\nZASADY KRYTYCZNE:\n- ZWRACASZ CA\u0141Y OPIS\n- NIE zwracasz samego fragmentu\n- NIE przepisujesz ani nie modyfikujesz tytu\u0142u\n- NIE dodajesz \u017cadnych dodatkowych zda\u0144 ani komentarzy\n- NIE u\u017cywasz cudzys\u0142ow\u00f3w\n- PAMI\u0118TAJ BARDZO WA\u017bNE by zwr\u00f3ci\u0107 DOK\u0141ADNIE CA\u0141Y opis czyli ze wszystkimi znacznikami html zamykaj\u0105cymi otwieraj\u0105cymi itp\n- D\u0141UGO\u015a\u0106 ZWR\u00d3CONEJ ODPOWIEDZI powinna by\u0107 bardzo zbli\u017cona do szablonu A NAPEWNO NIE UCI\u0118TA W PO\u0141OWIE DAJ *CA\u0141O\u015a\u0106*\n\nPRZYK\u0141AD:\nSzablon: <section class=\"\\"section\\"\"><div class=\"\\"item\" item-12\\\"=\"\"><section class=\"\\"text-item\\"\"><p>Zmie\u0144 pok\u00f3j swojego malucha w prehistoryczn\u0105 krain\u0119....\nPoprawna odpowied\u017a: <section class=\"\\"section\\"\"><div class=\"\\"item\" item-12\\\"=\"\"><section class=\"\\"text-item\\"\"><p>Zamie\u0144 pok\u00f3j dziecka w prawdziwe centrum kosmiczne....\nODPOWIED\u0179:\nZwr\u00f3\u0107 WY\u0141\u0104CZNIE gotowy opis",
"inputType": "binary",
"binaryPropertyName": "image",
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.googleGemini",
"typeVersion": 1.1,
"position": [
-1088,
2416
],
"id": "b9999563-6cc6-4272-b471-430e66c92b20",
"name": "Generuj Opis1"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "99d5a23d-2ca1-4d78-b138-3ad2b0751a94",
"leftValue": "={{ $('Webhook - Odbierz Produkty').item.json.body.stareSzablony }}",
"rightValue": "true",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {
"ignoreCase": false
}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
-4736,
3424
],
"id": "31736d36-9cd9-4ee3-ae24-23e82fece075",
"name": "If3"
},
{
"parameters": {
"jsCode": "const products = $('2. Pobierz pe\u0142ne dane3').first().json.products;\nconst firstKey = Object.keys(products || {})[0];\nif (!firstKey || !products[firstKey]) throw new Error('[B\u0141\u0104D] Brak produkt\u00f3w.');\nconst description = products[firstKey].text_fields?.description;\nif (!description) throw new Error('[B\u0141\u0104D] Brak pola description.');\nreturn [{ json: { result: description } }];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-4432,
3344
],
"id": "cede9a1d-ff40-4ea1-a4f8-184242be296c",
"name": "Pobierz Szablon Opisu1"
},
{
"parameters": {
"jsCode": "let aiResponse = $input.first().json.content?.parts?.[0]?.text || $input.first().json.text || \"\";\n\nconst szablon = $('Inicjalizuj Stan1').first().json.szablon || \"\";\n\n// Zamiast szuka\u0107 w nadpisanym JSON-ie (kt\u00f3ry Gemini czy\u015bci), \n// u\u017cywamy wbudowanej zmiennej $runIndex, kt\u00f3ra zlicza ile razy ten w\u0119ze\u0142 wykona\u0142 si\u0119 w p\u0119tli.\nlet currentAttempt = typeof $runIndex !== 'undefined' ? $runIndex : 0;\n\nlet cleanDesc = aiResponse.replace(/^```(html)?\\s*/gi, '').replace(/\\s*```$/g, '').trim();\n\nlet isValid = true;\nlet reason = \"\";\nlet suggestion = \"\";\n\nif (!cleanDesc) {\n isValid = false;\n reason = \"Odpowied\u017a AI jest ca\u0142kowicie pusta.\";\n suggestion = \"Zwr\u00f3\u0107 pe\u0142ny kod HTML z opisem.\";\n}\n\nif (isValid && !cleanDesc.startsWith('<')) {\n isValid = false;\n reason = \"Wygenerowany tekst nie zaczyna si\u0119 od znacznika HTML (np. <section>). AI prawdopodobnie doda\u0142o wst\u0119p (np. 'Oto opis:').\";\n suggestion = \"Zwr\u00f3\u0107 WY\u0141\u0104CZNIE kod HTML. Nie pisz \u017cadnych s\u0142\u00f3w wst\u0119pu, zacznij od znaku '<'.\";\n}\n\nif (isValid && cleanDesc.length < (szablon.length * 0.5)) {\n isValid = false;\n reason = `Zwr\u00f3cony opis jest nienaturalnie kr\u00f3tki (${cleanDesc.length} znak\u00f3w vs szablon ${szablon.length} znak\u00f3w). Zosta\u0142 brutalnie uci\u0119ty.`;\n suggestion = \"Wygenerowa\u0142e\u015b tylko fragment. Przeanalizuj CA\u0141Y szablon i zwr\u00f3\u0107 go w 100% (od pocz\u0105tku do samego ko\u0144ca), bez ucinania w po\u0142owie.\";\n}\n\nconst countOpenSection = (cleanDesc.match(/<section/gi) || []).length;\nconst countCloseSection = (cleanDesc.match(/<\\/section>/gi) || []).length;\nconst countOpenDiv = (cleanDesc.match(/<div/gi) || []).length;\nconst countCloseDiv = (cleanDesc.match(/<\\/div>/gi) || []).length;\n\nif (isValid && (countOpenSection !== countCloseSection || countOpenDiv !== countCloseDiv)) {\n isValid = false;\n reason = `B\u0142\u0105d sk\u0142adni HTML. Niezgodna liczba tag\u00f3w. <section> (otwarte: ${countOpenSection}, zamkni\u0119te: ${countCloseSection}), <div> (otwarte: ${countOpenDiv}, zamkni\u0119te: ${countCloseDiv}).`;\n suggestion = \"Upewnij si\u0119, \u017ce KA\u017bDY otwarty tag <section> i <div> ma sw\u00f3j odpowiednik zamykaj\u0105cy (</section>, </div>). Skup si\u0119 na poprawnym zamkni\u0119ciu struktury HTML na samym ko\u0144cu, kod nie mo\u017ce by\u0107 urwany.\";\n}\n\nreturn {\n json: {\n ...$input.first().json,\n isValid: isValid,\n currentDesc: cleanDesc,\n lastDescReason: reason,\n lastDescSuggestion: suggestion,\n descAttempt: isValid ? currentAttempt : currentAttempt + 1\n }\n};"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-832,
2416
],
"id": "e079f6d7-190f-4077-9a5e-58ef148672af",
"name": "Weryfikator Opisu"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "570dd3d7-a258-4af7-a17a-f074014565b8",
"leftValue": "={{ $json.isValid }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equals"
}
},
{
"id": "b1be06e6-aa58-4b2b-8e75-06054307cdf1",
"leftValue": "={{ $json.descAttempt }}",
"rightValue": 2,
"operator": {
"type": "number",
"operation": "gt"
}
}
],
"combinator": "or"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
-624,
2416
],
"id": "9a980feb-4ec7-41cc-a1db-77f860b062e3",
"name": "If6"
},
{
"parameters": {
"operation": "resize",
"dataPropertyName": "=image",
"width": 400,
"height": 400,
"resizeOption": "onlyIfLarger",
"options": {}
},
"type": "n8n-nodes-base.editImage",
"typeVersion": 1,
"position": [
-1296,
2416
],
"id": "c74e6647-b38a-4545-a064-eaa80b7f83c5",
"name": "Zmie\u0144 Rozmiar1"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "fb1a8c99-11f6-4d39-80ba-46938ead814f",
"leftValue": "={{ $('Webhook - Odbierz Produkty').item.json.body.stareSzablony }}",
"rightValue": "true",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
-2000,
4176
],
"id": "ac3dc711-d621-4c3f-a4f1-8000565bc03d",
"name": "If7"
},
{
"parameters": {
"jsCode": "const data = $input.first().json;\n\nif (data.payload && data.payload.text_fields) {\n data.payload.text_fields.description = $('mapuj1').first().json.description;\n}\n\nreturn [{ json: data }];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-1616,
4032
],
"id": "624c86e9-ebef-4e43-a9e7-a37ea403d608",
"name": "Dostosuj Opis (AI ON & FULL Description)"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "16754619-392a-4619-9696-9ee4cd05aad9",
"leftValue": "={{ $('Webhook - Odbierz Produkty').item.json.body.stareSzablony }}",
"rightValue": "true",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
-4832,
4752
],
"id": "dfcbf4b2-af5e-4020-be41-2f1129afe7e5",
"name": "If8"
},
{
"parameters": {
"jsCode": "const products = $input.first().json.products || {};\nconst firstProduct = Object.values(products)[0] || {};\nconst description = firstProduct.text_fields?.description || \"\";\n\nreturn [\n {\n json: {\n description: description\n }\n }\n];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-4592,
4672
],
"id": "72826a87-4b2a-4a77-af80-d1ca3c486296",
"name": "Przygotuj JSON dla Webhooka"
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ $json }}",
"options": {}
},
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.5,
"position": [
-4400,
4672
],
"id": "217cd4c5-f6b8-45a7-b91e-8aba9b501bd6",
"name": "Respond to Webhook4"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "fb1a8c99-11f6-4d39-80ba-46938ead814f",
"leftValue": "={{ $('Webhook - Odbierz Produkty').item.json.body.stareSzablony }}",
"rightValue": "true",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
-1824,
4432
],
"id": "584b181c-e8b6-4e45-be35-e5f1cfff9c62",
"name": "If9"
},
{
"parameters": {
"jsCode": "const data = $input.first().json;\n\nif (data.payload && data.payload.text_fields) {\n data.payload.text_fields.description = $('Webhook - Odbierz Produkty').first().json.body.semanticVariation;\n}\n\nreturn [{ json: data }];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-1664,
4368
],
"id": "4d9c398e-b58d-4b76-9b70-eb369f964f48",
"name": "Dostosuj Opis (AI OFF & FULL Description)"
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={\n \"description\": \"{{ $json.result }}\"\n}",
"options": {}
},
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.5,
"position": [
-4400,
4816
],
"id": "db71fb49-de2b-40e2-8ede-63ae492ab1a4",
"name": "Respond to Webhook3"
},
{
"parameters": {
"jsCode": "const products=$input.first().json.products;\nconst firstKey=Object.keys(products)[0];\nif(!firstKey||!products[firstKey])throw new Error('Brak produkt\u00f3w');\nconst description=products[firstKey].text_fields?.description;\nif(!description)throw new Error('Brak description');\nconst match=description.match(/<b>(.*?)<\\/b>/i);\nif(!match)return[{json:{result:null,message:'Brak <b> w opisie'}}];\nlet text=match[1].trim().replace(/ /gi,' ').replace(/\\s+/g,' ');\nconst words=text.split(/\\s+/);\nconst shortWords=['z','w','na','do','i','o','u'];\nlet cutIndex=words.length-2;\nif(shortWords.includes(words[words.length-2]?.toLowerCase()))cutIndex=words.length-1;\nif(words.length>2)text=words.slice(0,cutIndex).join(' ')+' ...';\nelse text='...';\nreturn[{json:{result:`<b>${text}</b>`}}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-4608,
4816
],
"id": "1304ae38-8652-4041-aed0-8620d3c5ead9",
"name": "Code in JavaScript"
},
{
"parameters": {
"method": "POST",
"url": "https://api.baselinker.com/connector.php",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-BLToken",
"value": "={{ $env.BASELINKER_TOKEN }}"
}
]
},
"sendBody": true,
"contentType": "form-urlencoded",
"bodyParameters": {
"parameters": [
{
"name": "method",
"value": "getInventoryProductsData"
},
{
"name": "parameters",
"value": "={\"inventory_id\": {{ $('Pobierz ID Katalog\u00f3w1').item.json.inventories[0].inventory_id }},\"products\":[{{ Object.keys($json.products)[0] }}]}"
}
]
},
"options": {}
},
"name": "2. Pobierz pe\u0142ne dane1",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
-5040,
4752
],
"id": "987f9261-ca8b-4137-94d7-59a439dd4690"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "sku1-check",
"leftValue": "={{ $json.products }}",
"rightValue": "",
"operator": {
"type": "object",
"operation": "notEmpty",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
-5296,
4752
],
"id": "d1f4e02d-c83d-4ac5-86ea-7f9a7f0dec7e",
"name": "Czy znaleziono sku2"
},
{
"parameters": {
"method": "POST",
"url": "https://api.baselinker.com/connector.php",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-BLToken",
"value": "={{ $env.BASELINKER_TOKEN }}"
}
]
},
"sendBody": true,
"contentType": "form-urlencoded",
"bodyParameters": {
"parameters": [
{
"name": "method",
"value": "getInventoryProductsList"
},
{
"name": "parameters",
"value": "={\"inventory_id\": {{ $json.inventories[0].inventory_id }},\"filter_sku\": \"{{ $('Webhook - Odbierz Produkty').item.json.body.sku }}\"}"
}
]
},
"options": {}
},
"name": "1. Znajd\u017a po SKU1",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
-5472,
4752
],
"id": "242991ab-a7a4-4e1d-852f-02719f8cdb67"
},
{
"parameters": {
"method": "POST",
"url": "https://api.baselinker.com/connector.php",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-BLToken",
"value": "={{ $env.BASELINKER_TOKEN }}"
}
]
},
"sendBody": true,
"contentType": "form-urlencoded",
"bodyParameters": {
"parameters": [
{
"name": "method",
"value": "getInventories"
}
]
},
"options": {}
},
"name": "Pobierz ID Katalog\u00f3w1",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
-5664,
4752
],
"id": "035712a8-12b6-45c0-83ca-3af8dc1403a4"
},
{
"parameters": {
"respondWith": "noData",
"options": {}
},
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.5,
"position": [
-1168,
4352
],
"id": "6c02bc48-6740-4228-8650-48ea01393220",
"name": "Respond to Webhook5"
},
{
"parameters": {
"method": "POST",
"url": "https://api.baselinker.com/connector.php",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-BLToken",
"value": "={{ $env.BASELINKER_TOKEN }}"
}
]
},
"sendBody": true,
"contentType": "form-urlencoded",
"bodyParameters": {
"parameters": [
{
"name": "method",
"value": "addInventoryProduct"
},
{
"name": "parameters",
"value": "={{ JSON.stringify($json.payload) }}"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
-1376,
4352
],
"id": "7d4e504c-62bc-4518-b5c0-4cffe3c571c4",
"name": "8. Wy\u015blij do BaseLinker"
},
{
"parameters": {
"jsCode": "const data = $input.first().json;\nconst desc = data.payload?.text_fields?.description;\n\nif (!desc) return [{ json: data }];\n\nconst m = desc.match(/<b>(.*?)<\\/b>/i);\nif (!m) return [{ json: data }];\n\nconst words = m[1].trim().split(/\\s+/);\n\nif (words.length > 0) {\n words[words.length - 1] = $('Webhook - Odbierz Produkty').first().json.body.semanticVariation;\n}\n\n// \ud83d\udc47 dodana spacja przed </b>\ndata.payload.text_fields.description = desc.replace(\n /<b>.*?<\\/b>/i,\n `<b>${words.join(' ')} </b>`\n);\n\nreturn [{ json: data }];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-1664,
4528
],
"id": "7826e791-7854-4197-820c-194a2e999920",
"name": "Dostosuj Opis (AI OFF)1"
},
{
"parameters": {
"jsCode": "const data = $input.first().json;\nconst desc = data.payload?.text_fields?.description;\n\nif (!desc) return [{ json: data }];\n\nconst m = desc.match(/<b>(.*?)<\\/b>/i);\nif (!m) return [{ json: data }];\n\nconst origText = m[1].trim();\nconst mapText = $('mapuj1').first().json.description?.trim();\n\nif (!mapText) return [{ json: data }];\n\nconst origWords = origText.split(/\\s+/);\nconst firstWord = origWords[0].toLowerCase();\n\nlet newBContent = \"\";\n\n// 1. Sprawdzamy, czy w mapowaniu jest ju\u017c g\u0142\u00f3wne s\u0142owo z orygina\u0142u (np. \"Naklejki\")\nif (mapText.toLowerCase().includes(firstWord)) {\n // Je\u015bli tak, mapowanie ma pe\u0142ny tekst - nadpisujemy ca\u0142o\u015b\u0107, by nie duplikowa\u0107\n newBContent = mapText;\n} else {\n // Je\u015bli nie, zachowujemy oryginalny pocz\u0105tek i podmieniamy tylko ostatnie s\u0142owo\n origWords[origWords.length - 1] = mapText;\n newBContent = origWords.join(' ');\n}\n\n// 2. Automatyczna korekta gramatyczna przedimk\u00f3w \"z\" / \"ze\"\n// Zmienia \"z s\u0142oniem\" na \"ze s\u0142oniem\", \"z zwierz\u0105tkami\" na \"ze zwierz\u0105tkami\"\nnewBContent = newBContent.replace(/\\b(z)\\s+(s\u0142|zw|z\u0142|sz|rz|zm|zn|zb|zd|zg|sk|sp|st|\u015bn)/gi, 'ze $2');\n// Zmienia b\u0142\u0119dne \"ze liskami\" na \"z liskami\", \"ze lwem\" na \"z lwem\"\nnewBContent = newBContent.replace(/\\b(ze)\\s+([lkmntpwjcbdgf])/gi, 'z $2');\n\n// 3. Wstrzykni\u0119cie poprawionego tekstu do g\u0142\u00f3wnego opisu\ndata.payload.text_fields.description = desc.replace(/<b>.*?<\\/b>/i, `<b>${newBContent}</b>`);\n\nreturn [{ json: data }];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-1616,
4224
],
"id": "66f86207-5eea-422e-bd32-5e77a86347e1",
"name": "Dostosuj Opis (AI ON)1"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "ai-check2",
"leftValue": "={{ $('Webhook - Odbierz Produkty').item.json.body.useAI }}",
"rightValue": "true",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
-2144,
4352
],
"id": "8d8b2eab-feb3-4067-b1a6-7cf45590e3d7",
"name": "If10"
},
{
"parameters": {
"mode": "chooseBranch",
"useDataOfInput": 2
},
"type": "n8n-nodes-base.merge",
"typeVersion": 3.2,
"position": [
-2336,
4368
],
"id": "1dd707d9-19f2-46a3-bd65-efafba75cb67",
"name": "Merge1"
},
{
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "const item = $input.item;\nconst src = $('4. Rozwi\u0144 na Osobne Zdj\u0119cia').item.json;\nconst base64 = item.json?.data || '';\nconst images = {};\n\nif (base64) {\n // Znajd\u017a faktyczn\u0105 pozycj\u0119 w dedupedKeys po indeksie (0-based)\n const orderedKeys = src.orderedKeys || [];\n const keyIndex = orderedKeys.findIndex(e => e.key === src.currentKey);\n const position = keyIndex >= 0 ? keyIndex : (src.currentPosition ?? 1) - 1;\n images[String(position)] = `data:${base64}`;\n}\n\nreturn {\n json: {\n product: src.product,\n orderedKeys: src.orderedKeys,\n currentKey: src.currentKey,\n currentPosition: src.currentPosition ?? 0,\n totalImages: src.totalImages,\n images,\n skuData: src.skuData\n }\n};"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-2800,
4464
],
"id": "48bc7751-8c27-42eb-a76c-c98046953efb",
"name": "6. Przypisz Zdj\u0119cie do Pozycji"
},
{
"parameters": {
"jsCode": "const { product, orderedKeys, skuData } = $input.item.json;\nconst webhookBinary = $('Webhook - Odbierz Produkty').item.binary || {};\n\nif (!orderedKeys || orderedKeys.length === 0) {\n return [{ json: { product, orderedKeys: [], currentKey: null, currentPosition: 1, totalImages: 0, images: {}, skuData } }];\n}\n\n// Odfiltruj duplikaty po fileName \u2014 zachowaj pierwsze wyst\u0105pienie\nconst seenFileNames = new Set();\nconst dedupedKeys = orderedKeys.filter(({ key }) => {\n const fileName = webhookBinary[key]?.fileName;\n if (!fileName || seenFileNames.has(fileName)) return false;\n seenFileNames.add(fileName);\n return true;\n});\n\nreturn dedupedKeys.map(({ key, position }) => ({\n json: {\n product,\n orderedKeys: dedupedKeys,\n currentKey: key,\n currentPosition: position,\n totalImages: dedupedKeys.length,\n images: {},\n skuData\n },\n binary: webhookBinary[key] ? { currentBinary: webhookBinary[key] } : {}\n}));"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-3296,
4464
],
"id": "f5509f86-de30-41f3-9bdd-65c58213b47e",
"name": "4. Rozwi\u0144 na Osobne Zdj\u0119cia"
},
{
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// 3. WYCI\u0104GNIJ DANE I KLUCZE ZDJ\u0118\u0106\n//\n// Miniaturka (min) \u2192 pozycja 1 w BaseLinker\n// Pozosta\u0142e zdj\u0119cia \u2192 pozycje 2, 3, 4... wg kolejno\u015bci numeru z nazwy pliku\n//\n// SKU: przekazywane z w\u0119z\u0142a 'Wybierz Miniaturk\u0119'\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nconst raw = $input.item.json;\nconst inventoryId = $('Pobierz ID Katalog\u00f3w3').item.json.inventories[0].inventory_id;\n\nconst productId = Object.keys(raw.products)[0];\nif (!productId) throw new Error('[VALIDATION] Brak produktu w odpowiedzi z BaseLinker.');\n\nconst product = raw.products[productId];\nproduct.inventory_id = String(inventoryId);\n\nconst webhookBinary = $('Webhook - Odbierz Produkty').item.binary || {};\n\nfunction parseFileName(fileName) {\n if (!fileName) return null;\n const base = fileName.replace(/\\.[^.]+$/, '');\n const m = base.match(/^([A-Za-z]+-)?([0-9]+)_([^_]+)/);\n if (!m) return null;\n const prefix = m[1] || '';\n const skuRaw = m[2];\n const segment = m[3].toLowerCase();\n const isThumbnail = segment === 'min';\n const imageNumber = isThumbnail ? null : parseInt(segment, 10);\n return { prefix, skuRaw, isThumbnail, imageNumber };\n}\n\nconst allKeys = Object.keys(webhookBinary).filter(k => /^images\\d+$/.test(k));\nconst thumbnailRaw = [];\nconst regularRaw = [];\n\nfor (const key of allKeys) {\n const fileName = webhookBinary[key]?.fileName || '';\n const parsed = parseFileName(fileName);\n if (!parsed) continue;\n if (parsed.isThumbnail) thumbnailRaw.push({ key, parsed, fileName });\n else regularRaw.push({ key, parsed, fileName });\n}\n\nregularRaw.sort((a, b) => (a.parsed.imageNumber || 0) - (b.parsed.imageNumber || 0));\n\n// Miniaturka \u2014 klucz z w\u0119z\u0142a 'Wybierz Miniaturk\u0119' (je\u015bli dost\u0119pny)\nlet thumbKey;\ntry { thumbKey = $('Wybierz Miniaturk\u01191').first().json.chosenThumbnailKey; } catch(e) { thumbKey = thumbnailRaw[0]?.key; }\n\nconst orderedKeys = [];\nif (thumbKey && webhookBinary[thumbKey]) orderedKeys.push({ key: thumbKey, position: 1 });\n\nlet pos = 2;\nfor (const reg of regularRaw) {\n if (webhookBinary[reg.key]) orderedKeys.push({ key: reg.key, position: pos++ });\n}\n\n// SKU data z w\u0119z\u0142a parsowania\nlet skuData = {};\ntry {\n const pd = $('Wybierz Miniaturk\u01191').first().json;\n skuData = { skuPrefix: pd.skuPrefix, skuRaw: pd.skuRaw };\n} catch(e) {\n if (thumbnailRaw.length > 0) skuData = { skuPrefix: thumbnailRaw[0].parsed.prefix, skuRaw: thumbnailRaw[0].parsed.skuRaw };\n}\n\nreturn { json: { product, orderedKeys, skuData } };"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-3520,
4464
],
"id": "cf4dae0c-e9a5-46d2-a0de-eab6686afb9f",
"name": "3. Wyci\u0105gnij Dane i Klucze Zdj\u0119\u0107"
},
{
"parameters": {
"jsCode": "const products = $('2. Pobierz pe\u0142ne dane3').first().json.products;\nconst firstKey = Object.keys(products || {})[0];\nif (!firstKey || !products[firstKey]) throw new Error('[B\u0141\u0104D] Brak produkt\u00f3w.');\nconst description = products[firstKey].text_fields?.description;\nif (!description) throw new Error('[B\u0141\u0104D] Brak pola description.');\nconst match = description.match(/<b>(.*?)<\\/b>/i);\nif (!match) return [{ json: { result: null, message: 'Brak tagu <b> w opisie' } }];\nlet text = match[1].trim().replace(/ /gi, ' ').replace(/\\s+/g, ' ');\nconst words = text.split(/\\s+/);\nconst shortWords = ['z','w','na','do','i','o','u','ze','po','za','a','oraz'];\nlet cutIndex = words.length - 2;\nif (shortWords.includes((words[words.length - 2] || '').toLowerCase())) cutIndex = words.length - 1;\nconst trimmed = words.length > 2 ? words.slice(0, cutIndex).join(' ') + ' ...' : '...';\nreturn [{ json: { result: `<b>${trimmed}</b>` } }];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-4432,
3488
],
"id": "b10cd56f-6bad-4a31-93ed-8c5423e18413",
"name": "Pobierz Szablon Opisu2"
},
{
"parameters": {
"jsCode": "// Przeka\u017c wybran\u0105 miniaturk\u0119 do pipeline'u obrazowego\nconst src = $('Wybierz Miniaturk\u01191').first();\nconst webhookBinary = $('Webhook - Odbierz Produkty').first().binary || {};\nconst thumbKey = src.json.chosenThumbnailKey;\nif (!thumbKey || !webhookBinary[thumbKey]) {\n throw new Error('[B\u0141\u0104D] Brak wybranej miniaturki w binary webhooka.');\n}\nreturn { json: src.json, binary: { image: webhookBinary[thumbKey] } };"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-4288,
3616
],
"id": "6f1dd001-d6e1-4559-b42e-b03846314b73",
"name": "Wyodr\u0119bnij Obraz1"
},
{
"parameters": {
"jsCode": "const { thumbnailEntries, regularEntries, firstImageName } = $input.item.json;\nconst webhookBinary = $('Webhook - Odbierz Produkty').first().binary || {};\n\nfunction parseFileSize(sizeStr) {\n if (!sizeStr) return 0;\n const match = sizeStr.match(/([\\d.]+)\\s*(KB|MB|GB|B)/i);\n if (!match) return 0;\n const val = parseFloat(match[1]);\n const unit = match[2].toUpperCase();\n if (unit === 'GB') return val * 1024 * 1024 * 1024;\n if (unit === 'MB') return val * 1024 * 1024;\n if (unit === 'KB') return val * 1024;\n return val;\n}\n\nlet chosenKey = thumbnailEntries[0].key;\nlet chosenFileName = thumbnailEntries[0].fileName;\nlet chosenPrefix = thumbnailEntries[0].prefix;\nlet chosenSkuRaw = thumbnailEntries[0].skuRaw;\n\nif (thumbnailEntries.length > 1) {\n let bestSize = -Infinity;\n\n for (const entry of thumbnailEntries) {\n const binData = webhookBinary[entry.key];\n if (!binData) continue;\n\n const sizeBytes = parseFileSize(binData.fileSize);\n console.log(`[${entry.fileName}] fileSize: ${binData.fileSize} = ${sizeBytes} bajt\u00f3w`);\n\n if (sizeBytes > bestSize) {\n bestSize = sizeBytes;\n chosenKey = entry.key;\n chosenFileName = entry.fileName;\n chosenPrefix = entry.prefix;\n chosenSkuRaw = entry.skuRaw;\n }\n }\n\n console.log(`Wybrano: ${chosenFileName}`);\n}\n\nreturn {\n json: {\n thumbnailEntries,\n regularEntries,\n firstImageName,\n chosenThumbnailKey: chosenKey,\n chosenThumbnailFileName: chosenFileName,\n skuPrefix: chosenPrefix,\n skuRaw: chosenSkuRaw\n },\n binary: {\n image: webhookBinary[chosenKey]\n }\n};"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-4416,
3968
],
"id": "9690996e-82d8-4f2c-b867-57297fb225f5",
"name": "Wybierz Miniaturk\u01191"
},
{
"parameters": {
"jsCode": "// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// PARSUJ NAZWY PLIK\u00d3W Z BINARY WEBHOOKA\n//\n// Obs\u0142ugiwane formaty nazw:\n// DN-271_min_boy.jpg \u2192 miniaturka (boy)\n// DN-271_min_girl.jpg \u2192 miniaturka (girl)\n// 214_001min_girl.jpg \u2192 miniaturka (girl)\n// 214_001_girl.jpg \u2192 zdj\u0119cie nr 1 / awaryjna miniaturka\n// 214_1l.jpg \u2192 zdj\u0119cie nr 1 / awaryjna miniaturka\n// 271_2_baner.jpg \u2192 zdj\u0119cie nr 2\n// DN-261_5_opis_3.jpg \u2192 zdj\u0119cie nr 5\n//\n// Regu\u0142y:\n// - Segment po SKU zawiera \"min\" \u2192 miniaturka\n// - Segment zaczyna si\u0119 cyfr\u0105 \u2192 numer pozycji zdj\u0119cia\n// - Gdy nie ma miniaturki \"min\", zdj\u0119cie z najni\u017cszym numerem\n// zostaje u\u017cyte jako miniaturka\n// - Wszystko po pierwszym segmencie jest ignorowane\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nconst webhookBinary = $('Webhook - Odbierz Produkty').first().binary || {};\n\nfunction parseFileName(fileName) {\n if (!fileName) return null;\n\n const base = fileName.replace(/\\.[^.]+$/, '');\n\n // Opcjonalny prefix, SKU oraz pierwszy segment po SKU\n //\n // Przyk\u0142ady:\n // DN-271_min_boy \u2192 prefix: DN-, SKU: 271, segment: min\n // 214_001_girl \u2192 prefix: \"\", SKU: 214, segment: 001\n // 214_1l \u2192 prefix: \"\", SKU: 214, segment: 1l\n const match = base.match(/^([A-Za-z]+-)?([0-9]+)_([^_]+)/);\n\n if (!match) return null;\n\n const prefix = match[1] || '';\n const skuRaw = match[2];\n const segment = match[3].toLowerCase();\n\n // Miniaturka, gdy segment zawiera:\n // min, 001min, 1min itd.\n const isThumbnail = /^[0-9]*min/i.test(segment);\n\n // Pobierz cyfry znajduj\u0105ce si\u0119 na pocz\u0105tku segmentu:\n // 001 \u2192 1\n // 1l \u2192 1\n // 02x \u2192 2\n // baner \u2192 brak numeru\n const numberMatch = segment.match(/^([0-9]+)/);\n\n const imageNumber = isThumbnail || !numberMatch\n ? null\n : parseInt(numberMatch[1], 10);\n\n // P\u0142e\u0107 mo\u017ce znajdowa\u0107 si\u0119 w dowolnym miejscu nazwy\n const gender = /girl/i.test(base)\n ? 'girl'\n : (/boy/i.test(base) ? 'boy' : null);\n\n return {\n prefix,\n skuRaw,\n segment,\n isThumbnail,\n imageNumber,\n gender\n };\n}\n\nconst allKeys = Object.keys(webhookBinary)\n .filter(key => /^images\\d+$/.test(key));\n\nconst thumbnailEntries = [];\nconst regularEntries = [];\n\nfor (const key of allKeys) {\n const fileName = webhookBinary[key]?.fileName || '';\n const parsed = parseFileName(fileName);\n\n if (!parsed) continue;\n\n const entry = {\n key,\n fileName,\n parsed\n };\n\n if (parsed.isThumbnail) {\n thumbnailEntries.push(entry);\n } else if (parsed.imageNumber !== null) {\n // Dodajemy tylko pliki, z kt\u00f3rych uda\u0142o si\u0119 odczyta\u0107 numer\n regularEntries.push(entry);\n }\n}\n\n// Sortowanie zdj\u0119\u0107 wed\u0142ug numeru.\n// Przy identycznym numerze zachowujemy dodatkowo kolejno\u015b\u0107 kluczy images1,\n// images2 itd.\nregularEntries.sort((a, b) => {\n const numberDifference =\n a.parsed.imageNumber - b.parsed.imageNumber;\n\n if (numberDifference !== 0) {\n return numberDifference;\n }\n\n const keyNumberA = parseInt(a.key.replace(/\\D/g, ''), 10) || 0;\n const keyNumberB = parseInt(b.key.replace(/\\D/g, ''), 10) || 0;\n\n return keyNumberA - keyNumberB;\n});\n\n// Awaryjna miniaturka:\n// je\u017celi nie znaleziono pliku z \"min\", wybierz zdj\u0119cie\n// z najni\u017cszym numerem.\nlet usedFallbackThumbnail = false;\n\nif (thumbnailEntries.length === 0) {\n if (regularEntries.length === 0) {\n throw new Error(\n '[B\u0141\u0104D] Nie znaleziono miniaturki ani \u017cadnego zdj\u0119cia z numerem w nazwie.'\n );\n }\n\n const fallbackEntry = regularEntries.shift();\n\n fallbackEntry.parsed.isThumbnail = true;\n thumbnailEntries.push(fallbackEntry);\n\n usedFallbackThumbnail = true;\n}\n\nreturn {\n json: {\n thumbnailEntries: thumbnailEntries.map(entry => ({\n key: entry.key,\n fileName: entry.fileName,\n prefix: entry.parsed.prefix,\n skuRaw: entry.parsed.skuRaw,\n gender: entry.parsed.gender,\n fallback: usedFallbackThumbnail\n })),\n\n regularEntries: regularEntries.map(entry => ({\n key: entry.key,\n fileName: entry.fileName,\n imageNumber: entry.parsed.imageNumber,\n gender: entry.parsed.gender\n })),\n\n firstImageName: thumbnailEntries[0].fileName,\n usedFallbackThumbnail\n }\n};"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-4640,
4016
],
"id": "761d9710-fdbe-4271-a794-b72390ebca23",
"name": "Parsuj Nazwy Plik\u00f3w1"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "ai-check",
"leftValue": "={{ $('Webhook - Odbierz Produkty').item.json.body.useAI }}",
"rightValue": "true",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
-4880,
4208
],
"id": "c30998d7-8207-49e5-a3c6-f215e5d6720b",
"name": "If11"
},
{
"parameters": {
"method": "POST",
"url": "https://api.baselinker.com/connector.php",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-BLToken",
"value": "={{ $env.BASELINKER_TOKEN }}"
}
]
},
"sendBody": true,
"contentType": "form-urlencoded",
"bodyParameters": {
"parameters": [
{
"name": "method",
"value": "getInventoryProductsData"
},
{
"name": "parameters",
"value": "={\"inventory_id\": {{ $('Pobierz ID Katalog\u00f3w3').item.json.inventories[0].inventory_id }},\"products\":[{{ Object.keys($json.products)[0] }}]}"
}
]
},
"options": {}
},
"name": "2. Pobierz pe\u0142ne dane3",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
-5280,
4256
],
"id": "8cc3ac2b-8fbb-466e-849f-a1be729c3b44"
},
{
"parameters": {
"authentication": "oAuth2",
"resource": "message",
"guildId": {
"__rl": true,
"value": "={{ $env.DISCORD_GUILD_ID }}",
"mode": "id"
},
"channelId": {
"__rl": true,
"value": "={{ $env.DISCORD_CHANNEL_ID }}",
"mode": "id"
},
"content": "Nie znaleziono szablonowego SKU",
"options": {}
},
"type": "n8n-nodes-base.discord",
"typeVersion": 2,
"position": [
-5120,
4560
],
"id": "25dfa24c-4666-4494-b49f-063acd0e5c74",
"name": "Send a message3"
},
{
"parameters": {
"respondWith": "json",
"responseBody": "{\n \"error\": \"Nie znaleziono SKU szablonu\"\n}",
"options": {}
},
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.5,
"position": [
-5296,
4560
],
"id": "a1a47392-cbd5-4b89-b7c1-a2b8b7e823dd",
"name": "Zwr\u00f3\u0107 b\u0142\u0105d nie znalezienia SKU1"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "sku-check",
"leftValue": "={{ $json.products }}",
"rightValue": "",
"operator": {
"type": "object",
"operation": "notEmpty",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
-5456,
4272
],
"id": "969a9b07-48be-4b99-8663-0c070a5aefd2",
"name": "Czy znaleziono sku3"
},
{
"parameters": {
"method": "POST",
"url": "https://api.baselinker.com/connector.php",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-BLToken",
"value": "={{ $env.BASELINKER_TOKEN }}"
}
]
},
"sendBody": true,
"contentType": "form-urlencoded",
"bodyParameters": {
"parameters": [
{
"name": "method",
"value": "getInventoryProductsList"
},
{
"name": "parameters",
"value": "={\"inventory_id\": {{ $json.inventories[0].inventory_id }},\"filter_sku\": \"{{ $('Webhook - Odbierz Produkty').item.json.body.sku }}\"}"
}
]
},
"options": {}
},
"name": "1. Znajd\u017a po SKU3",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
-5616,
4256
],
"id": "aad4cf8e-5f9f-4330-9078-1c240bc2c901"
},
{
"parameters": {
"method": "POST",
"url": "https://api.baselinker.com/connector.php",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-BLToken",
"value": "={{ $env.BASELINKER_TOKEN }}"
}
]
},
"sendBody": true,
"contentType": "form-urlencoded",
"bodyParameters": {
"parameters": [
{
"name": "method",
"value": "getInventories"
}
]
},
"options": {}
},
"name": "Pobierz ID Katalog\u00f3w3",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
-5824,
4272
],
"id": "173d1b06-81b5-4b9e-8332-0bf45e877a77"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "action-check",
"leftValue": "={{ $json.body.action }}",
"rightValue": "checkdescription",
"operator": {
"type": "string",
"operation": "notEquals"
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
-6128,
4576
],
"id": "e1bdb183-c5ec-43e0-b056-c6e341deb2eb",
"name": "If12"
},
{
"parameters": {
"respondWith": "json",
"responseBody": "{\n \"error\": \"Podane has\u0142o jest nieprawid\u0142owe\"\n}",
"options": {
"responseCode": 401
}
},
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.5,
"position": [
-6128,
4736
],
"id": "605bc562-f53d-4d86-9e5b-9f5899cfab00",
"name": "Respond to Webhook6"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "pwd-check",
"leftValue": "={{ $json.body.password || '' }}",
"rightValue": "={{ $env.WORKFLOW_ACCESS_PASSWORD }}",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
-6416,
4752
],
"id": "f3d3471a-3d85-48dc-8597-ae040f71bd64",
"name": "Sprawdz has\u0142o1"
},
{
"parameters": {
"httpMethod": "POST",
"path": "baselinker-ai",
"responseMode": "responseNode",
"options": {
"allowedOrigins": "={{ $env.WEBHOOK_ALLOWED_ORIGIN }}"
}
},
"id": "12f314c7-0f9b-4160-80e4-e388809c8d13",
"name": "Webhook - Odbierz Produkty",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
-6592,
4576
]
},
{
"parameters": {
"mode": "chooseBranch",
"useDataOfInput": 2
},
"type": "n8n-nodes-base.merge",
"typeVersion": 3.2,
"position": [
-4128,
3328
],
"id": "9a181ff5-84b0-4dab-ba35-476352046461",
"name": "Po\u0142\u0105cz Dane1"
},
{
"parameters": {
"operation": "resize",
"dataPropertyName": "=image",
"width": 150,
"height": 150,
"resizeOption": "onlyIfLarger",
"options": {}
},
"type": "n8n-nodes-base.editImage",
"typeVersion": 1,
"position": [
-3904,
3328
],
"id": "67f725ad-6c61-41d6-a208-36e71fcaa8b2",
"name": "Zmie\u0144 Rozmiar2"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "init-01",
"name": "titleAttempt",
"value": 0,
"type": "number"
},
{
"id": "init-02",
"name": "currentTitle",
"value": "",
"type": "string"
},
{
"id": "init-03",
"name": "lastTitleReason",
"value": "",
"type": "string"
},
{
"id": "init-04",
"name": "lastTitleSuggestion",
"value": "",
"type": "string"
},
{
"id": "init-05",
"name": "descAttempt",
"value": 0,
"type": "number"
},
{
"id": "init-06",
"name": "currentDesc",
"value": "",
"type": "string"
},
{
"id": "init-07",
"name": "lastDescReason",
"value": "",
"type": "string"
},
{
"id": "init-08",
"name": "lastDescSuggestion",
"value": "",
"type": "string"
},
{
"id": "init-09",
"name": "szablon",
"value": "={{ $('Pobierz Szablon Opisu2').isExecuted ? $('Pobierz Szablon Opisu2').first().json.result : $('Pobierz Szablon Opisu1').first().json.result }}",
"type": "string"
},
{
"id": "init-10",
"name": "nazwaPliku",
"value": "={{ $('Wybierz Miniaturk\u01191').first().json.chosenThumbnailFileName || '' }}",
"type": "string"
},
{
"id": "init-11",
"name": "tytulSzablon",
"value": "={{ Object.values($('2. Pobierz pe\u0142ne dane3').first().json.products || {})?.[0]?.text_fields?.name || '' }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
-3680,
3328
],
"id": "2002ee56-bda5-4a36-aa29-ac3834d0567d",
"name": "Inicjalizuj Stan1"
},
{
"parameters": {
"jsCode": "const state = { ...$input.item.json };\nlet imageBinary;\nif ($input.item.binary?.image) {\n imageBinary = $input.item.binary.image;\n} else {\n const wb = $('Webhook - Odbierz Produkty').first().binary || {};\n const k = $('Wybierz Miniaturk\u01191').first().json.chosenThumbnailKey;\n if (!k) throw new Error('[B\u0141\u0104D] Brak klucza miniaturki.');\n imageBinary = wb[k];\n}\nreturn { json: state, binary: { image: imageBinary } };"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-3216,
3360
],
"id": "315dd526-600d-45a2-80c6-ad2e46e1ccdd",
"name": "Wstrzyknij Obraz T1"
},
{
"parameters": {
"resource": "image",
"operation": "analyze",
"modelId": {
"__rl": true,
"value": "models/gemini-2.5-flash-lite",
"mode": "list"
},
"text": "=Jeste\u015b ekspertem od tworzenia tytu\u0142\u00f3w produkt\u00f3w na Allegro.\n\n{{ $json.titleAttempt > 0 ? '\u26a0\ufe0f POPRZEDNIA PR\u00d3BA NR ' + $json.titleAttempt + ' ODRZUCONA\\nOdrzucony tytu\u0142: \"' + $json.currentTitle + '\"\\nPow\u00f3d odrzucenia: ' + $json.lastTitleReason + ($json.lastTitleSuggestion ? '\\nSugestia poprawki: ' + $json.lastTitleSuggestion : '') + '\\n\\nUWZGL\u0118DNIJ powy\u017csze uwagi i wygeneruj POPRAWIONY tytu\u0142.\\n' : '' }}\nZADANIE: Stw\u00f3rz NOWY tytu\u0142 produktu inspirowany szablonem \u2014 NIE kopiuj szablonu.\n\nDANE WEJ\u015aCIOWE:\n- Nazwa pliku: {{ $('Inicjalizuj Stan1').item.json.nazwaPliku }}\n- Szablon (wzorzec do na\u015bladowania, NIE gotowa odpowied\u017a): {{ $('Inicjalizuj Stan1').item.json.tytulSzablon }}\n\nKROK 1 \u2014 OKRE\u015aL P\u0141E\u0106 (obowi\u0105zkowe, sprawd\u017a w tej kolejno\u015bci):\n- Nazwa pliku zawiera \"girl\" \u2192 MUSISZ u\u017cy\u0107 \"dla Dziewczynki\"\n- Nazwa pliku zawiera \"boy\" \u2192 MUSISZ u\u017cy\u0107 \"dla Ch\u0142opca\"\n- Brak girl/boy \u2192 oce\u0144 obraz i wybierz odpowiednie okre\u015blenie LUB JE\u017bELI UWA\u017bASZ ZE PASUJE DLA DW\u00d3CH P\u0141CI ZOSTAW \"Dla Dzieci\"\n\nKROK 2 \u2014 OKRE\u015aL MOTYW z obrazu:\n- Sp\u00f3jrz na obraz i nazwij JEDEN g\u0142\u00f3wny motyw (np. Lisek, Jednoro\u017cec, Dinozaur)\n- Motyw MUSI by\u0107 w MIANOWNIKU\n- NIE u\u017cywaj motywu z szablonu \u2014 u\u017cyj tego co widzisz na obrazie\n\nKROK 3 \u2014 ZBUDUJ TYTU\u0141:\n- We\u017a struktur\u0119 szablonu (kolejno\u015b\u0107 s\u0142\u00f3w, styl)\n- Zamie\u0144 w szablonie: stare okre\u015blenie p\u0142ci \u2192 nowe z Kroku 1\n- Zamie\u0144 w szablonie: stare s\u0142owo motywu (ostatnie s\u0142owo) \u2192 nowe z Kroku 2\n- Sprawd\u017a czy tytu\u0142 ma max 120 znak\u00f3w\n\nSZABLON TO WZORZEC \u2014 jego ostatnie s\u0142owo (motyw) i okre\u015blenie p\u0142ci ZAWSZE musz\u0105 zosta\u0107 zmienione.\n\nZwr\u00f3\u0107 WY\u0141\u0104CZNIE gotowy tytu\u0142 \u2014 jedna linia, bez komentarzy, bez cudzys\u0142ow\u00f3w.",
"inputType": "binary",
"binaryPropertyName": "image",
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.googleGemini",
"typeVersion": 1.1,
"position": [
-2976,
3360
],
"id": "5e699b3f-2584-401b-90c8-ac3838e9125d",
"name": "Generuj Tytu\u01421"
},
{
"parameters": {
"jsCode": "const generatedTitle = ($input.item.json.content?.parts?.[0]?.text || '').trim().replace(/\\n/g, ' ');\nconst state = $('Wstrzyknij Obraz T1').item.json;\nreturn { json: { ...state, currentTitle: generatedTitle } };"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-2768,
3392
],
"id": "a1fc04b3-fb94-436d-8933-f58fb514a508",
"name": "Zapisz Kandydata T1"
},
{
"parameters": {
"modelId": {
"__rl": true,
"value": "models/gemini-3.1-flash-lite-preview",
"mode": "list"
},
"messages": {
"values": [
{
"content": "=Jeste\u015b weryfikatorem tytu\u0142\u00f3w. Oceniasz WY\u0141\u0104CZNIE wed\u0142ug podanych kryteri\u00f3w.\n\nTYTU\u0141 DO WERYFIKACJI: \"{{ $json.currentTitle }}\"\nNAZWA PLIKU: \"{{ $('Inicjalizuj Stan1').item.json.nazwaPliku }}\"\n\nKRYTERIA:\n\nODBIORCA:\nTytu\u0142 musi zawiera\u0107 przynajmniej jedno poprawne okre\u015blenie odbiorcy.\n\nZasady:\n- Je\u015bli plik zawiera \"girl\" \u2192 wymagane \"dla Dziewczynki\" LUB \"dla Dzieci Dziewczynki\"\n- Je\u015bli plik zawiera \"boy\" \u2192 wymagane \"dla Ch\u0142opca\" LUB \"dla Dzieci Ch\u0142opca\"\n- Je\u015bli brak \"girl\"/\"boy\" \u2192 wymagane \"dla Dzieci\"\n\nNiedozwolone:\n- Brak jakiegokolwiek okre\u015blenia odbiorcy\n- Wi\u0119cej ni\u017c dwa okre\u015blenia odbiorcy \u0142\u0105cznie\n- Konstrukcje inne ni\u017c wymienione powy\u017cej (np. samo \"Ch\u0142opca\" bez \"dla\")\n\nWA\u017bNE przy liczeniu okre\u015ble\u0144: \"dla Dzieci Ch\u0142opca\" traktuj jako JEDNO okre\u015blenie, nie dwa.\n\nMOTYW:\nTytu\u0142 musi zawiera\u0107 konkretny rzeczownik w mianowniku opisuj\u0105cy fizyczny motyw wizualny, np.:\n- zwierz\u0119 (np. lis, kot, dinozaur)\n- posta\u0107 (np. ksi\u0119\u017cniczka, astronauta)\n- obiekt (np. samoch\u00f3d, balon, rakieta)\n\nNiedozwolone s\u0105 motywy abstrakcyjne lub og\u00f3lne, np.:\n\"podr\u00f3\u017ce\", \"praca\", \"marzenia\", \"zwiedzanie\", \"styl \u017cycia\" itp.\n\nD\u0141UGO\u015a\u0106:\nMaksymalnie 120 znak\u00f3w\n\nCZYSTO\u015a\u0106:\nBrak:\n- cudzys\u0142ow\u00f3w\n- nawias\u00f3w\n- emoji\n- wielokropk\u00f3w\n\nOdpowiedz WY\u0141\u0104CZNIE w JSON (bez markdown):\n{\"valid\": true/false, \"reason\": \"...\", \"suggestion\": \"...\"}"
}
]
},
"builtInTools": {},
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.googleGemini",
"typeVersion": 1.1,
"position": [
-2544,
3360
],
"id": "71592255-86cb-417f-bde9-4a7ac3a3109a",
"name": "Weryfikuj Tytu\u01421",
"disabled": true
},
{
"parameters": {
"jsCode": "const raw = ($input.item.json.content?.parts?.[0]?.text || '').trim();\nconst clean = raw.replace(/^```json\\s*/im,'').replace(/^```\\s*/im,'').replace(/```\\s*$/im,'').trim();\nlet parsed;\ntry { parsed = JSON.parse(clean); } catch(e) {\n const m = clean.match(/\"valid\"\
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
BaseLinker Product Automation - Full Sanitized Workflow. Uses googleGemini, editImage, httpRequest, discord. Webhook trigger; 89 nodes.
Source: https://github.com/Over7oader/baselinker-ai-listing-automation/blob/fa3c06c06aa4af6dddecc2c0141a218b30faf62e/workflows/baselinker-product-automation-full.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
runout. Uses httpRequest, googleGemini, discord. Webhook trigger; 10 nodes.
This workflow captures new leads via webhook, enriches and scores them with Apollo and Google Gemini, logs everything in Google Sheets, and automates outreach, reply handling, follow-ups, meeting prep
Postagem Redes — Portal: Ações. Uses openAi, googleGemini, ollama, httpRequest. Webhook trigger; 58 nodes.
This workflow helps you repurpose your YouTube videos across multiple social media platforms with zero manual effort. It’s designed for creators, businesses, and marketers who want to maximize reach w
This workflow automates the process of generating stylized product photos for e-commerce by combining real product shots with creative templates. It enables the creation of a complete set of images fo