Meta Ads Manager Integration
Overview
Meta Ads Manager (Facebook Ads) integration syncs advertising data from Meta's Marketing API into Gridlink. Each client can have one or more linked Meta ad accounts, enabling centralized reporting across the portfolio.
Authentication
Meta Ads uses the Graph API with System User Access Tokens issued through Meta Business Manager.
Setup Steps
ads_read permissionact_XXXXXXXXX), a label, and the access tokenToken Lifecycle
Required Credentials
| Credential | Where to Find | Stored In |
|---|---|---|
| App ID | developers.facebook.com → App Dashboard | Reference only |
| App Secret | developers.facebook.com → Settings → Basic | Reference only |
| Ad Account ID | business.facebook.com → Accounts → Ad Accounts | meta_ad_accounts.ad_account_id |
| Access Token | business.facebook.com → System Users → Generate Token | meta_ad_accounts.access_token |
Sync Behavior
Direction
Read-only. Gridlink pulls advertising data from Meta but never writes back. Campaign management is done in Meta Ads Manager directly.
Frequency
Every 15 minutes via meta-sync.timer systemd timer.
Lookback Window
--days 30)Rate Limits
Meta Graph API has variable rate limits based on app tier. The sync engine:
Objects Synced
| Meta Object | Mirror Table | Key Fields |
|---|---|---|
| Ad Accounts | meta_ad_accounts | ad_account_id, client_id, access_token, status |
| Campaigns | meta_campaigns | name, objective, status, effective_status, daily/lifetime budget, bid_strategy |
| Ad Sets | meta_adsets | name, campaign_id, status, budget, targeting (JSON), optimization_goal, billing_event |
| Ads | meta_ads | name, adset_id, campaign_id, status, creative (body, title, link, image, thumbnail) |
| Ad Insights (daily) | meta_ad_insights | ad/adset/campaign_id, date, impressions, clicks, CTR, CPC, CPM, spend, reach, frequency, conversions, video views (25/50/75/100%), actions (JSON) |
| Account Insights (daily) | meta_account_insights | account, date, impressions, clicks, CTR, CPC, CPM, spend, reach, frequency, conversions, actions (JSON) |
Data Model
Hierarchy
meta_ad_accounts (linked to client)
└── meta_campaigns
└── meta_adsets
└── meta_ads
└── meta_ad_insights (daily per ad)
└── meta_account_insights (daily rollup)
Key Relationships
meta_ad_accounts.client_id → clients.id (which client owns this ad account)meta_campaigns.meta_account_id → meta_ad_accounts.idmeta_adsets.campaign_id → meta_campaigns.campaign_idmeta_ads.adset_id → meta_adsets.adset_idmeta_ad_insights.ad_id → meta_ads.ad_idBudgets
Meta returns budgets in cents (e.g., 500000 = $5,000). The sync engine converts to dollars before storing.
Actions & Conversions
The actions field is a JSON array of action objects from Meta, e.g.:
[
{"action_type": "link_click", "value": "42"},
{"action_type": "landing_page_view", "value": "38"},
{"action_type": "lead", "value": "5"}
]
The conversions field is a simplified integer count. For detailed breakdowns, query the actions JSON.
Manual Sync
# Sync all accounts
python3 /opt/gridlink/backend/meta_sync.py
Sync specific account (by meta_ad_accounts.id)
python3 /opt/gridlink/backend/meta_sync.py --account 1
Extended lookback (30 days of insights)
python3 /opt/gridlink/backend/meta_sync.py --days 30
Or via API:
# Sync all
curl -X POST http://localhost:5000/api/meta-ads/sync
Sync specific account
curl -X POST http://localhost:5000/api/meta-ads/sync -H 'Content-Type: application/json' -d '{"account_id": 1}'
Extended lookback
curl -X POST http://localhost:5000/api/meta-ads/sync -H 'Content-Type: application/json' -d '{"days": 30}'
Sync Logs
All sync operations are logged to sync_log with component_type = 'meta_ads'. Object types:
meta_campaignsmeta_adsetsmeta_adsmeta_ad_insightsmeta_account_insightsView recent sync history:
curl http://localhost:5000/api/meta-ads/sync-status
Troubleshooting
| Issue | Cause | Fix |
|---|---|---|
| "access token could not be decrypted" | Token corrupted or truncated | Re-enter token in client settings |
| "Permissions error" | System user lacks ads_read | Re-assign permissions in Business Manager |
| Empty insights | No ad spend in lookback window | Extend lookback with --days 30 |
| Rate limit errors | Too many API calls | Sync engine auto-retries with backoff |
Last updated: 5/28/2026