Insights Paid Ads

Meta Marketing API: A Comprehensive Guide

The complete practitioner guide for agencies and developers.

IQY marketing api wordpress feature image
In this article
  1. What the Meta Marketing API Actually Is
  2. Do You Actually Need It?
  3. API vs. Ads Manager
  4. Setting Up Access
  5. 1. Create the developer app
  6. 2. Connect Business Manager
  7. 3. Permissions
  8. 4. Tokens, get this part right (seriously)
  9. Verify before you build
  10. First call
  11. Creating Campaigns Programmatically
  12. The campaign object
  13. Ad sets
  14. Ads and creatives
  15. Batching
  16. The Insights API
  17. The actions array
  18. Attribution windows
  19. The Conversions API
  20. Run it alongside the pixel with deduplication
  21. Advantage+ via the API
  22. Rate Limits, Errors, and the Stuff That Breaks at 1am (Maybe)
  23. Rate limits
  24. Error codes worth memorizing
  25. Recurring gotchas
  26. Meta Marketing API version
  27. Multi-Account Workflows for Agencies
  28. Partner access, not credential sharing
  29. One system user, many accounts
  30. Reporting across fifty accounts
  31. Expect variation
  32. FAQ
  33. Is the Marketing API free?
  34. Do I need App Review?
  35. Marketing API vs. Graph API, Chad what’s the difference?
  36. Where’s my ad account ID?
  37. How often do new versions ship?
  38. Does this cover Instagram ads?
  39. Best token type for production?
  40. What about iOS 14?

If you’ve ever spent a Monday morning exporting CSVs from Ads Manager for twelve different accounts, this guide is for you. The Meta Marketing API exists so software can do that job instead creating campaigns, moving budgets, pulling reports, and once you’re past a certain scale there’s really no other sane way to run things.

That said, most advertisers don’t need it, and I want to be upfront about that before walking you through setup. Ads Manager handles one account perfectly well. The API starts earning its keep when the interface itself becomes the bottleneck: dozens of accounts, hundreds of live campaigns, weekly creative rotations, reporting that has to land in a warehouse instead of a spreadsheet.

This guide covers the whole arc, how the pieces of the API ecosystem fit together, authenticate without losing a day to token problems, programmatic campaign creation, Insights reporting at scale, plus the topics most write-ups quietly skip: the Conversions API, Advantage+ campaign types, version management, error handling, and the multi-account patterns agencies depend on.

What the Meta Marketing API Actually Is

Strip away the branding and it’s a set of Graph API endpoints that talk to the same advertising infrastructure Ads Manager does. Same campaigns, same delivery system, different access point. Your application sends an HTTP request, Meta processes it, structured data comes back. Every third-party ad tool you’ve ever seen managing Meta campaigns is built on exactly this, like Hootsuite, Sprout Social, and even Semrush Social Media Management Toolkit.

Where newcomers get tangled up is in assuming it’s one API. It isn’t. There are three functional areas, and in practice you’ll touch at least two:

The Meta Marketing API is a set of Graph API endpoints that allows applications to interact with Meta’s advertising infrastructure programmatically. When someone says “Meta Marketing API” without qualification, this is what they mean.

The Ads Insights API is the reporting layer that sits on top. The core API tells you what an ad is; Insights tells you how it performed. Delivery, cost, conversions, and engagement, with breakdowns by date, geography, platform, and demographics. One thing worth knowing before you write any code: Insights requests are asynchronous. You submit a report job and poll for the result. More on that later because it shapes your whole pipeline design.

The Ad Library API is the odd one out, programmatic access to publicly visible ads, useful for competitive research. Temper your expectations here. Access is gated, spend and impressions come back as ranges rather than exact figures, and you won’t get CTRs at all. It tells you what competitors are running and roughly how hard they’re pushing it, not how well it’s working.

APIWhat it’s forTypical user
Marketing API (core)Creating and managing campaigns, ad sets, adsDevelopers, growth engineers
Ads Insights APIPerformance data and reportingData teams, performance marketers
Ad Library APICompetitor ad researchStrategists, researchers

