AutomationFlowsData & Sheets › Post Scheduler

Post Scheduler

Post Scheduler. Uses postgres, googleDrive, httpRequest. Scheduled trigger; 20 nodes.

Cron / scheduled trigger★★★★☆ complexity20 nodesPostgresGoogle DriveHTTP Request
Data & Sheets Trigger: Cron / scheduled Nodes: 20 Complexity: ★★★★☆ Added:

This workflow follows the Google Drive → HTTP Request 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 →

Download .json
{
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 1
            }
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        16,
        -96
      ],
      "id": "07f36081-6e50-4957-8852-5ca340fab7ce",
      "name": "Schedule Trigger"
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT \n  psc.id as config_id,\n  psc.page_id,\n  psc.current_file_index,\n  psc.captions,\n  psc.slot_group_ids,\n  p.facebook_page_id,\n  p.access_token_webhook as access_token,\n  p.name as page_name,\n  -- Find the slot index matching NOW\n  (\n    SELECT i - 1\n    FROM generate_series(1, array_length(psc.post_times, 1)) i\n    WHERE DATE_TRUNC('minute', psc.post_times[i]::TIME) = DATE_TRUNC('minute', CURRENT_TIME::TIME)\n    LIMIT 1\n  ) as time_index,\n  psc.subfolder_ids,\n  psc.subfolder_names,\n  psc.last_posted_times\nFROM post_schedule_config psc\nJOIN pages p ON p.id = psc.page_id\nWHERE psc.is_active = true\n  AND p.is_active = true\n  AND DATE_TRUNC('minute', CURRENT_TIME::TIME) = ANY(\n    ARRAY(SELECT DATE_TRUNC('minute', t) FROM UNNEST(psc.post_times) AS t)\n  )\n  -- Per-slot deduplication: only block if THIS SPECIFIC SLOT already posted today\n  AND (\n    psc.last_posted_times IS NULL\n    OR array_length(psc.last_posted_times, 1) IS NULL\n    OR psc.last_posted_times[(\n        SELECT i\n        FROM generate_series(1, array_length(psc.post_times, 1)) i\n        WHERE DATE_TRUNC('minute', psc.post_times[i]::TIME) = DATE_TRUNC('minute', CURRENT_TIME::TIME)\n        LIMIT 1\n      )] IS NULL\n    OR DATE(psc.last_posted_times[(\n        SELECT i\n        FROM generate_series(1, array_length(psc.post_times, 1)) i\n        WHERE DATE_TRUNC('minute', psc.post_times[i]::TIME) = DATE_TRUNC('minute', CURRENT_TIME::TIME)\n        LIMIT 1\n      )]) < CURRENT_DATE\n  );",
        "options": {
          "connectionTimeout": 5000000
        }
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        224,
        -96
      ],
      "id": "c83adc34-0b00-481c-9796-01f590eb6a8d",
      "name": "Postgres - Get_Scheduled_Posts_Now",
      "alwaysOutputData": true,
      "retryOnFail": true,
      "waitBetweenTries": 5000,
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "f9218b5c-3b4d-411f-9a50-d038ab159861",
              "leftValue": "={{ $json.config_id !== undefined && $json.config_id !== null }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        432,
        -96
      ],
      "id": "1ed1a07c-23ab-420e-8dda-6910f879f1a1",
      "name": "Has_Posts_To_Make"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        768,
        -112
      ],
      "id": "f1ce7f80-29af-4390-a4d6-28ee7ca970c6",
      "name": "Loop_Over_Configs"
    },
    {
      "parameters": {
        "jsCode": "const loopData = $input.first().json;\n\nconst timeIndex = loopData.time_index;\nconst safeIndex = timeIndex !== null && timeIndex !== undefined ? timeIndex : 0;\n\nconst subfolderIds = loopData.subfolder_ids || [];\nconst subfolderNames = loopData.subfolder_names || [];\n\nconst currentSubfolderId = subfolderIds[safeIndex] || subfolderIds[0];\nconst currentSubfolderName = subfolderNames[safeIndex] || subfolderNames[0];\n\n// Extract group IDs for this slot from slot_group_ids (JSONB array of arrays)\nlet slotGroupIds = [];\ntry {\n  const sgRaw = loopData.slot_group_ids;\n  const sgArr = typeof sgRaw === 'string' ? JSON.parse(sgRaw) : (sgRaw || []);\n  slotGroupIds = (sgArr[safeIndex] || []);\n} catch(e) {\n  slotGroupIds = [];\n}\n\nreturn [{\n  json: {\n    ...loopData,\n    current_subfolder_id: currentSubfolderId,\n    current_subfolder_name: currentSubfolderName,\n    time_index: safeIndex,\n    slot_group_ids_for_slot: slotGroupIds\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        992,
        -96
      ],
      "id": "38561b40-f15c-4b4c-82b6-52b8a6689d37",
      "name": "Code_Extract_Subfolder_ID"
    },
    {
      "parameters": {
        "resource": "fileFolder",
        "searchMethod": "query",
        "queryString": "={{ \"'\" + $json.current_subfolder_id + \"' in parents\" }}",
        "returnAll": true,
        "filter": {},
        "options": {
          "fields": [
            "id",
            "name",
            "mimeType"
          ]
        }
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        1184,
        -96
      ],
      "id": "5db14240-e9bd-465d-96f5-5db51099b0ef",
      "name": "Google_Drive_List_Files",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Get all files from Google Drive\nconst allFiles = $input.all();\n\n// Get config data from the loop\nconst loopData = $('Loop_Over_Configs').item.json;\nconst timeIndex = loopData.time_index;\nconst subfolderIds = loopData.subfolder_ids;\nconst subfolderNames = loopData.subfolder_names;\nconst slotGroupIds = loopData.slot_group_ids_for_slot || [];\n\n// Filter only images and videos\nconst imageTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/jpg'];\nconst videoTypes = ['video/mp4', 'video/quicktime', 'video/x-msvideo', 'video/x-matroska'];\n\nconst mediaFiles = allFiles.filter(item => {\n  const mimeType = item.json.mimeType;\n  return imageTypes.includes(mimeType) || videoTypes.includes(mimeType);\n});\n\nif (mediaFiles.length === 0) {\n  return [{ \n    json: {\n      error: 'No media files found in subfolder',\n      config_id: loopData.config_id,\n      page_id: loopData.page_id\n    }\n  }];\n}\n\n// Sort by name for stable, predictable ordering\nmediaFiles.sort((a, b) => a.json.name.localeCompare(b.json.name));\n\nconst currentIndex = loopData.current_file_index;\nconst fileIndex = currentIndex % mediaFiles.length;\nconst selectedFile = mediaFiles[fileIndex].json;\nconst fileType = imageTypes.includes(selectedFile.mimeType) ? 'image' : 'video';\nconst nextIndex = currentIndex + 1;\n\nreturn [{ \n  json: {\n    file_id: selectedFile.id,\n    file_name: selectedFile.name,\n    file_type: fileType,\n    mime_type: selectedFile.mimeType,\n    current_index: currentIndex,\n    next_index: nextIndex,\n    total_files: mediaFiles.length,\n    config_id: loopData.config_id,\n    page_id: loopData.page_id,\n    facebook_page_id: loopData.facebook_page_id,\n    access_token: loopData.access_token,\n    time_index: timeIndex,\n    subfolder_id: subfolderIds[timeIndex],\n    subfolder_name: subfolderNames[timeIndex],\n    slot_group_ids_for_slot: slotGroupIds\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1360,
        -96
      ],
      "id": "84be80fc-798d-4a42-beee-df7a9232ed1f",
      "name": "Code_Select_File_By_Index"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "6f95b24d-afcd-451f-a03d-6872989ba255",
              "leftValue": "={{ $json.error === undefined && $json.file_id !== undefined }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        1568,
        -96
      ],
      "id": "268ae8d7-64f9-42c8-b17a-a962fd7779f4",
      "name": "IF_File_Found"
    },
    {
      "parameters": {
        "operation": "download",
        "fileId": {
          "__rl": true,
          "value": "={{ $json.file_id }}",
          "mode": "id"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        1808,
        -112
      ],
      "id": "48eee034-a7ca-48c3-bc76-4064a2d960cb",
      "name": "Google_Drive_Download_File",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const fileData = $('Code_Select_File_By_Index').first().json;\nconst loopData = $('Loop_Over_Configs').first().json;\n\n// Parse captions array\nlet captions = [];\nif (loopData.captions && loopData.captions !== 'null') {\n  try {\n    captions = Array.isArray(loopData.captions) ? loopData.captions : JSON.parse(loopData.captions);\n  } catch(e) {\n    captions = [];\n  }\n}\n\nconst timeIndex = fileData.time_index || 0;\nconst defaultCaption = '\ud83d\udcf8 Nouveau contenu !';\n\nlet caption;\nif (captions.length > 0 && captions[timeIndex]) {\n  caption = captions[timeIndex];\n} else {\n  caption = defaultCaption;\n}\n\nconst inputItem = $input.first();\n\nreturn [{\n  json: {\n    file_id: fileData.file_id,\n    file_name: fileData.file_name,\n    file_type: fileData.file_type,\n    mime_type: fileData.mime_type,\n    current_index: fileData.current_index,\n    next_index: fileData.next_index,\n    total_files: fileData.total_files,\n    config_id: fileData.config_id,\n    page_id: fileData.page_id,\n    facebook_page_id: loopData.facebook_page_id,\n    access_token: loopData.access_token,\n    caption: caption,\n    subfolder_id: fileData.subfolder_id,\n    subfolder_name: fileData.subfolder_name,\n    slot_group_ids_for_slot: fileData.slot_group_ids_for_slot || []\n  },\n  binary: inputItem.binary\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2016,
        -112
      ],
      "id": "d3cb408b-b867-4b83-9d15-4e5340d6b1f9",
      "name": "Code: Prepare_Caption"
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.file_type === 'image' }}",
                    "rightValue": "",
                    "operator": {
                      "type": "boolean",
                      "operation": "true",
                      "singleValue": true
                    },
                    "id": "0135578b-63e3-4f43-820b-5a05974c5517"
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Image"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "8b5020b3-49af-42db-b1d8-a613c2e37c1a",
                    "leftValue": "={{ $json.file_type === 'image' }}",
                    "rightValue": "",
                    "operator": {
                      "type": "boolean",
                      "operation": "false",
                      "singleValue": true
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Video"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.4,
      "position": [
        2224,
        -112
      ],
      "id": "1614ec9c-a8a2-470e-89de-65f969eec8ba",
      "name": "Image_Or_Video"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://graph.facebook.com/v21.0/{{ $json.facebook_page_id }}/photos",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "access_token",
              "value": "={{ $json.access_token }}"
            }
          ]
        },
        "sendBody": true,
        "contentType": "multipart-form-data",
        "bodyParameters": {
          "parameters": [
            {
              "name": "message",
              "value": "={{ $json.caption }}"
            },
            {
              "parameterType": "formBinaryData",
              "name": "source",
              "inputDataFieldName": "data"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        2448,
        -208
      ],
      "id": "b9cefbf7-ab07-48a7-ab69-778eb1e06606",
      "name": "HTTP_Post_Image_To_Facebook"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://graph.facebook.com/v21.0/{{ $json.facebook_page_id }}/videos",
        "sendBody": true,
        "contentType": "multipart-form-data",
        "bodyParameters": {
          "parameters": [
            {
              "name": "description",
              "value": "={{ $json.caption }}"
            },
            {
              "name": "access_token",
              "value": "={{ $json.access_token }}"
            },
            {
              "parameterType": "formBinaryData",
              "name": "source",
              "inputDataFieldName": "data"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        2448,
        -48
      ],
      "id": "2f446845-6dea-4686-93a8-63cd0212297a",
      "name": "HTTP - Post_Video_To_Facebook"
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3.2,
      "position": [
        2672,
        -112
      ],
      "id": "3dc4780f-de07-49a3-9da4-0ae7b4a0e856",
      "name": "Merge1"
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO posted_files (\n  page_id, \n  google_drive_file_id, \n  file_name, \n  file_type,\n  facebook_post_id,\n  status,\n  posted_at\n) VALUES (\n  '{{ $('Image_Or_Video').item.json.page_id }}'::uuid,\n  '{{ $('Image_Or_Video').item.json.file_id }}',\n  '{{ $('Image_Or_Video').item.json.file_name }}',\n  '{{ $('Image_Or_Video').item.json.file_type }}',\n  '{{ $json.id ?? $json.post_id ?? \"\" }}',\n  'success',\n  NOW()\n);\n\nUPDATE post_schedule_config\nSET\n  last_posted_at = NOW(),\n  current_file_index = {{ $('Image_Or_Video').item.json.next_index }},\n  -- Update only the slot that just posted; leave other slots untouched.\n  -- Uses a subquery to rebuild the array with NOW() at position (time_index + 1).\n  last_posted_times = (\n    SELECT ARRAY(\n      SELECT CASE \n        WHEN i = {{ $('Image_Or_Video').item.json.time_index }} + 1\n        THEN NOW()\n        ELSE COALESCE(last_posted_times[i], NULL)\n      END\n      FROM generate_series(\n        1,\n        GREATEST(\n          COALESCE(array_length(post_times, 1), 1),\n          {{ $('Image_Or_Video').item.json.time_index }} + 1\n        )\n      ) i\n    )\n  )\nWHERE id = '{{ $('Image_Or_Video').item.json.config_id }}'::uuid;",
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        2864,
        -112
      ],
      "id": "de262538-a905-4196-98e4-891828deeabf",
      "name": "Postgres - Log_Posted_File",
      "alwaysOutputData": true,
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Fetch facebook_groups rows for each group ID in slot_group_ids_for_slot\n// Returns one item per group that is active, or empty array if no groups\n\nconst prepData = $('Code: Prepare_Caption').first().json;\nconst groupIds = prepData.slot_group_ids_for_slot || [];\n\nif (groupIds.length === 0) return [];\n\n// Fetch group details from PostgREST\nconst baseUrl = 'http://207.180.232.14:3002';\nconst results = [];\n\nfor (const groupRowId of groupIds) {\n  const resp = await $http.get(`${baseUrl}/facebook_groups?id=eq.${groupRowId}&is_active=eq.true&select=id,group_id,group_name`);\n  const rows = Array.isArray(resp.data) ? resp.data : [];\n  for (const row of rows) {\n    results.push({\n      json: {\n        group_row_id: row.id,\n        facebook_group_id: row.group_id,\n        group_name: row.group_name,\n        file_id: prepData.file_id,\n        file_name: prepData.file_name,\n        file_type: prepData.file_type,\n        mime_type: prepData.mime_type,\n        caption: prepData.caption,\n        access_token: prepData.access_token\n      },\n      binary: $('Code: Prepare_Caption').first().binary\n    });\n  }\n}\n\nreturn results;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3080,
        -112
      ],
      "id": "aa000001-0000-0000-0000-000000000001",
      "name": "Code_Prepare_Group_Posts"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "gg000001",
              "leftValue": "={{ $json.facebook_group_id !== undefined }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        3280,
        -112
      ],
      "id": "aa000002-0000-0000-0000-000000000002",
      "name": "IF_Has_Groups"
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.file_type === 'image' }}",
                    "rightValue": "",
                    "operator": {
                      "type": "boolean",
                      "operation": "true",
                      "singleValue": true
                    },
                    "id": "gg000003"
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Image"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "gg000004",
                    "leftValue": "={{ $json.file_type === 'image' }}",
                    "rightValue": "",
                    "operator": {
                      "type": "boolean",
                      "operation": "false",
                      "singleValue": true
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Video"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.4,
      "position": [
        3480,
        -112
      ],
      "id": "aa000003-0000-0000-0000-000000000003",
      "name": "Group_Image_Or_Video"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://graph.facebook.com/v21.0/{{ $json.facebook_group_id }}/photos",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "access_token",
              "value": "={{ $json.access_token }}"
            }
          ]
        },
        "sendBody": true,
        "contentType": "multipart-form-data",
        "bodyParameters": {
          "parameters": [
            {
              "name": "message",
              "value": "={{ $json.caption }}"
            },
            {
              "parameterType": "formBinaryData",
              "name": "source",
              "inputDataFieldName": "data"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        3680,
        -208
      ],
      "id": "aa000004-0000-0000-0000-000000000004",
      "name": "HTTP_Post_Image_To_Group"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://graph.facebook.com/v21.0/{{ $json.facebook_group_id }}/videos",
        "sendBody": true,
        "contentType": "multipart-form-data",
        "bodyParameters": {
          "parameters": [
            {
              "name": "description",
              "value": "={{ $json.caption }}"
            },
            {
              "name": "access_token",
              "value": "={{ $json.access_token }}"
            },
            {
              "parameterType": "formBinaryData",
              "name": "source",
              "inputDataFieldName": "data"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        3680,
        -48
      ],
      "id": "aa000005-0000-0000-0000-000000000005",
      "name": "HTTP_Post_Video_To_Group"
    }
  ],
  "connections": {
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Postgres - Get_Scheduled_Posts_Now",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Postgres - Get_Scheduled_Posts_Now": {
      "main": [
        [
          {
            "node": "Has_Posts_To_Make",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has_Posts_To_Make": {
      "main": [
        [
          {
            "node": "Loop_Over_Configs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop_Over_Configs": {
      "main": [
        [],
        [
          {
            "node": "Code_Extract_Subfolder_ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code_Extract_Subfolder_ID": {
      "main": [
        [
          {
            "node": "Google_Drive_List_Files",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google_Drive_List_Files": {
      "main": [
        [
          {
            "node": "Code_Select_File_By_Index",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code_Select_File_By_Index": {
      "main": [
        [
          {
            "node": "IF_File_Found",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF_File_Found": {
      "main": [
        [
          {
            "node": "Google_Drive_Download_File",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Google_Drive_Download_File": {
      "main": [
        [
          {
            "node": "Code: Prepare_Caption",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code: Prepare_Caption": {
      "main": [
        [
          {
            "node": "Image_Or_Video",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Image_Or_Video": {
      "main": [
        [
          {
            "node": "HTTP_Post_Image_To_Facebook",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "HTTP - Post_Video_To_Facebook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP_Post_Image_To_Facebook": {
      "main": [
        [
          {
            "node": "Merge1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP - Post_Video_To_Facebook": {
      "main": [
        [
          {
            "node": "Merge1",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Merge1": {
      "main": [
        [
          {
            "node": "Postgres - Log_Posted_File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Postgres - Log_Posted_File": {
      "main": [
        [
          {
            "node": "Code_Prepare_Group_Posts",
            "type": "main",
            "index": 0
          },
          {
            "node": "Loop_Over_Configs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code_Prepare_Group_Posts": {
      "main": [
        [
          {
            "node": "IF_Has_Groups",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF_Has_Groups": {
      "main": [
        [
          {
            "node": "Group_Image_Or_Video",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Group_Image_Or_Video": {
      "main": [
        [
          {
            "node": "HTTP_Post_Image_To_Group",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "HTTP_Post_Video_To_Group",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "templateCredsSetupCompleted": true
  }
}

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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Post Scheduler. Uses postgres, googleDrive, httpRequest. Scheduled trigger; 20 nodes.

Source: https://github.com/hitchMCM/mcmbotflowdashboard/blob/343983119f24877a90f639ad21a148fcb88d5c6e/n8n/post_scheduler.json — original creator credit. Request a take-down →

More Data & Sheets workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Data & Sheets

Automated Knowledge Management Backup & Recovery. Uses executeCommand, postgres, httpRequest, googleDrive. Scheduled trigger; 30 nodes.

Execute Command, Postgres, HTTP Request +1
Data & Sheets

This workflow is a multi-system document synchronization pipeline built in n8n, designed to automatically sync and back up files between Microsoft SharePoint, Supabase/Postgres, and Google Drive.

HTTP Request, Supabase, Postgres +1
Data & Sheets

This workflow acts as a junior finance research analyst for a UK boutique M&A or corporate finance team. It listens for Slack messages, classifies the request, gathers company or market data, and prod

HTTP Request, Google Drive, Google Docs +5
Data & Sheets

Disparador 1.8. Uses itemLists, postgres, emailSend, httpRequest. Scheduled trigger; 85 nodes.

Item Lists, Postgres, Email Send +1
Data & Sheets

공유회_알림톡_크론. Uses postgres, httpRequest, n8n-nodes-solapi. Scheduled trigger; 39 nodes.

Postgres, HTTP Request, N8N Nodes Solapi