Skip to content

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).