All three live inside Meta’s broader Graph API, where every object is a node and the connections between them are edges. The Marketing API is a specialized slice of that graph, scoped to advertising.

Do You Actually Need It?

Probably not. Honestly I say that as someone arguing you should read the rest of this guide anyway.

Plenty of advertisers spending real money every month are better served by Ads Manager, or by a third-party tool that already wraps the API for them. The integration has a learning curve, and it comes with a recurring cost of time and effort to keep things running. Every quarterly version release is a potential breaking change someone has to check. That cost only makes sense in a handful of situations.

The clearest one is multi-account management. Try running campaigns for thirty clients through a browser and you’ll feel the problem in your wrists before the end of week one. The API gives you bulk operations and unified reporting from a single codebase, and there’s no browser-based equivalent.

Automation is the second. Budget pacing rules, creative rotation schedules, automated bid adjustments, and dayparting logic, none of it exists without programmatic control. Ads Manager’s built-in rules cover maybe ten percent of what teams actually want to automate.

Then there’s data plumbing. If your reporting lives in a warehouse or a BI tool, the API pulls structured data on a schedule and the Monday morning CSV ritual ends. If you’re building an ad tech product, there’s no decision to make, the Marketing API is the only way in. And if you’re implementing server-side conversion tracking, the Conversions API (covered below) requires direct integration.

If none of those describe your situation, you can proceed close this tab and go optimize a campaign instead. The API will still be here when you scaling up your workflow.

API vs. Ads Manager

These aren’t competitors. They’re two interfaces to the same machine, and the question is never “which one is better”. It’s which one fits the operation in front of you.

DifferencesAds ManagerMarketing API
InterfaceVisual, in the browserHTTP requests, your code
SetupNoneApp, tokens, permissions, review
AutomationBasic rulesAnything you can write
Multi-account workOne at a time, manuallyNative
ReportingPre-built dashboardsAny metric, any breakdown, any destination
Ongoing maintenanceNoneVersion upgrades, token management

The browser wins on speed for one-off work. The visual layout also surfaces anomalies you’d miss scanning raw JSON.

The API wins everywhere volume matters. Most teams I’ve worked with end up using both: Ads Manager for daily review and quick interventions, the API for bulk operations, scheduled reporting, and anything that runs while people sleep.

Setting Up Access

Four ingredients: a developer app, a Business Manager connection, permissions, and a token. The whole thing takes under an hour to setup. Here’s how you configure Meta Marketing API.

1. Create the developer app

Go to developers.facebook.com and create a new app.

Meta Developer Account Creation

Then, in the app dashboard, find Use Cases and add Marketing API. That switches on the advertising endpoints.

Meta Marketing API Developer App Use Cases

2. Connect Business Manager

The app needs to be attached to a Business Manager account (Meta now calls the surrounding interface Business Suite, but everyone still says Business Manager). Under Business Settings → Apps, add your new app.

Meta Business Suite Apps Account

For agencies, a word of advice: when you need access client ad accounts, use partner access. Have the client grant your Business Manager access from their side. Do not collect client credentials or personal tokens, it’s an audit nightmare, it breaks the moment someone changes a password, and partner access exists precisely so you never have to do it.

3. Permissions

Access control runs on OAuth 2.0 scopes. Three matter for advertising work:

  • ads_read – read-only access to account data and insights
  • ads_management – read and write; campaign creation lives here
  • business_management – Business Manager assets, including pages and ad accounts
Meta Business Suite Systems Users

If your production app touches data belonging to other users or businesses, Meta’s App Review stands between you and advanced permissions. For testing against your own accounts, development mode lets you skip it entirely.

4. Tokens, get this part right (seriously)

Every request authenticates with an access token, and the type you pick matters more than the rest of the setup combined.

Short-lived user tokens come out of the OAuth flow and expire in about an hour. Fine for poking at endpoints in a REPL, useless beyond that. Long-lived user tokens last 60 days after a server-side exchange, which sounds workable until the refresh you meant to automate doesn’t happen and your pipeline dies on a weekend.

