My current Problem 
[Disclaimer: I’m very new to n8n!]
I have a workflow that looks up users via HTTP Request to an external API (Clerk). Before, I just needed to know if they actually were customers of mine.
I did that using this expression: {{ $(‘Clerk Lookup’).all().length > 0 }}
That way if a User Object was returned, this was my “True” Path that I continued with downstream.
Now I actually want to handle the Users who are non-Customers (=NOT in my Clerk DB). Therefore I’m looking for a way to not only filter out the existing customers but also make the Data of the non-customers available downstream because I want to send them an email. This is where I am currently completely lost. (The middle part of the workflow, right after the two Clerk Lookup Nodes)
Fyi: I want to stick with the HTTP Request node because I can use n8n’s inbuilt Credentials features, with the Code Node I would have to hard-code my Clerk.com API (I believe).
{
"nodes": [
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "aa375f4d-1152-4bca-b059-f7a889d44fca",
"leftValue": "={{ $json.Punkte }}",
"rightValue": 7,
"operator": {
"type": "number",
"operation": "gte"
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
220,
0
],
"id": "00ad52a2-7a8d-4a51-bb6f-59c9215db92f",
"name": "If"
},
{
"parameters": {
"url": "={{$json[\"render_url\"]}}",
"options": {
"response": {
"response": {
"responseFormat": "file",
"outputPropertyName": "=data"
}
}
}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1360,
-280
],
"id": "ee3ada3f-f187-4138-9474-7c05c4eaabda",
"name": "Download PDF"
},
{
"parameters": {
"method": "POST",
"url": "https://api.templated.io/v1/render",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer YOUR_TOKEN_HERE"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"template\": \"f7a62531-9bb8-4119-b421-d16e8bb8360c\",\n \"format\": \"pdf\",\n \"layers\": {\n \"name\": { \"text\": \"{{ $json['Dein Name (erscheint auf dem Zertifikat) '] }}\" },\n \"title\": { \"text\": \"{{ $json['Fortbildungstitel'] }}\" },\n \"date\": { \"text\": \"{{ $json['Zeitstempel'].split(' ')[0] }}\" }\n }\n}",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1160,
-280
],
"id": "8eb324dc-13ec-476b-abe8-2b7d07e2100f",
"name": "Create PDF"
},
{
"parameters": {
"fromEmail": " <[email protected]>"
"toEmail": "={{ $('Merge').item.json['Deine Email-Adresse'] }}",
"subject": "Versuch's nochmal! ",
"emailFormat": "text",
"text": "Hey,\n\nDu hast leider die Mindestpunktzahl von 7/10 nicht erreicht. 🥲\n\nVersuch's einfach nochmal - bin sicher, dass es diesmal klappt! 😋",
"options": {
"appendAttribution": false
}
},
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2.1,
"position": [
400,
580
],
"id": "bff58a61-ca80-4835-b1fb-514b0eb8f444",
"name": "Nicht bestanden Email",
"webhookId": "c01e0664-d220-42a4-a8e5-da1904da5b2c",
"credentials": {
"smtp": {
"id": "AcJw452tbxtY5muD",
"name": "SMTP account"
}
},
"disabled": true
},
{
"parameters": {
"fromEmail": " <[email protected]>",
"toEmail": "={{ $('Merge1').item.json['Deine Email-Adresse'] }}",
"subject": "Hier ist Dein Zertifikat! 📄🎖️",
"html": "Yay! Du hast das CME-Quiz bestanden! 🥳\n\nIm Anhang findest Du das Zertifikat zum Herunterladen ⬇️",
"options": {
"appendAttribution": false,
"attachments": "=data"
}
},
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2.1,
"position": [
1740,
-280
],
"id": "234bf9b0-a539-4282-9d3b-8cd9b7598932",
"name": "Bestanden Email",
"webhookId": "3dda19e8-f145-44be-afa5-3b1eacdcfcc7",
"credentials": {
"smtp": {
"id": "AcJw452tbxtY5muD",
"name": "SMTP account"
}
}
},
{
"parameters": {
"url": "https://api.clerk.com/v1/users",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "email_address",
"value": "={{ $json['Deine Email-Adresse'] }}"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
480,
-20
],
"id": "7b4a4f86-efbb-4607-950e-93085e5a054b",
"name": "Clerk Lookup",
"alwaysOutputData": true,
"credentials": {
"httpHeaderAuth": {
"id": "swBdRbw3i8CwGhkk",
"name": "Header Auth account"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "20bdc076-bf81-437a-aa8f-d509ea54a730",
"leftValue": "={{ $json.id ? 1 : 0 }}",
"rightValue": 0,
"operator": {
"type": "number",
"operation": "gt"
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
700,
80
],
"id": "19397c5f-9f7c-4a50-9627-ea66704ee7b0",
"name": "If1",
"alwaysOutputData": false
},
{
"parameters": {
"method": "PATCH",
"url": "=https://api.clerk.com/v1/users/{{$json.userId}}",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ $json.patch }}",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1800,
80
],
"id": "1990ee1a-1e1a-4149-9d29-6d932cd5062d",
"name": "HTTP Request",
"credentials": {
"httpHeaderAuth": {
"id": "swBdRbw3i8CwGhkk",
"name": "Header Auth account"
}
}
},
{
"parameters": {
"numberInputs": 10
},
"type": "n8n-nodes-base.merge",
"typeVersion": 3.1,
"position": [
0,
0
],
"id": "52cdef6b-cccd-481c-a0dc-11d1b329ea7b",
"name": "Merge"
},
{
"parameters": {
"content": "## Clerk DB Update\n\n- Patched das Clerk User Object mit den Änderungen aus dem Prepare Clerk Update Node (+2 CME Punkte)",
"height": 180,
"width": 230
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
1760,
220
],
"id": "2e187d97-4ad1-48f0-8855-dee2477e6ce3",
"name": "Sticky Note"
},
{
"parameters": {
"mode": "combine",
"combineBy": "combineByPosition",
"options": {}
},
"type": "n8n-nodes-base.merge",
"typeVersion": 3.1,
"position": [
960,
-380
],
"id": "a5b1ef2f-a46d-4761-9aeb-7b6ca2edf542",
"name": "Merge1"
},
{
"parameters": {
"jsCode": "// Flip gmail.com ↔ googlemail.com for all input items\nconst items = [];\n\nfor (const item of $input.all()) {\n const email = item.json['Deine Email-Adresse'];\n \n if (email.includes('@gmail.com') || email.includes('@googlemail.com')) {\n const flippedEmail = email.includes('@gmail.com') \n ? email.replace('@gmail.com', '@googlemail.com')\n : email.replace('@googlemail.com', '@gmail.com');\n \n console.log(`Flipping email from \"${email}\" to \"${flippedEmail}\"`);\n \n items.push({ \n json: { \n ...item.json, \n 'Deine Email-Adresse': flippedEmail \n } \n });\n } else {\n // Not a gmail variant, return original\n items.push({ json: item.json });\n }\n}\n\nreturn items;"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
420,
240
],
"name": "Email Flip",
"id": "cfe5a9e3-6025-4184-a65d-b4bab605eb26"
},
{
"parameters": {
"url": "https://api.clerk.com/v1/users",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "email_address",
"value": "={{ $json['Deine Email-Adresse'] }}"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
560,
240
],
"name": "Clerk Lookup 2",
"id": "7c07346a-ad53-4e4a-b5ef-e23a80d1ef8d",
"alwaysOutputData": true,
"credentials": {
"httpHeaderAuth": {
"id": "swBdRbw3i8CwGhkk",
"name": "Header Auth account"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "user-found-condition-2",
"leftValue": "={{ Object.keys($json).length }}",
"rightValue": 0,
"operator": {
"type": "number",
"operation": "gt"
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
700,
240
],
"name": "If User Found 2",
"id": "857fde85-8ba9-4e29-8998-4f4d485713a6"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "13bfa4b9-aa31-4b4b-bf7d-83c83efe8c86",
"name": "Dein Name (erscheint auf dem Zertifikat) ",
"value": "={{ $json['Dein Name (erscheint auf dem Zertifikat)'] }}",
"type": "string"
},
{
"id": "ee00b96a-1c22-42a2-a5c1-3a8035754251",
"name": "Deine Email-Adresse",
"value": "={{ $json['Deine Email-Adresse'].trim() }}",
"type": "string"
},
{
"id": "acaa6909-25be-405a-8a33-61a0961b4d07",
"name": "Fortbildungstitel",
"value": "={{ $json.Fortbildungstitel }}",
"type": "string"
},
{
"id": "31241ed1-8cdb-4ce6-a759-8524d64018e4",
"name": "Punkte",
"value": "={{ $json.Punkte }}",
"type": "number"
},
{
"id": "d18e3708-7436-4f8e-b1e2-e00c0fc2b9e6",
"name": "Zeitstempel",
"value": "={{ $json.Zeitstempel }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
-400,
160
],
"id": "69873a73-7698-42c4-89ae-0b1b941dd8cf",
"name": "Edit Fields4"
},
{
"parameters": {
"jsCode": "// Deduplicate Clerk user objects within the incoming items (across branches).\n// Keeps only the first occurrence of every unique user.id.\n\nconst seenIds = new Set();\nconst outputItems = [];\n\nfor (const item of $input.all()) {\n const users = Array.isArray(item.json) ? item.json : [item.json];\n\n for (const user of users) {\n const id = user && user.id;\n if (id && !seenIds.has(id)) {\n seenIds.add(id);\n outputItems.push({ json: user });\n }\n }\n}\n\nreturn outputItems;"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1160,
80
],
"id": "877e116d-2e11-415a-8e4f-b8256e6035bb",
"name": "Deduplicate Users",
"alwaysOutputData": false
},
{
"parameters": {},
"type": "n8n-nodes-base.merge",
"typeVersion": 3.1,
"position": [
1020,
80
],
"id": "c0b47d67-d45a-4b10-936b-a23ab628de30",
"name": "Merge2"
},
{
"parameters": {
"jsCode": "// Build incremental Clerk PATCH payload (+2 CME points)\n// Input: full Clerk user object (from Deduplicate Users)\n// Output: { userId, patch }\n\nconst user = $json;\nconst currentPM = user.private_metadata || {};\nconst currentCP = currentPM.cmePoints || {};\nconst newPoints = (currentCP.internal || 0) + 2;\n\nreturn [{\n json: {\n userId: user.id,\n patch: {\n private_metadata: {\n ...currentPM,\n cmePoints: {\n ...currentCP,\n internal: newPoints,\n },\n },\n },\n },\n}];"
},
"id": "302634c2-3d35-447d-87a3-3640e463fd46",
"name": "Prepare Clerk Update",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1420,
80
]
},
{
"parameters": {
"content": "## Prepare Clerk Update\n\n- Nimmt das Clerk-User-Objekt entgegen\n- Liest vorhandene private_metadata.cmePoints.internal\n- Addiert +2 (oder setzt auf 2, falls noch nicht vorhanden)\n- Baut einen kompakten PATCH-Body (json.patch) der _nur_ dieses Feld aktualisiert, ohne andere Felder zu überschreiben\n- Liefert außerdem die userId – beides geht an den HTTP-Request-Node",
"height": 340,
"width": 300
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
1340,
220
],
"id": "81329b7d-9726-4fa1-84eb-a2b6e634d7ab",
"name": "Sticky Note4"
},
{
"parameters": {
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
},
"documentId": {
"__rl": true,
"value": "1VMEDmBNQXlhgMwK_mzkbiw4InQ8kBGanybs37K7zwPM",
"mode": "list",
"cachedResultName": "🎖️TL-CME-Quiz-Results",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1VMEDmBNQXlhgMwK_mzkbiw4InQ8kBGanybs37K7zwPM/edit?usp=drivesdk"
},
"sheetName": {
"__rl": true,
"value": 1528782937,
"mode": "list",
"cachedResultName": "Testtabelle(tobedeleted)",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1VMEDmBNQXlhgMwK_mzkbiw4InQ8kBGanybs37K7zwPM/edit#gid=1528782937"
},
"event": "rowAdded",
"options": {}
},
"type": "n8n-nodes-base.googleSheetsTrigger",
"typeVersion": 1,
"position": [
-600,
160
],
"id": "7efc5a62-d72a-468a-9f06-0432d4b69e2f",
"name": "Testtabelle",
"credentials": {
"googleSheetsTriggerOAuth2Api": {
"id": "fJADkBxk1SlYdgQN",
"name": "Google Sheets Trigger account"
}
}
},
{
"parameters": {
"content": "## LATEST FIX:\n\nRun for each item eingestellt → Error (muss daher auf Once For All eingestellt bleiben)"
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
1360,
-40
],
"id": "5cf61892-57bc-4246-bb09-e2396619db05",
"name": "Sticky Note5"
}
],
"connections": {
"If": {
"main": [
[
{
"node": "Clerk Lookup",
"type": "main",
"index": 0
},
{
"node": "Email Flip",
"type": "main",
"index": 0
}
],
[
{
"node": "Nicht bestanden Email",
"type": "main",
"index": 0
}
]
]
},
"Download PDF": {
"main": [
[]
]
},
"Create PDF": {
"main": [
[
{
"node": "Download PDF",
"type": "main",
"index": 0
}
]
]
},
"Clerk Lookup": {
"main": [
[
{
"node": "If1",
"type": "main",
"index": 0
}
]
]
},
"If1": {
"main": [
[
{
"node": "Merge2",
"type": "main",
"index": 0
}
],
[]
]
},
"Merge": {
"main": [
[
{
"node": "If",
"type": "main",
"index": 0
},
{
"node": "Merge1",
"type": "main",
"index": 0
}
]
]
},
"Merge1": {
"main": [
[
{
"node": "Create PDF",
"type": "main",
"index": 0
}
]
]
},
"Email Flip": {
"main": [
[
{
"node": "Clerk Lookup 2",
"type": "main",
"index": 0
}
]
]
},
"Clerk Lookup 2": {
"main": [
[
{
"node": "If User Found 2",
"type": "main",
"index": 0
}
]
]
},
"If User Found 2": {
"main": [
[
{
"node": "Merge2",
"type": "main",
"index": 1
}
]
]
},
"Edit Fields4": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 9
}
]
]
},
"Deduplicate Users": {
"main": [
[
{
"node": "Merge1",
"type": "main",
"index": 1
},
{
"node": "Prepare Clerk Update",
"type": "main",
"index": 0
}
]
]
},
"Merge2": {
"main": [
[
{
"node": "Deduplicate Users",
"type": "main",
"index": 0
}
]
]
},
"Prepare Clerk Update": {
"main": [
[
{
"node": "HTTP Request",
"type": "main",
"index": 0
}
]
]
},
"Testtabelle": {
"main": [
[
{
"node": "Edit Fields4",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {},
"meta": {
"templateCredsSetupCompleted": true,
"instanceId": "2b303379e16742056ad8f3cf60b01791e2b69b655811816a953611fd1a1c72c9"
}
}
I’m still very new to automating and n8n, I even built a custom MCP Server to help me create workflows using natural language (Cursor/Claude). But even o3 Pro wasn’t able to figure out this specific problem, it often hallucinates abilities of certain nodes.
I’m using the Cloud version of n8n (v. 1.93.x)