This workflow follows the HTTP Request → Anthropic Chat 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": "Szybkie Kursiki - AI Course Generator",
"nodes": [
{
"parameters": {},
"id": "manual-trigger",
"name": "Manual Trigger",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
250,
300
]
},
{
"parameters": {
"authentication": "predefinedCredentialType",
"nodeCredentialType": "anthropicApi",
"resource": "message",
"model": "claude-sonnet-4-5-20250929",
"text": "={{ $json.coursePrompt }}",
"options": {
"systemMessage": "Jeste\u015b ekspertem w tworzeniu kurs\u00f3w edukacyjnych online. Twoim zadaniem jest wygenerowanie kompletnej struktury kursu w formacie JSON.\n\nKurs musi zawiera\u0107:\n1. Podstawowe informacje o kursie (tytu\u0142, kr\u00f3tki opis, pe\u0142ny opis, ikona Font Awesome, tagi)\n2. Seri\u0119 lekcji (minimum 3-5 lekcji)\n3. Ka\u017cda lekcja MUSI zawiera\u0107:\n - Tytu\u0142\n - Kolejno\u015b\u0107 (order)\n - Tre\u015b\u0107 w formacie Markdown (content_markdown) - szczeg\u00f3\u0142owa, merytoryczna tre\u015b\u0107 lekcji z przyk\u0142adami kodu\n - Quiz z 3-5 pytaniami wielokrotnego wyboru\n - Zadanie praktyczne (practical_task) z przyk\u0142adami i rozwi\u0105zaniem\n\nFormat JSON:\n```json\n{\n \"course\": {\n \"title\": \"Nazwa kursu\",\n \"short_description\": \"Kr\u00f3tki opis kursu (max 200 znak\u00f3w)\",\n \"description\": \"Pe\u0142ny opis kursu - czego si\u0119 nauczysz, dla kogo jest kurs\",\n \"icon\": \"fas fa-code\",\n \"tags\": [\"Python\", \"Backend\", \"API\"]\n },\n \"lessons\": [\n {\n \"title\": \"Tytu\u0142 lekcji\",\n \"order\": 0,\n \"content_markdown\": \"# Wprowadzenie\\n\\nTre\u015b\u0107 lekcji w markdown...\\n\\n```python\\nprint('Hello World')\\n```\\n\\n## Kolejna sekcja\\n\\nWi\u0119cej tre\u015bci...\",\n \"quiz\": {\n \"title\": \"Quiz - Tytu\u0142 lekcji\",\n \"description\": \"Sprawd\u017a swoj\u0105 wiedz\u0119\",\n \"questions\": [\n {\n \"text\": \"Tre\u015b\u0107 pytania?\",\n \"order\": 0,\n \"explanation\": \"Wyja\u015bnienie poprawnej odpowiedzi\",\n \"answers\": [\n {\n \"text\": \"Odpowied\u017a 1\",\n \"is_correct\": true,\n \"order\": 0\n },\n {\n \"text\": \"Odpowied\u017a 2\",\n \"is_correct\": false,\n \"order\": 1\n }\n ]\n }\n ]\n },\n \"practical_task\": {\n \"title\": \"Zadanie praktyczne - Tytu\u0142\",\n \"content_markdown\": \"# Zadanie\\n\\nOpis zadania do wykonania...\",\n \"instructions_markdown\": \"## Instrukcje\\n\\n1. Krok 1\\n2. Krok 2\",\n \"example_markdown\": \"## Przyk\u0142ad\\n\\n```python\\nprzyk\u0142adowy_kod()\\n```\",\n \"hints_markdown\": \"## Wskaz\u00f3wki\\n\\n- Wskaz\u00f3wka 1\\n- Wskaz\u00f3wka 2\",\n \"solution_markdown\": \"## Rozwi\u0105zanie\\n\\n```python\\nrozwiazanie_zadania()\\n```\\n\\nWyja\u015bnienie...\"\n }\n }\n ]\n}\n```\n\nWA\u017bNE:\n- Tre\u015b\u0107 lekcji (content_markdown) powinna by\u0107 szczeg\u00f3\u0142owa (min 500 s\u0142\u00f3w)\n- U\u017cywaj prawid\u0142owego formatowania Markdown\n- Bloki kodu musz\u0105 mie\u0107 okre\u015blony j\u0119zyk (```python, ```javascript, itp.)\n- Ka\u017cde pytanie w quizie musi mie\u0107 co najmniej 4 odpowiedzi\n- Tylko jedna odpowied\u017a mo\u017ce by\u0107 poprawna (is_correct: true)\n- Zadania praktyczne musz\u0105 by\u0107 konkretne i wykonalne\n- U\u017cywaj polskich znak\u00f3w (\u0105, \u0107, \u0119, \u0142, \u0144, \u00f3, \u015b, \u017a, \u017c)\n\nODPOWIED\u0179 WY\u0141\u0104CZNIE POPRAWNYM JSON-em, bez dodatkowych komentarzy ani wyja\u015bnie\u0144."
}
},
"id": "anthropic-claude",
"name": "Generate Course with Claude",
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"typeVersion": 1,
"position": [
450,
300
]
},
{
"parameters": {
"jsCode": "// Extract JSON from Claude's response\nconst response = $input.first().json.response;\n\n// Try to parse the response\nlet courseData;\n\ntry {\n // Check if response contains markdown code blocks\n const jsonMatch = response.match(/```(?:json)?\\s*([\\s\\S]*?)```/);\n \n if (jsonMatch) {\n // Extract JSON from code block\n courseData = JSON.parse(jsonMatch[1].trim());\n } else {\n // Try to parse directly\n courseData = JSON.parse(response);\n }\n \n // Validate required fields\n if (!courseData.course || !courseData.course.title) {\n throw new Error('Missing course title');\n }\n \n if (!courseData.lessons || courseData.lessons.length === 0) {\n throw new Error('No lessons provided');\n }\n \n // Ensure all lessons have required fields\n courseData.lessons.forEach((lesson, index) => {\n if (!lesson.title) {\n throw new Error(`Lesson ${index} missing title`);\n }\n if (lesson.order === undefined) {\n lesson.order = index;\n }\n if (!lesson.content_markdown) {\n throw new Error(`Lesson ${index} missing content_markdown`);\n }\n });\n \n return {\n json: courseData\n };\n \n} catch (error) {\n throw new Error(`Failed to parse Claude response: ${error.message}\\n\\nResponse: ${response}`);\n}"
},
"id": "code-parser",
"name": "Parse and Validate JSON",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
650,
300
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $env.DJANGO_APP_URL }}/api/import-course/",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-Import-Token",
"value": "={{ $env.COURSE_IMPORT_TOKEN }}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": []
},
"body": "={{ JSON.stringify($json) }}",
"options": {}
},
"id": "http-import",
"name": "Import Course to Django",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
850,
300
]
},
{
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.status }}",
"operation": "equals",
"value2": "ok"
}
]
}
},
"id": "check-success",
"name": "Check Import Success",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
1050,
300
]
},
{
"parameters": {
"values": {
"string": [
{
"name": "status",
"value": "success"
},
{
"name": "message",
"value": "Kurs zosta\u0142 pomy\u015blnie utworzony!"
},
{
"name": "course_title",
"value": "={{ $json.course_title }}"
},
{
"name": "course_slug",
"value": "={{ $json.course_slug }}"
},
{
"name": "lessons_count",
"value": "={{ $json.lessons_count }}"
},
{
"name": "admin_url",
"value": "={{ $env.DJANGO_APP_URL }}{{ $json.admin_url }}"
},
{
"name": "preview_url",
"value": "={{ $env.DJANGO_APP_URL }}/course/{{ $json.course_slug }}/"
}
]
},
"options": {}
},
"id": "success-output",
"name": "Success Output",
"type": "n8n-nodes-base.set",
"typeVersion": 2,
"position": [
1250,
200
]
},
{
"parameters": {
"values": {
"string": [
{
"name": "status",
"value": "error"
},
{
"name": "message",
"value": "Nie uda\u0142o si\u0119 zaimportowa\u0107 kursu"
},
{
"name": "error",
"value": "={{ $json.error || 'Unknown error' }}"
}
]
},
"options": {}
},
"id": "error-output",
"name": "Error Output",
"type": "n8n-nodes-base.set",
"typeVersion": 2,
"position": [
1250,
400
]
}
],
"connections": {
"Manual Trigger": {
"main": [
[
{
"node": "Generate Course with Claude",
"type": "main",
"index": 0
}
]
]
},
"Generate Course with Claude": {
"main": [
[
{
"node": "Parse and Validate JSON",
"type": "main",
"index": 0
}
]
]
},
"Parse and Validate JSON": {
"main": [
[
{
"node": "Import Course to Django",
"type": "main",
"index": 0
}
]
]
},
"Import Course to Django": {
"main": [
[
{
"node": "Check Import Success",
"type": "main",
"index": 0
}
]
]
},
"Check Import Success": {
"main": [
[
{
"node": "Success Output",
"type": "main",
"index": 0
}
],
[
{
"node": "Error Output",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"staticData": null,
"tags": [],
"triggerCount": 1,
"updatedAt": "2026-02-02T00:00:00.000Z",
"versionId": "1"
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Szybkie Kursiki - AI Course Generator. Uses lmChatAnthropic, httpRequest. Event-driven trigger; 7 nodes.
Source: https://github.com/Sul3j/szybkie-kursiki/blob/7a41c67048c38e3d720c52f72553d5ea0cd49935/n8n-workflows/course-generator-workflow.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.
Episode 18 Scary Stories TikTok final. Uses httpRequest, lmChatOpenAi, lmChatOllama, lmChatDeepSeek. Event-driven trigger; 83 nodes.
Influencer 2.0. Uses formTrigger, form, informationExtractor, lmChatOpenAi. Event-driven trigger; 93 nodes.
Transform your Gmail sent folder into a comprehensive, enriched contact database automatically. This workflow processes hundreds or thousands of sent emails, extracting and enriching contact informati
This template can be used to automatically label your incoming Gmail messages with AI and to build a knowledge graph from the emails tagged with a specific label to brainstorm new ideas based on them.
Author: CSChin Example Source: https://www.ncl.ac.uk/singapore/staff/profile/chengchin.html#publications