What you want for production is a system user token. A system user is a non-human identity inside Business Manager, it represents your application rather than a person, its tokens don’t expire, and it doesn’t break when an employee leaves or gets their personal account flagged. Create one under System Users in Business Manager, grant it the ad account permissions it needs, generate a token.

Meta Business Suite Systems Users Tokens

Please store that token in password manager.

Verify before you build

Before writing integration code, paste the token into the Access Token Debugger. For a correctly set up system user token you should see Type: System User, Expires: Never, Valid: True, and your three scopes listed. If a scope is missing, regenerate the token from Business Manager with the right boxes checked. Two minutes of checking here saves an hour of decoding cryptic permission errors later because error code 200 in particular tells you almost nothing about which permission is missing.

Meta Access Tokens Debugger

First call

Sanity-check the whole chain by listing the ad accounts your token can see in Meta Graph API Explorer:

GET https://graph.facebook.com/v25.0/me/adaccounts?fields=id,name,account_status
?fields=id,name,account_status
&access_token=YOUR_TOKEN

Meta Graph API Explorer

If you get back an array of account objects with IDs and names, everything works from app, token, permissions, Business Manager link. That means you’re in. the matrix. Just kidding though.

Creating Campaigns Programmatically

Meta’s structure has three levels, and the API enforces the order: campaign first, then ad sets inside it, then ads inside those.

The campaign object

A campaign mostly defines the objective. The fields you actually need at creation time are objective, name, status, and special_ad_categories (which is required even when empty, yes, really).

POST https://graph.facebook.com/v25.0/act_{ad_account_id}/campaigns

{
"name": "seo_leads_jabodetabek",
"objective": "OUTCOME_LEADS",
"status": "PAUSED",
"special_ad_categories": [],

"buying_type": "AUCTION",
"daily_budget": 250000,
"bid_strategy": "LOWEST_COST_WITHOUT_CAP"
}

campaign creation graph api explorer

Create everything in PAUSED status. Spend should never go live while you’re still wiring up the layers underneath, and an active campaign with a half-configured ad set is exactly the kind of mistake you only make once. You can also further verify that code in Meta Ads Manager.

meta ad campaign created from graph api explorer

Objectives now follow the ODAX naming scheme: OUTCOME_AWARENESS, OUTCOME_TRAFFIC, OUTCOME_ENGAGEMENT, OUTCOME_LEADS, OUTCOME_APP_PROMOTION, OUTCOME_SALES. The legacy names — LINK_CLICKS, CONVERSIONS, and the rest — are dead. Per Meta’s v21.0 release notes, new ad sets and ads using non-ODAX objectives have been blocked since v21.0 (October 2024), and current API versions reject them outright. If an older tutorial uses them, that’s your cue to find a newer tutorial.

Ad sets

This is the configuration-heavy level and where most of your debugging hours will go. An ad set carries budget, schedule, audience, placements, and the optimization goal.

POST https://graph.facebook.com/v25.0/act_{ad_account_id}/adsets

{
"name": "seo_leads_jabodetabek",
"campaign_id": "campaign_id",
"status": "PAUSED",
"billing_event": "IMPRESSIONS",
"optimization_goal": "LEAD_GENERATION",
"bid_strategy": "LOWEST_COST_WITHOUT_CAP",
"start_time": "2026-06-17T00:00:00+0700",
"dsa_beneficiary": "IQY Digital",
"dsa_payor": "IQY Digital",
"promoted_object": {
"page_id": "page_id"
},
"targeting": {
"age_min": 25,
"age_max": 55,
"genders": [0],
"geo_locations": {
"regions": [
{"key": "1462", "name": "Jakarta"},
{"key": "1838", "name": "West Java"},
{"key": "1841", "name": "Banten"}
],
"location_types": ["home", "recent"]
},
"locales": [25],
"interests": [
{"id": "6003232518610", "name": "Digital marketing"},
{"id": "6003195797498", "name": "Entrepreneurship"},
{"id": "6003370636074", "name": "Search engine optimisation (software)"}
],
"targeting_automation": {
"advantage_audience": 0
}
}
}

graph api explorer ad set creation

