{
  "id": "IoPwQybp6rbdWwVV",
  "name": "Publish Facebook Reels from a Video URL",
  "tags": [],
  "nodes": [
    {
      "id": "0d23c905-fb94-4b9e-ae40-507eb484793e",
      "name": "Receive Reel Request",
      "type": "n8n-nodes-base.webhook",
      "position": [
        0,
        0
      ],
      "parameters": {
        "path": "facebook-reel-publish",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "43c18308-b84c-45f1-8218-23b131b03238",
      "name": "Set Facebook Page ID",
      "type": "n8n-nodes-base.set",
      "position": [
        224,
        0
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "page-id-1",
              "name": "page_id",
              "type": "string",
              "value": "YOUR_FACEBOOK_PAGE_ID"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "f978ac0a-c43c-4ea8-b44d-6b43acff4729",
      "name": "Start Upload Session",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        448,
        0
      ],
      "parameters": {
        "url": "=https://graph.facebook.com/v25.0/{{ $('Set Facebook Page ID').first().json.page_id }}/video_reels",
        "method": "POST",
        "options": {},
        "jsonBody": "={ \"upload_phase\": \"start\" }",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "645c5f70-83b1-408f-979e-db17ba41f534",
      "name": "Upload Video from URL",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        672,
        0
      ],
      "parameters": {
        "url": "=https://rupload.facebook.com/video-upload/v25.0/{{ $json.video_id }}",
        "method": "POST",
        "options": {
          "timeout": 120000
        },
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "file_url",
              "value": "={{ $('Receive Reel Request').first().json.body.video_url }}"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "3d5bcd9b-8459-428f-b764-db69556c3916",
      "name": "Wait for Processing",
      "type": "n8n-nodes-base.wait",
      "position": [
        880,
        0
      ],
      "parameters": {
        "amount": 8
      },
      "typeVersion": 1.1
    },
    {
      "id": "1186f848-8e2c-4fee-9c1c-dc7333951228",
      "name": "Finish Upload (Draft, Schedule or Publish)",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1104,
        0
      ],
      "parameters": {
        "url": "=https://graph.facebook.com/v25.0/{{ $('Set Facebook Page ID').first().json.page_id }}/video_reels",
        "method": "POST",
        "options": {
          "timeout": 60000
        },
        "jsonBody": "={{ JSON.stringify(Object.assign({\n  upload_phase: 'finish',\n  video_id: $('Start Upload Session').first().json.video_id,\n  video_state: $('Receive Reel Request').first().json.body.video_state || 'DRAFT',\n  description: $('Receive Reel Request').first().json.body.caption || ''\n}, $('Receive Reel Request').first().json.body.scheduled_publish_time ? { scheduled_publish_time: $('Receive Reel Request').first().json.body.scheduled_publish_time } : {})) }}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "20ce9581-1755-436c-8402-322d6244ebee",
      "name": "Build Reel Link",
      "type": "n8n-nodes-base.code",
      "position": [
        1328,
        0
      ],
      "parameters": {
        "jsCode": "\n// Build the response: the Reel link for the caller.\n// Errors from the finish call pass through as an error field.\nconst first = $input.first().json;\nconst vid = $('Start Upload Session').first().json.video_id;\nreturn [{ json: { video_id: vid, url: 'https://www.facebook.com/reel/' + vid, finish: first } }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "f04999f8-9d13-4359-a14b-9f58703e828e",
      "name": "Respond with Reel Link",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1552,
        0
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1.1
    },
    {
      "id": "61676334-5f0a-442a-81a0-6812e169d2d0",
      "name": "Note -760x-280",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -560,
        -384
      ],
      "parameters": {
        "width": 480,
        "height": 896,
        "content": "## Publish Facebook Reels from a video URL\n\n**How it works**\n- A webhook receives a JSON request with `video_url`, `caption` and an optional `video_state` (`DRAFT`, `SCHEDULED` or `PUBLISHED`, default `DRAFT`) plus `scheduled_publish_time` (unix timestamp, only for `SCHEDULED`).\n- The workflow runs Facebook's official three-phase Reel upload: it starts an upload session, lets Facebook pull the video directly from your URL (no file handling in n8n), then finishes the upload with your caption and publishing mode.\n- It responds with the new Reel's video id and link.\n\n**Setup steps**\n1. In Meta's developer portal, create an app connected to your Facebook Page and get a **Page access token** with `pages_show_list`, `pages_read_engagement` and `pages_manage_posts`. Page tokens of this type do not expire.\n2. Create an **HTTP Header Auth** credential: name `Authorization`, value `Bearer <your Page access token>`, and attach it to the three Facebook nodes.\n3. Enter your **Facebook Page ID** in the \"Set Facebook Page ID\" node.\n4. Send a POST request to the webhook, e.g. `{\"video_url\": \"https://example.com/my-reel.mp4\", \"caption\": \"Hello!\", \"video_state\": \"DRAFT\"}`.\n\nThe video must be publicly reachable, vertical (9:16) and max 90 seconds. Drafts appear in Meta Business Suite for review before publishing.\n\n**Why HTTP Request instead of the Facebook Graph API node?** The Reels upload phase requires the `rupload.facebook.com` host and a custom `file_url` header. The native node supports neither, so this template uses HTTP Request throughout: one credential covers all three calls."
      },
      "typeVersion": 1
    },
    {
      "id": "287f5719-f954-4957-ad0c-6e7661e90c29",
      "name": "Note -40x-140",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -48,
        -144
      ],
      "parameters": {
        "color": 7,
        "width": 500,
        "height": 360,
        "content": "## 1. Receive request\nThe webhook takes `video_url`, `caption` and the publishing mode from your app or another workflow. Your Page ID is set once here."
      },
      "typeVersion": 1
    },
    {
      "id": "e605e795-3ff4-42e8-a982-fee3e4b96ef2",
      "name": "Note 480x-140",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        480,
        -144
      ],
      "parameters": {
        "color": 7,
        "width": 840,
        "height": 360,
        "content": "## 2. Three-phase upload\nStart an upload session, let Facebook pull the video from your URL, then finish with caption and `DRAFT` / `SCHEDULED` / `PUBLISHED`."
      },
      "typeVersion": 1
    },
    {
      "id": "23dbaf6f-3500-4eb1-895d-a1a2e047ead4",
      "name": "Note 1340x-140",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1344,
        -144
      ],
      "parameters": {
        "color": 7,
        "width": 420,
        "height": 360,
        "content": "## 3. Respond\nReturns the video id and the Reel link to the caller."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "794c2631-e8e6-46ac-8975-19636f3464ba",
  "nodeGroups": [],
  "connections": {
    "Build Reel Link": {
      "main": [
        [
          {
            "node": "Respond with Reel Link",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for Processing": {
      "main": [
        [
          {
            "node": "Finish Upload (Draft, Schedule or Publish)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Receive Reel Request": {
      "main": [
        [
          {
            "node": "Set Facebook Page ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Facebook Page ID": {
      "main": [
        [
          {
            "node": "Start Upload Session",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Start Upload Session": {
      "main": [
        [
          {
            "node": "Upload Video from URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload Video from URL": {
      "main": [
        [
          {
            "node": "Wait for Processing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Finish Upload (Draft, Schedule or Publish)": {
      "main": [
        [
          {
            "node": "Build Reel Link",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}