This workflow follows the HTTP Request → Notion 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 07",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "{{WEBHOOK_PATH_WF07_NAMED}}",
"options": {
"responseData": ""
}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [
-1152,
-32
],
"id": "7e9fac3a-d27c-409a-8f87-3980fc4042a5",
"name": "WorkFlow07"
},
{
"parameters": {
"resource": "databasePage",
"operation": "getAll",
"databaseId": {
"__rl": true,
"value": "{{NOTION_DB_ID_DEMANDES_D_ACHAT}}",
"mode": "list",
"cachedResultName": "Demandes d\u2019achat",
"cachedResultUrl": "https://www.notion.so/{{NOTION_DB_ID_DEMANDES_D_ACHAT}}"
},
"returnAll": true,
"simple": false,
"filterType": "manual",
"matchType": "allFilters",
"filters": {
"conditions": [
{
"key": "\ud83d\udd34Statut demande|status",
"condition": "equals",
"statusValue": "\u00c0 traiter"
},
{
"key": "\ud83d\udd34\ud83d\udcc6Master Fournisseurs|rich_text",
"condition": "contains",
"richTextValue": "={{ $('Edit Webhook').item.json[\"\ud83d\udd34\ud83d\udcc6Master Fournisseurs\"] }}"
},
{
"key": "PO Cr\u00e9er|checkbox",
"condition": "equals"
},
{
"key": "Livr\u00e9|checkbox",
"condition": "equals"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
144,
-32
],
"id": "ed1ebfae-44d0-4095-aebb-e0844bc21ffc",
"name": "Get Demande Achat",
"credentials": {
"notionApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "f15b795d-5689-46c7-9805-cc0c227d9e5c",
"leftValue": "={{ $json[\"\ud83d\udd34Statut demande\"] }}",
"rightValue": "\u00c0 traiter",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
-320,
-32
],
"id": "737350d0-8a78-48aa-a32d-78d48c854b89",
"name": "If"
},
{
"parameters": {
"values": {
"string": [
{
"name": "_log.workflow",
"value": "={{$workflow.name}}"
},
{
"name": "_log.executionId",
"value": "={{$execution.id}}"
}
]
},
"options": {}
},
"id": "5de50256-8565-48ef-ada6-f0f5aeb29f27",
"name": "Log Meta (expressions)",
"type": "n8n-nodes-base.set",
"typeVersion": 1,
"position": [
-928,
-32
]
},
{
"parameters": {
"functionCode": "return items.map(i => {\n const startedAt = new Date().toISOString();\n i.json._log = {\n runId: startedAt,\n workflow: i.json._log?.workflow || null,\n executionId: i.json._log?.executionId || null,\n startedAt,\n ok: 0,\n ko: 0,\n actions: [],\n failedNodes: {}\n };\n return i;\n});"
},
"id": "0be87325-7c00-458f-a9cc-9030b9de8411",
"name": "Start Log",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
-736,
-32
]
},
{
"parameters": {
"resource": "databasePage",
"operation": "update",
"pageId": {
"__rl": true,
"value": "={{ $json.ItemID }}",
"mode": "id"
},
"propertiesUi": {
"propertyValues": [
{
"key": "Auto task|select",
"selectValue": "Erreur: Item d\u00e9j\u00e0 trait\u00e9"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
-320,
208
],
"id": "b0719d90-1e31-4f30-ac90-e5f1d70e5f21",
"name": "Update Erreur",
"credentials": {
"notionApi": {
"name": "<your credential>"
}
},
"onError": "continueRegularOutput"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "b7387bc1-c69c-40f7-a89f-0ed7185baa97",
"name": "ItemID",
"value": "={{ $json.body.data.id }}",
"type": "string"
},
{
"id": "f48ecfbd-385d-4244-a2cc-7ccc4a4078da",
"name": "\ud83d\udd34Statut demande",
"value": "={{ $('WorkFlow07').item.json.body.data.properties[\"\ud83d\udd34Statut demande\"].status.name }}",
"type": "string"
},
{
"id": "e28454e1-8502-49f0-a66d-94e4094230b3",
"name": "\ud83d\udd34\ud83d\udcc6Master Fournisseurs",
"value": "={{ $('WorkFlow07').item.json.body.data.properties[\"\ud83d\udd34\ud83d\udcc6Master Fournisseurs\"].rich_text[0].plain_text }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
-512,
-32
],
"id": "13c41e12-71c5-4247-ba09-edb7456f8d5b",
"name": "Edit Webhook",
"onError": "continueRegularOutput"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "4c56bd49-b1b5-4905-8040-77b93346ecc5",
"name": "Quantit\u00e9",
"value": "={{ $json.properties[\"\u2705Quantit\u00e9\"].number || \"\"}}",
"type": "number"
},
{
"id": "17a7407f-99da-4e96-a10f-3d2b50328bc1",
"name": "unitaire",
"value": "={{ $json.properties[\"\ud83d\udcb2Co\u00fbt unitaire ($)\"].number || \"\"}}",
"type": "number"
},
{
"id": "2e192972-338c-4902-892d-65657c267b06",
"name": "Petit Total",
"value": "={{ $json.properties[\"\ud83d\udd34Co\u00fbt total ($)\"].formula.number || \"\"}}",
"type": "number"
},
{
"id": "41140ea4-62e6-4e6a-892b-b6f23d3b7e61",
"name": "Responsable",
"value": "={{ $json.properties[\"\ud83d\udd34Responsable achat\"].rich_text[0].plain_text || \"\"}}",
"type": "string"
},
{
"id": "bd69e36d-0fc7-427c-8f66-189497198b13",
"name": "Demandeur",
"value": "={{ $json.properties[\"\ud83d\udfe1Demandeur\"].rich_text[0].plain_text }}",
"type": "string"
},
{
"id": "e7afbdb8-4a8c-42fa-89b9-4c60123e02e6",
"name": "D\u00e9partements",
"value": "={{ $json.properties[\"\ud83d\udfe1D\u00e9partements\"] || \"\"}}",
"type": "object"
},
{
"id": "f3e4859f-e9f7-4e58-b6e8-118c5a7bac76",
"name": "Nom Commun",
"value": "={{ $json.properties[\"\ud83d\udd34Nom Commun\"].rich_text[0].text.content || \"\"}}",
"type": "string"
},
{
"id": "4041e6d5-26b5-45bd-88a2-390d349b4eb3",
"name": "Criticit\u00e9",
"value": "={{ $json.properties[\"\ud83d\udd34Criticit\u00e9\"].number || \"\" }}",
"type": "number"
},
{
"id": "4db7691d-0af5-484c-9c63-8e39c7505511",
"name": "properties[\"\ud83d\udd34Types de consommables\"]",
"value": "={{ $json.properties[\"\ud83d\udd34Types de consommables\"].rich_text[0].plain_text || \"\"}}",
"type": "string"
},
{
"id": "4b23e735-1dcd-424a-999d-8d0cae7351a5",
"name": "Mode de paiement",
"value": "={{ $json.properties[\"\ud83d\udfe1Mode de paiement\"].select || \"\"}}",
"type": "string"
},
{
"id": "56f41967-3a4d-4b1c-b023-64bac3b0b77f",
"name": "No d'article",
"value": "={{ $json.properties[\"\ud83d\udd34No d'article\"].rich_text[0].text.content || \"\"}}",
"type": "string"
},
{
"id": "38f19a52-6337-464b-890b-41bd6ddb83df",
"name": "Nom Item",
"value": "={{ $json.properties.Demande.title[0].plain_text || \"\" }}",
"type": "string"
},
{
"id": "34714d70-b34a-44d3-8de0-33f240ca8d0d",
"name": "URL",
"value": "={{ $json.properties[\"\ud83d\udd34URL\"].url }}",
"type": "string"
},
{
"id": "59ffb04f-4bbc-4b1a-86cf-7cfd2a767e21",
"name": "id",
"value": "={{ $json.id }}",
"type": "string"
},
{
"id": "613a4e78-d508-4959-b88e-f7ada7263073",
"name": "Proc\u00e9d\u00e9",
"value": "={{ $json.properties[\"\ud83d\udd34Types de proc\u00e9d\u00e9\"].rich_text[0].plain_text }}",
"type": "string"
},
{
"id": "63d224d2-5f02-4ade-9c75-59ec5af61281",
"name": "Statut Demande",
"value": "={{ $json.properties[\"\ud83d\udd34Statut demande\"].status.name }}",
"type": "string"
},
{
"id": "bbe6467c-5f63-4e23-bc8d-c254f2d94852",
"name": "Priorit\u00e9",
"value": "={{ $json.properties[\"\u2705Urgence\"].select.name }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
768,
-32
],
"id": "a781da8c-f8f0-41aa-a256-cd1a7667f104",
"name": "Edit Demande",
"onError": "continueRegularOutput"
},
{
"parameters": {
"jsCode": "// R\u00e9cup\u00e9rer tous les items d'entr\u00e9e\nconst items = $input.all();\n\n// Initialiser les variables\nlet grandTotal = 0;\nlet erreur = null;\nlet finalPriorite = \"Normal\"; // Valeur par d\u00e9faut\n\n// Fonction pour v\u00e9rifier si une valeur est un nombre valide et positif\nfunction isValidPositiveNumber(value) {\n return value !== null && value !== undefined && typeof value === 'number' && !isNaN(value) && isFinite(value) && value > 0;\n}\n\n// Calculer la priorit\u00e9 finale selon la hi\u00e9rarchie Normal < Urgent < Tr\u00e8s urgent\nitems.forEach(item => {\n const priorite = item.json[\"priorit\u00e9\"] || item.json[\"Priorit\u00e9\"];\n \n if (priorite === \"Tr\u00e8s urgent\") {\n finalPriorite = \"Tr\u00e8s urgent\"; // Plus haute priorit\u00e9, on peut arr\u00eater\n } else if (priorite === \"Urgent\" && finalPriorite !== \"Tr\u00e8s urgent\") {\n finalPriorite = \"Urgent\"; // Seulement si on n'a pas d\u00e9j\u00e0 \"Tr\u00e8s urgent\"\n }\n // Si priorite === \"Normal\", on garde la valeur actuelle de finalPriorite\n});\n\n// 1. V\u00e9rifier les \"Quantit\u00e9\" de tous les items (nombre, pas null, sup\u00e9rieur \u00e0 0)\nlet quantiteError = false;\nitems.forEach(item => {\n const quantite = item.json[\"Quantit\u00e9\"];\n if (!isValidPositiveNumber(quantite)) {\n quantiteError = true;\n }\n});\n\n// Si erreur sur les quantit\u00e9s\nif (quantiteError) {\n erreur = \"Erreur: Quantit\u00e9\";\n} else {\n erreur = null;\n}\n\n// 2. V\u00e9rifier les \"unitaire\" de tous les items (nombre et sup\u00e9rieur \u00e0 0)\nlet unitaireError = false;\nitems.forEach(item => {\n const unitaire = item.json[\"unitaire\"];\n if (!isValidPositiveNumber(unitaire)) {\n unitaireError = true;\n }\n});\n\n// 3. Si pas d'erreur sur quantit\u00e9 ET pas d'erreur sur unitaire \u2192 calculer Grand Total\nif (erreur === null && !unitaireError) {\n items.forEach(item => {\n const petitTotal = item.json[\"Petit Total\"];\n // Additionner les Petit Total (pas besoin de v\u00e9rifier, on additionne directement)\n grandTotal += petitTotal;\n });\n} else {\n grandTotal = null;\n}\n\n// Cr\u00e9er les items de sortie - un pour chaque item d'entr\u00e9e\nconst outputItems = items.map((item, index) => {\n const data = item.json;\n \n // V\u00e9rifier si CET item sp\u00e9cifique a une erreur de quantit\u00e9\n const quantite = data[\"Quantit\u00e9\"];\n const itemQuantiteError = !isValidPositiveNumber(quantite);\n \n return {\n json: {\n // Garder toutes les donn\u00e9es originales\n ...data,\n // Ajouter les informations de validation\n \"Grand Total\": grandTotal,\n \"Erreur\": erreur,\n \"Erreur item\": itemQuantiteError ? \"Erreur: Quantit\u00e9\" : null,\n // Ajouter la priorit\u00e9 finale\n \"FinalPriorit\u00e9\": finalPriorite\n }\n };\n});\n\nreturn outputItems;"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
976,
-32
],
"id": "989a86c4-8b3c-4853-9ebe-210f23f2c315",
"name": "Grand Total",
"alwaysOutputData": false
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "f15b795d-5689-46c7-9805-cc0c227d9e5c",
"leftValue": "={{ $json.Erreur }}",
"rightValue": "null",
"operator": {
"type": "string",
"operation": "notExists",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
1184,
-32
],
"id": "adb2e8f1-f546-4f71-a60f-2cc98e9c4a08",
"name": "If1"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "f15b795d-5689-46c7-9805-cc0c227d9e5c",
"leftValue": "={{ $json[\"Erreur item\"] }}",
"rightValue": "null",
"operator": {
"type": "string",
"operation": "notExists",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
1184,
256
],
"id": "c9e6c946-bb72-4596-a92d-e3559fcc06bb",
"name": "If2"
},
{
"parameters": {},
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [
1440,
192
],
"id": "9572b9ed-05fc-432c-abe7-b40641d95115",
"name": "No Operation, do nothing"
},
{
"parameters": {
"resource": "databasePage",
"operation": "update",
"pageId": {
"__rl": true,
"value": "={{ $json.id }}",
"mode": "id"
},
"propertiesUi": {
"propertyValues": [
{
"key": "Auto task|select",
"selectValue": "Erreur: Check Quantity"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
1440,
352
],
"id": "e03151f3-6e89-4ce4-80f7-cb10e9227de9",
"name": "Erreur Quaniti\u00e9",
"credentials": {
"notionApi": {
"name": "<your credential>"
}
},
"onError": "continueRegularOutput"
},
{
"parameters": {
"jsCode": "// ItemsID (robuste) \u2014 \"item i\" = \"Quantit\u00e9 X unitaire$\" (unitaire \u00e0 2 d\u00e9cimales)\n// + champs additionnels par i : Critici\u00e9 i, Consommable i, No Article i, Proc\u00e9d\u00e9 i, Name item i\n\nconst rows = $input.all();\nif (!rows.length) return [];\n\n// Parse tol\u00e9rant: enl\u00e8ve $/espaces, remplace virgule par point\nconst parseNum = (v) => {\n if (v === null || v === undefined || v === '') return null;\n const n = Number(String(v).replace(/\\s|\\$/g, '').replace(',', '.'));\n return Number.isFinite(n) ? n : null;\n};\n\n// Libell\u00e9 format\u00e9: \"Quantit\u00e9 X unitaire$\"\nconst fmt = (q, u) => {\n const nq = parseNum(q);\n const nu = parseNum(u);\n if (nq !== null && nu !== null) return `${nq} X ${nu.toFixed(2)}$`;\n if (nq !== null && nu === null) return `${nq}`;\n if (nq === null && nu !== null) return `${nu.toFixed(2)}$`;\n return 'Non sp\u00e9cifi\u00e9';\n};\n\n// Helper pour lire une propri\u00e9t\u00e9 tol\u00e9rante (top-level ou sous \"properties\")\nconst getProp = (r, key) =>\n r.json[key] ??\n (r.json.properties && r.json.properties[key]) ??\n null;\n\nconst increment = rows.length;\nconst itemsID = rows.map(r => r.json.id).filter(Boolean).join(', ');\n\nconst itemList = {};\nconst lienList = {};\nconst criticieList = {};\nconst consommableList = {};\nconst noArticleList = {};\nconst procedeList = {};\nconst nameItemList = {};\n\nrows.forEach((r, i) => {\n const y = i + 1;\n const qte = getProp(r, 'Quantit\u00e9');\n const unit = getProp(r, 'unitaire');\n const url = getProp(r, 'URL');\n\n // Champs additionnels (sources)\n const criticite = getProp(r, 'Criticit\u00e9');\n const consommable = getProp(r, '\ud83d\udd34Types de consommables');\n const noArticle = getProp(r, \"No d'article\");\n const procede = getProp(r, 'Proc\u00e9d\u00e9');\n const nomCommun = getProp(r, 'Nom Commun');\n\n // Sorties\n itemList[`item ${y}`] = fmt(qte, unit); // \"2 X 53.00$\" | \"2\" | \"53.00$\" | \"Non sp\u00e9cifi\u00e9\"\n lienList[`Lien ${y}`] = url || null;\n\n criticieList[`Critici\u00e9 ${y}`] = criticite ?? null;\n consommableList[`Consommable ${y}`] = consommable ?? null;\n noArticleList[`No Article ${y}`] = noArticle ?? null;\n procedeList[`Proc\u00e9d\u00e9 ${y}`] = procede ?? null;\n nameItemList[`Name item ${y}`] = nomCommun ?? null;\n});\n\nreturn [{\n json: {\n ...rows[0].json, // base\n increment,\n ItemsID: itemsID,\n // listes\n ...itemList,\n ...lienList,\n ...criticieList,\n ...consommableList,\n ...noArticleList,\n ...procedeList,\n ...nameItemList,\n }\n}];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1440,
-48
],
"id": "2f1e986b-1c06-40a3-b995-08a483c14e2c",
"name": "ItemsID"
},
{
"parameters": {
"resource": "databasePage",
"databaseId": {
"__rl": true,
"value": "{{NOTION_DB_ID_BONS_DE_COMMANDE_PO}}",
"mode": "list",
"cachedResultName": "Bons de Commande (PO)",
"cachedResultUrl": "https://www.notion.so/{{NOTION_DB_ID_BONS_DE_COMMANDE_PO}}"
},
"simple": false,
"propertiesUi": {
"propertyValues": [
{
"key": "Date cr\u00e9ation PO|date",
"includeTime": false,
"date": "={{ $now }}"
},
{
"key": "Total estim\u00e9|number",
"numberValue": "={{ $json[\"Grand Total\"] }}"
},
{
"key": "Num\u00e9ro PO|title",
"title": "PO"
},
{
"key": "Priorit\u00e9|select",
"selectValue": "={{ $json[\"FinalPriorit\u00e9\"] }}"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
1664,
-48
],
"id": "a03fde78-ad25-482a-af3d-8e6bd3e3b9c6",
"name": "Create PO page",
"executeOnce": false,
"credentials": {
"notionApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"method": "PATCH",
"url": "=https://api.notion.com/v1/pages/{{ $json.id }}",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "notionApi",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ \n JSON.stringify((() => {\n const ItemsIDs = $('ItemsID').item.json.ItemsID;\n const POName = 'PO' + '-' + $json.properties.Identifiant.unique_id.number;\n \n // Convertir la string en array d'objets pour Notion\n const relationArray = ItemsIDs\n .split(\", \") // S\u00e9parer par virgule-espace\n .map(id => ({ id: id.trim() })); // Cr\u00e9er un objet {id: \"...\"} pour chaque ID\n \n // Payload PATCH\n return {\n properties: {\n title: { \n title: [\n {\n type: \"text\",\n text: { content: POName }\n }\n ]\n }, \n oXxi: { relation: relationArray }\n }\n };\n })())\n}}",
"options": {
"batching": {
"batch": {
"batchSize": 1
}
}
}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1856,
-48
],
"id": "ff171e46-410e-49d8-9f9a-a8ef17708273",
"name": "HTTP Update PO",
"credentials": {
"notionApi": {
"name": "<your credential>"
}
},
"notes": "Demandes incluses : oXxi"
},
{
"parameters": {
"method": "PATCH",
"url": "=https://api.notion.com/v1/blocks/{{ $json.target_id }}/children",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "notionApi",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify($json.body) }}",
"options": {
"batching": {
"batch": {
"batchSize": 90
}
}
}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
2448,
-48
],
"id": "15db5ec2-6803-4ac7-bcf6-65b89e7cb11a",
"name": "HTTP To do PO",
"credentials": {
"notionApi": {
"name": "<your credential>"
}
},
"notes": "Demandes incluses : oXxi"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "1641a4b1-28d3-44de-ad3c-2669de3da543",
"name": "po_page_id",
"value": "={{ $json.id }}",
"type": "string"
},
{
"id": "535c7dc3-f3f5-4b7e-bee3-d197a4198555",
"name": "po_title",
"value": "={{ $json.properties[\"Num\u00e9ro PO\"].title[0].plain_text }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
2048,
-48
],
"id": "0321a5f2-bd5e-4939-a98c-c29be8b0a577",
"name": "Edit Fields"
},
{
"parameters": {
"jsCode": "// === CONFIG: remplace par les noms exacts de tes nodes ===\nconst NODE_ITEMS = 'ItemsID'; // node qui sort increment, ItemsID, item i, No Article i, Criticit\u00e9 i, Name item i, Proc\u00e9d\u00e9 i, Consommable i\nconst NODE_PO_CREATE = 'Create PO page'; // node Notion qui a cr\u00e9\u00e9 la page PO (pour r\u00e9cup\u00e9rer son id)\n\n// === UTILITAIRES ===\nconst SAFE_BATCH = 90;\nfunction chunk(arr, size) { const out=[]; for (let i=0;i<arr.length;i+=size) out.push(arr.slice(i,i+size)); return out; }\n\nfunction buildHeadingExact(text) {\n return {\n object: \"block\",\n type: \"heading_2\",\n heading_2: { rich_text: [{ type: \"text\", text: { content: text } }], is_toggleable: false }\n };\n}\n\n// Ach\u00e2t \u2014 3 colonnes : 1) lien consommable (mention page), 2) item i, 3) \"Criticit\u00e9 : <valeur>\" si non vide\nfunction buildToDoAchat(relId, label, criticite, fallbackFirstColText) {\n const rt = [];\n\n // Colonne 1 : lien consommable (mention page si possible)\n if (relId) {\n rt.push({ type: \"mention\", mention: { type: \"page\", page: { id: relId } } });\n } else if (fallbackFirstColText && String(fallbackFirstColText).trim() !== '') {\n rt.push({ type: \"text\", text: { content: String(fallbackFirstColText).trim() } });\n } else {\n rt.push({ type: \"text\", text: { content: \" \" } });\n }\n\n // Colonne 2 : item (i)\n const col2 = (label && String(label).trim()) ? String(label).trim() : '';\n if (col2 !== '') {\n rt.push({ type: \"text\", text: { content: \" \u2014 \" } });\n rt.push({ type: \"text\", text: { content: col2 } });\n }\n\n // Colonne 3 : \"Criticit\u00e9 : <valeur>\" uniquement si valeur non vide\n const c = (criticite !== null && criticite !== undefined) ? String(criticite).trim() : '';\n if (c !== '') {\n rt.push({ type: \"text\", text: { content: \" \u2014 \" } });\n rt.push({ type: \"text\", text: { content: \"Criticit\u00e9 : \" } });\n rt.push({ type: \"text\", text: { content: c } });\n }\n\n return { object: \"block\", type: \"to_do\", to_do: { rich_text: rt, checked: false } };\n}\n\n// Ligne sous Ach\u00e2t : \"<NoArticle | Lien i> -> URL\" ; si NoArticle vide, utiliser \"Lien i\"\nfunction buildAchatLinkLine(i, noArticle, url) {\n const u = (url && String(url).trim() !== '') ? String(url).trim() : '';\n if (u === '') return null;\n const art = (noArticle !== null && noArticle !== undefined) ? String(noArticle).trim() : '';\n const label = (art !== '') ? art : `Lien ${i}`;\n return {\n object: \"block\",\n type: \"paragraph\",\n paragraph: {\n rich_text: [\n { type: \"text\", text: { content: `${label} -> ` } },\n { type: \"text\", text: { content: u, link: { url: u } } }\n ]\n }\n };\n}\n\n// Reception \u2014 2 colonnes : 1) Name item i, 2) Proc\u00e9d\u00e9 i (si non vide)\nfunction buildToDoReception(nameItem, procede) {\n const rt = [];\n const col1 = (nameItem && String(nameItem).trim()) ? String(nameItem).trim() : '';\n const col2 = (procede && String(procede).trim()) ? String(procede).trim() : '';\n if (col1 !== '') rt.push({ type: \"text\", text: { content: col1 } });\n if (col2 !== '') {\n if (rt.length > 0) rt.push({ type: \"text\", text: { content: \" \u2014 \" } });\n rt.push({ type: \"text\", text: { content: col2 } });\n }\n if (rt.length === 0) rt.push({ type: \"text\", text: { content: \" \" } });\n return { object: \"block\", type: \"to_do\", to_do: { rich_text: rt, checked: false } };\n}\n\n// Ligne sous Reception : valeur seule de \"Consommable i\" (sans libell\u00e9)\nfunction buildConsommableValueLine(value) {\n const v = (value !== null && value !== undefined) ? String(value).trim() : '';\n if (v === '') return null;\n return { object: \"block\", type: \"paragraph\", paragraph: { rich_text: [{ type: \"text\", text: { content: v } }] } };\n}\n\n// === R\u00c9CUP DES DONN\u00c9ES EN AMONT ===\nconst itemsNodeItems = $(NODE_ITEMS).all();\nif (!itemsNodeItems.length) throw new Error('Aucun output du node ItemsID');\nconst base = itemsNodeItems[0].json;\n\nconst poCreate = $(NODE_PO_CREATE).item.json || {};\nconst poId = poCreate.id || base.po_page_id;\nif (!poId) throw new Error('ID de la page PO introuvable. V\u00e9rifie NODE_PO_CREATE.id ou base.po_page_id');\n\n// === NOMBRE D\u2019ITEMS & IDs de pages consommables ===\nconst ids = (base.ItemsID || '').split(',').map(s => s.trim()).filter(Boolean);\nlet inc = Number(base.increment) || 0;\nif (!inc) {\n const itemKeys = Object.keys(base).filter(k => /^item\\s+\\d+$/i.test(k));\n inc = Math.max(ids.length, itemKeys.length, 0);\n}\n\n// === CONSTRUCTION DES BLOCS ===\nconst blocks = [];\n\n// Titres EXACTS\nblocks.push(buildHeadingExact('Ach\u00e2t'));\n\nfor (let i = 1; i <= inc; i++) {\n const label = base[`item ${i}`]; // \"35 X 56.00$\"\n const criticite = base[`Criticit\u00e9 ${i}`] ?? base[`Critici\u00e9 ${i}`]; // garder vide si absent\n const noArticle = base[`No Article ${i}`];\n const nameItem = base[`Name item ${i}`];\n const url = base[`Lien ${i}`] || null;\n const relId = ids[i - 1] || null;\n\n // Ach\u00e2t \u2014 to_do (3 colonnes, Criticit\u00e9 avec son libell\u00e9 si pr\u00e9sent)\n const firstColFallback = nameItem || '';\n blocks.push(buildToDoAchat(relId, label, criticite ?? '', firstColFallback));\n\n // Sous Ach\u00e2t : \"<NoArticle | Lien i> -> URL\" (si URL pr\u00e9sent)\n const linkLine = buildAchatLinkLine(i, noArticle, url);\n if (linkLine) blocks.push(linkLine);\n}\n\nblocks.push(buildHeadingExact('Reception'));\n\nfor (let i = 1; i <= inc; i++) {\n const nameItem = base[`Name item ${i}`] ?? '';\n const procede = base[`Proc\u00e9d\u00e9 ${i}`] ?? '';\n const consommable = base[`Consommable ${i}`] ?? '';\n\n // Reception \u2014 to_do (2 colonnes)\n blocks.push(buildToDoReception(nameItem, procede));\n\n // Sous Reception : valeur de Consommable i (sans libell\u00e9)\n const consLine = buildConsommableValueLine(consommable);\n if (consLine) blocks.push(consLine);\n}\n\n// === BATCHING \u2192 1 item / requ\u00eate append ===\nconst batches = chunk(blocks, SAFE_BATCH);\nreturn batches.map(batch => ({ json: { target_id: poId, body: { children: batch } } }));\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2256,
-48
],
"id": "5341404f-1e21-4727-8a3f-f774806d6e35",
"name": "Liste To do"
},
{
"parameters": {},
"type": "n8n-nodes-base.merge",
"typeVersion": 3.2,
"position": [
2480,
416
],
"id": "b2aebef6-1bfb-4a85-877f-f6976f051d52",
"name": "Merge"
},
{
"parameters": {
"resource": "databasePage",
"operation": "update",
"pageId": {
"__rl": true,
"value": "={{ $('Edit Demande').item.json.id }}",
"mode": "id"
},
"propertiesUi": {
"propertyValues": [
{
"key": "\ud83d\udd34Statut demande|status",
"statusValue": "En cours"
},
{
"key": "PO Cr\u00e9er|checkbox",
"checkboxValue": true
}
]
},
"options": {}
},
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
2688,
416
],
"id": "17bb7cc7-2e2f-40b7-96b6-de2ed61771ba",
"name": "Update Demandes",
"credentials": {
"notionApi": {
"name": "<your credential>"
}
},
"onError": "continueRegularOutput"
},
{
"parameters": {
"options": {
"reset": true
}
},
"type": "n8n-nodes-base.splitInBatches",
"typeVersion": 3,
"position": [
-64,
-48
],
"id": "539d1d8d-f613-4f97-82f4-36234407960c",
"name": "Loop Over Items"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "79c90d27-697d-4a50-9280-7e1be6be47c4",
"leftValue": "={{ $json.isFirstResponsable }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
512,
-32
],
"id": "1f862375-8c13-4a86-8f37-6ec7dc6bd00a",
"name": "If3"
},
{
"parameters": {},
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [
768,
160
],
"id": "ac312be6-73a1-4de2-be76-5bf53c0faf9f",
"name": "No Operation, do nothing1"
},
{
"parameters": {
"jsCode": "// R\u00e9cup\u00e9rer tous les items d'entr\u00e9e\nconst items = $input.all();\n\nif (items.length === 0) {\n return [{ json: { message: \"Aucun item \u00e0 traiter\" } }];\n}\n\n// Trouver le premier responsable (premier item qui a un responsable d\u00e9fini)\nlet firstResponsable = null;\n\nfor (let item of items) {\n if (item.json.properties && \n item.json.properties[\"\ud83d\udd34Responsable achat\"] && \n item.json.properties[\"\ud83d\udd34Responsable achat\"].rich_text && \n item.json.properties[\"\ud83d\udd34Responsable achat\"].rich_text[0] && \n item.json.properties[\"\ud83d\udd34Responsable achat\"].rich_text[0].plain_text) {\n firstResponsable = item.json.properties[\"\ud83d\udd34Responsable achat\"].rich_text[0].plain_text;\n break; // Arr\u00eater d\u00e8s qu'on trouve le premier\n }\n}\n\n// Retourner TOUS les items avec une constante bool\u00e9enne\nreturn items.map((item, index) => {\n // Extraire le responsable de cet item\n let itemResponsable = null;\n if (item.json.properties && \n item.json.properties[\"\ud83d\udd34Responsable achat\"] && \n item.json.properties[\"\ud83d\udd34Responsable achat\"].rich_text && \n item.json.properties[\"\ud83d\udd34Responsable achat\"].rich_text[0] && \n item.json.properties[\"\ud83d\udd34Responsable achat\"].rich_text[0].plain_text) {\n itemResponsable = item.json.properties[\"\ud83d\udd34Responsable achat\"].rich_text[0].plain_text;\n }\n \n return {\n json: {\n ...item.json,\n isFirstResponsable: itemResponsable === firstResponsable\n }\n };\n});"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
320,
-32
],
"id": "16730c70-02c7-4916-80f0-b8a428ec088d",
"name": "Assign responsable"
},
{
"parameters": {
"content": "## Webhook Notion trigger de la base Demande d'achat\n**Double click** to edit me. [Guide](https://docs.n8n.io/workflows/sticky-notes/)",
"height": 256,
"width": 592,
"color": 6
},
"type": "n8n-nodes-base.stickyNote",
"position": [
-1200,
-112
],
"typeVersion": 1,
"id": "fa945f45-4239-4dff-8c09-442f2df8bd77",
"name": "Sticky Note"
},
{
"parameters": {
"content": "## Scan des demandes et regroupements par PO\n**Double click** to edit me. [Guide](https://docs.n8n.io/workflows/sticky-notes/)",
"height": 736,
"width": 1744,
"color": 5
},
"type": "n8n-nodes-base.stickyNote",
"position": [
-608,
-112
],
"typeVersion": 1,
"id": "c0de9f63-1d99-4591-aa9a-3407cfdf7286",
"name": "Sticky Note1"
},
{
"parameters": {
"content": "## Productions des PO par reponsable\n**Double click** to edit me. [Guide](https://docs.n8n.io/workflows/sticky-notes/)",
"height": 736,
"width": 1744,
"color": 4
},
"type": "n8n-nodes-base.stickyNote",
"position": [
1136,
-112
],
"typeVersion": 1,
"id": "fa813be8-f561-48f8-9c23-7cf74fcfb2a1",
"name": "Sticky Note2"
}
],
"connections": {
"WorkFlow07": {
"main": [
[
{
"node": "Log Meta (expressions)",
"type": "main",
"index": 0
}
]
]
},
"If": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
],
[
{
"node": "Update Erreur",
"type": "main",
"index": 0
}
]
]
},
"Log Meta (expressions)": {
"main": [
[
{
"node": "Start Log",
"type": "main",
"index": 0
}
]
]
},
"Start Log": {
"main": [
[
{
"node": "Edit Webhook",
"type": "main",
"index": 0
}
]
]
},
"Edit Webhook": {
"main": [
[
{
"node": "If",
"type": "main",
"index": 0
}
]
]
},
"Get Demande Achat": {
"main": [
[
{
"node": "Assign responsable",
"type": "main",
"index": 0
}
]
]
},
"Edit Demande": {
"main": [
[
{
"node": "Grand Total",
"type": "main",
"index": 0
},
{
"node": "Merge",
"type": "main",
"index": 0
}
]
]
},
"Grand Total": {
"main": [
[
{
"node": "If1",
"type": "main",
"index": 0
}
]
]
},
"If1": {
"main": [
[
{
"node": "ItemsID",
"type": "main",
"index": 0
}
],
[
{
"node": "If2",
"type": "main",
"index": 0
}
]
]
},
"If2": {
"main": [
[
{
"node": "No Operation, do nothing",
"type": "main",
"index": 0
}
],
[
{
"node": "Erreur Quaniti\u00e9",
"type": "main",
"index": 0
}
]
]
},
"ItemsID": {
"main": [
[
{
"node": "Create PO page",
"type": "main",
"index": 0
}
]
]
},
"Create PO page": {
"main": [
[
{
"node": "HTTP Update PO",
"type": "main",
"index": 0
}
]
]
},
"HTTP Update PO": {
"main": [
[
{
"node": "Edit Fields",
"type": "main",
"index": 0
}
]
]
},
"Edit Fields": {
"main": [
[
{
"node": "Liste To do",
"type": "main",
"index": 0
}
]
]
},
"Liste To do": {
"main": [
[
{
"node": "HTTP To do PO",
"type": "main",
"index": 0
}
]
]
},
"HTTP To do PO": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
}
]
]
},
"Merge": {
"main": [
[
{
"node": "Update Demandes",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[],
[
{
"node": "Get Demande Achat",
"type": "main",
"index": 0
}
]
]
},
"Update Demandes": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"If3": {
"main": [
[
{
"node": "Edit Demande",
"type": "main",
"index": 0
}
],
[
{
"node": "No Operation, do nothing1",
"type": "main",
"index": 0
}
]
]
},
"Assign responsable": {
"main": [
[
{
"node": "If3",
"type": "main",
"index": 0
}
]
]
}
},
"active": true,
"settings": {
"executionOrder": "v1"
},
"versionId": "566f2d1e-da90-4f5d-bcb1-6d2ef1f4ef5e",
"meta": {
"templateCredsSetupCompleted": true
},
"id": "PJf5ViYz9Yoo3rJb",
"tags": [
{
"updatedAt": "2025-09-12T22:39:32.525Z",
"createdAt": "2025-09-12T22:39:32.525Z",
"id": "ob1iUzBDY4oAYrZ0",
"name": "Achat"
},
{
"updatedAt": "2025-09-16T22:04:01.439Z",
"createdAt": "2025-09-16T22:04:01.439Z",
"id": "RdtIHOQokgm6xJPW",
"name": "Semi-Auto"
}
]
}
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.
notionApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
WorkFlow 07. Uses notion, httpRequest. Webhook trigger; 28 nodes.
Source: https://github.com/WealthFinPilot/notion-qms-platform/blob/main/exports/workflows/wf-07-regroupement-achat-po-sur-demande.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.
This workflow automates the entire lifecycle of a service-based client, combining four distinct business flows into a single view: Intake Leads: Receives a webhook from your form builder, validates th
This solution enables you to manage all your Notion and Todoist tasks from different workspaces as well as your calendar events in a single place. This is 2 way sync with partial support for recurring