The fields that matter:

  • campaign_id – returned from the campaign creation call
  • daily_budget or lifetime_budget – in the smallest currency unit, so cents for USD; sending 50 when you meant fifty dollars buys you fifty cents of reach
  • billing_event – almost always IMPRESSIONS
  • optimization_goal, OFFSITE_CONVERSIONS, LINK_CLICKS, REACH, and so on
  • targeting – a JSON object covering geo, age, interests, placements
  • start_time / end_time – Unix timestamps
  • promoted_object – mandatory for conversion campaigns; this is where you specify the pixel and event
meta ad set created from graph api explorer

Ads and creatives

An ad is the join between a creative and an ad set. Creatives can be defined inline or created once as standalone objects and referenced by ID. At any kind of scale, do the latter. One creative attached to many ads keeps the account clean and your code shorter. The creation call itself is small: adset_id, a creative_id or inline spec, name, and status (paused, as always, during setup).

Batching

Creating objects one request at a time gets old immediately. The Graph API accepts batch requests up to 50 sub-requests in a single HTTP call, each with its own method, path, and body, with responses returned as an array. Spinning up 200 ads for a creative test, or repricing 50 ad sets, goes from minutes to seconds.

Batches also support dependency chaining: a sub-request can reference an earlier sub-request’s output with {result=N:$.id} syntax. That means campaign-plus-ad-set in one round trip instead of two.

The Insights API

This is the specific API use for reporting. Impressions, clicks, spend, conversions, cost per result, and ROAS or for any object at any level of the hierarchy.

The single most important thing to internalize: Insights is asynchronous. You POST a report request, receive a report_run_id, poll until the job status says completed, then fetch results from the corresponding insights edge. Architect around that from the start, because retrofitting polling logic into a pipeline that assumed synchronous responses is miserable.

A typical request:

POST https://graph.facebook.com/v25.0/act_{ad_account_id}/insights

{
"level": "ad",
"date_preset": "last_30d",
"fields": "ad_id,ad_name,impressions,clicks,spend,actions,cost_per_action_type",
"time_increment": 1
}

Set level explicitly every single time like account, campaign, adset, or ad. The default varies by endpoint, and silent defaults that vary are how reporting bugs are born. date_preset handles relative ranges (yesterday, last_7d, last_30d, this_month).

For exact dates use time_range with since/until instead. time_increment: 1 gives daily rows, monthly aggregates, and omitting it collapses the whole range into one row. breakdowns splits by age, gender, country, publisher_platform, device_platform, placement and more. Combinations are allowed but not all of them, and the error messages won’t always explain which rule you broke. filtering trims the result set, useful for things like “only ads above a spend threshold.”

The actions array

Something the official docs underplay: conversion data doesn’t arrive as flat columns. It’s nested in an actions array, where each element pairs an action_type (offsite_conversion.fb_pixel_purchase, link_click, etc.) with a value. Extracting specific conversion events is post-processing you write yourself. Plan for it.

Attribution windows

The same campaign can report meaningfully different numbers depending on attribution settings. Meta supports 1-day click, 7-day click, 1-day view, and 7-day view windows. If your pipeline needs run-over-run comparability, pin action_attribution_windows explicitly. Otherwise, at some point, two reports of the same campaign will disagree and you’ll lose an afternoon discovering why.

The Conversions API

Technically the Conversions API (CAPI) is a separate product from the Marketing API. Practically, it’s often the piece that decides whether your whole Meta integration delivers value, so it belongs in this guide.

The backstory matters. For years the Meta Pixel, a JavaScript snippet firing PageView, AddToCart, Purchase events from the browser was the entire tracking story. Then third-party cookie restrictions, ad blockers, and iOS 14’s App Tracking Transparency started eating those events. According to Meta’s own measurement research, browser-side pixel signals were degraded significantly following iOS 14, independent analyses put conversion signal loss in the 20–40% range for many advertisers. At that point Meta’s optimization is flying with a fogged windshield, and your CPAs show it.

CAPI’s answer is to move event transmission server-side. Events go out as POST requests from your server to Meta’s /events endpoint with each one carrying an event name, a Unix timestamp, hashed user identifiers (email, phone, IP, user agent — SHA-256 hashed before leaving your server, so raw PII never travels), custom data like purchase value and currency, and the source URL. Nothing in the browser means nothing for ad blockers or iOS to intercept.

