{
  "id": "JdpB1DL6CoVRuGB3",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Jasper AI Content Creator",
  "tags": [],
  "nodes": [
    {
      "id": "89a3fcb6-4395-4632-8036-02f28902c482",
      "name": "README",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -448,
        -320
      ],
      "parameters": {
        "width": 800,
        "height": 848,
        "content": "# Jasper AI Content Creator\n\nGenerates SEO blog posts, ad copy, email sequences, and social captions using Claude AI.\n\n## Setup\n1. Add your ANTHROPIC_API_KEY in the Set Config node\n2. Configure Serper API key for SEO data (optional)\n3. Set your WordPress, Mailchimp, Airtable credentials\n4. POST to the webhook URL\n\n## Webhook Payload\n```\n{\n  \"topic\": \"Best AI Tools 2025\",\n  \"contentType\": \"blog_post\",\n  \"keyword\": \"ai tools for marketing\",\n  \"tone\": \"professional\",\n  \"audience\": \"SMB marketers\",\n  \"wordCount\": 1500,\n  \"brand\": \"YourBrand\",\n  \"clientEmail\": \"client@email.com\"\n}\n```\n\n## Content Types\n- blog_post\n- ad_copy\n- email_sequence\n- social_captions\n\n## Flow\nWebhook -> Config -> SEO Fetch -> Build Prompt -> Claude AI -> Parse Response -> Save to Sheet -> Send Email -> Respond"
      },
      "typeVersion": 1
    },
    {
      "id": "075ca433-b1cf-4fc8-9fab-7445bb31ee30",
      "name": "Stage 1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        416,
        -128
      ],
      "parameters": {
        "color": 4,
        "width": 584,
        "height": 452,
        "content": "## Stage 1 - Intake\nWebhook receives brief, Set node stores config values, HTTP node fetches top Google results for the keyword to give Claude competitor context."
      },
      "typeVersion": 1
    },
    {
      "id": "f3654273-1853-4318-b0af-a504e9e13bb1",
      "name": "Stage 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1024,
        -128
      ],
      "parameters": {
        "color": 3,
        "width": 552,
        "height": 532,
        "content": "## Stage 2 - Generate\nCode node builds the Claude prompt based on content type. HTTP Request calls Anthropic API. Another Code node parses the response and extracts clean content + SEO metadata."
      },
      "typeVersion": 1
    },
    {
      "id": "b3c5e80a-1155-4db1-aac5-fcc2cd71bc18",
      "name": "Stage 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1616,
        -128
      ],
      "parameters": {
        "color": 6,
        "width": 520,
        "height": 564,
        "content": "## Stage 3 - Publish\nGoogle Sheets logs every job. HTTP Request sends delivery email via SendGrid. Webhook responds with JSON summary including SEO score, meta title, and content preview."
      },
      "typeVersion": 1
    },
    {
      "id": "d047e225-8069-484a-af0f-7c94592830ea",
      "name": "Receive Brief",
      "type": "n8n-nodes-base.webhook",
      "position": [
        464,
        144
      ],
      "parameters": {
        "path": "content-brief",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "80a1438d-c755-4574-92c1-4c104bc6a8c6",
      "name": "Set Config",
      "type": "n8n-nodes-base.set",
      "position": [
        656,
        144
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "a1",
              "name": "topic",
              "type": "string",
              "value": "={{ $json.body.topic || $json.topic || 'AI Tools for Marketing' }}"
            },
            {
              "id": "a2",
              "name": "contentType",
              "type": "string",
              "value": "={{ $json.body.contentType || $json.contentType || 'blog_post' }}"
            },
            {
              "id": "a3",
              "name": "keyword",
              "type": "string",
              "value": "={{ $json.body.keyword || $json.keyword || $json.body.topic || 'ai tools' }}"
            },
            {
              "id": "a4",
              "name": "tone",
              "type": "string",
              "value": "={{ $json.body.tone || $json.tone || 'professional' }}"
            },
            {
              "id": "a5",
              "name": "audience",
              "type": "string",
              "value": "={{ $json.body.audience || $json.audience || 'business owners' }}"
            },
            {
              "id": "a6",
              "name": "wordCount",
              "type": "number",
              "value": "={{ $json.body.wordCount || $json.wordCount || 1200 }}"
            },
            {
              "id": "a7",
              "name": "brand",
              "type": "string",
              "value": "={{ $json.body.brand || $json.brand || 'YourBrand' }}"
            },
            {
              "id": "a8",
              "name": "clientEmail",
              "type": "string",
              "value": "={{ $json.body.clientEmail || $json.clientEmail || '' }}"
            },
            {
              "id": "a9",
              "name": "jobId",
              "type": "string",
              "value": "={{ 'JAS-' + Date.now() }}"
            },
            {
              "id": "a10",
              "name": "anthropicKey",
              "type": "string",
              "value": "YOUR_ANTHROPIC_API_KEY"
            },
            {
              "id": "a11",
              "name": "serperKey",
              "type": "string",
              "value": "YOUR_SERPER_API_KEY"
            },
            {
              "id": "a12",
              "name": "sendgridKey",
              "type": "string",
              "value": "YOUR_SENDGRID_API_KEY"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "2fee290b-02e2-4f44-bc28-eb1deaed7709",
      "name": "Fetch SERP Data",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        864,
        144
      ],
      "parameters": {
        "url": "https://google.serper.dev/search",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify({ q: $json.keyword, num: 5 }) }}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "X-API-KEY",
              "value": "={{ $json.serperKey }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2,
      "continueOnFail": true
    },
    {
      "id": "eac2193f-2cb9-440d-baaf-91ce2bb5a448",
      "name": "Build Claude Prompt",
      "type": "n8n-nodes-base.code",
      "position": [
        1056,
        144
      ],
      "parameters": {
        "jsCode": "\nvar cfg = $('Set Config').first().json;\nvar serp = $('Fetch SERP Data').first().json;\n\nvar competitors = '';\ntry {\n  var organic = serp.organic || [];\n  competitors = organic.slice(0,4).map(function(r){ return '- ' + r.title; }).join('\\n');\n} catch(e) { competitors = 'No competitor data'; }\n\nvar type = cfg.contentType || 'blog_post';\nvar prompts = {};\n\nprompts['blog_post'] = 'Write a ' + cfg.wordCount + '-word SEO blog post.\\nTopic: ' + cfg.topic + '\\nKeyword (use 3-5 times): ' + cfg.keyword + '\\nTone: ' + cfg.tone + '\\nAudience: ' + cfg.audience + '\\nBrand: ' + cfg.brand + '\\nCompetitor titles to beat:\\n' + competitors + '\\n\\nStructure: H1 with keyword > intro hook > 4-5 H2 sections > FAQ (3 questions) > conclusion with CTA.\\n\\nEnd with:\\nMETA_TITLE: (max 55 chars)\\nMETA_DESC: (max 155 chars)\\nSEO_SCORE: (0-100 number only)';\n\nprompts['ad_copy'] = 'Write high-converting ad copy.\\nProduct/Topic: ' + cfg.topic + '\\nKeyword: ' + cfg.keyword + '\\nBrand: ' + cfg.brand + '\\nAudience: ' + cfg.audience + '\\n\\nProvide:\\n1. GOOGLE ADS - 3 sets of (Headline 1 max30, Headline 2 max30, Headline 3 max30, Desc 1 max90, Desc 2 max90)\\n2. META ADS - 3 variations of (Primary text max125, Headline max40, Description max30)\\n3. EMAIL SUBJECTS - 3 subject lines with preview text\\n\\nEnd with:\\nMETA_TITLE: best headline as meta title\\nMETA_DESC: best description\\nSEO_SCORE: 65';\n\nprompts['email_sequence'] = 'Write a 4-email drip sequence.\\nTopic: ' + cfg.topic + '\\nBrand: ' + cfg.brand + '\\nAudience: ' + cfg.audience + '\\nTone: ' + cfg.tone + '\\n\\nEmail 1 (send immediately): Welcome - subject, preview, body 180 words, CTA\\nEmail 2 (day 2): Value Nurture - subject, preview, body 200 words, CTA\\nEmail 3 (day 4): Social Proof - subject, preview, body 200 words, CTA\\nEmail 4 (day 7): Sales Close - subject, preview, body 250 words, CTA\\n\\nUse {{first_name}} for personalization.\\n\\nEnd with:\\nMETA_TITLE: Email sequence title\\nMETA_DESC: Sequence description\\nSEO_SCORE: 70';\n\nprompts['social_captions'] = 'Write social media content.\\nTopic: ' + cfg.topic + '\\nBrand: ' + cfg.brand + '\\nAudience: ' + cfg.audience + '\\nTone: ' + cfg.tone + '\\n\\n1. LINKEDIN POST (1000-1300 chars, professional, line breaks, CTA, 3 hashtags)\\n2. TWITTER THREAD (5 tweets max 280 chars each, hook first, end with CTA)\\n3. TWITTER STANDALONE (1 viral tweet max 280 chars)\\n4. INSTAGRAM CAPTION (with emoji, storytelling, CTA, 25 hashtags at end)\\n5. INSTAGRAM CAROUSEL (5 slides: slide headline + 2 bullet points each)\\n\\nEnd with:\\nMETA_TITLE: Best headline from above\\nMETA_DESC: Best caption summary\\nSEO_SCORE: 72';\n\nvar prompt = prompts[type] || prompts['blog_post'];\n\nreturn [{ json: {\n  topic: cfg.topic,\n  contentType: cfg.contentType,\n  keyword: cfg.keyword,\n  tone: cfg.tone,\n  audience: cfg.audience,\n  wordCount: cfg.wordCount,\n  brand: cfg.brand,\n  clientEmail: cfg.clientEmail,\n  jobId: cfg.jobId,\n  anthropicKey: cfg.anthropicKey,\n  sendgridKey: cfg.sendgridKey,\n  claudePrompt: prompt,\n  competitors: competitors\n}}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "1a314124-cb2c-4196-b0ae-542f51762824",
      "name": "Call Claude AI",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1264,
        144
      ],
      "parameters": {
        "url": "https://api.anthropic.com/v1/messages",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify({ model: \"claude-sonnet-4-20250514\", max_tokens: 4000, system: \"You are a world-class marketing copywriter and SEO expert. Always follow the exact format requested.\", messages: [{ role: \"user\", content: $json.claudePrompt }] }) }}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "x-api-key",
              "value": "={{ $json.anthropicKey }}"
            },
            {
              "name": "anthropic-version",
              "value": "2023-06-01"
            },
            {
              "name": "content-type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "d2a2d489-1d69-477a-ab1b-9043ed8e4624",
      "name": "Parse Claude Response",
      "type": "n8n-nodes-base.code",
      "position": [
        1456,
        144
      ],
      "parameters": {
        "jsCode": "\nvar claudeRaw = $('Call Claude AI').first().json;\nvar brief = $('Build Claude Prompt').first().json;\n\nvar content = '';\ntry {\n  if (claudeRaw.content && Array.isArray(claudeRaw.content)) {\n    content = claudeRaw.content.map(function(b){ return b.text || ''; }).join('\\n');\n  } else if (claudeRaw.text) {\n    content = claudeRaw.text;\n  } else {\n    content = JSON.stringify(claudeRaw);\n  }\n} catch(e) {\n  content = 'Error extracting content: ' + e.message;\n}\n\nvar metaTitle = '';\nvar metaDesc = '';\nvar seoScore = 0;\n\ntry {\n  var mtMatch = content.match(/META_TITLE:\\s*(.+)/);\n  if (mtMatch) metaTitle = mtMatch[1].trim();\n  var mdMatch = content.match(/META_DESC:\\s*(.+)/);\n  if (mdMatch) metaDesc = mdMatch[1].trim();\n  var ssMatch = content.match(/SEO_SCORE:\\s*(\\d+)/);\n  if (ssMatch) seoScore = parseInt(ssMatch[1]);\n} catch(e) {}\n\nif (!metaTitle) metaTitle = brief.topic;\nif (!metaDesc) metaDesc = 'Read our guide on ' + brief.topic;\nif (!seoScore) seoScore = 72;\n\nvar slug = (brief.keyword || brief.topic).toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');\n\nvar valueMap = { blog_post: 250, ad_copy: 150, email_sequence: 350, social_captions: 120 };\n\nreturn [{ json: {\n  jobId: brief.jobId,\n  contentType: brief.contentType,\n  topic: brief.topic,\n  keyword: brief.keyword,\n  brand: brief.brand,\n  clientEmail: brief.clientEmail,\n  sendgridKey: brief.sendgridKey,\n  generatedContent: content,\n  contentLength: content.length,\n  metaTitle: metaTitle,\n  metaDesc: metaDesc,\n  seoScore: seoScore,\n  slug: slug,\n  estimatedValue: valueMap[brief.contentType] || 200,\n  generatedAt: new Date().toISOString()\n}}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "e576fa4e-3082-468b-add4-8c4eb0cb13ac",
      "name": "Save to Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1664,
        48
      ],
      "parameters": {
        "columns": {
          "value": {},
          "schema": [],
          "mappingMode": "autoMapInputData",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Content Log"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID"
        },
        "authentication": "serviceAccount"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5,
      "continueOnFail": true
    },
    {
      "id": "703a38b4-3015-498d-8b66-ca4a299c86f3",
      "name": "Send Delivery Email",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1664,
        240
      ],
      "parameters": {
        "url": "https://api.sendgrid.com/v3/mail/send",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify({ personalizations: [{ to: [{ email: $json.clientEmail || \"client@example.com\" }] }], from: { email: \"noreply@youragency.com\", name: \"Content Engine\" }, subject: \"Content ready: \" + $json.topic, content: [{ type: \"text/plain\", value: \"Your content is ready!\\n\\nJob: \" + $json.jobId + \"\\nType: \" + $json.contentType + \"\\nTopic: \" + $json.topic + \"\\nSEO Score: \" + $json.seoScore + \"/100\\nMeta Title: \" + $json.metaTitle + \"\\n\\nContent Preview:\\n\" + ($json.generatedContent || \"\").substring(0, 500) + \"...\" }] }) }}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "={{ 'Bearer ' + $json.sendgridKey }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2,
      "continueOnFail": true
    },
    {
      "id": "bbbaeaeb-d8a5-461d-988d-2a204c56eeef",
      "name": "Send Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1856,
        144
      ],
      "parameters": {
        "options": {
          "responseCode": 200
        },
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify({ success: true, jobId: $json.jobId, contentType: $json.contentType, topic: $json.topic, seoScore: $json.seoScore, metaTitle: $json.metaTitle, metaDesc: $json.metaDesc, slug: $json.slug, estimatedValue: $json.estimatedValue, contentLength: $json.contentLength, generatedAt: $json.generatedAt }) }}"
      },
      "typeVersion": 1.1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "0696ac8a-e4cf-4806-8ae7-b13c45b77838",
  "connections": {
    "Set Config": {
      "main": [
        [
          {
            "node": "Fetch SERP Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Receive Brief": {
      "main": [
        [
          {
            "node": "Set Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call Claude AI": {
      "main": [
        [
          {
            "node": "Parse Claude Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch SERP Data": {
      "main": [
        [
          {
            "node": "Build Claude Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Claude Prompt": {
      "main": [
        [
          {
            "node": "Call Claude AI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Delivery Email": {
      "main": [
        [
          {
            "node": "Send Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Claude Response": {
      "main": [
        [
          {
            "node": "Save to Google Sheets",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send Delivery Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save to Google Sheets": {
      "main": [
        [
          {
            "node": "Send Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}