This workflow follows the Execute Workflow Trigger → 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": "WorkFlow 05.01",
"nodes": [
{
"parameters": {
"inputSource": "passthrough"
},
"type": "n8n-nodes-base.executeWorkflowTrigger",
"typeVersion": 1.1,
"position": [
-464,
-16
],
"id": "4b80fc0a-703d-4f32-90e5-44e1eae5b9fd",
"name": "Workflow 05.01",
"onError": "continueRegularOutput"
},
{
"parameters": {
"resource": "databasePage",
"databaseId": {
"__rl": true,
"value": "{{NOTION_DB_ID_ARCHIVES_QUALITE}}",
"mode": "list",
"cachedResultName": "Archives Qualit\u00e9",
"cachedResultUrl": "https://www.notion.so/{{NOTION_DB_ID_ARCHIVES_QUALITE}}"
},
"propertiesUi": {
"propertyValues": [
{
"key": "Nom|title",
"title": "={{ $json[\"T\u00e2che\"] }}"
},
{
"key": "Date de planification|date",
"includeTime": false,
"date": "={{ $json[\"Date de planification\"].date.start }}"
},
{
"key": "Dead line|date",
"includeTime": false,
"date": "={{ $json[\"Dead line\"].date.start }}"
},
{
"key": "Date compl\u00e9t\u00e9|date",
"includeTime": false,
"date": "={{ $json[\"Date compl\u00e9t\u00e9\"].date.start }}"
},
{
"key": "Types de tache|rich_text",
"textContent": "={{ $json[\"Type de t\u00e2che\"] }}"
},
{
"key": "\u00c9tat|rich_text",
"textContent": "={{ $json[\"\u00c9tat\"] }}"
},
{
"key": "Cr\u00e9ateur|rich_text",
"textContent": "={{ $json[\"Cr\u00e9ateur\"] }}"
},
{
"key": "Priorit\u00e9|rich_text",
"textContent": "={{ $json[\"Priorit\u00e9\"] }}"
},
{
"key": "Note|rich_text",
"textContent": "={{ $json.Note }}"
},
{
"key": "Ticket|number",
"numberValue": "={{ $json.Ticket }}"
},
{
"key": "Approuv\u00e9e|rich_text",
"textContent": "={{ $json.Verification }}"
},
{
"key": "Mention|rich_text",
"textContent": "={{ $json.Mention }}"
},
{
"key": "Nom Responsable|rich_text",
"textContent": "={{ $json.Approbateur }}"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
-256,
-16
],
"id": "2add0235-f497-42bc-a061-4492e321d381",
"name": "Create Archives Qualit\u00e9",
"credentials": {
"notionApi": {
"name": "<your credential>"
}
},
"onError": "continueErrorOutput",
"notes": "Archives Qualit\u00e9 : {{NOTION_DB_ID_ARCHIVES_QUALITE}}"
},
{
"parameters": {},
"type": "n8n-nodes-base.merge",
"typeVersion": 3.2,
"position": [
2512,
416
],
"id": "9e95808e-85fd-42b9-86b7-6242f3197415",
"name": "Merge1"
},
{
"parameters": {
"values": {
"string": [
{
"name": "_lastNode",
"value": "={{ ($workflow.name || 'Unknown Workflow') + \" - \" + ($json._log?.actions?.find(action => !action.ok)?.node || Object.keys($json._log?.failedNodes || {})[0] || 'UnknownNode') }}"
},
{
"name": "_hadError",
"value": "={{ $json.error !== undefined }}"
},
{
"name": "_errMsg",
"value": "={{ $json.error?.message || ''}}"
}
]
},
"options": {}
},
"id": "86d4b536-6c33-4d47-91f4-91ba60d1baf4",
"name": "Log Snapshot3",
"type": "n8n-nodes-base.set",
"typeVersion": 1,
"position": [
3136,
160
],
"onError": "continueRegularOutput"
},
{
"parameters": {
"method": "PATCH",
"url": "=https://api.notion.com/v1/pages/{{ $('Edit Qualit\u00e9 Participant').item.json.id }}",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "notionApi",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ \n JSON.stringify((() => {\n // Relation fixe\n const Departement = $json.Departement;\n const responsableId = $json.ResponsableID;\n \n // CORRECTION: Parser la string avec virgules en array\n const equipeString = $json[\"\u00c9quipeID\"] || \"\";\n let operateursIDs = [];\n \n if (equipeString) {\n // Split par virgule + nettoyage + suppression doublons\n operateursIDs = Array.from(\n new Set(\n equipeString\n .split(',') // Split par virgule\n .map(id => id.trim()) // Enlever espaces\n .filter(id => id && id.length > 0) // Enlever vides\n )\n ).map(id => ({ id })); // Format Notion\n }\n \n // Validation s\u00e9curit\u00e9\n if (!Departement || !responsableId) {\n console.log(\"Erreur: D\u00e9partement ou Responsable manquant\");\n return null;\n }\n \n // Payload PATCH\n return {\n properties: {\n 'ehl{': { relation: operateursIDs },\n 'pXDv': { relation: [{ id: responsableId }] },\n 'VuU{': { relation: [{ id: Departement }] }\n }\n };\n })())\n}}",
"options": {
"batching": {
"batch": {
"batchSize": 1
}
}
}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
160,
-16
],
"id": "edf20b9e-fb9e-4f0d-99cd-9ebcb33350ca",
"name": "HTTP Participant Qualit\u00e9",
"alwaysOutputData": false,
"retryOnFail": true,
"credentials": {
"notionApi": {
"name": "<your credential>"
}
},
"onError": "continueErrorOutput"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "acd45495-b47b-40d5-8ada-6d4129baaf98",
"name": "ResponsableID",
"value": "={{ $('Workflow 05.01').item.json.ResponsableID }}",
"type": "string"
},
{
"id": "be122791-58bf-4682-9263-8219b7d9bdcb",
"name": "\u00c9quipeID",
"value": "={{ $('Workflow 05.01').item.json[\"\u00c9quipeID\"] }}",
"type": "string"
},
{
"id": "65c4a217-dde3-43a3-9fab-7114f59eda05",
"name": "Departement",
"value": "={{ $('Workflow 05.01').item.json.Departement }}",
"type": "string"
},
{
"id": "20f4be72-54de-4cac-886a-92a7e71d81c1",
"name": "id",
"value": "={{ $json.id }}",
"type": "string"
},
{
"id": "16d1c080-158c-465e-86aa-a04a2e92204b",
"name": "T\u00e2cheid",
"value": "={{ $('Workflow 05.01').item.json[\"T\u00e2cheid\"] }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
-32,
-32
],
"id": "47014790-9adc-42d5-b598-39b58ddd2e03",
"name": "Edit Qualit\u00e9 Participant"
},
{
"parameters": {
"functionCode": "return items.map(i => {\n const log = i.json._log || {};\n \n // LIGNE 5 CORRIG\u00c9E\n const nodeName = i.json._lastNode || 'UnknownNode';\n \n const failed = !!i.json._hadError || !!i.json.error;\n \n // Message adaptatif\n const msg = i.json.error?.message || \n i.json._errMsg || \n (failed ? 'Erreur d\u00e9tect\u00e9e' : 'Succ\u00e8s');\n \n (log.actions ||= []).push({ node: nodeName, ok: !failed, msg });\n \n if (failed) {\n log.ko = (log.ko || 0) + 1;\n log.failedNodes = log.failedNodes || {};\n log.failedNodes[nodeName] = true;\n } else {\n log.ok = (log.ok || 0) + 1;\n }\n \n i.json._log = log;\n return i;\n});"
},
"id": "220cd4f1-152e-4990-aa46-87c0d0f83640",
"name": "Update Log2",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
-32,
448
]
},
{
"parameters": {
"values": {
"string": [
{
"name": "_lastNode",
"value": "={{ ($workflow.name || 'Unknown Workflow') + \" - \" + ($json._log?.actions?.find(action => !action.ok)?.node || Object.keys($json._log?.failedNodes || {})[0] || 'UnknownNode') }}"
},
{
"name": "_hadError",
"value": "={{ $json.error !== undefined }}"
},
{
"name": "_errMsg",
"value": "={{ $json.error?.message || ''}}"
}
]
},
"options": {}
},
"id": "020b81fe-782b-403b-b050-5ab819673670",
"name": "Log Snapshot1",
"type": "n8n-nodes-base.set",
"typeVersion": 1,
"position": [
-224,
448
]
},
{
"parameters": {
"resource": "block",
"operation": "getAll",
"blockId": {
"__rl": true,
"value": "={{ $('Workflow 05.01').item.json[\"T\u00e2cheid\"] }}",
"mode": "id"
},
"returnAll": true,
"fetchNestedBlocks": true,
"simplifyOutput": false
},
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
368,
-16
],
"id": "f449e74c-8309-420a-80e0-d8d10696f800",
"name": "Get many child blocks",
"alwaysOutputData": true,
"executeOnce": true,
"credentials": {
"notionApi": {
"name": "<your credential>"
}
},
"onError": "continueErrorOutput"
},
{
"parameters": {
"jsCode": "/**\n * Format 1 bloc \u2014 \u00e0 placer dans la Loop (Split in Batches = 1)\n * Entr\u00e9e : { top, childrenMap, dest_id, root }\n * Sortie : [{\n * dest_id,\n * children_payload: { children: [ formattedWithChildren ] },\n * debug: {...}\n * }]\n */\n\nconst original = $json.top;\nconst childrenMap = $json.childrenMap || {};\nconst destId = $json.dest_id;\nconst rootInfo = $json.root || null;\n\nfunction detectType(block) {\n if (typeof block?.type === 'string' && block[block.type]) return block.type;\n const KNOWN = ['paragraph','heading_1','heading_2','heading_3','bulleted_list_item','numbered_list_item','to_do','toggle','quote','code','callout','divider','table_of_contents','link_to_page','synced_block','bookmark','image','video','pdf','file','column_list','column','table','table_row','equation'];\n for (const k of KNOWN) if (block && block[k]) return k;\n if (block?.unsupported) return 'unsupported';\n return null;\n}\n\nfunction rt(node) {\n if (!node) return [{ type:'text', text:{ content:'' }, annotations:{ bold:false, italic:false, strikethrough:false, underline:false, code:false, color:'default' }, plain_text:'', href:null }];\n if (Array.isArray(node.text)) return node.text;\n if (Array.isArray(node.rich_text)) return node.rich_text;\n return [{ type:'text', text:{ content:'' }, annotations:{ bold:false, italic:false, strikethrough:false, underline:false, code:false, color:'default' }, plain_text:'', href:null }];\n}\n\nfunction getChildrenOf(id) {\n const arr = childrenMap[id];\n return Array.isArray(arr) ? arr : [];\n}\n\nfunction formatOne(b) {\n const t = detectType(b) || 'paragraph';\n let out = { object:'block', type:t };\n\n switch (t) {\n case 'paragraph':\n out.paragraph = { rich_text: rt(b.paragraph), color: b.paragraph?.color || 'default' };\n break;\n case 'heading_1':\n out.heading_1 = { rich_text: rt(b.heading_1), color: b.heading_1?.color || 'default', is_toggleable: false };\n break;\n case 'heading_2':\n out.heading_2 = { rich_text: rt(b.heading_2), color: b.heading_2?.color || 'default', is_toggleable: false };\n break;\n case 'heading_3':\n out.heading_3 = { rich_text: rt(b.heading_3), color: b.heading_3?.color || 'default', is_toggleable: false };\n break;\n case 'bulleted_list_item':\n out.bulleted_list_item = { rich_text: rt(b.bulleted_list_item), color: b.bulleted_list_item?.color || 'default' };\n break;\n case 'numbered_list_item':\n out.numbered_list_item = { rich_text: rt(b.numbered_list_item), color: b.numbered_list_item?.color || 'default' };\n break;\n case 'to_do':\n out.to_do = { rich_text: rt(b.to_do), checked: b.to_do?.checked || false, color: b.to_do?.color || 'default' };\n break;\n case 'quote':\n out.quote = { rich_text: rt(b.quote), color: b.quote?.color || 'default' };\n break;\n case 'code':\n out.code = { rich_text: rt(b.code), language: b.code?.language || 'plain text', caption: Array.isArray(b.code?.caption)? b.code.caption : [] };\n break;\n case 'divider':\n out.divider = {}; break;\n case 'callout':\n out.callout = { rich_text: rt(b.callout), icon: b.callout?.icon ?? { emoji:'\ud83d\udca1' }, color: b.callout?.color || 'default' };\n break;\n case 'toggle':\n out.toggle = { rich_text: rt(b.toggle), color: b.toggle?.color || 'default' };\n break;\n default:\n out.type = 'paragraph';\n out.paragraph = { rich_text: [{ type:'text', text:{ content:'[Bloc converti]' }, annotations:{ bold:false, italic:false, strikethrough:false, underline:false, code:false, color:'default' }, plain_text:'[Bloc converti]', href:null }], color: 'default' };\n break;\n }\n\n const kids = getChildrenOf(b.id);\n if (kids.length > 0) {\n out.children = kids.map(ch => formatOne(ch));\n if (t === 'heading_1' && out.heading_1) out.heading_1.is_toggleable = true;\n if (t === 'heading_2' && out.heading_2) out.heading_2.is_toggleable = true;\n if (t === 'heading_3' && out.heading_3) out.heading_3.is_toggleable = true;\n }\n return out;\n}\n\nconst formatted = formatOne(original);\nconst payload = { children: [ formatted ] };\n\nreturn [{\n json: {\n dest_id: destId,\n children_payload: payload,\n debug: {\n root: rootInfo,\n source_block_id: original.id,\n children_count: (childrenMap[original.id]?.length || 0)\n }\n }\n \n}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1184,
-16
],
"id": "23666467-6f85-4b2d-8978-d76a70e68f30",
"name": "Code",
"onError": "continueRegularOutput"
},
{
"parameters": {
"options": {}
},
"type": "n8n-nodes-base.splitInBatches",
"typeVersion": 3,
"position": [
976,
-32
],
"id": "0abb1453-d615-4ab4-aa0f-8f3f28435ce2",
"name": "Loop Over Items1"
},
{
"parameters": {
"method": "PATCH",
"url": "=https://api.notion.com/v1/blocks/{{ $json.parentId }}/children",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "notionApi",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"contentType": "raw",
"rawContentType": "application/json",
"body": "={{ JSON.stringify({ children: [ $json.block ] }) }}",
"options": {
"batching": {
"batch": {}
}
}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1744,
-16
],
"id": "dd93e291-3e15-499a-a4d0-ac8296dc3742",
"name": "HTTP Request",
"credentials": {
"notionApi": {
"name": "<your credential>"
},
"httpHeaderAuth": {
"name": "<your credential>"
}
},
"onError": "continueErrorOutput"
},
{
"parameters": {
"jsCode": "/**\n * Index Children \u2014 MULTI-PAGE\n * - Construit childrenMap (parent_block_id -> [children])\n * - D\u00e9tecte TOUTES les pages sources pr\u00e9sentes dans l'input\n * - \u00c9met un item par bloc top-level POUR CHAQUE page\n * - Supporte un mapping optionnel source_page_id -> dest_id\n *\n * Entr\u00e9e: items (top-level + sous-blocs) de plusieurs pages possibles\n * Sortie: [{ json: { top, childrenMap, dest_id, root:{type:'page', id:'...'} } }, ...]\n */\n\nfunction normId(s){ return (s||'').toString().replace(/-/g,'').toLowerCase(); }\n\n// 1) Tous les blocs\nconst all = $input.all().map(i => i.json);\n\n// 2) Destination par d\u00e9faut (optionnelle)\nlet defaultDestId;\ntry { defaultDestId = $('Set Destination').first().json.destination_id; } catch (e) {}\nif (!defaultDestId) { try { defaultDestId = $('Create Archives Qualit\u00e9').first().json.id; } catch (e) {} }\n\n// 3) Mapping source_page_id -> dest_id (OPTIONNEL)\n// Cr\u00e9e un node \"Set Destinations\" en amont qui renvoie plusieurs lignes {source_page_id, dest_id}\nconst destMap = {};\ntry {\n const rows = $('Set Destinations').all().map(n => n.json);\n for (const r of rows) {\n if (r?.source_page_id && r?.dest_id) destMap[normId(r.source_page_id)] = String(r.dest_id);\n }\n} catch (e) { /* mapping absent = OK */ }\n\n// 4) Roots explicites ? (si tu gardes un \u201cSet Root\u201d, on ne traite QUE celle-ci)\nlet explicitRoot = null;\ntry {\n const r = $('Set Root').first().json;\n if (r?.root_id) explicitRoot = { type: String(r.root_type || 'page'), id: String(r.root_id) };\n} catch (e) {}\n\n// 5) Construire childrenMap global (OK multi-pages, ids Notion sont uniques)\nconst childrenMap = {}; // { [blockId]: Block[] }\nfor (const b of all) {\n if (b?.parent?.type === 'block_id' && b.parent.block_id) {\n const pid = b.parent.block_id;\n if (!childrenMap[pid]) childrenMap[pid] = [];\n childrenMap[pid].push(b);\n }\n}\n\n// 6) Lister les pages pr\u00e9sentes dans l'input\nconst pagesSeen = new Map(); // normPageId -> rawPageId\nfor (const b of all) {\n if (b?.parent?.type === 'page_id' && b.parent.page_id) {\n const nid = normId(b.parent.page_id);\n if (!pagesSeen.has(nid)) pagesSeen.set(nid, b.parent.page_id);\n }\n}\n\n// 7) D\u00e9terminer les roots \u00e0 traiter\nlet roots = [];\nif (explicitRoot?.type === 'page' && explicitRoot.id) {\n roots = [ explicitRoot ];\n} else {\n // traite TOUTES les pages rencontr\u00e9es\n roots = [...pagesSeen.entries()].map(([nid, raw]) => ({ type: 'page', id: raw }));\n // fallback : s\u2019il n\u2019y a aucune page vue (rare), tente une heuristique\n if (roots.length === 0) {\n const firstTop = all.find(x => x?.parent?.type==='page_id' && x.parent.page_id);\n if (firstTop) roots = [{ type:'page', id:firstTop.parent.page_id }];\n }\n}\n\n// 8) Construire la sortie : tous les top-level de chaque page, avec dest_id d\u00e9di\u00e9\nconst out = [];\nfor (const root of roots) {\n const rid = normId(root.id);\n const topLevel = all.filter(b => b?.parent?.type === 'page_id' && normId(b.parent.page_id) === rid);\n\n // destination pour CETTE page : mapping > d\u00e9faut > undefined (on laisse HTTP \u00e9chouer proprement si vide)\n const destForThisPage = destMap[rid] || defaultDestId || undefined;\n\n for (const b of topLevel) {\n out.push({\n json: { top: b, childrenMap, dest_id: destForThisPage, root }\n });\n }\n}\n\nreturn out;\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
560,
-32
],
"id": "a42c4295-88a8-460e-b7ea-4309689bd3ca",
"name": "Index Children",
"onError": "continueRegularOutput"
},
{
"parameters": {
"jsCode": "/**\n * Build Cascade Queue \u2014 retire `children` du parent et seed la file\n */\nconst destId = $json.dest_id;\nconst parent = ($json.children_payload?.children || [])[0];\n\nif (!destId || !parent) {\n return [{ json: { error: 'missing_dest_or_parent' } }];\n}\n\n// strip children au parent\nconst kids = Array.isArray(parent.children) ? parent.children : [];\nconst parentNoKids = { ...parent };\ndelete parentNoKids.children;\n\n// initialise la file avec 1 t\u00e2che \"cr\u00e9er le parent sous destId\"\nconst queue = [{\n parentId: destId,\n block: parentNoKids,\n children: kids\n}];\n\nreturn [{ json: { queue } }];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1376,
-16
],
"id": "48e84026-db38-440e-9be1-78849e04b74d",
"name": "Build case Q",
"onError": "continueRegularOutput"
},
{
"parameters": {
"jsCode": "/**\n * Pop Task \u2014 sort la prochaine t\u00e2che de la file\n */\nconst q = Array.isArray($json.queue) ? $json.queue : [];\nif (q.length === 0) {\n return [{ json: { done: true, queue: [] } }];\n}\n\nconst task = q.shift();\nreturn [{\n json: {\n done: false,\n queue: q, // \u2190 gard\u00e9 pour Merge/After\n parentId: task.parentId, // \u2190 utilis\u00e9 par HTTP URL\n block: task.block, // \u2190 utilis\u00e9 par HTTP body (sans children !)\n children: task.children || [] // \u2190 gard\u00e9 pour After Append\n }\n}];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1568,
-16
],
"id": "5abc5dbb-3e81-4be9-b926-15ed808fc3fb",
"name": "pop task",
"onError": "continueRegularOutput"
},
{
"parameters": {
"jsCode": "/**\n * After Append \u2014 version \"apr\u00e8s Merge (Pass Through)\"\n * Entr\u00e9e (depuis Merge):\n * - champs de Pop Task: queue[], children[], parentId, block\n * - r\u00e9ponse HTTP Notion: results[0].id, etc.\n * Sortie:\n * - { queue: [...prochaines t\u00e2ches...] }\n */\n\n// 1) Lire la r\u00e9ponse Notion (c\u00f4t\u00e9 HTTP)\nconst resp = $json; // Merge a copi\u00e9 la r\u00e9ponse HTTP dans le m\u00eame objet\nconst results = resp.results || resp.data?.results || [];\nconst newId = results[0]?.id;\n\n// 2) Lire la file et les enfants venant de Pop Task (conserv\u00e9s par le Merge)\nlet q = Array.isArray($json.queue) ? $json.queue : [];\nconst kids = Array.isArray($json.children) ? $json.children : [];\n\n// 3) Si l'API n'a pas renvoy\u00e9 d'ID, on log et on continue (ou tu peux throw si tu veux stopper)\nif (!newId) {\n return [{\n json: { error: 'append_failed_no_id', queue: q, debug: { resp_has_results: results.length } }\n }];\n}\n\n// 4) Chaque enfant devient une t\u00e2che sous newId (strip de ses propres children)\nfunction strip(b) {\n const copy = { ...b };\n const k = Array.isArray(b.children) ? b.children : [];\n delete copy.children;\n return { copy, k };\n}\n\nfor (const child of kids) {\n const { copy, k } = strip(child);\n q.push({ parentId: newId, block: copy, children: k });\n}\n\n// 5) Retourner la nouvelle queue\nreturn [{ json: { queue: q } }];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1984,
144
],
"id": "a0e59a4d-60a1-494d-9437-112249eb7cb7",
"name": "After Append Block",
"onError": "continueRegularOutput"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "3c57946b-89b4-4b4e-b158-c3962400c2c5",
"leftValue": "={{ Array.isArray($json.queue) && $json.queue.length > 0 }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
2208,
144
],
"id": "994bd547-5baf-44b6-91d5-d6cefe9f5815",
"name": "If",
"alwaysOutputData": false,
"onError": "continueRegularOutput"
},
{
"parameters": {
"mode": "combine",
"combineBy": "combineByPosition",
"options": {}
},
"type": "n8n-nodes-base.merge",
"typeVersion": 3.2,
"position": [
1760,
144
],
"id": "90ae3763-3a77-4738-b9f1-cb3ad9807e89",
"name": "Merge",
"alwaysOutputData": true,
"onError": "continueRegularOutput"
},
{
"parameters": {
"operation": "archive",
"pageId": {
"__rl": true,
"value": "={{ $('Edit Qualit\u00e9 Participant').item.json.T\u00e2cheid }}",
"mode": "id"
}
},
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
1984,
-224
],
"id": "74bf8988-26ba-4d49-80e1-8104bf61f65a",
"name": "Archive page",
"executeOnce": true,
"credentials": {
"notionApi": {
"name": "<your credential>"
}
},
"onError": "continueErrorOutput"
},
{
"parameters": {
"functionCode": "return items.map(i => {\n const log = i.json._log || {};\n \n // LIGNE 5 CORRIG\u00c9E\n const nodeName = i.json._lastNode || 'UnknownNode';\n \n const failed = !!i.json._hadError || !!i.json.error;\n \n // Message adaptatif\n const msg = i.json.error?.message || \n i.json._errMsg || \n (failed ? 'Erreur d\u00e9tect\u00e9e' : 'Succ\u00e8s');\n \n (log.actions ||= []).push({ node: nodeName, ok: !failed, msg });\n \n if (failed) {\n log.ko = (log.ko || 0) + 1;\n log.failedNodes = log.failedNodes || {};\n log.failedNodes[nodeName] = true;\n } else {\n log.ok = (log.ok || 0) + 1;\n }\n \n i.json._log = log;\n return i;\n});"
},
"id": "a5cb1cc7-724c-4d04-bb1f-076c2e4ff80c",
"name": "Update Log",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
2208,
0
]
},
{
"parameters": {
"values": {
"string": [
{
"name": "_lastNode",
"value": "={{ ($workflow.name || 'Unknown Workflow') + \" - \" + ($json._log?.actions?.find(action => !action.ok)?.node || Object.keys($json._log?.failedNodes || {})[0] || 'UnknownNode') }}"
},
{
"name": "_hadError",
"value": "={{ $json.error !== undefined }}"
},
{
"name": "_errMsg",
"value": "={{ $json.error?.message || ''}}"
}
]
},
"options": {}
},
"id": "364bc00a-60e4-4e1b-a9c5-0b048b60ef6e",
"name": "Log Snapshot",
"type": "n8n-nodes-base.set",
"typeVersion": 1,
"position": [
1984,
0
]
},
{
"parameters": {},
"type": "n8n-nodes-base.merge",
"typeVersion": 3.2,
"position": [
2896,
160
],
"id": "99dae071-cd50-4be5-b159-780ca4d089e9",
"name": "Merge3"
},
{
"parameters": {
"functionCode": "return items.map(i => {\n const log = i.json._log || {};\n \n // LIGNE 5 CORRIG\u00c9E\n const nodeName = i.json._lastNode || 'UnknownNode';\n \n const failed = !!i.json._hadError || !!i.json.error;\n \n // Message adaptatif\n const msg = i.json.error?.message || \n i.json._errMsg || \n (failed ? 'Erreur d\u00e9tect\u00e9e' : 'Succ\u00e8s');\n \n (log.actions ||= []).push({ node: nodeName, ok: !failed, msg });\n \n if (failed) {\n log.ko = (log.ko || 0) + 1;\n log.failedNodes = log.failedNodes || {};\n log.failedNodes[nodeName] = true;\n } else {\n log.ok = (log.ok || 0) + 1;\n }\n \n i.json._log = log;\n return i;\n});"
},
"id": "e00d965e-ad95-45b1-ab17-e985b49e7c44",
"name": "Update Log3",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
752,
-32
]
},
{
"parameters": {
"functionCode": "return items.map(i => {\n const log = i.json._log || {};\n \n // LIGNE 5 CORRIG\u00c9E\n const nodeName = i.json._lastNode || 'UnknownNode';\n \n const failed = !!i.json._hadError || !!i.json.error;\n \n // Message adaptatif\n const msg = i.json.error?.message || \n i.json._errMsg || \n (failed ? 'Erreur d\u00e9tect\u00e9e' : 'Succ\u00e8s');\n \n (log.actions ||= []).push({ node: nodeName, ok: !failed, msg });\n \n if (failed) {\n log.ko = (log.ko || 0) + 1;\n log.failedNodes = log.failedNodes || {};\n log.failedNodes[nodeName] = true;\n } else {\n log.ok = (log.ok || 0) + 1;\n }\n \n i.json._log = log;\n return i;\n});"
},
"id": "8f382dd8-4123-465f-b4c2-fc99a52dffab",
"name": "Update Log4",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
1744,
-224
]
},
{
"parameters": {
"jsCode": "const allLogs = $input.all();\n\nconst consolidated = {\n workflow: allLogs[0].json._log?.workflow,\n startedAt: allLogs[0].json._log?.startedAt,\n finishedAt: new Date().toISOString(),\n ok: allLogs.reduce((sum, item) => sum + (item.json._log?.ok || 0), 0),\n ko: allLogs.reduce((sum, item) => sum + (item.json._log?.ko || 0), 0),\n \n // R\u00e9cup\u00e9ration des nodes en \u00e9chec (inchang\u00e9)\n failedNodes: allLogs.reduce((acc, item) => {\n if (item.json._hadError || item.json.error) {\n const nodeName = item.json._lastNode || item.json.error?.name || 'UnknownNode';\n acc[nodeName] = {\n error: true,\n message: item.json.error?.message || item.json._errMsg || 'Erreur inconnue'\n };\n }\n return acc;\n }, {}),\n \n // CORRECTION : R\u00e9cup\u00e9rer les vraies actions depuis _log.actions\n actions: allLogs.reduce((acc, item) => {\n // R\u00e9cup\u00e9rer les actions existantes dans _log.actions\n const existingActions = item.json._log?.actions || [];\n \n // Ajouter les actions existantes\n acc.push(...existingActions);\n \n // Si il y a une erreur globale sur cet item, ajouter une action d'erreur\n if (item.json._hadError || item.json.error) {\n const nodeName = item.json._lastNode || item.json.error?.name || 'UnknownNode';\n acc.push({\n node: nodeName,\n ok: false,\n msg: item.json.error?.message || item.json._errMsg || 'Erreur'\n });\n }\n \n return acc;\n }, [])\n};\n\nreturn [{ json: { _log: consolidated } }];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
3328,
160
],
"id": "e8b8d395-28ab-4472-a78d-fea36b8fe8d5",
"name": "Returns item"
},
{
"parameters": {},
"type": "n8n-nodes-base.merge",
"typeVersion": 3.2,
"position": [
1200,
-224
],
"id": "4607d3bb-afb5-4ccd-8b27-d51852ce5709",
"name": "Merge2"
}
],
"connections": {
"Workflow 05.01": {
"main": [
[
{
"node": "Create Archives Qualit\u00e9",
"type": "main",
"index": 0
}
]
]
},
"Create Archives Qualit\u00e9": {
"main": [
[
{
"node": "Edit Qualit\u00e9 Participant",
"type": "main",
"index": 0
}
],
[
{
"node": "Log Snapshot1",
"type": "main",
"index": 0
}
]
]
},
"Merge1": {
"main": [
[
{
"node": "Merge3",
"type": "main",
"index": 1
}
]
]
},
"Log Snapshot3": {
"main": [
[
{
"node": "Returns item",
"type": "main",
"index": 0
}
]
]
},
"HTTP Participant Qualit\u00e9": {
"main": [
[
{
"node": "Get many child blocks",
"type": "main",
"index": 0
}
],
[
{
"node": "Log Snapshot1",
"type": "main",
"index": 0
}
]
]
},
"Edit Qualit\u00e9 Participant": {
"main": [
[
{
"node": "HTTP Participant Qualit\u00e9",
"type": "main",
"index": 0
},
{
"node": "Merge2",
"type": "main",
"index": 0
}
]
]
},
"Log Snapshot1": {
"main": [
[
{
"node": "Update Log2",
"type": "main",
"index": 0
}
]
]
},
"Update Log2": {
"main": [
[
{
"node": "Merge1",
"type": "main",
"index": 1
}
]
]
},
"Get many child blocks": {
"main": [
[
{
"node": "Index Children",
"type": "main",
"index": 0
}
],
[
{
"node": "Log Snapshot1",
"type": "main",
"index": 0
}
]
]
},
"Code": {
"main": [
[
{
"node": "Build case Q",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items1": {
"main": [
[
{
"node": "Merge2",
"type": "main",
"index": 1
}
],
[
{
"node": "Code",
"type": "main",
"index": 0
}
]
]
},
"HTTP Request": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
}
],
[
{
"node": "Log Snapshot",
"type": "main",
"index": 0
}
]
]
},
"Index Children": {
"main": [
[
{
"node": "Update Log3",
"type": "main",
"index": 0
}
]
]
},
"Build case Q": {
"main": [
[
{
"node": "pop task",
"type": "main",
"index": 0
}
]
]
},
"pop task": {
"main": [
[
{
"node": "HTTP Request",
"type": "main",
"index": 0
},
{
"node": "Merge",
"type": "main",
"index": 1
}
]
]
},
"After Append Block": {
"main": [
[
{
"node": "If",
"type": "main",
"index": 0
}
]
]
},
"If": {
"main": [
[
{
"node": "pop task",
"type": "main",
"index": 0
}
],
[
{
"node": "Loop Over Items1",
"type": "main",
"index": 0
}
]
]
},
"Merge": {
"main": [
[
{
"node": "After Append Block",
"type": "main",
"index": 0
}
]
]
},
"Log Snapshot": {
"main": [
[
{
"node": "Update Log",
"type": "main",
"index": 0
}
]
]
},
"Archive page": {
"main": [
[
{
"node": "Merge3",
"type": "main",
"index": 0
}
],
[
{
"node": "Log Snapshot",
"type": "main",
"index": 0
}
]
]
},
"Update Log": {
"main": [
[
{
"node": "Merge1",
"type": "main",
"index": 0
}
]
]
},
"Merge3": {
"main": [
[
{
"node": "Log Snapshot3",
"type": "main",
"index": 0
}
]
]
},
"Update Log3": {
"main": [
[
{
"node": "Loop Over Items1",
"type": "main",
"index": 0
}
]
]
},
"Update Log4": {
"main": [
[
{
"node": "Archive page",
"type": "main",
"index": 0
}
]
]
},
"Merge2": {
"main": [
[
{
"node": "Update Log4",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "0bbadfc1-7089-41c5-8cb0-ea58b325329e",
"meta": {
"templateCredsSetupCompleted": true
},
"id": "aPTwM9HqpwCbuavW",
"tags": [
{
"createdAt": "2025-08-26T22:10:40.037Z",
"updatedAt": "2025-08-26T22:10:40.037Z",
"id": "41B38HIWO9KNrCRH",
"name": "Archivage"
},
{
"createdAt": "2025-08-28T22:08:55.219Z",
"updatedAt": "2025-08-28T22:08:55.219Z",
"id": "n8XOLUF2FX0GmM4w",
"name": "Archivage Qualit\u00e9"
}
]
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
httpHeaderAuthnotionApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
WorkFlow 05.01. Uses executeWorkflowTrigger, notion, httpRequest. Event-driven trigger; 26 nodes.
Source: https://github.com/WealthFinPilot/notion-qms-platform/blob/main/exports/workflows/wf-05-01-archive-tache-qualite.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.
Workflow 01.01. Uses notion, executeWorkflowTrigger, httpRequest. Event-driven trigger; 60 nodes.
Automate sales call analysis and store structured insights in Notion with AI-powered intelligence.
WorkFlow 01.02. Uses notion, httpRequest, executeWorkflowTrigger. Event-driven trigger; 27 nodes.
WorkFlow 05.02. Uses httpRequest, notion, executeWorkflowTrigger. Event-driven trigger; 26 nodes.
WorkFlow 05.03. Uses notion, httpRequest, executeWorkflowTrigger. Event-driven trigger; 26 nodes.