Run it alongside the pixel with deduplication

The recommended architecture is redundancy: keep the pixel for its immediacy, send CAPI events as the reliable backstop. The catch is that running both without deduplication double-counts conversions, which quietly corrupts Meta’s optimization. The fix is a shared event_id you generate once and pass to both the pixel call and the CAPI call for the same conversion; Meta collapses matching IDs into a single event. Get this working before launch. If your CPAs suddenly look too good to be true after enabling CAPI, this is almost certainly why.

If you already have a Marketing API integration, adding CAPI is a modest lift, same token format, same Graph API base URL, same app. Meta’s official Conversions API documentation reports improved event match quality scores and more efficient delivery when CAPI supplements the pixel.

Advantage+ via the API

Advantage+ is Meta’s family of AI-driven campaign types, automating decisions advertisers used to make by hand — targeting, placements, creative selection, budget split. Whatever your feelings about handing the wheel to Meta’s machine learning, this is unambiguously the direction the platform is moving, and everything is reachable through the API.

Advantage+ Shopping Campaigns (ASC) are the flagship, aimed at e-commerce. You supply creatives and a conversion event; Meta decides audience, creative rotation, and the prospecting/retargeting split. Via the API, set OUTCOME_SALES as the objective and include the ASC-specific parameters — "is_skadnetwork_attribution": true for app campaigns. Structurally, ASC ad sets accept much broader audience definitions and deliberately strip out manual targeting controls.

Advantage+ Audience replaces hard targeting constraints with an optional “suggestion” Meta is free to override when it predicts better performance elsewhere. Enable it inside the ad set’s targeting spec: "targeting_optimization_types": [{"targeting_optimization_type": "ADVANTAGE_AUDIENCE"}].

Advantage+ Creative lets Meta modify your assets example features like crops, backgrounds, text variants, overlays like social proof labels. It’s switched on at the ad level with "advantage_plus_creative_spec" in the creative object. If your integration manages creative at scale, this reframes the job: you’re supplying a palette, not a finished asset.

So when do you use it? Advantage+ trades control for efficiency, and the trade pays off when conversion volume is healthy, Meta’s guidance is 50+ conversions per week per ad set for the optimization to stabilize. Manual campaigns remain the right call for hypothesis testing, variable isolation, and brand work with placement constraints.

Rate Limits, Errors, and the Stuff That Breaks at 1am (Maybe)

Nobody’s favorite section, and the one that separates integrations that survive production from those that don’t.

Rate limits

The Marketing API uses Business Use Case (BUC) rate limiting, which is not a flat calls-per-minute counter. Meta computes a call budget per app based partly on the number of active ad objects in the accounts it manages — bigger, busier accounts get more headroom. Your current standing comes back in every response’s headers: x-business-use-case-usage for the BUC category and x-app-usage at the app level. Read them. When usage creeps past 80%, throttle yourself, because once Meta does it for you (error 17) the only remedy is waiting.

Error codes worth memorizing

CodeMeaningWhat to do
190Invalid/expired tokenRegenerate. Do not retry — the token won’t resurrect itself
200Permission errorCheck token scopes and account access
4 / 17App / user request limitExponential backoff, then retry
100Invalid parameterCheck field names against the docs for your version
1Unknown errorBrief delay, retry; escalate if persistent
368Policy blockReview the ad content against Meta’s policies

Recurring gotchas

A few issues come up often enough to list. “Invalid OAuth access token” on a system user token usually means a Business Manager permission change or security event invalidated it, you can try regenerate and update your stored copy. Insights returning all zeros is usually attribution window settings or a date range with no data; fresh pixels also need 24–48 hours before anything populates. “Objective not supported” on campaign creation means you’re using a deprecated legacy objective name, switch to ODAX.

And the sneakiest one: batch requests always return HTTP 200 at the top level, even when sub-requests inside failed. The failures are buried in individual response objects in the array. Check every item’s code field, or your system will happily mark failed operations as successful and you’ll find out from a confused client instead of a log line.

