This workflow follows the HTTP Request → Postgres 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": "wf009-publishing-0000000000000",
"name": "WF-009-publishing",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "*/30 * * * *"
}
]
}
},
"id": "c90900000-0009-0009-0009-000000000001",
"name": "Schedule 30min",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
0,
500
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT * FROM v_publishing_queue LIMIT 1",
"options": {}
},
"id": "c90900000-0009-0009-0009-000000000002",
"name": "Poll Publishing Queue",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
220,
500
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"typeValidation": "loose"
},
"conditions": [
{
"leftValue": "={{ $json.id }}",
"rightValue": "",
"operator": {
"type": "any",
"operation": "exists"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "c90900000-0009-0009-0009-000000000003",
"name": "Has Record?",
"type": "n8n-nodes-base.filter",
"typeVersion": 2.2,
"position": [
440,
500
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"typeValidation": "loose"
},
"conditions": [
{
"leftValue": "={{ !$json.scheduled_at || new Date($json.scheduled_at) <= new Date() }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "c90900000-0009-0009-0009-000000000004",
"name": "Is Time To Publish?",
"type": "n8n-nodes-base.filter",
"typeVersion": 2.2,
"position": [
660,
500
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "=SELECT ca.hook_variations, ca.story_arc, ca.seo_data, ca.cta_variations, ca.facts, s.title, s.platform, s.channel_id FROM content_assets ca, scripts s WHERE ca.id = {{ $json.asset_id }} AND s.id = {{ $json.script_id }}",
"options": {}
},
"id": "c90900000-0009-0009-0009-000000000005",
"name": "Fetch Full Context",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
880,
500
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "=SELECT media_type, file_path FROM media_assets WHERE asset_id = {{ $('Poll Publishing Queue').first().json.asset_id }} AND (script_id = {{ $('Poll Publishing Queue').first().json.script_id }} OR script_id IS NULL) AND media_type IN ('video','thumbnail') ORDER BY id DESC",
"options": {}
},
"id": "c90900000-0009-0009-0009-000000000006",
"name": "Fetch Media Files",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
1100,
500
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"aggregate": "aggregateAllItemData",
"destinationFieldName": "files"
},
"id": "c90900000-0009-0009-0009-000000000007",
"name": "Aggregate Media Files",
"type": "n8n-nodes-base.aggregate",
"typeVersion": 1,
"position": [
1320,
500
]
},
{
"parameters": {
"jsCode": "const pr = $('Poll Publishing Queue').first().json;\nconst ctx = $('Fetch Full Context').first().json;\nconst files = $('Aggregate Media Files').first().json.files || [];\nconst video = files.find(f => f.media_type === 'video');\nconst thumbnail = files.find(f => f.media_type === 'thumbnail');\n\nconst hook = (ctx.hook_variations || [])[0]?.text || '';\nconst takeaway = ctx.story_arc?.key_takeaway || '';\nconst cta = (ctx.cta_variations || []).find(c => c.platform === ctx.platform) || (ctx.cta_variations || [])[0] || {};\nconst tags = (ctx.seo_data?.tags || []).slice(0, 30);\nconst hashtags = tags.slice(0, 15).map(t => '#' + String(t).replace(/[^a-zA-Z0-9]/g, '')).join(' ');\n\nconst description = [\n hook,\n '',\n takeaway,\n '',\n cta.text || '',\n '',\n hashtags\n].filter(l => l !== undefined).join('\\n');\n\nreturn [{ json: {\n record_id: pr.id,\n asset_id: pr.asset_id,\n script_id: pr.script_id,\n channel_id: ctx.channel_id,\n title: ctx.title,\n description,\n tags,\n video_file_path: video ? video.file_path : null,\n thumbnail_file_path: thumbnail ? thumbnail.file_path : null\n} }];"
},
"id": "c90900000-0009-0009-0009-000000000008",
"name": "Build YouTube Metadata",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1540,
500
]
},
{
"parameters": {
"method": "GET",
"url": "=http://media-api:8080/api/v1/file?path={{ $('Build YouTube Metadata').first().json.video_file_path }}",
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
}
},
"id": "c90900000-0009-0009-0009-000000000010",
"name": "Download Video Binary",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1980,
500
]
},
{
"parameters": {
"method": "POST",
"url": "https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "youTubeOAuth2Api",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "X-Upload-Content-Type",
"value": "video/mp4"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ snippet: { title: $('Build YouTube Metadata').first().json.title, description: $('Build YouTube Metadata').first().json.description, tags: $('Build YouTube Metadata').first().json.tags, categoryId: '28', defaultLanguage: 'en' }, status: { privacyStatus: 'unlisted', selfDeclaredMadeForKids: false }, alterations: { hasAlterations: true } }) }}",
"options": {
"response": {
"response": {
"fullResponse": true
}
}
}
},
"id": "c90900000-0009-0009-0009-000000000011",
"name": "Initiate Resumable Upload",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
2200,
500
],
"credentials": {
"youTubeOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "return [{ json: { location: $json.headers.location }, binary: $('Download Video Binary').first().binary }];"
},
"id": "c90900000-0009-0009-0009-000000000025",
"name": "Merge Upload URL With Binary",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2310,
500
]
},
{
"parameters": {
"method": "PUT",
"url": "={{ $json.location }}",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "youTubeOAuth2Api",
"sendBody": true,
"contentType": "binaryData",
"inputDataFieldName": "data",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "video/mp4"
}
]
},
"options": {}
},
"id": "c90900000-0009-0009-0009-000000000012",
"name": "Upload Video Binary",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
2420,
500
],
"credentials": {
"youTubeOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"typeValidation": "loose"
},
"conditions": [
{
"leftValue": "={{ $json.id }}",
"rightValue": "",
"operator": {
"type": "string",
"operation": "notEmpty"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "c90900000-0009-0009-0009-000000000013",
"name": "Upload Success?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
2640,
500
]
},
{
"parameters": {
"jsCode": "return [{ json: {\n workflow_name: 'WF-009-publishing',\n execution_id: String($execution.id),\n node_name: 'Upload Video Binary',\n error_type: 'publish_failed',\n error_message: `YouTube video upload failed: ${JSON.stringify($json.error || $json)}`.slice(0, 1000),\n payload: { record_id: $('Build YouTube Metadata').first().json.record_id, asset_id: $('Build YouTube Metadata').first().json.asset_id }\n} }];"
},
"id": "c90900000-0009-0009-0009-000000000014",
"name": "Build DLQ Payload",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2860,
640
]
},
{
"parameters": {
"workflowId": {
"__rl": true,
"value": "sub002-dead-letter-queue-0000000",
"mode": "id"
},
"options": {}
},
"id": "c90900000-0009-0009-0009-000000000015",
"name": "Log to SUB-002",
"type": "n8n-nodes-base.executeWorkflow",
"typeVersion": 1.1,
"position": [
3080,
640
]
},
{
"parameters": {
"method": "GET",
"url": "=http://media-api:8080/api/v1/file?path={{ $('Build YouTube Metadata').first().json.thumbnail_file_path }}",
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
}
},
"id": "c90900000-0009-0009-0009-000000000016",
"name": "Download Thumbnail Binary",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
2860,
400
]
},
{
"parameters": {
"method": "POST",
"url": "=https://www.googleapis.com/upload/youtube/v3/thumbnails/set?videoId={{ $('Upload Video Binary').first().json.id }}",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "youTubeOAuth2Api",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "image/png"
}
]
},
"sendBody": true,
"contentType": "binaryData",
"inputDataFieldName": "data",
"options": {}
},
"id": "c90900000-0009-0009-0009-000000000017",
"name": "Upload Thumbnail",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
3080,
400
],
"onError": "continueRegularOutput",
"credentials": {
"youTubeOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"amount": 1800,
"unit": "seconds"
},
"id": "c90900000-0009-0009-0009-000000000018",
"name": "Wait 30 Minutes",
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
3300,
400
]
},
{
"parameters": {
"method": "PUT",
"url": "https://www.googleapis.com/youtube/v3/videos?part=status",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "youTubeOAuth2Api",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ id: $('Upload Video Binary').first().json.id, status: { privacyStatus: 'public' } }) }}",
"options": {}
},
"id": "c90900000-0009-0009-0009-000000000020",
"name": "Set Video Public",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
3740,
400
],
"credentials": {
"youTubeOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "=UPDATE publishing_records SET status = 'published', platform_id = '{{ $('Upload Video Binary').first().json.id }}', platform_url = 'https://youtube.com/watch?v={{ $('Upload Video Binary').first().json.id }}', published_at = NOW() WHERE id = {{ $('Build YouTube Metadata').first().json.record_id }} RETURNING id, platform_url",
"options": {}
},
"id": "c90900000-0009-0009-0009-000000000021",
"name": "Update Publishing Record",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
3960,
400
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "return [{ json: {\n message: `\\u2705 Published: ${$json.platform_url}`,\n parse_mode: 'Markdown',\n inline_keyboard: []\n} }];"
},
"id": "c90900000-0009-0009-0009-000000000022",
"name": "Build Success Message",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
4180,
400
]
},
{
"parameters": {
"workflowId": {
"__rl": true,
"value": "sub003-telegram-notification-000000",
"mode": "id"
},
"options": {}
},
"id": "c90900000-0009-0009-0009-000000000023",
"name": "Notify Success",
"type": "n8n-nodes-base.executeWorkflow",
"typeVersion": 1.1,
"position": [
4400,
400
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "=INSERT INTO workflow_logs (workflow_name, execution_id, status, input_summary, output_summary) VALUES ('WF-009-publishing', '{{ $execution.id }}', 'completed', '{{ JSON.stringify({ record_id: $('Build YouTube Metadata').first().json.record_id }) }}'::jsonb, '{{ JSON.stringify({ video_id: $('Upload Video Binary').first().json.id }) }}'::jsonb)",
"options": {}
},
"id": "c90900000-0009-0009-0009-000000000024",
"name": "Log Result Success",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
4620,
400
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
}
],
"connections": {
"Schedule 30min": {
"main": [
[
{
"node": "Poll Publishing Queue",
"type": "main",
"index": 0
}
]
]
},
"Poll Publishing Queue": {
"main": [
[
{
"node": "Has Record?",
"type": "main",
"index": 0
}
]
]
},
"Has Record?": {
"main": [
[
{
"node": "Is Time To Publish?",
"type": "main",
"index": 0
}
]
]
},
"Is Time To Publish?": {
"main": [
[
{
"node": "Fetch Full Context",
"type": "main",
"index": 0
}
]
]
},
"Fetch Full Context": {
"main": [
[
{
"node": "Fetch Media Files",
"type": "main",
"index": 0
}
]
]
},
"Fetch Media Files": {
"main": [
[
{
"node": "Aggregate Media Files",
"type": "main",
"index": 0
}
]
]
},
"Aggregate Media Files": {
"main": [
[
{
"node": "Build YouTube Metadata",
"type": "main",
"index": 0
}
]
]
},
"Build YouTube Metadata": {
"main": [
[
{
"node": "Download Video Binary",
"type": "main",
"index": 0
}
]
]
},
"Download Video Binary": {
"main": [
[
{
"node": "Initiate Resumable Upload",
"type": "main",
"index": 0
}
]
]
},
"Initiate Resumable Upload": {
"main": [
[
{
"node": "Merge Upload URL With Binary",
"type": "main",
"index": 0
}
]
]
},
"Merge Upload URL With Binary": {
"main": [
[
{
"node": "Upload Video Binary",
"type": "main",
"index": 0
}
]
]
},
"Upload Video Binary": {
"main": [
[
{
"node": "Upload Success?",
"type": "main",
"index": 0
}
]
]
},
"Upload Success?": {
"main": [
[
{
"node": "Download Thumbnail Binary",
"type": "main",
"index": 0
}
],
[
{
"node": "Build DLQ Payload",
"type": "main",
"index": 0
}
]
]
},
"Build DLQ Payload": {
"main": [
[
{
"node": "Log to SUB-002",
"type": "main",
"index": 0
}
]
]
},
"Download Thumbnail Binary": {
"main": [
[
{
"node": "Upload Thumbnail",
"type": "main",
"index": 0
}
]
]
},
"Upload Thumbnail": {
"main": [
[
{
"node": "Wait 30 Minutes",
"type": "main",
"index": 0
}
]
]
},
"Wait 30 Minutes": {
"main": [
[
{
"node": "Set Video Public",
"type": "main",
"index": 0
}
]
]
},
"Set Video Public": {
"main": [
[
{
"node": "Update Publishing Record",
"type": "main",
"index": 0
}
]
]
},
"Update Publishing Record": {
"main": [
[
{
"node": "Build Success Message",
"type": "main",
"index": 0
}
]
]
},
"Build Success Message": {
"main": [
[
{
"node": "Notify Success",
"type": "main",
"index": 0
}
]
]
},
"Notify Success": {
"main": [
[
{
"node": "Log Result Success",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
postgresyouTubeOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
WF-009-publishing. Uses postgres, httpRequest. Scheduled trigger; 23 nodes.
Source: https://github.com/navin-labs/content-factory-os/blob/main/n8n/workflows/main/WF-009-publishing.json — 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.
Disparador 1.8. Uses itemLists, postgres, emailSend, httpRequest. Scheduled trigger; 85 nodes.
공유회_알림톡_크론. Uses postgres, httpRequest, n8n-nodes-solapi. Scheduled trigger; 39 nodes.
QuepasaAutomatic. Uses postgres, postgresTrigger, httpRequest. Scheduled trigger; 39 nodes.
QuepasaAutomatic. Uses postgres, postgresTrigger, httpRequest. Scheduled trigger; 39 nodes.
QuepasaAutomatic. Uses postgres, postgresTrigger, httpRequest. Scheduled trigger; 39 nodes.