{
  "name": "Weekly plan generator",
  "nodes": [
    {
      "parameters": {},
      "id": "00000000-0000-4000-8000-000000000040",
      "name": "When clicking ‘Test workflow’",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "00000000-0000-4000-8000-000000000041",
              "name": "topic",
              "value": "[YOUR TOPIC, e.g. AI agents for marketing]",
              "type": "string"
            },
            {
              "id": "00000000-0000-4000-8000-000000000042",
              "name": "platform",
              "value": "x",
              "type": "string"
            },
            {
              "id": "00000000-0000-4000-8000-000000000043",
              "name": "count",
              "value": "7",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "00000000-0000-4000-8000-000000000044",
      "name": "1. Topic",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        220,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.openai.com/v1/chat/completions",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"model\": \"gpt-4o-mini\",\n  \"temperature\": 0.9,\n  \"messages\": [\n    { \"role\": \"system\", \"content\": \"You are a social media strategist. Create {{ $('1. Topic').first().json.count }} distinct post ideas for {{ $('1. Topic').first().json.platform }} about the topic. Output ONLY a JSON array of strings, one idea per element, no markdown.\" },\n    { \"role\": \"user\", \"content\": \"Topic: {{ $('1. Topic').first().json.topic }}\" }\n  ]\n}"
      },
      "id": "00000000-0000-4000-8000-000000000045",
      "name": "2. Plan the week (AI)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        440,
        0
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "2",
          "name": "OpenAI API Key"
        }
      }
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const raw = ($input.first().json.choices?.[0]?.message?.content || '').trim();\nlet arr = [];\ntry { arr = JSON.parse(raw.replace(/```json\\n?/g, '').replace(/```/g, '').trim()); } catch (e) { arr = raw.split(/\\n+/).map((s) => s.replace(/^\\d+\\.\\s*/, '').trim()).filter(Boolean); }\nif (!Array.isArray(arr)) arr = [String(arr)];\nreturn arr.filter(Boolean).map((idea) => ({ json: { idea: String(idea).replace(/^[\"']|[\"']$/g, '').trim() } }));"
      },
      "id": "00000000-0000-4000-8000-000000000046",
      "name": "3. Split ideas",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        660,
        0
      ]
    },
    {
      "parameters": {
        "maxItems": 1
      },
      "id": "00000000-0000-4000-8000-000000000047",
      "name": "4. One per run",
      "type": "n8n-nodes-base.limit",
      "typeVersion": 1,
      "position": [
        880,
        0
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "00000000-0000-4000-8000-000000000048",
              "name": "platform",
              "value": "={{ $('1. Topic').first().json.platform }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "00000000-0000-4000-8000-000000000049",
      "name": "5. Set platform",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1100,
        0
      ]
    },
    {
      "parameters": {
        "content": "WHAT THIS DOES\nOne topic in, a week of content out: the AI plans N distinct post ideas, then each run takes one idea, writes the post, finds the best slot in the PostSider calendar and creates a draft there. Approve in the app to publish.\n\nSETUP (once, about 4 minutes)\n1. PostSider API key: app.postsider.com > Settings > API > Create key (ps_...).\n2. n8n credentials (Header Auth): \"PostSider API Key\" (Authorization = ps_...) and \"OpenAI API Key\" (Authorization = Bearer sk-...).\n3. Open \"1. Topic\": set topic, platform (x, linkedin, facebook, ...) and count (how many posts to plan).\n4. Replace [YOUR POSTSIDER CHANNEL ID] with a real channel id (app > Settings > Channels).\n\nHOW TO RUN\n1. Click \"Test workflow\" once to create the plan and schedule the first post.\n2. Run again to schedule the next idea from the plan (or add a Schedule Trigger).\n3. Approve the drafts in the app to publish them at their slots.\n\nSELF-HOSTED POSTSIDER\nReplace api.postsider.com with your domain; add /api if your install serves the API under /api.",
        "height": 680,
        "width": 620,
        "color": 3
      },
      "id": "00000000-0000-4000-8000-000000000055",
      "name": "How to use",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        0,
        -460
      ]
    },
    {
      "parameters": {
        "content": "SETUP STEP BY STEP\nFollow in order. Do this once per workflow.\n\nSTEP 1 - Create the n8n credentials (Header Auth):\n  a. \"PostSider API Key\": Name = Authorization, Value = your ps_ key (app.postsider.com > Settings > API > Create key).\n  b. \"OpenAI API Key\": Name = Authorization, Value = Bearer sk-... (platform.openai.com).\n\nSTEP 2 - \"1. Topic\" (Set node):\n  topic = your niche or subject (e.g. \"AI agents for marketing\")\n  platform = where to post (x, linkedin, facebook, instagram, ...)\n  count = how many post ideas to plan (e.g. 7 for a week)\n\nSTEP 3 - Select the \"PostSider API Key\" credential on:\n  - \"6. Find best slot\"\n  - \"6. Create draft\"\n  - \"6. Request approval\"\n\nSTEP 4 - Select the \"OpenAI API Key\" credential on:\n  - \"2. Plan the week (AI)\"\n  - \"6. Generate post (AI)\"\n\nSTEP 5 - Replace the channel id:\n  Replace [YOUR POSTSIDER CHANNEL ID] in \"6. Find best slot\" and \"6. Build draft\" with your real channel id (app > Settings > Channels). The platform type in \"6. Build draft\" is filled automatically from \"1. Topic\".\n\nSTEP 6 - Run:\n  Click \"Test workflow\" once: the plan is created and the first post is scheduled. Run again for the next idea, or add a Schedule Trigger (e.g. daily) and approve drafts in the app.",
        "height": 720,
        "width": 640,
        "color": 3
      },
      "id": "00000000-0000-4000-8000-000000000056",
      "name": "Setup step by step",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        0,
        -1220
      ]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "https://api.postsider.com/public/v1/find-slot/[YOUR POSTSIDER CHANNEL ID]"
      },
      "id": "00000000-0000-4000-8000-000000000050",
      "name": "6. Find best slot",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1320,
        0
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "1",
          "name": "PostSider API Key"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.openai.com/v1/chat/completions",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"model\": \"gpt-4o-mini\",\n  \"temperature\": 0.8,\n  \"messages\": [\n    { \"role\": \"system\", \"content\": \"You write social media posts for the chosen platform. Rules: Match the platform tone and limits. Sharp hook, natural hashtags. Respond with the post text only.\" },\n    { \"role\": \"user\", \"content\": \"Topic: {{ $('4. One per run').first().json.idea }}. Tone: {{ $('4. One per run').first().json.tone }}. Write the post.\" }\n  ]\n}"
      },
      "id": "00000000-0000-4000-8000-000000000051",
      "name": "6. Generate post (AI)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1540,
        0
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "2",
          "name": "OpenAI API Key"
        }
      }
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const slot = $('6. Find best slot').first().json; // { date } UTC, append 'Z'\nconst ai = $input.first().json;\nconst content = (ai.choices?.[0]?.message?.content || '').trim();\nreturn [{\n  json: {\n    body: {\n      type: 'draft',\n      date: slot.date + 'Z',\n      shortLink: false,\n      tags: [],\n      posts: [{\n        integration: { id: '[YOUR POSTSIDER CHANNEL ID]' },\n        value: [{ content, image: [] }],\n        settings: {}\n      }]\n    }\n  }\n}];"
      },
      "id": "00000000-0000-4000-8000-000000000052",
      "name": "6. Build draft",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1760,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.postsider.com/public/v1/posts",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($json.body) }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Idempotency-Key",
              "value": "=ps-{{ $now.toISO() }}"
            }
          ]
        }
      },
      "id": "00000000-0000-4000-8000-000000000053",
      "name": "6. Create draft",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1980,
        0
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "1",
          "name": "PostSider API Key"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://api.postsider.com/public/v1/posts/{{ $json.postId }}/request-approval"
      },
      "id": "00000000-0000-4000-8000-000000000054",
      "name": "6. Request approval",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2200,
        0
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "1",
          "name": "PostSider API Key"
        }
      }
    }
  ],
  "connections": {
    "6. Find best slot": {
      "main": [
        [
          {
            "node": "6. Generate post (AI)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6. Generate post (AI)": {
      "main": [
        [
          {
            "node": "6. Build draft",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6. Build draft": {
      "main": [
        [
          {
            "node": "6. Create draft",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6. Create draft": {
      "main": [
        [
          {
            "node": "6. Request approval",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking ‘Test workflow’": {
      "main": [
        [
          {
            "node": "1. Topic",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1. Topic": {
      "main": [
        [
          {
            "node": "2. Plan the week (AI)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2. Plan the week (AI)": {
      "main": [
        [
          {
            "node": "3. Split ideas",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3. Split ideas": {
      "main": [
        [
          {
            "node": "4. One per run",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "4. One per run": {
      "main": [
        [
          {
            "node": "5. Set platform",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "5. Set platform": {
      "main": [
        [
          {
            "node": "6. Find best slot",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {},
  "active": false,
  "tags": [
    "PostSider",
    "AI",
    "Plan",
    "Content"
  ]
}