Meta Marketing API
The Meta Marketing API connector reaches https://graph.facebook.com/v26.0, the Graph API, as one Facebook user or one system user. It answers the questions you would otherwise open Ads Manager for: which campaigns are live, what each ad set spends and targets, how the ads did this week, broken down however insights can break them down. It can also create campaigns, ad sets, ads and creatives, pause and change them, and delete them, and every one of those ships switched off and asks a human before it runs.
What you need
1. A Meta app. Create one at developers.facebook.com/apps with the Business type and connect it to the Business portfolio that owns the ad accounts. Add the Marketing API product. Under App settings, Basic, the App ID is the OAuth client id and the App secret is the client secret. Leave Require App Secret switched off: the gateway does not sign calls with an app secret proof.
Under Facebook Login for Business, Settings, add your gateway's address followed by /oauth/callback to Valid OAuth Redirect URIs. Meta insists on HTTPS there, with one exception: while the app is in Development mode, http://localhost redirects are accepted, so a gateway on your own machine can use http://localhost:7376/oauth/callback. A tunneled or hosted gateway uses its https://<your-gateway-host>/oauth/callback.
2. Who can sign in. In Development mode only people with a role on the app (admins, developers, testers) can authorize it, which is fine when the ad accounts are yours. To let other businesses connect, the app has to pass App Review for ads_read and ads_management and switch to Live mode.
3. An ad account id. Meta writes them as act_1234567890; every action here takes the digits as ad_account_id and puts the act_ back for you. ad_accounts.list finds the ones the signed-in user can reach.
Add the connection
In the console, open Access, Connections, Add connection, pick Meta Marketing API from the catalog, and under the credential choose OAuth, then Gateway-held · your own app. Paste the App ID and App secret, check the redirect URI matches one on your app, and choose Add. Facebook's dialog opens in a new tab; approve it as a user with access to the ad accounts, and your browser lands on the gateway's "Connected" page once the token is sealed. The REST calls are the same as on the Reddit page with "preset_id": "meta-ads".
No refresh token: the sixty-day exchange
Meta is the one provider in the catalog that issues no refresh token. What the code exchange returns is a user token that lasts an hour or two, and the gateway normally refuses to seal a credential it could never refresh. For this connector it does one more thing first: it exchanges that short-lived token for a long-lived one (grant_type=fb_exchange_token, with the app id and secret) and seals that instead. A long-lived token lasts about sixty days.
Keeping it alive works the same way. A still-valid long-lived token can be exchanged again for a fresh sixty days, so whenever the connection is used in the last seven days of its token's life, the gateway exchanges it on that call and seals the new one. A connection that goes unused for more than sixty days expires, because an expired token cannot be exchanged, and the connection then needs authorizing again from the console. The seven-day window, rather than the two minutes other connectors get, is there so that any routine use in the final week renews the token.
Two things follow. If you change the user's password or Meta logs them out of every session, the token dies and the connection needs re-authorizing, as any Meta integration does. And an agent that runs weekly keeps its connection alive indefinitely; one that runs quarterly does not, so give that one a system user token instead.
Or a system user token
If you would rather not depend on a user's login, Business settings can create a system user with access to the ad accounts and generate a token for it with the same two permissions; those tokens do not expire unless revoked. Add the connection with API key as the credential and paste the token. Everything below works the same way, and nothing is exchanged or refreshed.
What the agent can do
| Action | What it does | On by default |
|---|---|---|
me.read | Reads the user or system user the connection acts as | Yes |
ad_accounts.list, ad_accounts.read | Lists the ad accounts the user can reach; reads one | Yes |
campaigns.list, adsets.list, ads.list | Lists an account's campaigns, ad sets and ads, filterable by status and date | Yes |
creatives.list | Lists an account's ad creatives | Yes |
audiences.list | Lists an account's custom audiences | Yes |
insights.read | Reads performance for an account at campaign, ad set or ad level | Yes |
objects.read, objects.insights | Reads one campaign, ad set, ad, creative or audience by id; reads its performance | Yes |
delivery.estimate | Estimates the audience size and daily reach for a targeting | Yes |
targeting.search | Searches targeting options: interests, behaviors, locations | Yes |
campaigns.create, adsets.create, ads.create | Creates a campaign; an ad set with its budget, bid and targeting; an ad from a creative | No, and needs approval |
creatives.create | Creates an ad creative, the content an ad publishes under your pages | No, and needs approval |
objects.update | Changes a campaign, ad set or ad, including pausing or activating it and changing its budget | No, and needs approval |
objects.delete | Deletes a campaign, ad set, ad or creative | No, and needs approval |
Good to know
- Ask for
fields. The Graph API returns only an object's id and name unlessfieldsnames what you want:fields=name,status,daily_budget,targetingonadsets.list,fields=spend,impressions,clicks,actionsoninsights.read. The Marketing API reference lists them per object. - Insights are flexible.
insights.readtakeslevel(campaign,adset,ad),date_preset(last_7d,this_month) ortime_range({"since":"2026-10-01","until":"2026-10-25"}),time_incrementfor a daily series,breakdownssuch asage,genderorpublisher_platform, andfiltering.objects.insightsdoes the same for a single campaign, ad set or ad. - Updates and deletes go by id, whatever the object. The Graph API changes any object with a
POSTto its id and removes it with aDELETE, and nothing in the id says whether it is a campaign or an ad.objects.updateandobjects.deleteare therefore one action each, and a grant for either covers every object type the token can reach. Pausing isobjects.updatewithstatus: PAUSED;ACTIVEresumes, and both ask for an approval, since the second one starts spending. - Budgets are in the account's smallest currency unit:
daily_budget: 1000is $10.00 in a USD account. - Paging. List responses carry
paging.cursors.after; pass it back asafter, withlimit, to get the next page. - Bodies are JSON. The connector sends creates and updates as JSON objects, which the Graph API accepts, so nested values such as
targetingandobject_story_specgo in as objects, not pre-encoded strings. - Personal fields are redacted.
emailandphoneare blanked before the agent sees them. - The API version is pinned. The connector pins v26.0, current as of October 2026; Meta keeps each version for about two years. When it goes, Use a different host on the connection form takes
https://graph.facebook.com/v27.0with no gateway update, because the host is the same. The authorize and token endpoints are pinned in the connector itself and move with a gateway release; Meta keeps a version's OAuth endpoints alive as long as the version.