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 →
{
"id": "image-to-anki",
"name": "Image to Anki Deck (APKG)",
"nodes": [
{
"id": "webhook-trigger",
"name": "Webhook Trigger",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
100,
300
],
"parameters": {
"path": "image-to-anki",
"httpMethod": "POST",
"responseMode": "responseNode",
"options": {}
}
},
{
"id": "normalize-input",
"name": "Normalize Input",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
300,
300
],
"parameters": {
"jsCode": "// Normalize and validate input - returns error JSON if invalid\nconst body = $input.first().json.body || {};\nconst deckName = (body.deckName && typeof body.deckName === 'string') ? body.deckName.trim() : 'Vocabulary';\n// Audio is ON by default (opt-out, not opt-in)\nconst includeAudio = body.includeAudio !== false;\nconst mode = (body.mode === 'suffix') ? 'suffix' : 'vocabulary';\n\nif (body.imageUrl && typeof body.imageUrl === 'string' && body.imageUrl.length > 0) {\n return [{ json: { ...($input.first().json), imageSource: body.imageUrl, inputType: 'url', isValid: true, base64Only: null, deckName, includeAudio, mode } }];\n}\n\nif (body.imageData && typeof body.imageData === 'string' && body.imageData.length > 0) {\n let data = body.imageData;\n if (!data.startsWith('data:')) {\n data = 'data:image/png;base64,' + data;\n }\n const base64Only = data.split('base64,')[1] || null;\n return [{ json: { ...($input.first().json), imageSource: data, inputType: 'base64', isValid: true, base64Only, deckName, includeAudio, mode } }];\n}\n\nreturn [{ json: { isValid: false, error: 'Missing image. Send POST with {\"imageUrl\": \"...\"} or {\"imageData\": \"...\"}' } }];\n"
}
},
{
"id": "check-valid",
"name": "Check Valid",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
500,
300
],
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "loose"
},
"conditions": [
{
"id": "is-valid",
"leftValue": "={{ $json.isValid }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
}
},
{
"id": "error-response",
"name": "Error Response",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
700,
500
],
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify({ success: false, error: $json.error }) }}",
"options": {
"responseCode": 400
}
}
},
{
"id": "create-job",
"name": "Create Job",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
700,
300
],
"parameters": {
"jsCode": "const fs = require('fs');\nconst path = require('path');\nconst crypto = require('crypto');\n\nconst item = $input.first().json;\nconst jobId = crypto.randomUUID();\nconst jobDir = path.join('/var/lib/n8n/jobs', jobId);\nconst includeAudio = item.includeAudio !== false;\nconst mode = (item.mode === 'suffix') ? 'suffix' : 'vocabulary';\n\n// Create job directory\nfs.mkdirSync(jobDir, { recursive: true });\n\n// Write initial status\nconst status = {\n status: 'queued',\n phase: 'Job queued, starting processing...',\n progress: 0,\n wordCount: null,\n currentWord: null,\n includeAudio,\n mode,\n createdAt: new Date().toISOString()\n};\nfs.writeFileSync(path.join(jobDir, 'status.json'), JSON.stringify(status, null, 2));\n\n// Build status URL\nconst host = item.headers?.host || 'localhost:5678';\nconst protocol = host.includes('ts.net') ? 'https' : 'http';\nconst statusUrl = `${protocol}://${host}/webhook/anki-status?id=${jobId}`;\nconst deckName = item.deckName || 'Vocabulary';\n\nreturn [{ json: { jobId, jobDir, statusUrl, imageSource: item.imageSource, deckName, includeAudio, mode, host } }];\n"
}
},
{
"id": "trigger-worker",
"name": "Trigger Worker",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
900,
300
],
"continueOnFail": true,
"parameters": {
"method": "POST",
"url": "=http://127.0.0.1:5678/webhook/anki-worker",
"authentication": "none",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ jobId: $json.jobId, imageSource: $json.imageSource, deckName: $json.deckName, includeAudio: $json.includeAudio, mode: $json.mode }) }}",
"options": {
"timeout": 1000
}
}
},
{
"id": "accepted-response",
"name": "Accepted Response",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
1100,
300
],
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify({ success: true, status: 'processing', jobId: $('Create Job').first().json.jobId, statusUrl: $('Create Job').first().json.statusUrl, message: 'Job accepted. Poll statusUrl for progress.' }) }}",
"options": {
"responseCode": 202
}
}
}
],
"connections": {
"Webhook Trigger": {
"main": [
[
{
"node": "Normalize Input",
"type": "main",
"index": 0
}
]
]
},
"Normalize Input": {
"main": [
[
{
"node": "Check Valid",
"type": "main",
"index": 0
}
]
]
},
"Check Valid": {
"main": [
[
{
"node": "Create Job",
"type": "main",
"index": 0
}
],
[
{
"node": "Error Response",
"type": "main",
"index": 0
}
]
]
},
"Create Job": {
"main": [
[
{
"node": "Trigger Worker",
"type": "main",
"index": 0
}
]
]
},
"Trigger Worker": {
"main": [
[
{
"node": "Accepted Response",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"active": true,
"versionId": "28701dde-acfd-460c-a39f-fdd4d9660115"
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Image to Anki Deck (APKG). Uses httpRequest. Webhook trigger; 7 nodes.
Source: https://github.com/alexandru-savinov/nixos-config/blob/abbfe975654bcfa221398b95aca49c1e36758e6e/n8n-workflows/image-to-anki.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 n8n template provides enterprise-level version control for your workflows using GitHub integration. Stop losing hours to broken workflows and manual exports – get proper commit history, visual di
This flow creates dummy files for every item added in your *Arrs (Radarr/Sonarr) with the tag .
This workflow acts as a central API gateway for all technical indicator agents in the Binance Spot Market Quant AI system. It listens for incoming webhook requests and dynamically routes them to the c
Sign PDF documents with legally-compliant digital signatures using X.509 certificates. Supports multiple PAdES signature levels (B, T, LT, LTA) with optional visible stamps.
📡 This workflow serves as the central Alpha Vantage API fetcher for Tesla trading indicators, delivering cleaned 20-point JSON outputs for three timeframes: , , and . It is required by the following a