Technical specification for Facebook auto-posting and ad campaign creation via n8n + Facebook Graph API + Marketing API
System User Token is the #1 priority. This is the permanent token that never expires. Without it, you'll need to refresh tokens every 60 days. To create one: Business Manager → Business Settings → System Users → Add → Admin role → Generate Token → Select your app → Enable: pages_manage_posts, pages_read_engagement, ads_management, ads_read → Set expiration to "Never" → Generate.
| Permission | For | How to Enable |
|---|---|---|
pages_manage_posts | Publishing posts to page | App Review → Add Permission (or Live Mode for owned pages) |
pages_read_engagement | Reading page data + getting page token | App Review → Add Permission |
ads_management | Creating ad sets, creatives, ads | Marketing API access (standard or advanced) |
ads_read | Reading campaign performance | Marketing API access |
business_management | Managing business assets | Business Manager system user |
Watches the "GTM Posts" Notion database for new entries with status = "Ready to Publish". Polls every 5 minutes.
Checks that Caption and Image URL both exist. Routes to error handler if missing.
Uses the Graph API to post a photo with caption to the Facebook Page. This is the core API call.
Image URL must be publicly accessible. Facebook fetches the image from the URL. If using Notion file URLs, they expire after 1 hour. Solution: use a permanent host (Cloudflare R2, S3, Imgur) or fetch+re-upload within the workflow before posting.
Updates the original Notion row: Status → "Published", adds the FB Post ID and publish timestamp.
Created in Business Manager → System Users. Never expires. Set once in n8n credentials, forget about it. This is the production-grade approach.
If System User isn't available. Exchange short-lived token → long-lived (60 days). Set up a cron workflow to refresh every 30 days.
Watches "GTM Campaigns" DB for rows with status = "Launch". Contains all ad parameters: budget, targeting, creative URL, copy.
Creates an ad set under the existing campaign. Defines budget, schedule, targeting, and optimization goal.
Downloads the ad image from the URL stored in Notion. Returns binary data for upload.
Uploads the image to the ad account's image library. Returns a hash used in the creative.
Combines the uploaded image with ad copy, headline, CTA button, and link to create the ad creative object.
Creates the actual ad by linking the creative to the ad set. Starts in PAUSED status for review.
Updates the campaign row in Notion with all created IDs for tracking and management.
| Property | Type |
|---|---|
| Post Name | Title |
| Caption | Rich Text |
| Image URL | URL |
| Platform | Select: FB, IG, Both |
| Status | Status: Draft → Ready to Publish → Published → Error |
| Business | Select: CC, DVC, FJ, Other |
| Page ID | Text (FB Page ID) |
| FB Post ID | Text (auto-filled) |
| Published At | Date (auto-filled) |
| Schedule For | Date (optional future post) |
| Property | Type |
|---|---|
| Campaign Name | Title |
| Ad Copy | Rich Text |
| Headline | Text |
| Description | Text |
| Creative Image URL | URL |
| Landing Page URL | URL |
| CTA | Select: LEARN_MORE, SHOP_NOW, SIGN_UP, BOOK_TRAVEL, CONTACT_US |
| Daily Budget | Number (USD) |
| Age Min / Age Max | Number |
| Countries | Text (comma-sep codes) |
| Interest ID / Name | Text |
| Campaign ID | Text (parent campaign) |
| Status | Status: Draft → Launch → Live → Error |
| Business | Select: CC, DVC, FJ, Other |
| Ad Set ID | Text (auto-filled) |
| Ad ID | Text (auto-filled) |
| Launched At | Date (auto-filled) |
Build "GTM Posts" and "GTM Campaigns" databases in Notion with all properties. No credentials needed. Can be done immediately.
Create the n8n workflow: Notion trigger → validate → post to FB → update Notion. Needs Page Access Token and Page ID to configure.
Create the n8n workflow: Notion trigger → create ad set → upload image → create creative → create ad → update Notion. Needs Ad Account ID, Campaign ID, Pixel ID.
Test both workflows with real data. Post goes live on FB page. Ad creates in paused state. Verify all Notion fields update correctly.
All ads are created with status: PAUSED. Nothing goes live until explicitly activated — either manually in Ads Manager or via a separate activation workflow.
Nothing fires until a human sets the status to "Ready to Publish" or "Launch" in Notion. This is the human approval gate.
Every action writes back to Notion: FB Post IDs, Ad IDs, timestamps, error messages. Complete paper trail for every execution.
Creating the Notion databases doesn't need any Facebook credentials. Once Fasai provides the tokens and IDs, the n8n workflows can be built in one session.