Skip to main content

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​

ActionWhat it doesOn by default
me.readReads the user or system user the connection acts asYes
ad_accounts.list, ad_accounts.readLists the ad accounts the user can reach; reads oneYes
campaigns.list, adsets.list, ads.listLists an account's campaigns, ad sets and ads, filterable by status and dateYes
creatives.listLists an account's ad creativesYes
audiences.listLists an account's custom audiencesYes
insights.readReads performance for an account at campaign, ad set or ad levelYes
objects.read, objects.insightsReads one campaign, ad set, ad, creative or audience by id; reads its performanceYes
delivery.estimateEstimates the audience size and daily reach for a targetingYes
targeting.searchSearches targeting options: interests, behaviors, locationsYes
campaigns.create, adsets.create, ads.createCreates a campaign; an ad set with its budget, bid and targeting; an ad from a creativeNo, and needs approval
creatives.createCreates an ad creative, the content an ad publishes under your pagesNo, and needs approval
objects.updateChanges a campaign, ad set or ad, including pausing or activating it and changing its budgetNo, and needs approval
objects.deleteDeletes a campaign, ad set, ad or creativeNo, and needs approval

Good to know​

  • Ask for fields. The Graph API returns only an object's id and name unless fields names what you want: fields=name,status,daily_budget,targeting on adsets.list, fields=spend,impressions,clicks,actions on insights.read. The Marketing API reference lists them per object.
  • Insights are flexible. insights.read takes level (campaign, adset, ad), date_preset (last_7d, this_month) or time_range ({"since":"2026-10-01","until":"2026-10-25"}), time_increment for a daily series, breakdowns such as age,gender or publisher_platform, and filtering. objects.insights does 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 POST to its id and removes it with a DELETE, and nothing in the id says whether it is a campaign or an ad. objects.update and objects.delete are therefore one action each, and a grant for either covers every object type the token can reach. Pausing is objects.update with status: PAUSED; ACTIVE resumes, and both ask for an approval, since the second one starts spending.
  • Budgets are in the account's smallest currency unit: daily_budget: 1000 is $10.00 in a USD account.
  • Paging. List responses carry paging.cursors.after; pass it back as after, with limit, 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 targeting and object_story_spec go in as objects, not pre-encoded strings.
  • Personal fields are redacted. email and phone are 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.0 with 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.