Meta Marketing API version

Meta ships a new API version roughly quarterly, and each lives about two years before deprecation. As of June 2026, v25.0 is the current stable version for new integrations and it carries significant breaking changes worth knowing before you upgrade:

  • v21.0 introduced ODAX enforcement – non-ODAX objectives can no longer be created
  • v22.0+ brought field-level deprecations across creative endpoints (instagram_actor_id, effective_instagram_story_id, and others removed)
  • v25.0 enforced Automation Unification – Advantage+ Shopping and Advantage+ App campaigns can no longer be created or updated through any Marketing API version as of May 2026, requiring migration to the new unified Advantage+ setup. The same release also introduced the forthcoming Page Viewer Metric (rolling out end of June 2026), which will replace the legacy reach metric across Facebook and Instagram so developers should begin planning migration to page_total_media_view_unique now.

If your codebase is still on v20.0 or earlier, upgrading directly to v25.0 will likely break campaign creation if you use ASC or AAC structures. Step through versions and validate each one before moving to the next. In my view this is the most underrated cost of running a Marketing API integration, these systems rarely break because of bugs in your code. They break because a version aged out and nobody updated a base URL.

Multi-Account Workflows for Agencies

Agencies face a structural problem solo advertisers never see: many client accounts, each with its own permissions, reporting needs, currencies, and quirks. The API has patterns for this, and the permission architecture is where to start because everything else hangs off it.

Partner access, not credential sharing

The correct model: your agency’s Business Manager requests partner access to the client’s ad account, the client approves it from their side, and your system user token gains access. The client can revoke at any time without touching your other accounts, Business Manager keeps per-account audit trails, and no client credentials ever leave the client’s control. Every alternative to this model is worse, and several are policy violations.

One system user, many accounts

You don’t maintain a token per client. A single system user, granted permissions across all approved client accounts, authenticates everything, the target account is specified per-call via the act_{ad_account_id} path. For each new client, either they add your Business Manager as a partner under Business Settings → Ad Accounts → Partners, or you send the access request through the API (requires business_management scope).

Reporting across fifty accounts

The naive approach for one Insights call per account, sequentially that is slow and chews through rate limits. Two patterns fix it. Where your Business Manager has admin access, some Insights queries run at the Business level and return per-account data in a single call. For everything else, exploit the fact that Insights is async anyway: fire job requests across all accounts simultaneously, collect the report_run_ids, and poll as they complete. Fanning out across 50 accounts costs nothing extra, and results arrive as they finish instead of queueing.

Expect variation

No two client accounts are configured the same, and your integration has to assume that. Read that again. Pixels will be missing on accounts where the client swears one is installed. Spend comes back in each account’s native currency, not yours. Accounts can be DISABLED or UNSETTLED, and only ACTIVE ones accept campaign creation. And Insights date ranges are interpreted in the ad account’s time zone, not UTC. In my experience, this last one generates more confused back-and-forth than every other item on this list combined.

FAQ

Is the Marketing API free?

The API itself, yes. You pay for ad spend exactly as you would otherwise; the API is just a different interface to the same account.

Do I need App Review?

Not for working with your own ad accounts because development mode allows every Marketing API permission without review. Review becomes mandatory when your app touches other users’ or businesses’ data, e.g. a SaaS product managing campaigns for customers.

Marketing API vs. Graph API, Chad what’s the difference?

The Graph API is Meta’s general-purpose API across all its platforms. The Marketing API is a specialized layer on top, scoped to advertising. Same infrastructure, same base URL.

Where’s my ad account ID?

Top navigation in Ads Manager, and in the URL, format act_XXXXXXXXXX. The act_ prefix is required in API calls, not decorative.

How often do new versions ship?

Quarterly, each supported for about two years. Deprecation dates are announced ahead of time via the changelog and emails to app admins.

Does this cover Instagram ads?

Correct.

Best token type for production?

Use system user tokens.

What about iOS 14?

The API itself is unaffected, your calls come from a server, not a user’s device.

(Next Step)

Want to turn your search data into a growth roadmap?

Plan with IQY