This workflow corresponds to n8n.io template #5773 — we link there as the canonical source.
This workflow follows the Agent → OpenRouter Chat recipe pattern — see all workflows that pair these two integrations.
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": "universal-social-generator",
"meta": {
"templateCredsSetupCompleted": false
},
"name": "Universal Social Media Content Generator with AI",
"tags": [
"social-media",
"automation",
"ai",
"content-generation",
"twitter",
"linkedin"
],
"nodes": [
{
"id": "c6047198-7450-4cb5-bceb-4e2b73358d84",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
280,
-180
],
"parameters": {
"rule": {
"interval": [
{
"description": "Triggers the workflow every 5 days at 9 AM. You can adjust the frequency and time based on your content posting schedule.",
"daysInterval": 5,
"triggerAtHour": 9
}
]
}
},
"description": "This node triggers your content generation workflow on a schedule. Default is every 5 days at 9 AM, but you can adjust this to daily, weekly, or any custom schedule that fits your content strategy. The workflow will start automatically at the specified time.",
"typeVersion": 1.2
},
{
"id": "ec142ab7-8ce7-4184-b5a7-a2dc017cf204",
"name": "Create Schedule Timestamp",
"type": "n8n-nodes-base.code",
"position": [
500,
-180
],
"parameters": {
"jsCode": "// This node creates a human-readable timestamp for the current schedule run\n// It helps track when each content generation session was initiated\n\nconst today = new Date();\nconst days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];\nconst scheduleName = `${days[today.getDay()]} ${today.getHours()}:00`;\n\nreturn [{\n json: {\n scheduleName: scheduleName,\n timestamp: new Date().toISOString(),\n workflowId: $workflow.id\n }\n}];"
},
"description": "Creates a human-readable timestamp and schedule name for tracking purposes. This helps you identify which schedule triggered the content generation, especially useful if you have multiple schedules running.",
"typeVersion": 2
},
{
"id": "f042b594-63ee-4f6f-8c8c-5c279b3e9725",
"name": "Request Content Topic via Telegram",
"type": "n8n-nodes-base.telegram",
"position": [
720,
-180
],
"parameters": {
"text": "\ud83d\ude80 **Content Generation Time!**\n\nIt's time for your {{ $json.scheduleName }} content creation session.\n\nPlease reply with:\n- Your topic or theme\n- Type 'single' for one post or 'thread' for multiple connected posts\n\nExample responses:\n- 'sustainable living tips - single'\n- 'how to start a podcast - thread'\n- 'morning motivation - single'",
"chatId": "{{ $credentials.telegramChatId }}",
"additionalFields": {}
},
"description": "Sends a message to your Telegram chat asking for the content topic and format. The message will appear in the Telegram chat/channel you've configured in the credentials. Make sure to set up your Telegram bot and add the chat ID in the credentials.",
"typeVersion": 1.2
},
{
"id": "14f2252b-731d-45a3-9fca-2042986054a7",
"name": "Wait for User Topic Reply",
"type": "n8n-nodes-base.telegramTrigger",
"position": [
720,
260
],
"parameters": {
"updates": [
"message"
],
"additionalFields": {}
},
"description": "This webhook listens for your reply in Telegram. When you send a message in response to the topic request, this node captures it and passes it to the next step. Make sure the webhook is properly configured in your Telegram bot settings.",
"typeVersion": 1.1
},
{
"id": "423bd47a-2512-492e-933a-ece6eafd82d2",
"name": "Validate Reply Format",
"type": "n8n-nodes-base.if",
"position": [
620,
580
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "486d068f-b5cb-4af4-aee8-beb09dd02802",
"operator": {
"type": "any",
"operation": "exists"
},
"leftValue": "={{ $json.message.reply_to_message }}"
},
{
"id": "9b8ba1b0-008e-4749-b808-9b9cfd8480ae",
"operator": {
"type": "string",
"operation": "isNotEmpty"
},
"leftValue": "={{ $json.message.text }}"
}
]
}
},
"description": "Checks if the Telegram message is a valid reply to the bot's request. It ensures the message is not empty and is actually a reply to the bot's prompt. This prevents the workflow from processing random messages in the chat.",
"typeVersion": 2
},
{
"id": "848c5396-8b1b-458c-ae14-b32314d0cdac",
"name": "Parse User Input",
"type": "n8n-nodes-base.code",
"position": [
860,
600
],
"parameters": {
"jsCode": "// This node parses the user input and validates the format\n// Expected format: 'topic - format' where format is 'single' or 'thread'\n// If no format is specified, it defaults to 'auto'\n\ntry {\n const userInput = $json.message.text;\n let topic, formatType;\n \n if (userInput.includes(' - ')) {\n const parts = userInput.split(' - ');\n topic = parts[0].trim();\n formatType = parts[1].trim().toLowerCase();\n } else {\n // If no format specified, default to auto\n topic = userInput.trim();\n formatType = \"auto\";\n }\n \n // Validate format type\n const validFormats = ['single', 'thread', 'auto'];\n if (!validFormats.includes(formatType)) {\n throw new Error(`Invalid format type: ${formatType}. Use 'single', 'thread', or 'auto'`);\n }\n \n // Validate topic length\n if (topic.length < 3) {\n throw new Error('Topic too short. Please provide a more detailed topic.');\n }\n \n return [{\n json: {\n topic: topic,\n format_type: formatType,\n chat_id: $json.message.chat.id,\n username: $json.message.from.username,\n original_message: userInput,\n validation_status: 'passed'\n }\n }];\n} catch (error) {\n return [{\n json: {\n error: error.message,\n validation_status: 'failed',\n chat_id: $json.message.chat.id\n }\n }];\n}"
},
"description": "Extracts the topic and format from the user's message. Supports three formats: 'single' (one post), 'thread' (multiple connected posts), or 'auto' (let AI decide). The topic must be at least 3 characters long. If format is not specified, defaults to 'auto'.",
"typeVersion": 2
},
{
"id": "c82ea174-70e4-4fa1-89df-1809d6a7beb1",
"name": "Input Validation Check",
"type": "n8n-nodes-base.if",
"position": [
1040,
600
],
"parameters": {
"options": {},
"conditions": {
"options": {},
"combinator": "and",
"conditions": [
{
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.validation_status }}",
"rightValue": "passed"
}
]
}
},
"description": "Routes the workflow based on validation results. If the input passes validation, it proceeds to content generation. If validation fails, it sends an error message back to the user with instructions on the correct format.",
"typeVersion": 2
},
{
"id": "d4b44f05-a404-4024-9a9d-c4a7ea968269",
"name": "Send Input Error Message",
"type": "n8n-nodes-base.telegram",
"position": [
1280,
900
],
"parameters": {
"text": "\u274c **Input Error**\n\n{{ $json.error }}\n\nPlease try again with the correct format:\n'your topic - single' or 'your topic - thread'\n\nExamples:\n- 'productivity tips - single'\n- 'beginner's guide to investing - thread'\n- 'motivational quote' (defaults to auto)",
"chatId": "={{ $json.chat_id }}",
"additionalFields": {}
},
"description": "Sends an error message to the user if their input format is incorrect. Provides clear examples of the expected format to help users correct their input.",
"typeVersion": 1.2
},
{
"id": "6a2eda85-388f-46a8-96db-8c1dea1893ec",
"name": "AI Content Generator",
"type": "@n8n/n8n-nodes-langchain.agent",
"maxTries": 3,
"position": [
1280,
220
],
"parameters": {
"text": "=Create social media content about: {{ $json.topic }}\nFormat type: {{ $json.format_type }}",
"options": {
"systemMessage": "=You are a professional social media content creator. Your task is to generate engaging, high-quality content for Twitter/X and LinkedIn.\n\nCONTENT REQUIREMENTS:\n\nCHARACTER COUNT:\n- EVERY tweet/post MUST be between 240-265 characters\n- Count characters before finalizing\n- Rewrite if outside this range\n\nFORMAT GUIDELINES:\n- For 'single': Create one standalone post\n- For 'thread': Create 3-6 connected posts that tell a complete story\n- For 'auto': Decide based on topic complexity (simple topics = single, complex = thread)\n\nWRITING STYLE:\n- Clear, conversational tone\n- Use simple language\n- Include 1-2 relevant hashtags\n- Be engaging and value-driven\n- Professional but approachable\n- NO numbered lists in the beginning of posts (avoid \"1/\", \"2/\" etc.)\n\nCONTENT STRUCTURE:\n- Hook: Start with an attention-grabbing statement\n- Value: Provide useful information or insights\n- Call-to-action: Encourage engagement (questions, thoughts, actions)\n\nADAPT TO TOPIC:\n- Business topics: Professional, data-driven\n- Creative topics: Inspiring, imaginative\n- Educational topics: Clear, structured\n- Personal topics: Authentic, relatable\n- Technical topics: Simple explanations, practical examples\n\nREMEMBER:\n- Quality over quantity\n- Each post should provide value\n- Maintain consistency in tone throughout threads\n- Use line breaks for readability\n- End threads with a summary or key takeaway"
},
"promptType": "define",
"hasOutputParser": true
},
"description": "The AI agent that generates your social media content. It uses the topic and format you provided to create posts optimized for engagement. The system prompt ensures consistent quality and character count. Configure retry attempts (default: 3) for reliability.",
"retryOnFail": true,
"typeVersion": 1.7
},
{
"id": "fba80a7f-9426-433d-af64-033effba9a06",
"name": "Structure AI Output",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
1480,
440
],
"parameters": {
"schemaType": "manual",
"inputSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"event_name\": {\n \"type\": \"string\",\n \"description\": \"Name or title for this content batch\"\n },\n \"event_description\": {\n \"type\": \"string\",\n \"description\": \"Brief description of the content theme\"\n },\n \"content_type\": {\n \"type\": \"string\",\n \"description\": \"Either 'single' or 'thread'\"\n },\n \"platform_posts\": {\n \"type\": \"object\",\n \"properties\": {\n \"Twitter\": {\n \"type\": \"object\",\n \"properties\": {\n \"thread\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"tweet_number\": {\n \"type\": \"integer\",\n \"description\": \"Order number in thread\"\n },\n \"post\": {\n \"type\": \"string\",\n \"description\": \"The actual tweet content\"\n },\n \"character_count\": {\n \"type\": \"integer\",\n \"description\": \"Character count for validation\"\n }\n }\n }\n },\n \"single_post\": {\n \"type\": \"string\",\n \"description\": \"Content for single post format\"\n },\n \"hashtags\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n },\n \"description\": \"List of hashtags used\"\n },\n \"thread_length\": {\n \"type\": \"integer\",\n \"description\": \"Number of posts in thread\"\n }\n }\n }\n }\n },\n \"additional_notes\": {\n \"type\": \"string\",\n \"description\": \"Any additional context or notes\"\n }\n }\n}"
},
"description": "Defines the expected JSON structure for the AI's output. This ensures the AI returns content in a consistent format that can be processed by subsequent nodes. The schema includes fields for both single posts and threads.",
"typeVersion": 1.2
},
{
"id": "09b580d2-71bc-44ab-ba69-96da0fc4bd2a",
"name": "Validate Generated Content",
"type": "n8n-nodes-base.code",
"position": [
1580,
220
],
"parameters": {
"jsCode": "// This node validates the AI-generated content to ensure quality standards\n// It checks character counts, structure, and content formatting\n\ntry {\n const aiOutput = $json.output || $json;\n \n // Validate AI output structure\n if (!aiOutput.platform_posts?.Twitter) {\n throw new Error('Invalid AI output: Missing Twitter platform data');\n }\n \n const twitterData = aiOutput.platform_posts.Twitter;\n let tweets = [];\n let contentType = 'unknown';\n \n // Handle thread content\n if (twitterData.thread && Array.isArray(twitterData.thread)) {\n tweets = twitterData.thread;\n contentType = 'thread';\n console.log('Processing thread with ' + tweets.length + ' tweets');\n }\n // Handle single tweet content\n else if (twitterData.single_post) {\n tweets = [{\n tweet_number: 1,\n post: twitterData.single_post,\n character_count: twitterData.single_post.length\n }];\n contentType = 'single';\n console.log('Processing single tweet');\n } else {\n throw new Error('No valid tweet content found in AI output');\n }\n \n // Validate each tweet\n const validatedTweets = [];\n const warnings = [];\n let criticalErrors = 0;\n \n tweets.forEach((tweet, index) => {\n const tweetNumber = index + 1;\n const content = tweet.post || '';\n const charCount = content.length;\n let tweetHasIssues = false;\n \n // Character count validation\n if (charCount < 240 || charCount > 265) {\n warnings.push('Tweet ' + tweetNumber + ': ' + charCount + ' characters (recommended 240-265)');\n // Only count as critical error if severely outside range\n if (charCount < 216 || charCount > 291) {\n criticalErrors++;\n tweetHasIssues = true;\n }\n }\n \n // Check for numbered format at start (e.g., \"1/\", \"2/\")\n if (/^\\d+[\\.\\/]/.test(content.trim())) {\n warnings.push('Tweet ' + tweetNumber + ': Starts with numbering (not recommended)');\n }\n \n validatedTweets.push({\n ...tweet,\n tweet_number: tweetNumber,\n character_count: charCount,\n has_issues: tweetHasIssues,\n validation_passed: !tweetHasIssues\n });\n \n console.log('Tweet ' + tweetNumber + ': ' + charCount + ' chars - \"' + content.substring(0, 50) + '...\"');\n });\n \n // Calculate error percentage\n const errorPercentage = (criticalErrors / tweets.length) * 100;\n const shouldPass = errorPercentage <= 30; // Pass if 30% or fewer critical errors\n \n console.log('Validation summary: ' + criticalErrors + '/' + tweets.length + ' critical errors (' + errorPercentage.toFixed(1) + '%)');\n console.log('Warnings: ' + warnings.length + ' total warnings');\n \n // Only fail if critical errors exceed 30%\n if (!shouldPass) {\n throw new Error('Critical validation failed: ' + errorPercentage.toFixed(1) + '% error rate exceeds 30% threshold');\n }\n \n return [{\n json: {\n ...aiOutput,\n content_type: contentType,\n tweet_count: validatedTweets.length,\n tweets_array: validatedTweets,\n validation_summary: {\n critical_errors: criticalErrors,\n error_percentage: Math.round(errorPercentage * 10) / 10,\n warnings: warnings.length,\n passed_threshold: shouldPass,\n warning_details: warnings\n },\n validation_status: 'passed',\n processed_at: new Date().toISOString()\n }\n }];\n \n} catch (error) {\n console.error('Content validation error:', error.message);\n return [{\n json: {\n error: error.message,\n validation_status: 'failed',\n processed_at: new Date().toISOString()\n }\n }];\n}"
},
"description": "Performs quality checks on AI-generated content: character count validation (240-265 chars), format checking, and structure validation. Allows up to 30% error rate for flexibility. Logs detailed validation results for debugging.",
"typeVersion": 2
},
{
"id": "48628c73-df64-4929-a6a8-55f2f12c3508",
"name": "Content Quality Gate",
"type": "n8n-nodes-base.if",
"position": [
1780,
220
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "96348250-726c-457a-8958-955c37e8d52f",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.validation_status }}",
"rightValue": "passed"
}
]
}
},
"description": "Final quality check before sending content for approval. Routes to preview creation if validation passed, or to error handling if content doesn't meet quality standards.",
"typeVersion": 2
},
{
"id": "44b0da94-d647-450c-854a-1b8ba0806b55",
"name": "Send Generation Error",
"type": "n8n-nodes-base.telegram",
"position": [
1980,
460
],
"parameters": {
"text": "\u274c **Content Generation Failed**\n\n{{ $json.error }}\n\nThe AI couldn't generate content that meets quality requirements. This usually happens with very complex or unclear topics.\n\nTips:\n- Try simplifying your topic\n- Be more specific about what you want\n- Try a different format (single vs thread)\n\nPlease try again with a different topic or approach.",
"chatId": "{{ $node['Parse User Input'].json.chat_id }}",
"additionalFields": {}
},
"description": "Notifies the user if content generation fails. Provides helpful tips on how to improve their topic or format choice for better results.",
"typeVersion": 1.2
},
{
"id": "30276c5b-ea66-4447-9421-fc16c2bfef5d",
"name": "Format Content Preview",
"type": "n8n-nodes-base.code",
"position": [
2000,
260
],
"parameters": {
"jsCode": "// Create a formatted preview of the generated content for user approval\nconst tweets = $json.tweets_array;\nconst contentType = $json.content_type;\n\nlet previewText = `\ud83d\udcdd **Generated ${contentType.toUpperCase()} Content**\\n\\n`;\npreviewText += `**Topic:** ${$node['Parse User Input'].json.topic}\\n`;\npreviewText += `**Format:** ${contentType}\\n`;\npreviewText += `**Post Count:** ${tweets.length}\\n\\n`;\n\n// Add each tweet to the preview\ntweets.forEach((tweet, index) => {\n const tweetNum = index + 1;\n previewText += `**Post ${tweetNum}** (${tweet.character_count} chars):\\n`;\n previewText += `${tweet.post}\\n\\n`;\n});\n\npreviewText += `---\\n**Ready to post?**\\nClick \u2705 to approve or \u274c to cancel`;\n\nreturn [{\n json: {\n ...($json),\n preview_text: previewText\n }\n}];"
},
"description": "Creates a readable preview of all generated content for user review. Shows the topic, format, character count for each post, and the full content. This allows users to review before posting.",
"typeVersion": 2
},
{
"id": "4ba432c8-9200-4dcb-959e-d6d096cba3fa",
"name": "Send Preview & Await Approval",
"type": "n8n-nodes-base.telegram",
"position": [
2260,
400
],
"parameters": {
"chatId": "{{ $node['Parse User Input'].json.chat_id }}",
"message": "={{ $json.preview_text }}",
"options": {
"appendAttribution": false
},
"operation": "sendAndWait",
"approvalOptions": {
"values": {
"approvalType": "double"
}
}
},
"description": "Sends the content preview to Telegram and waits for user approval. Users can click \u2705 to approve and post the content, or \u274c to cancel. The workflow pauses here until a response is received.",
"typeVersion": 1.2
},
{
"id": "c40d3bc1-e247-4e8c-964a-9a7a7287fcb6",
"name": "Check User Approval",
"type": "n8n-nodes-base.if",
"position": [
2480,
400
],
"parameters": {
"options": {},
"conditions": {
"options": {},
"combinator": "and",
"conditions": [
{
"operator": {
"type": "boolean",
"operation": "true"
},
"leftValue": "={{ $json.data.approved }}",
"rightValue": true
}
]
}
},
"description": "Routes the workflow based on user's approval decision. If approved (\u2705), proceeds to post the content. If rejected (\u274c), sends a cancellation message.",
"typeVersion": 2
},
{
"id": "ea61caeb-b22e-4169-a2e1-a6922f5b335e",
"name": "Send Cancellation Notice",
"type": "n8n-nodes-base.telegram",
"position": [
2720,
520
],
"parameters": {
"text": "\u274c **Content Cancelled**\n\nThe content has been cancelled as requested.\n\nYou can start over by sending a new topic anytime.",
"chatId": "={{ $node['Parse User Input'].json.chat_id }}",
"additionalFields": {}
},
"description": "Confirms to the user that their content has been cancelled and won't be posted. Encourages them to try again with a new topic.",
"typeVersion": 1.2
},
{
"id": "6a425708-64be-4784-9222-1bf4baeeee0d",
"name": "Split Posts for Publishing",
"type": "n8n-nodes-base.splitOut",
"position": [
2700,
280
],
"parameters": {
"options": {},
"fieldToSplitOut": "tweets_array"
},
"description": "Separates the array of posts into individual items for sequential posting. This is essential for threads, as each post needs to be published separately and linked together.",
"typeVersion": 1
},
{
"id": "591278b0-cbaa-4b19-9f21-b9cea1bf496d",
"name": "Web Research Tool (Optional)",
"type": "@tavily/n8n-nodes-tavily.tavilyTool",
"position": [
1360,
420
],
"parameters": {
"query": "={{ $fromAI('Query', '', 'string') }}",
"options": {}
},
"description": "Optional research tool that the AI can use to gather current information about the topic. Useful for trending topics, news, or fact-checking. Requires Tavily API credentials.",
"typeVersion": 1
},
{
"id": "7aaa1b89-a52e-4629-9a1f-298c1ff5b5f8",
"name": "AI Language Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
"position": [
1240,
400
],
"parameters": {
"model": "openai/gpt-4o",
"options": {}
},
"description": "The AI model used for content generation. Default is GPT-4 via OpenRouter. You can change this to other models like Claude, Gemini, or any model supported by OpenRouter. Model choice affects content quality and style.",
"typeVersion": 1
},
{
"id": "7ba56c4c-7803-46ce-9fab-4ed514d63943",
"name": "Workflow Documentation",
"type": "n8n-nodes-base.stickyNote",
"position": [
-440,
660
],
"parameters": {
"color": 4,
"width": 400,
"height": 800,
"content": "# Universal Social Media Content Generator\n\n## Overview\nThis workflow automates social media content creation using AI. It generates high-quality posts for Twitter/X and LinkedIn based on any topic you provide.\n\n## Features\n- **Scheduled or Manual Triggers**: Run automatically on schedule or start manually\n- **AI-Powered Generation**: Uses advanced language models to create engaging content\n- **Quality Validation**: Ensures posts meet character limits and quality standards\n- **Approval Workflow**: Review content before posting\n- **Multi-Platform Support**: Posts to both Twitter/X and LinkedIn\n- **Thread Support**: Create single posts or connected threads\n\n## Setup Requirements\n1. **Telegram Bot**: For receiving topics and approvals\n - Create a bot via @BotFather\n - Get your chat ID\n - Add credentials to n8n\n\n2. **OpenRouter API**: For AI content generation\n - Sign up at openrouter.ai\n - Add API key to credentials\n\n3. **Upload Post API**: For publishing to social platforms\n - Configure your social media accounts\n - Add credentials to n8n\n\n4. **Tavily API (Optional)**: For web research\n - Only needed if you want AI to research topics\n - Sign up at tavily.com\n\n## Usage\n1. Workflow triggers on schedule or manually\n2. You receive a Telegram message asking for topic\n3. Reply with format: \"your topic - single\" or \"your topic - thread\"\n4. AI generates content (240-265 chars per post)\n5. Review the preview in Telegram\n6. Approve (\u2705) or Cancel (\u274c)\n7. Content posts to your configured platforms\n\n## Customization\n- **Topics**: Works with any topic or niche\n- **Tone**: Adjust the AI system prompt for your brand voice\n- **Schedule**: Change trigger frequency as needed\n- **Platforms**: Modify which platforms to post to\n- **Validation**: Adjust character limits or quality thresholds\n\n## Tips\n- Be specific with topics for better results\n- Use 'thread' format for complex topics\n- Review and edit the AI system prompt for your needs\n- Test with different AI models for varied styles"
},
"description": "Complete documentation for setting up and using this workflow. Read this first to understand all features and requirements.",
"typeVersion": 1
},
{
"id": "ecbaf1e6-f852-4faa-ad06-231748c335b0",
"name": "Merge Approval Data",
"type": "n8n-nodes-base.merge",
"position": [
2260,
200
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineByPosition"
},
"description": "Combines the content data with the approval response to pass all necessary information to the next steps.",
"typeVersion": 3.2
},
{
"id": "622b3d5c-b200-4f06-927b-5b1364227c57",
"name": "Send Success Notification",
"type": "n8n-nodes-base.telegram",
"position": [
3040,
560
],
"parameters": {
"text": "\u2705 **Content Published Successfully!**\n\nLinkedIn: {{ $json.results.linkedin.success ? 'Posted' : 'Failed' }}\nTwitter/X: {{ $json.results.x.success ? 'Posted' : 'Failed' }}\n\nYour content is now live on the selected platforms. Check your accounts to see the posts and monitor engagement.",
"chatId": "{{ $node['Parse User Input'].json.chat_id }}",
"additionalFields": {
"appendAttribution": false
}
},
"description": "Sends a final confirmation message showing which platforms successfully received the content. Helps you track posting status and troubleshoot any platform-specific issues.",
"typeVersion": 1.2
},
{
"id": "125aba9a-b320-4349-b5d0-21fb4099941a",
"name": "Publish to Social Platforms",
"type": "n8n-nodes-upload-post.uploadPost",
"position": [
3080,
280
],
"parameters": {
"user": "{{ $credentials.username }}",
"title": "={{ $json.post }}",
"platform": [
"x",
"linkedin"
],
"operation": "uploadText",
"xReplySettings": "everyone"
},
"description": "Posts the content to Twitter/X and LinkedIn. Configure which platforms to use in the parameters. For threads, posts are published sequentially with proper reply chains on Twitter/X.",
"typeVersion": 1
}
],
"active": false,
"settings": {
"callerPolicy": "workflowsFromSameOwner",
"executionOrder": "v1"
},
"versionId": "1.0.0",
"connections": {
"Parse User Input": {
"main": [
[
{
"node": "Input Validation Check",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "Create Schedule Timestamp",
"type": "main",
"index": 0
}
]
]
},
"AI Language Model": {
"ai_languageModel": [
[
{
"node": "AI Content Generator",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Check User Approval": {
"main": [
[
{
"node": "Split Posts for Publishing",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Cancellation Notice",
"type": "main",
"index": 0
}
]
]
},
"Merge Approval Data": {
"main": [
[
{
"node": "Check User Approval",
"type": "main",
"index": 0
}
]
]
},
"Structure AI Output": {
"ai_outputParser": [
[
{
"node": "AI Content Generator",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"AI Content Generator": {
"main": [
[
{
"node": "Validate Generated Content",
"type": "main",
"index": 0
}
]
]
},
"Content Quality Gate": {
"main": [
[
{
"node": "Format Content Preview",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Generation Error",
"type": "main",
"index": 0
}
]
]
},
"Validate Reply Format": {
"main": [
[],
[
{
"node": "Parse User Input",
"type": "main",
"index": 0
}
]
]
},
"Format Content Preview": {
"main": [
[
{
"node": "Send Preview & Await Approval",
"type": "main",
"index": 0
},
{
"node": "Merge Approval Data",
"type": "main",
"index": 0
}
]
]
},
"Input Validation Check": {
"main": [
[
{
"node": "AI Content Generator",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Input Error Message",
"type": "main",
"index": 0
}
]
]
},
"Create Schedule Timestamp": {
"main": [
[
{
"node": "Request Content Topic via Telegram",
"type": "main",
"index": 0
}
]
]
},
"Send Success Notification": {
"main": [
[]
]
},
"Wait for User Topic Reply": {
"main": [
[
{
"node": "Validate Reply Format",
"type": "main",
"index": 0
}
]
]
},
"Split Posts for Publishing": {
"main": [
[
{
"node": "Publish to Social Platforms",
"type": "main",
"index": 0
}
]
]
},
"Validate Generated Content": {
"main": [
[
{
"node": "Content Quality Gate",
"type": "main",
"index": 0
}
]
]
},
"Publish to Social Platforms": {
"main": [
[
{
"node": "Send Success Notification",
"type": "main",
"index": 0
}
]
]
},
"Web Research Tool (Optional)": {
"ai_tool": [
[
{
"node": "AI Content Generator",
"type": "ai_tool",
"index": 0
}
]
]
},
"Send Preview & Await Approval": {
"main": [
[
{
"node": "Merge Approval Data",
"type": "main",
"index": 1
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Generate & Schedule Social Media Posts with GPT-4 and Telegram Approval Workflow
Source: https://n8n.io/workflows/5773/ — 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 cutting-edge n8n workflow is a comprehensive automation solution designed to streamline various Instagram operations. It combines an intelligent AI chatbot for direct message management, automate
This workflow automatically generates stock market insights for selected tickers (e.g. GAZP, SBER, LKOH) using historical data, technical indicators, and an AI model. The results are then sent to Tele
Promo Seeker automatically finds, verifies, and delivers active promo codes to users via Telegram or email using SerpAPI + Gemini (OpenRouter). Saves hours of manual searching and deduplicates results
This workflow contains community nodes that are only compatible with the self-hosted version of n8n.
RAG CHATBOT Main. Uses telegram, telegramTrigger, lmChatOpenAi, n8n-nodes-mcp. Event-driven trigger; 87 nodes.