{
  "name": "Automated social engine - X",
  "nodes": [
    {
      "parameters": {},
      "id": "00000000-0000-4000-8000-000000000001",
      "name": "When clicking ‘Test workflow’",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "00000000-0000-4000-8000-000000000002",
              "name": "idea",
              "value": "Our new PostSider n8n workflows are live",
              "type": "string"
            },
            {
              "id": "00000000-0000-4000-8000-000000000003",
              "name": "tone",
              "value": "confident and friendly",
              "type": "string"
            },
            {
              "id": "00000000-0000-4000-8000-000000000004",
              "name": "mode",
              "value": "approval",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "00000000-0000-4000-8000-000000000005",
      "name": "1. Post idea",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        220,
        0
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "00000000-0000-4000-8000-000000000006",
              "leftValue": "={{ ($('1. Post idea').first().json.mode || '').toLowerCase() }}",
              "rightValue": "approval",
              "operator": {
                "type": "string",
                "operation": "equals",
                "name": "filter.operator.equals"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "00000000-0000-4000-8000-000000000007",
      "name": "2. Mode?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        440,
        0
      ]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "https://api.postsider.com/public/v1/find-slot/[YOUR POSTSIDER X CHANNEL ID]"
      },
      "id": "00000000-0000-4000-8000-000000000008",
      "name": "3a. Find best slot",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        660,
        -180
      ],
      "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 X (Twitter). Rules: Max 280 characters. Sharp hook in the first line, confident tone, 1-3 relevant hashtags woven in naturally. No clickbait. Respond with the post text only.\" },\n    { \"role\": \"user\", \"content\": \"Topic: {{ $('1. Post idea').first().json.idea }}. Tone: {{ $('1. Post idea').first().json.tone }}. Write the post.\" }\n  ]\n}"
      },
      "id": "00000000-0000-4000-8000-000000000009",
      "name": "4a. Generate post (AI)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        880,
        -180
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "2",
          "name": "OpenAI API Key"
        }
      }
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const slot = $('3a. Find best slot').first().json; // { date } UTC, append 'Z'\nconst ai = $input.first().json;\nconst media = null;\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 X CHANNEL ID]' },\n        value: [{ content, image: [] }],\n        settings: {\"__type\":\"x\"}\n      }]\n    }\n  }\n}];"
      },
      "id": "00000000-0000-4000-8000-000000000010",
      "name": "5a. Build draft",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1100,
        -180
      ]
    },
    {
      "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-000000000011",
      "name": "6a. Create draft",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1320,
        -180
      ],
      "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-000000000012",
      "name": "7a. Request approval",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1540,
        -180
      ],
      "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 X (Twitter). Rules: Max 280 characters. Sharp hook in the first line, confident tone, 1-3 relevant hashtags woven in naturally. No clickbait. Respond with the post text only.\" },\n    { \"role\": \"user\", \"content\": \"Topic: {{ $('1. Post idea').first().json.idea }}. Tone: {{ $('1. Post idea').first().json.tone }}. Write the post.\" }\n  ]\n}"
      },
      "id": "00000000-0000-4000-8000-000000000013",
      "name": "4b. Generate post (AI)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        660,
        180
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "2",
          "name": "OpenAI API Key"
        }
      }
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const ai = $input.first().json;\nconst media = null;\nconst content = (ai.choices?.[0]?.message?.content || '').trim();\nreturn [{\n  json: {\n    body: {\n      type: 'now',\n      date: '',\n      shortLink: false,\n      tags: [],\n      posts: [{\n        integration: { id: '[YOUR POSTSIDER X CHANNEL ID]' },\n        value: [{ content, image: [] }],\n        settings: {\"__type\":\"x\"}\n      }]\n    }\n  }\n}];"
      },
      "id": "00000000-0000-4000-8000-000000000014",
      "name": "5b. Build post",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        880,
        180
      ]
    },
    {
      "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-000000000015",
      "name": "6b. Publish now",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1100,
        180
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "1",
          "name": "PostSider API Key"
        }
      }
    },
    {
      "parameters": {
        "content": "WHAT THIS DOES\nTurns your post idea into a ready-to-publish X (Twitter) post with AI and publishes it through PostSider, either immediately or via the approval queue. Enter the idea in \"1. Post idea\", pick the mode, run it.\n\nSETUP (once, about 3 minutes)\n1. PostSider API key: app.postsider.com > Settings > API > Create key. It starts with ps_ and is shown once, so save it.\n2. n8n credentials (both type Header Auth):\n   - \"PostSider API Key\": Name = Authorization, Value = your ps_ key. Select it on every node that talks to PostSider.\n   - \"OpenAI API Key\": Name = Authorization, Value = Bearer sk-... . Select it on the \"(AI)\" nodes.\n3. Channel: replace [YOUR POSTSIDER X CHANNEL ID] with a real channel id. Find it in the app under Settings > Channels.\n\n\nHOW TO RUN\n1. Open \"1. Post idea\" and set: idea (your topic), tone (optional), mode = \"approval\" (draft goes into the approval queue, approve in the app and PostSider schedules it) or mode = \"now\" (publishes immediately). The mode check is case-insensitive.\n2. Click \"Test workflow\".\n\nSELF-HOSTED POSTSIDER\nReplace api.postsider.com with your domain; add /api if your install serves the API under /api.",
        "height": 460,
        "width": 520,
        "color": 3
      },
      "id": "00000000-0000-4000-8000-000000000016",
      "name": "How to use",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        0,
        -440
      ]
    },
    {
      "parameters": {
        "content": "SETUP STEP BY STEP\nFollow in order. Do this once per workflow.\n\nSTEP 1 - Create the n8n credentials (do this once, both type 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-... (your OpenAI key, platform.openai.com).\n\nSTEP 2 - \"1. Post idea\" (Set node):\n  idea = your topic (e.g. \"Our new PostSider n8n workflows are live\")\n  tone = optional style (e.g. \"confident and friendly\")\n  mode = \"approval\" (goes into the approval queue) or \"now\" (publishes immediately)\n\n\nSTEP 3 - Select the \"PostSider API Key\" credential on these nodes:\n  - \"3a. Find best slot\" (Find best slot)\n  - \"6a. Create draft\" (Create draft)\n  - \"7a. Request approval\" (Request approval)\n  - \"6b. Publish now\" (Publish now)\n\nSTEP 4 - Select the \"OpenAI API Key\" credential on these nodes:\n  - \"4a. Generate post (AI)\" (Generate post, approval)\n  - \"4b. Generate post (AI)\" (Generate post, now)\n\n\nSTEP 5 - Replace the channel id:\n  Open \"3a. Find best slot\", \"6a. Create draft\", \"5a. Build draft\" and \"5b. Build post\" and replace [YOUR POSTSIDER X CHANNEL ID] with your real channel id (app > Settings > Channels).\n\nSTEP 6 - Run:\n  Click \"Test workflow\" once to verify everything works before activating the workflow.",
        "height": 640,
        "width": 620,
        "color": 3
      },
      "id": "00000000-0000-4000-8000-000000000017",
      "name": "Setup step by step",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        0,
        -940
      ]
    }
  ],
  "connections": {
    "1. Post idea": {
      "main": [
        [
          {
            "node": "2. Mode?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking ‘Test workflow’": {
      "main": [
        [
          {
            "node": "1. Post idea",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2. Mode?": {
      "main": [
        [
          {
            "node": "3a. Find best slot",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "4b. Generate post (AI)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3a. Find best slot": {
      "main": [
        [
          {
            "node": "4a. Generate post (AI)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "4a. Generate post (AI)": {
      "main": [
        [
          {
            "node": "5a. Build draft",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "5a. Build draft": {
      "main": [
        [
          {
            "node": "6a. Create draft",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6a. Create draft": {
      "main": [
        [
          {
            "node": "7a. Request approval",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "4b. Generate post (AI)": {
      "main": [
        [
          {
            "node": "5b. Build post",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "5b. Build post": {
      "main": [
        [
          {
            "node": "6b. Publish now",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {},
  "active": false,
  "tags": [
    "PostSider",
    "Automated social engine",
    "AI",
    "X"
  ]
}