{
  "id": "U1oAcmg6sXQaCOKm",
  "meta": {
    "instanceId": "592ab86418d16f6d35fe26275b159f790f264e346be9ab41a59d2e46ed226265"
  },
  "name": "Linkedin Auto",
  "tags": [],
  "nodes": [
    {
      "id": "c5a09a2f-88af-414e-87b9-055731b13fd1",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        688,
        224
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini",
          "cachedResultName": "gpt-4o-mini"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "id": "credential-id",
          "name": "openAiApi Credential"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "24115efb-96bc-48cb-9748-b6753c74ced4",
      "name": "Structured Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        816,
        224
      ],
      "parameters": {
        "schemaType": "manual",
        "inputSchema": "{\n\t\"type\": \"object\",\n\t\"properties\": {\n\t\t\"post\": {\n\t\t\t\"type\": \"string\"\n\t\t}\n}\n}"
      },
      "typeVersion": 1.2
    },
    {
      "id": "af2e19c8-4921-4c61-b6ce-1661e04b6baf",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        0,
        0
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1,
                3,
                5
              ],
              "triggerAtHour": 9,
              "triggerAtMinute": 30
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "958d6aba-08be-46d5-8441-232c6085b63e",
      "name": "writing the post",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        672,
        0
      ],
      "parameters": {
        "text": "=You are a professional LinkedIn content writer helping a technical writer build thought-leadership posts that maximize impressions and engagement.\n\n**Context & Quality Principles**\n\n* Clarify the topic before writing; if anything is unclear, ask follow-up questions first.\n* Write **only in active voice**.\n* Fact-check every statement; avoid ambiguity.\n* Keep the tone professional, direct, and slightly conversational (not stiff, not overly casual).\n* Do **not** use these words or phrases: meticulous, meticulously, navigating, complexities, realm, bespoke, tailored, towards, underpins, everchanging, ever-evolving, the world of, not only, seeking more than just, designed to enhance, it’s not merely, our suite, it is advisable, daunting, dive into, unique, ensure, utmost, in the heart of, when it comes to, in the realm of, amongst, unlock the secrets, unveil the secrets, robust.\n* If the topic is highly technical, adopt a developer-centric voice.\n* Aim for very high readability: varied sentence lengths, mostly short, crisp lines.\n* Cut all fluff; every sentence must add value.\n* Sprinkle **1–2 engagement cues mid-post** (e.g., “Ever faced this?” “Would you have done the same?”).\n* Encourage reflection and conversation; posts should feel like they invite community input.\n\n**Output Requirements**\n\n1. Start with 2–3 **hook variations** for the first line. The main post should pick the best one, but show the alternates.\n2. Write 3–5 short paragraphs that are concise, engaging, and rich in practical insights or reflections that people can apply or debate.\n3. End with a thought-provoking or community-driven question that drives comments.\n4. Add 4–6 relevant hashtags that balance **broad reach (e.g., #AI, #Startups)** with **niche visibility** (#TechnicalWriting, #DecisionAutomation).\n5. Use 2–4 natural, well-placed emojis to break monotony and add emphasis.\n6. Keep total length under 2500 characters (shorter posts often perform better).\n\n**Formatting Rules**\n\n* Do **not** use double quotes, special characters, or Markdown symbols in the post text.\n* Escape the text so it is JSON-compatible.\n* Provide the output in JSON format with fields: `hook_variations`, `post`, `hashtags`.\n\n**Post Input**\nUse this title:\n{{ $json['Post title'] }}",
        "options": {
          "systemMessage": "=You are an expert LinkedIn content strategist and copywriter.\nYour job is to generate thought-leadership posts for a technical writer that maximize impressions, engagement, and community interaction.\n\n## **Principles to Follow**\n\n* Always clarify the topic first if unclear.\n* Write only in **active voice**.\n* Fact-check every statement. Avoid vague or unverified claims.\n* Maintain a tone that is professional, direct, and slightly conversational. Never stiff, never overly casual.\n* If the topic is technical, adopt a **developer-centric voice**.\n* Keep posts highly readable: mix sentence lengths, but favor short, crisp lines.\n* Eliminate fluff: every sentence must provide value.\n* Include 1–2 **engagement cues mid-post** (e.g., Ever faced this? Would you have done the same?).\n* Posts should encourage reflection and conversation, not just broadcasting.\n\n## **Banned Words & Phrases**\n\nDo not use:\nmeticulous, meticulously, navigating, complexities, realm, bespoke, tailored, towards, underpins, everchanging, ever-evolving, the world of, not only, seeking more than just, designed to enhance, it’s not merely, our suite, it is advisable, daunting, dive into, unique, ensure, utmost, in the heart of, when it comes to, amongst, unlock the secrets, unveil the secrets, robust.\n\n## **Output Rules**\n\n1. Provide 2–3 strong **hook variations** for the opening line.\n2. Write the post in **3–5 short paragraphs**. Each must be concise, engaging, and packed with practical insights or reflections.\n3. End with a **thought-provoking, community-driven question** that invites comments.\n4. Add 4–6 relevant hashtags: balance broad reach (#AI, #Startups) with niche visibility (#TechnicalWriting, #DecisionAutomation).\n5. Use 2–4 natural emojis to add emphasis without overloading the text.\n6. Keep the post under **2500 characters**.\n\n## **Formatting Rules**\n\n* Do not use quotes, special characters, or Markdown formatting inside the post.\n* Escape all text so it is JSON-compatible.\n* Final output must be in strict **JSON format** with the following fields:\n\n```json\n{\n  \"hook_variations\": [],\n  \"post\": \"\",\n  \"hashtags\": []\n}\n```\n\n## **Post Input**\n\nUse this title as the seed topic:\n`{{ $json['Post title'] }}`\n"
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.8
    },
    {
      "id": "66c2ef92-3d87-4e3c-a6d4-fd336824e5b8",
      "name": "Create a post",
      "type": "n8n-nodes-base.linkedIn",
      "position": [
        1248,
        -16
      ],
      "parameters": {
        "text": "={{ $json.output.post }}",
        "person": "ioXQWCBoFo",
        "additionalFields": {}
      },
      "credentials": {
        "linkedInOAuth2Api": {
          "id": "credential-id",
          "name": "linkedInOAuth2Api Credential"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "22f5b4da-9ac9-46f0-88e2-f8c96c872d12",
      "name": "Fetch the pending contents from the sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        224,
        0
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "Pending",
              "lookupColumn": "Status"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1KeZa_v-ayxEAkCYUdMsH9GPmjCp7yTnBkG6J4f1gQJQ/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1KeZa_v-ayxEAkCYUdMsH9GPmjCp7yTnBkG6J4f1gQJQ",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1KeZa_v-ayxEAkCYUdMsH9GPmjCp7yTnBkG6J4f1gQJQ/edit?usp=drivesdk",
          "cachedResultName": "Linkedin Plan"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "credential-id",
          "name": "googleSheetsOAuth2Api Credential"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "1f57c9e8-1a65-4193-8221-58c56a8f72cb",
      "name": "Selecting the first one only",
      "type": "n8n-nodes-base.limit",
      "position": [
        448,
        0
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "9f83d2cb-bd60-4d3b-9887-cc5a6bf45f07",
      "name": "Update row to Done in sheet1",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1472,
        -16
      ],
      "parameters": {
        "columns": {
          "value": {
            "id": "={{ $('Selecting the first one only').item.json.id }}",
            "Status": "Done",
            "Column 5": "={{ $('writing the post').item.json.output.post }}"
          },
          "schema": [
            {
              "id": "id",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "id",
              "defaultMatch": true,
              "canBeUsedToMatch": true
            },
            {
              "id": "Post title",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Post title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Post description",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Post description",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Column 5",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Column 5",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1KeZa_v-ayxEAkCYUdMsH9GPmjCp7yTnBkG6J4f1gQJQ/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1KeZa_v-ayxEAkCYUdMsH9GPmjCp7yTnBkG6J4f1gQJQ",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1KeZa_v-ayxEAkCYUdMsH9GPmjCp7yTnBkG6J4f1gQJQ/edit?usp=drivesdk",
          "cachedResultName": "Linkedin Plan"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "credential-id",
          "name": "googleSheetsOAuth2Api Credential"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "10a4a1de-3b90-45ee-b8d1-feeacae5ab34",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -32,
        -256
      ],
      "parameters": {
        "width": 608,
        "height": 512,
        "content": "## Note: Fetch topics from Google Sheets\n\n* **Credentials:** Google Sheets (OAuth2)\n* **Node:** Google Sheets → Get Rows (Spreadsheet ID/URL, Tab = `Posts`)\n* **Filter:** IF → `Status` equals `Pending`\n* **Limit:** 1 item per run\n* **Fields to keep:** `id`, `Status`, `Post title`, optional `Hashtags`, `Notes`"
      },
      "typeVersion": 1
    },
    {
      "id": "52081427-4a81-47ca-a9a1-fafca4d6026c",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1152,
        -272
      ],
      "parameters": {
        "color": 2,
        "width": 1040,
        "height": 1264,
        "content": "\n\n## Step-by-step\n\n1. **Schedule Trigger**\n   Runs on **Mon/Wed/Fri at 09:30**.\n2. **Fetch pending rows (Google Sheets → Get Rows)**\n   Reads the sheet and filters rows where **Status = Pending**.\n3. **Limit**\n   Keeps only the first pending row so one post goes out per run.\n4. **Writing the post (Agent + OpenAI Chat Model + Structured Output Parser)**\n   Uses **Post title** (and optional `Notes`/`Hashtags`) as input. The agent returns JSON with a `post` field. Model set to **gpt-4o-mini** by default.\n5. **Create a post (LinkedIn)**\n   Publishes `{{$json.output.post}}` to the configured **person** (your profile URN).\n6. **Update the sheet (Google Sheets → Update)**\n   Matches by `id`, sets **Status = Done**, and writes the generated text into **Output post** (or your existing output column).\n\n## Customization\n\n* **Schedule** — change days/time in the Schedule node. Consider your n8n server timezone.\n* **Posts per run** — remove or raise the **Limit** to post more than one item.\n* **Style and tone** — edit the Agent’s system prompt. Add rules for line breaks, hashtags, or a closing CTA.\n* **Hashtags handling** — parse the `Hashtags` column in the prompt so the model appends them cleanly.\n* **Media posts** — add a branch that attaches `Image URL` (requires LinkedIn media upload endpoints).\n* **Company Page** — switch the **person** field to an **organization** URN tied to your LinkedIn app scope.\n\n## Troubleshooting\n\n* **No post created**\n\n  * Check the **If/Limit** path: is there any row with `Status = Pending`?\n  * Confirm the sheet **ID** and **tab name** in the Google Sheets nodes.\n* **Sheet not updating**\n\n  * The **Update** node must receive the original `id`. If you changed field names, remap them.\n  * Make sure `id` values are unique.\n* **LinkedIn errors (403/401/404)**\n\n  * Refresh **LinkedIn OAuth2** in Credentials.\n  * The **person/organization URN** is wrong or missing. Copy the exact URN from the LinkedIn node helper.\n  * App lacks required permissions for posting.\n* **Rate limit (429) or model errors**\n\n  * Add a short **Wait** before retries.\n  * Switch to a lighter model or simplify the prompt.\n* **Post too long or broken formatting**\n\n  * LinkedIn hard limit is \\~3,000 characters. Add a truncation step in Code or instruct the prompt to cap length.\n  * Replace double line breaks in the LinkedIn node if you see odd spacing.\n* **Timezone mismatch**\n\n  * The Schedule node uses the n8n instance timezone. Adjust or move to a Cron with explicit TZ if needed.\n\nNeed to post at a different cadence, or push two posts per day? Tweak the **Schedule** and **Limit** nodes and you’re set.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "5b4554b6-5841-4ad2-b167-1da7db6e8d4c",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        624,
        -288
      ],
      "parameters": {
        "color": 6,
        "width": 480,
        "height": 688,
        "content": "## Note: AI post generation\n\n* **Credentials:** OpenAI\n* **Nodes:** Agent → OpenAI Chat Model\n* **Prompt (brief):** 3–6 short lines, ≤1200 chars, append provided hashtags, no new emojis\n* **Inputs:** `{{$json[\"Post title\"]}}`, `{{$json[\"Hashtags\"]||\"\"}}`, `{{$json[\"Notes\"]||\"\"}}`\n* **Model:** `gpt-4o-mini`\n* **Output path:** `{{$json.output.post}}`"
      },
      "typeVersion": 1
    },
    {
      "id": "c1c7bbdb-a5e6-409d-9ebc-ff8e89a7f690",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1184,
        -288
      ],
      "parameters": {
        "color": 4,
        "width": 480,
        "height": 496,
        "content": "## Note: Publish to LinkedIn\n\n* **Credentials:** LinkedIn OAuth2\n* **Node:** LinkedIn → Create Post\n* **Person URN:** your profile URN (e.g., `urn:li:person:XXXX`)\n* **Text:** `{{$json.output.post}}` ; **Visibility:** PUBLIC\n* **Optional media:** add upload step for image URL\n* **After publish:** Google Sheets → Update by `id` → set `Status=Done`, write to `Output post`"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "41a299af-ba00-42f3-ab42-e65cc4a081e7",
  "connections": {
    "Create a post": {
      "main": [
        [
          {
            "node": "Update row to Done in sheet1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Fetch the pending contents from the sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "writing the post": {
      "main": [
        [
          {
            "node": "Create a post",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "writing the post",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "writing the post",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Selecting the first one only": {
      "main": [
        [
          {
            "node": "writing the post",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch the pending contents from the sheet": {
      "main": [
        [
          {
            "node": "Selecting the first one only",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}