This workflow corresponds to n8n.io template #16961 — we link there as the canonical source.
This workflow follows the HTTP Request → OpenAI 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 →
{
"name": "Generate branded AI images with OpenAI and post them to social media via PostFast",
"nodes": [
{
"id": "t2-sticky-main",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
16,
16
],
"parameters": {
"width": 544,
"height": 768,
"content": "## Generate branded AI images with OpenAI and post them to social media via PostFast\n\n### How it works\n\nRuns Monday, Wednesday and Friday mornings. Loads your brand settings, retrieves connected PostFast accounts, filters the target platforms, asks OpenAI for a caption plus an image prompt, renders the image with gpt-image-1, then uploads one copy per selected account through pre-signed S3 URLs and schedules each account's post with its own media key.\n\n### Setup steps\n\n- Install the verified PostFast community node (n8n Cloud: enable Verified Community Nodes in the Admin Panel; self-hosted: install n8n-nodes-postfast).\n- Connect your PostFast credentials (API key from Settings > API) on the three PostFast nodes.\n- Connect OpenAI credentials on both OpenAI nodes.\n- Update Set Brand and Style: brand name, image style, topics, target platforms.\n- Run once manually and review the scheduled posts in your PostFast dashboard before activating.\n\n### Customization\n\nAdjust the image style, topics, posting days, image size or platform filter. Up to 8 accounts per run (the upload endpoint issues at most 8 image URLs per request)."
},
"typeVersion": 1
},
{
"id": "t2-sticky-1",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
592,
32
],
"parameters": {
"color": 7,
"width": 448,
"height": 400,
"content": "## Start and configure\n\nTriggers three times a week and sets the brand, style, topics and platform filter for the run."
},
"typeVersion": 1
},
{
"id": "t2-sticky-2",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1104,
32
],
"parameters": {
"color": 7,
"width": 448,
"height": 400,
"content": "## Fetch target accounts\n\nGets connected PostFast accounts and keeps the platforms you selected."
},
"typeVersion": 1
},
{
"id": "t2-sticky-3",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1616,
32
],
"parameters": {
"color": 7,
"width": 880,
"height": 400,
"content": "## Create the visual\n\nOpenAI writes the caption and image prompt, PostFast issues one pre-signed upload URL per account, then gpt-image-1 renders the image."
},
"typeVersion": 1
},
{
"id": "t2-sticky-4",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
2560,
32
],
"parameters": {
"color": 7,
"width": 912,
"height": 400,
"content": "## Upload and schedule\n\nThe image is uploaded once per account (each PUT sends a matching Content-Type header), then every account gets its own scheduled post with its own media key, one hour ahead."
},
"typeVersion": 1
},
{
"id": "t2-trigger",
"name": "When Mon Wed Fri at 7am",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
656,
240
],
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"triggerAtDay": [
1,
3,
5
],
"triggerAtHour": 7
}
]
}
},
"typeVersion": 1.2
},
{
"id": "t2-config",
"name": "Set Brand and Style",
"type": "n8n-nodes-base.set",
"position": [
864,
240
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "b1",
"name": "brandName",
"type": "string",
"value": "YOUR BRAND NAME"
},
{
"id": "b2",
"name": "imageStyle",
"type": "string",
"value": "clean flat vector illustration, soft pastel palette, blue accents, white background, no text"
},
{
"id": "b3",
"name": "topics",
"type": "string",
"value": "topic one, topic two, topic three"
},
{
"id": "b4",
"name": "platformFilter",
"type": "string",
"value": "INSTAGRAM, FACEBOOK, LINKEDIN, X"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "t2-accounts",
"name": "Fetch PostFast Accounts",
"type": "n8n-nodes-postfast.postFast",
"position": [
1168,
240
],
"parameters": {
"resource": "socialAccount"
},
"typeVersion": 1
},
{
"id": "t2-filter",
"name": "Filter Target Accounts",
"type": "n8n-nodes-base.code",
"position": [
1392,
240
],
"parameters": {
"jsCode": "// Keep only connected accounts on the platforms chosen in the configuration.\nconst cfg = $('Set Brand and Style').first().json;\nconst wanted = String(cfg.platformFilter || '').split(',').map(s => s.trim().toUpperCase()).filter(Boolean);\nconst accounts = $input.all().map(i => i.json);\n\nconst selected = accounts.filter(a => {\n const status = String(a.connectionStatus || 'CONNECTED').toUpperCase();\n const platform = String(a.platform || '').toUpperCase();\n return status === 'CONNECTED' && (wanted.length === 0 || wanted.includes(platform));\n});\n\nif (selected.length === 0) {\n throw new Error('No connected accounts matched the platform filter. Check the Set Brand and Style node and your PostFast connections.');\n}\nif (selected.length > 8) {\n throw new Error('More than 8 matching accounts. The upload endpoint issues at most 8 image URLs per request, so narrow the platform filter.');\n}\n\nreturn [{ json: {\n accountIds: selected.map(a => a.id ?? a.socialMediaId)\n} }];"
},
"typeVersion": 2
},
{
"id": "t2-caption",
"name": "Write Caption and Image Prompt",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
1680,
240
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini",
"cachedResultName": "gpt-4o-mini"
},
"options": {},
"messages": {
"values": [
{
"content": "=You are the social media voice of {{ $('Set Brand and Style').first().json.brandName }}. Pick ONE topic from: {{ $('Set Brand and Style').first().json.topics }}.\n\nReturn ONLY valid JSON: {\"caption\": \"an engaging 40-120 word social post about the topic with 2-3 hashtags\", \"imagePrompt\": \"a detailed prompt for an image that matches the caption, in this style: {{ $('Set Brand and Style').first().json.imageStyle }}\"}"
}
]
},
"jsonOutput": true
},
"typeVersion": 1.8
},
{
"id": "t2-uploadurl",
"name": "Get Upload URL",
"type": "n8n-nodes-postfast.postFast",
"position": [
2000,
240
],
"parameters": {
"count": "={{ $('Filter Target Accounts').first().json.accountIds.length }}",
"resource": "file",
"contentType": "image/png"
},
"typeVersion": 1
},
{
"id": "t2-image",
"name": "Generate Post Image",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
2176,
240
],
"parameters": {
"prompt": "={{ $('Write Caption and Image Prompt').first().json.message.content.imagePrompt }}",
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-image-1",
"cachedResultName": "gpt-image-1"
},
"options": {
"size": "1024x1024"
},
"resource": "image"
},
"typeVersion": 2.3
},
{
"id": "t2-prepare",
"name": "Prepare Uploads",
"type": "n8n-nodes-base.code",
"position": [
2624,
240
],
"parameters": {
"jsCode": "// One upload per account: pair each pre-signed URL with an account and attach the image binary.\nconst raw = $('Get Upload URL').all().map(i => i.json);\nlet urls = raw;\nif (raw.length === 1 && Array.isArray(raw[0])) urls = raw[0];\nelse if (raw.length === 1 && Array.isArray(raw[0].data)) urls = raw[0].data;\nelse if (raw.length === 1 && Array.isArray(raw[0].urls)) urls = raw[0].urls;\n\nconst accountIds = $('Filter Target Accounts').first().json.accountIds;\nif (urls.length < accountIds.length) {\n throw new Error(`Got ${urls.length} signed URLs for ${accountIds.length} accounts. Check the Get Upload URL node's count.`);\n}\n\nconst binary = $('Generate Post Image').first().binary;\nreturn accountIds.map((accountId, i) => ({\n json: { accountId, signedUrl: urls[i].signedUrl, key: urls[i].key },\n binary\n}));"
},
"typeVersion": 2
},
{
"id": "t2-put",
"name": "Upload Image to S3",
"type": "n8n-nodes-base.httpRequest",
"position": [
2848,
240
],
"parameters": {
"url": "={{ $json.signedUrl }}",
"method": "PUT",
"options": {},
"sendBody": true,
"contentType": "binaryData",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "image/png"
}
]
},
"inputDataFieldName": "data"
},
"typeVersion": 4.2
},
{
"id": "t2-build",
"name": "Build Posts per Account",
"type": "n8n-nodes-base.code",
"position": [
3072,
240
],
"parameters": {
"jsCode": "// One scheduled post per account, each with its own uploaded media key.\nconst uploads = $('Prepare Uploads').all().map(i => i.json);\nconst caption = $('Write Caption and Image Prompt').first().json.message.content.caption;\nconst when = new Date(Date.now() + 60 * 60 * 1000).toISOString();\n\nreturn uploads.map(u => ({ json: {\n socialMediaId: u.accountId,\n content: caption,\n scheduledAt: when,\n mediaItemsJson: JSON.stringify([{ key: u.key, type: 'IMAGE', sortOrder: 0 }])\n} }));"
},
"typeVersion": 2
},
{
"id": "t2-create",
"name": "PostFast Scheduler",
"type": "n8n-nodes-postfast.postFast",
"position": [
3296,
240
],
"parameters": {
"posts": {
"post": [
{
"content": "={{ $json.content }}",
"scheduledAt": "={{ $json.scheduledAt }}",
"socialMediaId": "={{ $json.socialMediaId }}",
"mediaInputMode": "json",
"mediaItemsJson": "={{ $json.mediaItemsJson }}"
}
]
},
"controls": {}
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"connections": {
"Get Upload URL": {
"main": [
[
{
"node": "Generate Post Image",
"type": "main",
"index": 0
}
]
]
},
"Prepare Uploads": {
"main": [
[
{
"node": "Upload Image to S3",
"type": "main",
"index": 0
}
]
]
},
"Upload Image to S3": {
"main": [
[
{
"node": "Build Posts per Account",
"type": "main",
"index": 0
}
]
]
},
"Generate Post Image": {
"main": [
[
{
"node": "Prepare Uploads",
"type": "main",
"index": 0
}
]
]
},
"Set Brand and Style": {
"main": [
[
{
"node": "Fetch PostFast Accounts",
"type": "main",
"index": 0
}
]
]
},
"Filter Target Accounts": {
"main": [
[
{
"node": "Write Caption and Image Prompt",
"type": "main",
"index": 0
}
]
]
},
"Build Posts per Account": {
"main": [
[
{
"node": "PostFast Scheduler",
"type": "main",
"index": 0
}
]
]
},
"Fetch PostFast Accounts": {
"main": [
[
{
"node": "Filter Target Accounts",
"type": "main",
"index": 0
}
]
]
},
"When Mon Wed Fri at 7am": {
"main": [
[
{
"node": "Set Brand and Style",
"type": "main",
"index": 0
}
]
]
},
"Write Caption and Image Prompt": {
"main": [
[
{
"node": "Get Upload URL",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow runs three times a week to generate a branded social caption and AI image with OpenAI, then uploads the image via PostFast pre-signed URLs and schedules the post across selected connected social accounts. Runs on a schedule every Monday, Wednesday, and Friday at…
Source: https://n8n.io/workflows/16961/ — 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.
AI Institutional Stock Valuation Engine with Risk Scoring & Scenario Targets
Overview This is a production-grade, fully automated stock analysis system built entirely in n8n. It combines institutional-level financial analysis, dual AI model consensus, and a self-improving back
Workflow runs at 08:00 (UK), AI stories from TechCrunch, The Verge, and the OpenAI Blog via RSS, AI to select and editorially shape one signal into a post and image prompt, generates and QA-checks a p
This automation is a complete end-to-end system designed to find, qualify, and contact B2B leads — fully automated and powered by AI. Searches for target companies on LinkedIn via Ghost Genius API, us
This comprehensive n8n automation template orchestrates a complete end-to-end workflow for generating engaging short-form Point-of-View (POV) style videos using multiple AI services and automatically