Meta Ads
Access the Meta Marketing API with managed OAuth authentication. Manage ad accounts, campaigns, ad sets, ads, creatives, and retrieve performance insights.
Quick Start
# List ad accounts accessible to you
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/meta-ads/v25.0/me/adaccounts?fields=id,name,account_status,currency')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Base URL
https://api.maton.ai/meta-ads/{native-api-path}
Maton proxies requests to graph.facebook.com and automatically injects your OAuth token.
Authentication
All requests require the Maton API key in the Authorization header:
Authorization: Bearer $MATON_API_KEY
Environment Variable: Set your API key as MATON_API_KEY:
export MATON_API_KEY="YOUR_API_KEY"
Getting Your API Key
- Sign in or create an account at maton.ai
- Go to maton.ai/settings
- Copy your API key
Connection Management
Manage your Meta Ads OAuth connections at https://api.maton.ai.
List Connections
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections?app=meta-ads&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Create Connection
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'meta-ads'}).encode()
req = urllib.request.Request('https://api.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Get Connection
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Response:
{
"connection": {
"connection_id": "{connection_id}",
"status": "ACTIVE",
"creation_time": "2025-12-08T07:20:53.488460Z",
"last_updated_time": "2026-01-31T20:03:32.593153Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "meta-ads",
"metadata": {}
}
}
Open the returned url in a browser to complete OAuth authorization.
Delete Connection
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Specifying Connection
If you have multiple Meta Ads connections, specify which one to use with the Maton-Connection header:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/meta-ads/v25.0/me/adaccounts')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '{connection_id}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If you have multiple connections, always include this header to ensure requests go to the intended account.
Security & Permissions
- Access is scoped to ad accounts, campaigns, ad sets, ads, creatives, images, insights, and custom audiences within the connected Meta Ads account.
- All operations that create or modify ad resources require explicit user approval. Before creating, updating, or deleting campaigns, ad sets, ads, or creatives, confirm the target resource, account, and intended effect with the user.
- Activating ads or increasing budgets can incur real ad spend. Always confirm with the user before setting any campaign, ad set, or ad status to
ACTIVE, or modifying budget values.
API Reference
User & Ad Accounts
Get Current User
GET /meta-ads/v25.0/me?fields=id,name,email
List Ad Accounts
GET /meta-ads/v25.0/me/adaccounts?fields=id,name,account_status,currency,amount_spent
Get Ad Account Details
GET /meta-ads/v25.0/act_{ad_account_id}?fields=id,name,account_status,currency,spend_cap,amount_spent,balance
Campaigns
List Campaigns
GET /meta-ads/v25.0/act_{ad_account_id}/campaigns?fields=id,name,status,objective,daily_budget,lifetime_budget,created_time
Get Campaign
GET /meta-ads/v25.0/{campaign_id}?fields=id,name,status,objective,daily_budget,lifetime_budget
Create Campaign
POST /meta-ads/v25.0/act_{ad_account_id}/campaigns
Content-Type: application/json
{
"name": "My Campaign",
"objective": "OUTCOME_TRAFFIC",
"status": "PAUSED",
"special_ad_categories": []
}
Update Campaign
POST /meta-ads/v25.0/{campaign_id}
Content-Type: application/json
{
"name": "Updated Campaign Name",
"status": "ACTIVE"
}
Delete Campaign
DELETE /meta-ads/v25.0/{campaign_id}
Ad Sets
List Ad Sets
GET /meta-ads/v25.0/act_{ad_account_id}/adsets?fields=id,name,status,campaign_id,daily_budget,lifetime_budget,targeting,optimization_goal
Get Ad Set
GET /meta-ads/v25.0/{adset_id}?fields=id,name,status,campaign_id,daily_budget,targeting
Create Ad Set
POST /meta-ads/v25.0/act_{ad_account_id}/adsets
Content-Type: application/json
{
"name": "My Ad Set",
"campaign_id": "{campaign_id}",
"daily_budget": 1000,
"billing_event": "IMPRESSIONS",
"optimization_goal": "LINK_CLICKS",
"status": "PAUSED",
"targeting": {
"geo_locations": {
"countries": ["US"]
},
"age_min": 18,
"age_max": 65
}
}
Update Ad Set
POST /meta-ads/v25.0/{adset_id}
Content-Type: application/json
{
"name": "Updated Ad Set Name",
"status": "ACTIVE"
}
Delete Ad Set
DELETE /meta-ads/v25.0/{adset_id}
Ads
List Ads
GET /meta-ads/v25.0/act_{ad_account_id}/ads?fields=id,name,status,adset_id,creative,created_time,effective_status
Get Ad
GET /meta-ads/v25.0/{ad_id}?fields=id,name,status,adset_id,creative
Create Ad
POST /meta-ads/v25.0/act_{ad_account_id}/ads
Content-Type: application/json
{
"name": "My Ad",
"adset_id": "{adset_id}",
"creative": {"creative_id": "{creative_id}"},
"status": "PAUSED"
}
Update Ad
POST /meta-ads/v25.0/{ad_id}
Content-Type: application/json
{
"name": "Updated Ad Name",
"status": "ACTIVE"
}
Delete Ad
DELETE /meta-ads/v25.0/{ad_id}
Ad Creatives
List Ad Creatives
GET /meta-ads/v25.0/act_{ad_account_id}/adcreatives?fields=id,name,object_story_spec,thumbnail_url
Get Ad Creative
GET /meta-ads/v25.0/{creative_id}?fields=id,name,object_story_spec,thumbnail_url
Create Ad Creative
POST /meta-ads/v25.0/act_{ad_account_id}/adcreatives
Content-Type: application/json
{
"name": "My Creative",
"object_story_spec": {
"page_id": "{page_id}",
"link_data": {
"link": "https://example.com",
"message": "Check out our website!",
"name": "Example Site",
"image_hash": "{image_hash}"
}
}
}
Ad Images
Upload Ad Image
POST /meta-ads/v25.0/act_{ad_account_id}/adimages
Content-Type: multipart/form-data
filename=@/path/to/image.jpg
List Ad Images
GET /meta-ads/v25.0/act_{ad_account_id}/adimages?fields=hash,name,url,created_time
Insights (Analytics)
Get Account Insights
GET /meta-ads/v25.0/act_{ad_account_id}/insights?fields=impressions,clicks,spend,reach,cpc,cpm,ctr&date_preset=last_7d
Get Campaign Insights
GET /meta-ads/v25.0/{campaign_id}/insights?fields=impressions,clicks,spend,reach,actions&date_preset=last_30d
Get Ad Set Insights
GET /meta-ads/v25.0/{adset_id}/insights?fields=impressions,clicks,spend,reach,actions&date_preset=this_month
Get Ad Insights
GET /meta-ads/v25.0/{ad_id}/insights?fields=impressions,clicks,spend,reach,actions&date_preset=last_7d
Get Insights with Custom Date Range
GET /meta-ads/v25.0/act_{ad_account_id}/insights?fields=impressions,clicks,spend&time_range={"since":"2026-01-01","until":"2026-01-31"}
Get Insights with Breakdowns
GET /meta-ads/v25.0/act_{ad_account_id}/insights?fields=impressions,clicks,spend&breakdowns=age,gender&date_preset=last_7d
Custom Audiences
List Custom Audiences
GET /meta-ads/v25.0/act_{ad_account_id}/customaudiences?fields=id,name,subtype,approximate_count
Get Custom Audience
GET /meta-ads/v25.0/{custom_audience_id}?fields=id,name,subtype,approximate_count,description
Pagination
Use limit and cursors for pagination:
GET /meta-ads/v25.0/act_{ad_account_id}/campaigns?fields=id,name&limit=50
Response includes paging with cursors when more results exist:
{
"data": [...],
"paging": {
"cursors": {
"before": "MAZDZD",
"after": "MjQZD"
},
"next": "https://graph.facebook.com/..."
}
}
Use after cursor for next page:
GET /meta-ads/v25.0/act_{ad_account_id}/campaigns?fields=id,name&limit=50&after=MjQZD
Code Examples
JavaScript
const response = await fetch(
'https://api.maton.ai/meta-ads/v25.0/me/adaccounts?fields=id,name,account_status',
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
const data = await response.json();
console.log(data);
Python
import os
import requests
response = requests.get(
'https://api.maton.ai/meta-ads/v25.0/me/adaccounts',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'},
params={'fields': 'id,name,account_status'}
)
print(response.json())
Notes
- Ad Account IDs start with
act_followed by numeric ID - Campaign objectives include:
OUTCOME_AWARENESS,OUTCOME_ENGAGEMENT,OUTCOME_LEADS,OUTCOME_SALES,OUTCOME_TRAFFIC,OUTCOME_APP_PROMOTION - Status values:
ACTIVE,PAUSED,DELETED,ARCHIVED - Budget values are in the account's currency minor units (e.g., cents for USD)
special_ad_categoriesis required for campaigns (use[]for none, or include:HOUSING,EMPLOYMENT,CREDIT,ISSUES_ELECTIONS_POLITICS)- Date presets:
today,yesterday,this_month,last_month,this_quarter,last_7d,last_14d,last_28d,last_30d,last_90d - Breakdowns:
age,gender,country,region,dma,impression_device,platform_position,publisher_platform - IMPORTANT: When using curl commands, use
curl -gwhen URLs contain brackets to disable glob parsing - IMPORTANT: When piping curl output to
jqor other commands, environment variables like$MATON_API_KEYmay not expand correctly in some shell environments
Error Handling
| Status | Meaning |
|---|---|
| 400 | Missing Meta Ads connection |
| 401 | Invalid or missing Maton API key |
| 190 | Invalid or expired OAuth token |
| 200 | Permissions error from Meta |
| 429 | Rate limited |
| 4xx/5xx | Passthrough error from Meta Marketing API |
Common Error Codes from Meta
| Code | Meaning |
|---|---|
| 100 | Invalid parameter |
| 190 | Invalid OAuth access token |
| 200 | Requires permissions |
| 368 | Action blocked |
| 613 | Rate limit exceeded |
| 80004 | Ad account call limit exceeded |
Troubleshooting: API Key Issues
- Check that the
MATON_API_KEYenvironment variable is set:
echo $MATON_API_KEY
- Verify the API key is valid by listing connections:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Troubleshooting: Invalid App Name
- Ensure your URL path starts with
meta-ads. For example:
- Correct:
https://api.maton.ai/meta-ads/v25.0/me/adaccounts - Incorrect:
https://api.maton.ai/v25.0/me/adaccounts