This workflow follows the Chainllm → 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": "My workflow",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "/grade-card",
"responseMode": "responseNode",
"options": {}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [
-208,
-64
],
"id": "8e1b0603-a85a-407d-b490-064a3738e6ca",
"name": "Webhook"
},
{
"parameters": {
"numberInputs": 4
},
"type": "n8n-nodes-base.merge",
"typeVersion": 3.2,
"position": [
-16,
512
],
"id": "8a63f0b7-6c7c-4dd8-bf67-52922cc9a0b6",
"name": "Merge"
},
{
"parameters": {
"options": {}
},
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.5,
"position": [
640,
1120
],
"id": "286b4388-b5f6-423f-9f28-45ecb85485d7",
"name": "Respond to Webhook"
},
{
"parameters": {
"model": {
"__rl": true,
"value": "claude-haiku-4-5-20251001",
"mode": "list",
"cachedResultName": "Claude Haiku 4.5"
},
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"typeVersion": 1.3,
"position": [
768,
800
],
"id": "d3343a40-aca9-4244-a3df-f368a6fe0793",
"name": "Anthropic Chat Model",
"credentials": {
"anthropicApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"model": {
"__rl": true,
"value": "claude-haiku-4-5-20251001",
"mode": "list",
"cachedResultName": "Claude Haiku 4.5"
},
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"typeVersion": 1.3,
"position": [
640,
832
],
"id": "b1c2d3e4-f5a6-7890-abcd-ef1234567890",
"name": "Anthropic Chat Model 2",
"credentials": {
"anthropicApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"method": "POST",
"url": "=http://backend:8000/agents/crop",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "file_path",
"value": "={{ $json.body.saved_path }}"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
64,
16
],
"id": "c4c83424-af2e-49ae-aa53-f05e73f1ed5d",
"name": "Preprocessing"
},
{
"parameters": {
"method": "POST",
"url": "http://backend:8000/agents/centering",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "file_path",
"value": "={{ $json.cropped_path }}"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
-352,
304
],
"id": "0c605c7d-5208-44e9-a13b-eb8372808ec9",
"name": "centering agent"
},
{
"parameters": {
"method": "POST",
"url": "http://backend:8000/agents/corner",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "file_path",
"value": "={{ $json.cropped_path }}"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
0,
288
],
"id": "9b5c9ab8-401c-4612-86c2-e3f8108cfc3b",
"name": "corner agent"
},
{
"parameters": {
"method": "POST",
"url": "http://backend:8000/agents/edge",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "file_path",
"value": "={{ $json.cropped_path }}"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
720,
208
],
"id": "fad13dce-ca32-4bbf-ac7b-bd269ed27bf0",
"name": "edge agent"
},
{
"parameters": {
"promptType": "define",
"text": "=Be generous with surface_score. Minor scuffs, small scratches, or light\n print lines that do not significantly affect the card's appearance should\n still score 9.0 or above. Only score below 6 if there are clear, prominent\n defects visible to the naked eye.\n\n Respond in raw JSON only, no markdown:\n {\"surface_score\": <0-10>, \"defects_found\": [\"...\"], \"reasoning\": \"...\"}\n\n Scoring: 10=Gem Mint 8-9=Near Mint 6-7=Excellent 4-5=VG 0-3=Poor\n\n Image (base64): {{ $json.cropped_image }}",
"batching": {}
},
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"typeVersion": 1.9,
"position": [
416,
304
],
"id": "a5195c47-22f8-49e9-828d-8d5ab1e07f66",
"name": "surface agent"
},
{
"parameters": {
"promptType": "define",
"text": "=You are a trading card price analyst (Pokemon, Magic: The Gathering, Yu-Gi-Oh, sports cards, etc.).\n\nCard hint: {{ $json.card_name_hint || \"Unknown\" }}{{ $json.card_set_hint ? \" | Set: \" + $json.card_set_hint : \"\" }}\nPSA Grade: {{ $json.estimated_psa_grade }}\n\nIf the card name has a typo, correct it and use the closest matching real card.\nProvide estimated market price range in USD for this card at this PSA grade.\n\nRespond in raw JSON only \u2014 no markdown, no extra text, nothing after the closing brace:\n{\"card_name\":\"<corrected name>\",\"card_set\":\"<set or empty>\",\"card_number\":\"<e.g. 4/102 or empty>\",\"price_low\":<number>,\"price_mid\":<number>,\"price_high\":<number>,\"currency\":\"USD\"}",
"batching": {}
},
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"typeVersion": 1.9,
"position": [
384,
928
],
"id": "f1e2d3c4-b5a6-7890-1234-abcdef567890",
"name": "price lookup"
},
{
"parameters": {
"method": "POST",
"url": "http://backend:8000/analysis/save",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "unique_filename",
"value": "={{ $json.unique_filename }}"
},
{
"name": "original_filename",
"value": "={{ $json.original_filename }}"
},
{
"name": "file_path",
"value": "={{ $json.file_path }}"
},
{
"name": "corner_score",
"value": "={{ $json.corner_score }}"
},
{
"name": "surface_score",
"value": "={{ $json.surface_score }}"
},
{
"name": "centering_score",
"value": "={{ $json.centering_score }}"
},
{
"name": "overall_score",
"value": "={{ $json.overall_score }}"
},
{
"name": "estimated_psa_grade",
"value": "={{ $json.estimated_psa_grade }}"
},
{
"name": "recommend_submit",
"value": "={{ $json.recommend_submit }}"
},
{
"name": "recommendation_reason",
"value": "={{ $json.recommendation_reason }}"
},
{
"name": "edge_score",
"value": "={{ $json.edge_score }}"
},
{
"name": "card_name",
"value": "={{ $json.card_name }}"
},
{
"name": "card_set",
"value": "={{ $json.card_set }}"
},
{
"name": "card_number",
"value": "={{ $json.card_number }}"
},
{
"name": "price_low",
"value": "={{ $json.price_low }}"
},
{
"name": "price_mid",
"value": "={{ $json.price_mid }}"
},
{
"name": "price_high",
"value": "={{ $json.price_high }}"
},
{
"name": "price_currency",
"value": "={{ $json.price_currency }}"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
-48,
1120
],
"id": "8cbaca08-b99f-41b5-961f-ef9255987360",
"name": "save database"
},
{
"parameters": {
"jsCode": "const webhookBody = $('Webhook').first().json.body;\n const uniqueFilename = webhookBody.unique_filename || '';\n const originalFilename = webhookBody.original_filename || '';\n const savedPath = webhookBody.saved_path || '';\n const cardNameHint = webhookBody.card_name_hint || '';\n const cardSetHint = webhookBody.card_set_hint || '';\n\n const all = $input.all();\n const centering = all[0].json.centering_score;\n const corner = all[1].json.corner_score;\n const cornerBreakdown = all[1].json.corner_scores;\n const edge = all[3].json.edge_score;\n\n const claudeText = all[2].json.text;\n const cleaned = claudeText.replace(/```json\\s*/g, '').replace(/```\\s*/g, '').trim();\n const surfaceData = JSON.parse(cleaned);\n const surface = surfaceData.surface_score;\n const defects = surfaceData.defects_found;\n const reasoning = surfaceData.reasoning;\n\n const croppedImage = $('Preprocessing').first().json.cropped_image;\n\n const overall = corner * 0.35 + surface * 0.25 + centering * 0.15 + edge * 0.25;\n\n const thresholds = [\n [10, 9.2], [9, 8.2], [8, 7.2], [7, 6.2],\n [6, 5.2], [5, 4.2], [4, 3.2], [3, 2.2], [2, 1.2], [1, 0],\n ];\n let grade = 1;\n for (const [g, min] of thresholds) {\n if (overall >= min) { grade = g; break; }\n }\n\n const SUBMIT_THRESHOLD = 9.5;\n const recommendSubmit = grade >= SUBMIT_THRESHOLD;\n const reason = recommendSubmit\n ? `PSA ${grade} \u2014 gem mint (${overall.toFixed(1)}/10). High ROI.`\n : `PSA ${grade} \u2014 below threshold (${overall.toFixed(1)}/10, need \\u2265 ${SUBMIT_THRESHOLD}). ${reasoning}`;\n\n return [{\n json: {\n centering_score: Math.round(centering * 10) / 10,\n corner_score: Math.round(corner * 10) / 10,\n surface_score: Math.round(surface * 10) / 10,\n edge_score: Math.round(edge * 10) / 10,\n corner_breakdown: cornerBreakdown,\n surface_defects: defects,\n surface_reasoning: reasoning,\n overall_score: Math.round(overall * 100) / 100,\n estimated_psa_grade: grade,\n recommend_submit: recommendSubmit,\n recommendation_reason: reason,\n cropped_image: croppedImage,\n unique_filename: uniqueFilename,\n original_filename: originalFilename,\n file_path: savedPath,\n card_name_hint: cardNameHint,\n card_set_hint: cardSetHint,\n }\n }];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
112,
768
],
"id": "1242375e-ee44-485a-b823-8777fa8d9917",
"name": "grade calculator"
},
{
"parameters": {
"jsCode": "const gradeData = $('grade calculator').first().json;\nconst priceText = $input.first().json.text || '';\n\nlet priceData = {};\ntry {\n const match = priceText.match(/\\{[\\s\\S]*\\}/);\n priceData = match ? JSON.parse(match[0]) : {};\n} catch (e) {\n priceData = {};\n}\n\nreturn [{\n json: {\n ...gradeData,\n card_name: priceData.card_name || 'Unknown',\n card_set: priceData.card_set || '',\n card_number: priceData.card_number || '',\n price_low: priceData.price_low || 0,\n price_mid: priceData.price_mid || 0,\n price_high: priceData.price_high || 0,\n price_currency: priceData.currency || 'USD',\n }\n}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
384,
1040
],
"id": "a2b3c4d5-e6f7-8901-2345-678901234567",
"name": "merge price data"
}
],
"connections": {
"Webhook": {
"main": [
[
{
"node": "Preprocessing",
"type": "main",
"index": 0
}
]
]
},
"Merge": {
"main": [
[
{
"node": "grade calculator",
"type": "main",
"index": 0
}
]
]
},
"Anthropic Chat Model": {
"ai_languageModel": [
[
{
"node": "surface agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Anthropic Chat Model 2": {
"ai_languageModel": [
[
{
"node": "price lookup",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Preprocessing": {
"main": [
[
{
"node": "centering agent",
"type": "main",
"index": 0
},
{
"node": "corner agent",
"type": "main",
"index": 0
},
{
"node": "surface agent",
"type": "main",
"index": 0
},
{
"node": "edge agent",
"type": "main",
"index": 0
}
]
]
},
"centering agent": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
}
]
]
},
"corner agent": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
}
]
]
},
"edge agent": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 3
}
]
]
},
"surface agent": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 2
}
]
]
},
"grade calculator": {
"main": [
[
{
"node": "price lookup",
"type": "main",
"index": 0
}
]
]
},
"price lookup": {
"main": [
[
{
"node": "merge price data",
"type": "main",
"index": 0
}
]
]
},
"merge price data": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
},
{
"node": "save database",
"type": "main",
"index": 0
}
]
]
}
},
"active": true,
"settings": {
"executionOrder": "v1",
"binaryMode": "separate",
"availableInMCP": false
},
"versionId": "9fe4f5dc-83c1-4bbd-9c7a-ae213c9d8642",
"meta": {
"templateCredsSetupCompleted": true
},
"tags": []
}
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.
anthropicApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
N8N-Workflows. Uses lmChatAnthropic, httpRequest, chainLlm. Webhook trigger; 14 nodes.
Source: https://github.com/Tktarit/TCGX2/blob/7584c134fcd339e842bdc0030e390e270e9a579d/n8n-workflows/n8n-workflows.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.
Tired of grinding out YouTube content? This n8n workflow turns AI into your personal video factory—creating engaging, faceless shorts on autopilot. Perfect for creators, marketers, or side-hustlers lo
Faceless YouTube Generator. Uses httpRequest, limit, googleDrive, googleSheets. Webhook trigger; 49 nodes.
This workflow turns a spreadsheet row into a fully formatted, media-rich WordPress article. It pulls the outline and brand context from Google Sheets/Docs, drafts the article with Anthropic or Gemini,
Stop treating document review as a manual task. Let AI extract, classify, and route every contract, invoice, and NDA automatically.
Thread-Backend. Uses httpRequest, lmChatAnthropic, textClassifier, chainLlm. Webhook trigger; 35 nodes.