---
title: 'Meta Ads API: Marketing API setup, access and limits'
description: 'Understand Meta Marketing API access, permissions, version limits and curl/Python examples. Learn when to build directly or use a managed Actions API.'
canonical: 'https://plainrouter.com/library/meta-ads-api'
format: Guide
published_at: '2026-10-01'
last_updated: '2026-11-10'
---

The Meta Ads API is usually a name for Meta's **Marketing API**: use it to read advertising performance and manage campaigns, ad sets and ads. Use the Conversions API to send conversion events, or the Ad Library API to search public-ad records instead.

Our production implementation notes below were recorded on 11 October 2026. This guide also includes failed unauthenticated Graph API requests we captured on 28 October 2026, using no token and a deliberately fake account. Those errors show response and version handling; they are not successful account reads or production usage-header samples.

This guide covers direct integration first, then when a managed layer fits.

## Which Meta API do you need?

| API | Use it for | Important boundary |
| --- | --- | --- |
| Marketing API | Read account insights; create and manage advertising objects | Requires permissions and access to the advertiser's assets |
| Ad Library API | Search supported archived/public-ad transparency records | Coverage depends on the archive's rules; it is not private account reporting or campaign control |
| Conversions API | Send website, app or offline conversion signals to Meta | Sending an event does not create an ad or guarantee attribution |
| Graph API | The versioned objects, edges and request system underlying these integrations | It is the foundation, not a separate substitute for advertising permissions |

For event collection, start with [the Meta Conversions API guide](</library/meta-conversions-api>). For public-ad research, use Meta's [Ads Archive reference](<https://developers.facebook.com/docs/graph-api/reference/ads_archive/>).

## How to get Marketing API access

Start with a developer app and an ad account you are authorized to access. Add Marketing API access through the app dashboard, then check permissions, asset assignments and the app's access tier separately.

### Choose permissions for the job

Use ` ads_read ` for reading advertising reports. Use ` ads_management ` when the integration needs to manage ads; it also supports reads on accounts the token can access. Request additional permissions only when the selected endpoints require them. A permission does not grant access to every ad account.

Meta's current authorization documentation distinguishes two systems:

| System | Names | What it controls |
| --- | --- | --- |
| Permission/feature access level | Standard access, Advanced access | Whether an app can use a permission for its own use case or other advertisers |
| Marketing API Access Tier | Limited access, Full access | Marketing API capacity, business-management access and system-user capacity |

For an app managing only your own ad account, Standard permission access can be sufficient. Accessing other people's ad accounts requires the applicable Advanced permission access. Separately, Meta describes Limited Marketing API access as development-only and Full access as the reviewed tier for production advertisers. Development access still operates on production data; it is not a simulated ad account. [Meta authorization](<https://developers.facebook.com/documentation/ads-commerce/marketing-api/get-started/authorization>)

### Business verification and App Review

Business verification establishes the business's identity. App Review assesses requested permissions and features. Completing one does not automatically complete the other. Follow the dashboard's requirements for your use case, including verification when required, Advanced permissions and the Marketing API tier upgrade. Prepare a working demonstration of the access you request rather than requesting every permission preemptively.

### Choose the right token

For automation acting as your business, review Meta's system-user setup: assign the relevant assets and generate a token for the app with the permissions it needs. For software acting on behalf of customers, use the appropriate Meta authorization flow; a system-user token is not a shortcut around customer authorization. Store credentials on the server, monitor failures and plan revocation/replacement instead of assuming a token will remain valid forever. [System users](<https://developers.facebook.com/docs/marketing-api/system-users/>)

## Read ad insights, then pause one ad

These examples use **v26.0**. Load ` META_ACCESS_TOKEN `, ` META_AD_ACCOUNT_ID ` and ` META_AD_ID ` from your environment. The account ID is the numeric portion without ` act_ `; the ad ID identifies one ad. A reporting token needs ` ads_read ` or suitable management permission. Pausing needs ` ads_management ` and write access to that asset.

### curl: read first

```bash
: "${META_ACCESS_TOKEN:?Load a Meta access token}"
: "${META_AD_ACCOUNT_ID:?Set the numeric ad account ID}"

curl --fail-with-body --get \
  "https://graph.facebook.com/v26.0/act_${META_AD_ACCOUNT_ID}/insights" \
  --header "Authorization: Bearer ${META_ACCESS_TOKEN}" \
  --data-urlencode 'level=ad' \
  --data-urlencode 'fields=ad_id,ad_name,impressions,clicks,spend' \
  --data-urlencode 'date_preset=last_7d' \
  --data-urlencode 'limit=25'
```

