Marketing API — Overview¶
The Marketing API is a Graph API surface for reading advertising objects and their performance. This reference describes the sandbox deployment used by Nova Play, a mobile game studio that advertises 10 games. Every game has its own ad account, so you will work with 10 ad accounts, each holding a few campaigns, ad sets and ads, plus a daily performance history that goes back to 2026-06-30.
The API is read-only. All requests are HTTP GET, all responses are JSON.
Base URL¶
https://graph.huydata.com/v21.0
Every path in this documentation is relative to that base. The version segment
(v21.0) is mandatory; any other version returns error code 2500 (unknown path).
Object model¶
User (/me)
└── Ad Account act_<account_id> one per game
└── Campaign <campaign_id> objective, budget, dates
└── Ad Set <adset_id> targeting (countries, audience), promoted app
└── Ad <ad_id> creative (video / playable / image)
Performance metrics are not fields on these objects. They are read through the
Insights edge (/<object_id>/insights) at the level you choose: account,
campaign, adset or ad.
| Page | What it covers |
|---|---|
| Authentication | Access tokens, how to send them, what happens when they are wrong |
| Ad Account | /me/adaccounts, /act_<id> |
| Campaign | /act_<id>/campaigns, /<campaign_id>, naming convention, budgets |
| Ad Set | /act_<id>/adsets, /<campaign_id>/adsets, targeting and promoted_object |
| Ad | /act_<id>/ads, /<adset_id>/ads, nested creative{...} |
| Insights | Daily performance, actions, action values, cost per action, ROAS, country breakdown, data freshness |
| Paging | Cursor-based pagination with limit, after and paging.next |
| Errors & rate limiting | Error envelope, error codes, the 60 requests / minute limit |
Requesting fields¶
Graph API objects return only a minimal set of fields by default (usually id and
name, or id and account_id for ad accounts). Ask for what you need with the
fields parameter, as a comma-separated list:
?fields=id,name,status,daily_budget
Fields that are themselves objects can be expanded with a nested field list in braces:
?fields=id,name,creative{id,name,object_type}
Requesting a field that does not exist on the object type is an error (code 100),
not a silently empty value. See each object page for the list of valid fields.
Quickstart¶
The following four calls take you from a token to one day of ad-level performance.
1. List the ad accounts your token can see
curl -G "https://graph.huydata.com/v21.0/me/adaccounts" \
-d "access_token=$META_ACCESS_TOKEN" \
-d "fields=id,name,account_id,currency"
{
"data": [
{
"id": "act_199454714457591",
"name": "Dragon Merge Saga (Android)",
"account_id": "199454714457591",
"currency": "USD"
},
{
"id": "act_195371095837700",
"name": "Idle Mining Empire (Android)",
"account_id": "195371095837700",
"currency": "USD"
},
"..."
],
"paging": {
"cursors": { "before": "b2Zmc2V0OjA", "after": "b2Zmc2V0OjEw" }
}
}
2. List the campaigns of one account
curl -G "https://graph.huydata.com/v21.0/act_199454714457591/campaigns" \
-d "access_token=$META_ACCESS_TOKEN" \
-d "fields=id,name,status,daily_budget,start_time,stop_time"
3. List the ads with their creative
curl -G "https://graph.huydata.com/v21.0/act_199454714457591/ads" \
-d "access_token=$META_ACCESS_TOKEN" \
-d "fields=id,name,adset_id,campaign_id,status,creative{id,name,object_type}" \
-d "limit=500"
4. Pull one day of ad-level performance, broken down by country
curl -G "https://graph.huydata.com/v21.0/act_199454714457591/insights" \
-d "access_token=$META_ACCESS_TOKEN" \
-d "level=ad" \
-d "fields=campaign_id,adset_id,ad_id,ad_name,spend,impressions,clicks,actions,action_values" \
-d "breakdowns=country" \
--data-urlencode 'time_range={"since":"2026-10-27","until":"2026-10-27"}' \
-d "time_increment=1" \
-d "limit=500"
{
"data": [
{
"campaign_id": "12020064400866904",
"adset_id": "12024481725776212",
"ad_id": "12022015737750702",
"ad_name": "VID_UpgradeLoop_v3",
"spend": "46.47",
"impressions": "5175",
"clicks": "35",
"actions": [
{ "action_type": "video_view", "value": "2153" },
{ "action_type": "link_click", "value": "35" },
{ "action_type": "mobile_app_install", "value": "6" },
{ "action_type": "app_custom_event.fb_mobile_purchase", "value": "1" },
{ "action_type": "omni_purchase", "value": "1" }
],
"action_values": [
{ "action_type": "app_custom_event.fb_mobile_purchase", "value": "32.15" },
{ "action_type": "omni_purchase", "value": "32.15" }
],
"country": "AU",
"date_start": "2026-10-27",
"date_stop": "2026-10-27"
},
"..."
],
"paging": {
"cursors": { "before": "b2Zmc2V0OjA", "after": "b2Zmc2V0Ojgy" }
}
}
This single day is 82 rows for this account, so it fits in one page of 500 and there is
no paging.next. Ask for a week instead and the first page is full: the response then
contains paging.next, and you request that URL to get the next page, repeating until
paging.next is absent. See Paging.
Things to know before you build a daily pull¶
- All metric values are strings.
"spend": "46.47","impressions": "5175". Convert them yourself. - Report dates become available at 00:10 UTC of the following day. On 2026-10-30 the latest report date you can read is 2026-10-29. Requests for today return no rows.
- Conversions keep changing for 3 days. Installs and purchases attributed to a report date continue to increase until the date is 3 days old. Re-pull the last 3 report dates every day. Spend, impressions and clicks do not change.
- Rows with no delivery are not returned. An ad that did not spend on a given day (or in a given country) has no row for that day. Do not expect a dense grid.
- The per-token limit is 60 requests per minute. Exceeding it returns error code
17; wait 60 seconds before retrying. See Errors & rate limiting. - Money fields on objects are in cents (
daily_budget: "97000"is 970.00 USD). Money fields in insights are in currency units (spend: "46.47"is 46.47 USD). All accounts use USD and the UTC timezone.
The Nova Play catalogue¶
| Ad account | Game | OS | Store app id |
|---|---|---|---|
act_199454714457591 |
Dragon Merge Saga | Android | com.novaplay.dragonmerge |
act_195371095837700 |
Idle Mining Empire | Android | com.novaplay.idlemining |
act_121809552335695 |
Zombie Siege Defense | Android | com.novaplay.zombiesiege |
act_125122534005354 |
Puzzle Blast Mania | iOS | id1600000011 |
act_150990802394697 |
Castle Match Legends | iOS | id1600000012 |
act_193125515079317 |
Car Park Master 3D | Android | com.novaplay.carpark3d |
act_156105482446855 |
Sushi Shop Tycoon | iOS | id1600000013 |
act_105449962451954 |
Hero Tower Defense | Android | com.novaplay.herotd |
act_180249870419075 |
Word Garden Story | iOS | id1600000014 |
act_163968967411649 |
Pixel Survivors | Android | com.novaplay.pixelsurvivors |
Do not hard-code this table: discover it with /me/adaccounts and read the store app id
from promoted_app_store_url (account) or promoted_object.object_store_url (ad set).
Campaigns target one of 14 countries grouped into four regions: T1 (US, GB, CA, AU,
DE), SEA (VN, ID, PH, TH), LATAM (BR, MX) and EA (JP, KR, TW).