This retrieves one page of results. Follow pagination to collect the full result set; no rows is different from zero spend. Choose reporting windows and attribution settings consistently when comparing this output with Ads Manager. [Insights documentation](<https://developers.facebook.com/docs/marketing-api/insights/>)

### curl: explicitly opt in to pausing

The following request changes a real ad. Set ` CONFIRM_PAUSE ` to the same ad ID only after checking the account and target. The guard prevents a copied read example from immediately becoming a write.

```bash
: "${META_ACCESS_TOKEN:?Load a Meta access token}"
: "${META_AD_ID:?Set the ad ID}"

if [ "${CONFIRM_PAUSE:-}" = "$META_AD_ID" ]; then
  curl --fail-with-body --request POST \
    "https://graph.facebook.com/v26.0/${META_AD_ID}" \
    --header "Authorization: Bearer ${META_ACCESS_TOKEN}" \
    --data-urlencode 'status=PAUSED'
else
  printf '%s\n' 'No change sent: CONFIRM_PAUSE must match META_AD_ID.'
fi
```

After a successful response, read the ad's ` status ` and ` effective_status ` to verify its configuration. Effective status also reflects surrounding delivery conditions. A write response is not proof of a performance outcome. [Ad reference](<https://developers.facebook.com/docs/marketing-api/reference/adgroup/>)

### Python: Meta's official SDK

Install ` facebook-business ` in your project environment and lock the version you validate for deployment. The following uses the same environment variables and explicit pause guard:

```python
import os

from facebook_business.api import FacebookAdsApi
from facebook_business.adobjects.ad import Ad
from facebook_business.adobjects.adaccount import AdAccount

FacebookAdsApi.init(
    access_token=os.environ["META_ACCESS_TOKEN"],
    api_version="v26.0",
)

account = AdAccount("act_" + os.environ["META_AD_ACCOUNT_ID"])
rows = account.get_insights(
    fields=["ad_id", "ad_name", "impressions", "clicks", "spend"],
    params={"level": "ad", "date_preset": "last_7d", "limit": 25},
)
for row in rows:  # The SDK cursor can fetch subsequent pages.
    print(dict(row))

ad_id = os.environ.get("META_AD_ID")
if ad_id and os.environ.get("CONFIRM_PAUSE") == ad_id:
    ad = Ad(ad_id)
    ad.api_update(params={"status": "PAUSED"})
    print(dict(ad.api_get(fields=["status", "effective_status"])))
```

These are small request examples, not a complete production worker. Add secret management, request/error logging without tokens, pagination bounds and recovery handling. If your app requires app-secret proof, configure that too; Meta's SDK supports initializing with your app ID and app secret. See the [official Python Business SDK on GitHub](<https://github.com/facebook/facebook-python-business-sdk>).

## Rate limits and API versions: what breaks in production?

**There is no single request allowance for every Marketing API call.** Limits vary by access tier, account, operation and business use case. Reporting can also hit app-level limits; repeated edits to one object have separate throttling. Inspect the usage headers and error details returned by your actual endpoint. [Marketing API rate limits](<https://developers.facebook.com/docs/marketing-api/overview/rate-limiting/>)

Keep reporting jobs bounded, request only needed fields and use asynchronous Insights jobs for large reports. Back off with jitter on transient throttling, serialize conflicting edits and stop retrying permanent permission errors. After a write times out, read the target state before retrying: a lost response does not prove the change failed.

Pin an API version and schedule upgrades. Marketing API retirement dates differ from general Graph API dates. As of 28 October 2026, Meta's dedicated [Marketing API changelog](<https://developers.facebook.com/documentation/ads-commerce/marketing-api/marketing-api-changelog>) lists v26.0 as available, v25.0 through 23 February 2027 and v24.0 through 10 November 2026; v26.0's end date is still TBD.

Meta's [general Graph API changelog](<https://developers.facebook.com/docs/graph-api/changelog/>) still shows 6 October 2026 in its embedded Marketing API table. The two schedules disagree; use the API-specific schedule when planning ads upgrades and recheck it before deployment. The disagreement does not establish whether a particular authenticated endpoint remains usable.

Marketing API calls to retired versions can fail or auto-upgrade only where Meta's endpoint rules allow, and unversioned Marketing API calls are invalid. See [Marketing API versioning](<https://developers.facebook.com/documentation/ads-commerce/marketing-api/overview/versioning>) for those separate rules.

### Which API version does our integration use?

In our integration, Meta requests are pinned to ` v25.0 `; the tutorial examples above use ` v26.0 `. A tutorial’s version is not evidence that your deployed client uses it. Before an upgrade, inventory the actual request version and check the endpoints and fields you use against [Meta’s version changes and separate Marketing API retirement schedule](<https://developers.facebook.com/documentation/ads-commerce/marketing-api/marketing-api-changelog>).

### Which errors need reconnection or a corrected target?

In our integration, an authentication failure and an unavailable source object have different recovery paths. The table describes how our released integration handles these responses; it does not claim that the examples were captured from a live account.

| Response | What it means in this operation | What our integration does; what to check |
| --- | --- | --- |
| Code 190 | The credential cannot authenticate. Meta documents expired or invalid access tokens and further detail in error\_subcode. | Marks the Meta connection as needing reconnection and clears its stored credentials. Reauthorize the connection; repeating the same token is not recovery. |
| Code 100, subcode 33, when reading a source ad set | The requested source ad set cannot be read for the proposed operation. This is a specific case, not the meaning of every code-100 response. | Rejects that source for the operation instead of proceeding to a write. Recheck the object ID, selected account and asset permissions. An inaccessible object is not proof that it was deleted. |

Meta defines the error fields and authentication recovery in its [Graph API error-handling guide](<https://developers.facebook.com/docs/graph-api/guides/error-handling/>). Our code-100/subcode-33 treatment above is an integration safeguard, not a universal diagnosis from Meta.

### How does our integration budget requests from usage headers?

In our integration, account-management and Insights usage are tracked separately. We read ` acc_id_util_pct ` from ` X-Ad-Account-Usage `, and both ` app_id_util_pct ` and ` acc_id_util_pct ` from ` X-FB-Ads-Insights-Throttle `. For ` ads_management ` and ` ads_insights ` entries in business-use-case headers, we use the highest of ` call_count `, ` total_cputime ` and ` total_time `, rather than treating call count as the only constraint.

Our integration reduces capacity for the affected request classes when reported utilization reaches our configured 75% threshold, or when a business-use-case entry reports time needed to regain access. It uses the reported recovery duration where available, with a five-minute fallback. The 75% threshold and fallback are our safety choices, not Meta’s advertised quota. Missing or malformed usage fields do not become an invented zero-usage reading.

Meta describes these header fields and endpoint-specific limits in its [Marketing API rate-limit documentation](<https://developers.facebook.com/documentation/ads-commerce/marketing-api/overview/rate-limiting>). This is our implementation’s handling of provider feedback; we are not publishing a measured throughput result or a captured usage-header sample.

## What Meta returns when a call is wrong

On 28 October 2026, we called Graph API's ad-account Insights path with no token, no app and a deliberately fake account. Meta returned the failures below. The version column records the ` facebook-api-version ` response header from our test notes.

| Version requested for the fake account's ` /insights ` path | HTTP status | Response version header | Returned error |
| --- | --- | --- | --- |
| v22.0, v23.0, v24.0, v25.0 and v26.0 | 403 | Same as requested | ` OAuthException `, code ` 200 `: ` (#200) Provide valid app ID ` |
| v20.0 | 403 | v21.0 | ` OAuthException `, code ` 200 `: ` (#200) Provide valid app ID ` |
| No version in the URL | 403 | v21.0 | ` OAuthException `, code ` 200 `: ` (#200) Provide valid app ID ` |
| v27.0 | 400 | v21.0 | ` OAuthException `, code ` 2500 `: unknown path components |

One captured error body, with request and trace identifiers omitted:

```json
{
  "error": {
    "message": "(#200) Provide valid app ID",
    "type": "OAuthException",
    "code": 200
  }
}
```

The v20.0 and unversioned failures were answered under v21.0; their bodies contained the same app-ID error as the v22.0–v26.0 calls. The requested URL alone did not reveal that version difference. Pin the version and record the ` facebook-api-version ` header alongside the HTTP status and error code rather than relying on automatic fallback.

With no token or app, these requests produced an app-ID error rather than an explicit missing-token error. An app ID does not replace a token: an authenticated Marketing API read still needs the [appropriate credential and asset access](<https://developers.facebook.com/documentation/ads-commerce/marketing-api/get-started/authentication>).

These unauthenticated failures do not establish Marketing-API-specific retirement, an app's default version, successful endpoint availability or production rate limits. Meta documents a [dashboard-selected default for unversioned Graph calls](<https://developers.facebook.com/docs/graph-api/guides/versioning/>), but explicitly says [unversioned Marketing API calls are invalid](<https://developers.facebook.com/documentation/ads-commerce/marketing-api/overview/versioning>). The v21.0 header on our failed request does not override that rule.

## Build directly or use Plainrouter?

Build directly when you need the full Marketing API surface, including custom campaign creation, audiences or specialized reporting. You own Meta app access, tokens, version upgrades, retries and change safeguards.

Plainrouter is a managed option for a narrower set of tasks. For supported workflows, you connect your ad account through **Plainrouter's Meta connection** instead of creating your own Meta app and completing your own app review. You still need the account permissions and asset access required by that connection. [Connect Meta](<https://plainrouter.com/docs/signals/connect-meta>)

The [Actions API](<https://plainrouter.com/docs/api/actions>) supports pause/resume, budget changes and creative proposals through policy checks. Ask mode holds changes for human approval; Full runs agent changes that pass admission and workspace policy automatically. New ad copies are created paused. Decision receipts record execution outcomes and available verification evidence, including failures. In Custom, your switches decide which agent changes run on their own.

Use a **Write Workspace key**, an active ` propose-actions ` grant and the applicable role/abilities. POST ` /actions/dry-run `, relative to the documented workspace API base, previews supported changes without writing to Meta or creating a proposal; it may read provider state. Check each item's availability and decision before submitting a proposal.

Plainrouter is **not a full Marketing API replacement**: it does not offer arbitrary campaign or audience creation. Its [TypeScript, Python, Ruby and Go SDKs](<https://plainrouter.com/docs/sdk/overview>) are Conversion API clients, with a separate CLI; do not assume those SDKs wrap the Actions endpoints. Use the documented REST interface for Actions, or [Plainrouter's hosted Meta Ads MCP server](</solutions/meta-ads-mcp>) for agents. See the [developer workflow](</solutions/developers>) for the broader integration.

## Frequently asked questions

### Does Facebook have an API?

Yes. Meta’s [Marketing API documentation](<https://developers.facebook.com/documentation/ads-commerce/marketing-api>) covers authorized Facebook and Instagram advertising reporting and management. The Graph API is the underlying request system; public-ad research and conversion-event delivery use different APIs, as the table above explains.

### How do I get a Meta Ads API key?

The credential searchers call an API key is an access token: obtain a user token through the authorized login flow, or use a system-user token for an appropriate automated integration. The token needs the required permissions and access to the ad account; follow [the token section](<#choose-the-right-token>) and [Meta's access-token guide](<https://developers.facebook.com/documentation/facebook-login/guides/access-tokens>).

### Where is the Meta Ads API documentation?

The official reference is [Meta's Marketing API documentation](<https://developers.facebook.com/documentation/ads-commerce/marketing-api>), which covers ad management and reporting.

### How much is the Facebook API?

The public Marketing API documentation reviewed for this guide does not publish a per-call price. That does not make an integration cost-free: advertising spend, infrastructure, maintenance and any third-party tooling are separate costs. Access tiers and quotas still apply; this guide does not promise unlimited free usage.

### Do I need App Review?

Your own-account prototype and a product serving other advertisers have different requirements. Check both permission access and the Marketing API tier: Meta requires review for Advanced permissions and Full Marketing API access. Business verification is a separate requirement where applicable.

### What is the difference between ads\_read and ads\_management?

` ads_read ` supports ad reporting. ` ads_management ` supports managing ads and relevant reads on accessible accounts. Choose the least access your actual endpoints need; neither permission overrides asset assignments.

### Is Marketing API the same as Ad Library API?

No. Marketing API works with authorized advertisers' accounts and reporting. Ad Library API searches supported public-ad archive records and does not give you private campaign insights or control over another advertiser's ads.

### Can an AI agent use it?

Yes, through code or an MCP server that exposes the needed operations. Check account scope, read/write permissions and approval behavior separately: an agent calling a raw Marketing API write does not automatically get Plainrouter's proposal controls.

### Python or Node?

Both can call the HTTP API, and Meta publishes Business SDKs for both. Choose the language your team operates well; permissions, account access and version limits remain the same. Start with the [Python SDK](<https://github.com/facebook/facebook-python-business-sdk>) or [Node.js SDK](<https://github.com/facebook/facebook-nodejs-business-sdk>).
