Skip to content

Reporting

The Reporting endpoint returns aggregated performance metrics — spend, impressions, clicks, installs, purchases — for an advertiser account at the level of detail you choose: whole account, campaign, ad group or ad, optionally broken down by day and by country. This is the endpoint you call every day to collect ad performance.

Verify against Ads Manager

The same report is available on screen at ads-manager.huydata.com with the platform's own column names; its Totals row is the reference for your pipeline. See Ads Manager.

Get integrated report

GET /open_api/v1.3/report/integrated/get/

Parameters

Name Type Required Description
advertiser_id string Yes Advertiser account id. One account per call.
report_type string Yes Must be BASIC.
service_type string No AUCTION (default and only value).
data_level string Yes Aggregation level: AUCTION_ADVERTISER, AUCTION_CAMPAIGN, AUCTION_ADGROUP or AUCTION_AD.
dimensions JSON array of strings Yes Grouping keys. Must contain the id dimension that matches data_level (advertiser_id, campaign_id, adgroup_id or ad_id). May additionally contain stat_time_day (one row per day) and/or country_code (one row per country). No other dimension is accepted.
metrics JSON array of strings No Metrics to return, see Metrics. Default: ["spend","impressions","clicks","conversion"].
start_date string YYYY-MM-DD Yes, unless lifetime=true First report date, inclusive.
end_date string YYYY-MM-DD Yes, unless lifetime=true Last report date, inclusive. Must be on or after start_date.
lifetime boolean (true/false) No true returns the whole available history (2026-06-30 to the latest available date) and ignores start_date/end_date. Default false.
filtering JSON array of objects No Row filters, see Filtering. Note the different shape from the campaign/adgroup/ad endpoints.
order_field string No Metric to sort by: any numeric metric from the table below, or stat_time_day. A metric used here must also be listed in metrics, otherwise the call fails with 40001. Attribute metrics such as campaign_name cannot be used.
order_type string No DESC (default) or ASC. Any other value fails with 40001.
page integer No Page number, starting at 1. Default 1.
page_size integer No Rows per page, 1–1000. Default 10. Use 1000 for daily pulls.

Dimensions

data_level Required id dimension Optional dimensions
AUCTION_ADVERTISER advertiser_id stat_time_day, country_code
AUCTION_CAMPAIGN campaign_id stat_time_day, country_code
AUCTION_ADGROUP adgroup_id stat_time_day, country_code
AUCTION_AD ad_id stat_time_day, country_code
  • Without stat_time_day, metrics are summed over the whole date range (one row per entity, or per entity and country).
  • stat_time_day is returned as "YYYY-MM-DD 00:00:00" — a UTC day with a zero time component. Take the first 10 characters to get the date.
  • country_code is the ISO 3166-1 alpha-2 code (US, JP, VN, ...). The same codes are returned as region_code by /tool/region/get/.
  • Rows are sorted by stat_time_day, then id, then country_code unless order_field is given.
  • Rows with no delivery are not returned. If an ad did not deliver in a country on a day, there is no row with zeros — the row is absent. The number of rows therefore varies from day to day.

Metrics

All metric values are returned as strings, including counts and money. Convert them in your client (int() for counts, Decimal/float for the others).

Numeric metrics:

Metric Unit Description
spend USD, 2 decimals Amount spent.
impressions count Ad impressions.
clicks count Clicks.
ctr percent, 2 decimals clicks / impressions × 100.
cpm USD Cost per 1,000 impressions.
cpc USD Cost per click.
reach count Unique users reached. Summed across the rows of the group, so it is not de-duplicated across days or countries.
frequency ratio, 2 decimals impressions / reach.
conversion count App installs attributed to the ad — the optimization event of these accounts. Identical to app_install.
cost_per_conversion USD spend / conversion.
conversion_rate percent conversion / clicks × 100.
app_install count Same as conversion.
cost_per_app_install USD Same as cost_per_conversion.
purchase count In-app purchase events attributed to the ad.
total_purchase_value USD, 2 decimals Revenue of attributed purchases.
video_play_actions count Video plays (video and playable ads). 0 for image ads.
video_views_p100 count Plays that reached 100 % of the video.

Ratios are computed after aggregation and return "0.00" when the denominator is zero.

Attribute ("name/id") metrics — returned as strings in the same metrics object, useful to avoid a join with the entity endpoints:

Metric Available at Description
campaign_id campaign, ad group, ad Parent campaign id.
campaign_name campaign, ad group, ad Parent campaign name.
adgroup_id ad group, ad Parent ad group id.
adgroup_name ad group, ad Parent ad group name.
ad_name ad Ad name.
currency all levels USD.
objective_type all levels APP_PROMOTION.

Requesting an attribute metric at a level where it is not available fails with 40001 (for example Name/id metrics are not available at AUCTION_ADVERTISER level.).

Filtering

filtering is a JSON array of rule objects (a different shape from the filtering object used by /campaign/get/, /adgroup/get/ and /ad/get/):

[{"field_name": "campaign_ids", "filter_type": "IN", "filter_value": "[\"1871286220402645533\"]"}]
Key Type Description
field_name string campaign_ids, adgroup_ids, ad_ids or country_code.
filter_type string IN (default) or NOT_IN.
filter_value string A JSON-encoded array, as a string — the list is serialized a second time inside the outer JSON. A bare string ("JP") is accepted as a single value.

Rules are combined with AND. Filtering happens before aggregation, so filtering by country_code without the country_code dimension gives totals for the selected countries only.

Request: ad level, per day and country

curl -s -G "https://business-api.huydata.com/open_api/v1.3/report/integrated/get/" \
  -H "Access-Token: $TIKTOK_ACCESS_TOKEN" \
  --data-urlencode "advertiser_id=7643153585721644371" \
  --data-urlencode "report_type=BASIC" \
  --data-urlencode "data_level=AUCTION_AD" \
  --data-urlencode 'dimensions=["ad_id","stat_time_day","country_code"]' \
  --data-urlencode 'metrics=["campaign_id","campaign_name","adgroup_id","adgroup_name","ad_name","currency","objective_type","spend","impressions","clicks","ctr","cpm","cpc","reach","frequency","conversion","cost_per_conversion","conversion_rate","app_install","cost_per_app_install","purchase","total_purchase_value","video_play_actions","video_views_p100"]' \
  --data-urlencode "start_date=2026-10-27" \
  --data-urlencode "end_date=2026-10-29" \
  --data-urlencode 'filtering=[{"field_name":"ad_ids","filter_type":"IN","filter_value":"[\"1831381570943309792\"]"}]' \
  --data-urlencode "page_size=2"

Response

{
  "code": 0,
  "message": "OK",
  "request_id": "1f260e2ffae041bda805",
  "data": {
    "list": [
      {
        "dimensions": {
          "ad_id": "1831381570943309792",
          "stat_time_day": "2026-10-27 00:00:00",
          "country_code": "JP"
        },
        "metrics": {
          "campaign_id": "1871286220402645533",
          "campaign_name": "DMS_TT_AND_EA_INSTALL_202602",
          "adgroup_id": "1868805261510613175",
          "adgroup_name": "EA_Broad_JP-KR-TW",
          "ad_name": "VID_Tutorial_v1",
          "currency": "USD",
          "objective_type": "APP_PROMOTION",
          "spend": "11.56",
          "impressions": "1221",
          "clicks": "7",
          "ctr": "0.57",
          "cpm": "9.47",
          "cpc": "1.65",
          "reach": "739",
          "frequency": "1.65",
          "conversion": "1",
          "cost_per_conversion": "11.56",
          "conversion_rate": "14.29",
          "app_install": "1",
          "cost_per_app_install": "11.56",
          "purchase": "0",
          "total_purchase_value": "0.00",
          "video_play_actions": "631",
          "video_views_p100": "113"
        }
      },
      {
        "dimensions": {
          "ad_id": "1831381570943309792",
          "stat_time_day": "2026-10-27 00:00:00",
          "country_code": "KR"
        },
        "metrics": {
          "campaign_id": "1871286220402645533",
          "campaign_name": "DMS_TT_AND_EA_INSTALL_202602",
          "adgroup_id": "1868805261510613175",
          "adgroup_name": "EA_Broad_JP-KR-TW",
          "ad_name": "VID_Tutorial_v1",
          "currency": "USD",
          "objective_type": "APP_PROMOTION",
          "spend": "6.59",
          "impressions": "850",
          "clicks": "5",
          "ctr": "0.59",
          "cpm": "7.75",
          "cpc": "1.32",
          "reach": "542",
          "frequency": "1.57",
          "conversion": "0",
          "cost_per_conversion": "0.00",
          "conversion_rate": "0.00",
          "app_install": "0",
          "cost_per_app_install": "0.00",
          "purchase": "0",
          "total_purchase_value": "0.00",
          "video_play_actions": "490",
          "video_views_p100": "88"
        }
      }
    ],
    "page_info": {"page": 1, "page_size": 2, "total_number": 9, "total_page": 5}
  }
}

Each row has two objects: dimensions (the grouping keys you asked for) and metrics (everything in metrics, all strings).

Request: account totals per day, default metrics

curl -s -G "https://business-api.huydata.com/open_api/v1.3/report/integrated/get/" \
  -H "Access-Token: $TIKTOK_ACCESS_TOKEN" \
  --data-urlencode "advertiser_id=7643153585721644371" \
  --data-urlencode "report_type=BASIC" \
  --data-urlencode "data_level=AUCTION_ADVERTISER" \
  --data-urlencode 'dimensions=["advertiser_id","stat_time_day"]' \
  --data-urlencode "start_date=2026-10-27" \
  --data-urlencode "end_date=2026-10-29"
{
  "code": 0,
  "message": "OK",
  "request_id": "9ebdbbf6838e4f1a98ed",
  "data": {
    "list": [
      {"dimensions": {"advertiser_id": "7643153585721644371", "stat_time_day": "2026-10-27 00:00:00"}, "metrics": {"spend": "1216.74", "impressions": "239539", "clicks": "1510", "conversion": "296"}},
      {"dimensions": {"advertiser_id": "7643153585721644371", "stat_time_day": "2026-10-28 00:00:00"}, "metrics": {"spend": "1385.12", "impressions": "278177", "clicks": "1673", "conversion": "329"}},
      {"dimensions": {"advertiser_id": "7643153585721644371", "stat_time_day": "2026-10-29 00:00:00"}, "metrics": {"spend": "1433.99", "impressions": "271178", "clicks": "1599", "conversion": "271"}}
    ],
    "page_info": {"page": 1, "page_size": 10, "total_number": 3, "total_page": 1}
  }
}

Request: campaign lifetime totals, sorted by spend

curl -s -G "https://business-api.huydata.com/open_api/v1.3/report/integrated/get/" \
  -H "Access-Token: $TIKTOK_ACCESS_TOKEN" \
  --data-urlencode "advertiser_id=7643153585721644371" \
  --data-urlencode "report_type=BASIC" \
  --data-urlencode "data_level=AUCTION_CAMPAIGN" \
  --data-urlencode 'dimensions=["campaign_id"]' \
  --data-urlencode 'metrics=["campaign_name","objective_type","spend","impressions","clicks","conversion","cost_per_conversion","purchase","total_purchase_value"]' \
  --data-urlencode "lifetime=true" \
  --data-urlencode "order_field=spend" \
  --data-urlencode "order_type=DESC"
{
  "code": 0,
  "message": "OK",
  "request_id": "31db6f15f6734da4923d",
  "data": {
    "list": [
      {
        "dimensions": {"campaign_id": "1841269875139264223"},
        "metrics": {"campaign_name": "DMS_TT_AND_T1_INSTALL_202609", "objective_type": "APP_PROMOTION", "spend": "49229.02", "impressions": "7481258", "clicks": "50803", "conversion": "7817", "cost_per_conversion": "6.30", "purchase": "422", "total_purchase_value": "12560.35"}
      },
      {
        "dimensions": {"campaign_id": "1871286220402645533"},
        "metrics": {"campaign_name": "DMS_TT_AND_EA_INSTALL_202602", "objective_type": "APP_PROMOTION", "spend": "45272.34", "impressions": "6046186", "clicks": "30996", "conversion": "4411", "cost_per_conversion": "10.26", "purchase": "343", "total_purchase_value": "12254.40"}
      },
      {
        "dimensions": {"campaign_id": "1862348092944652029"},
        "metrics": {"campaign_name": "DMS_TT_AND_SEA_INSTALL_202604", "objective_type": "APP_PROMOTION", "spend": "14400.52", "impressions": "10931272", "clicks": "66969", "conversion": "19714", "cost_per_conversion": "0.73", "purchase": "268", "total_purchase_value": "4012.65"}
      }
    ],
    "page_info": {"page": 1, "page_size": 10, "total_number": 3, "total_page": 1}
  }
}

Request: ad groups of one campaign, two countries, one day

curl -s -G "https://business-api.huydata.com/open_api/v1.3/report/integrated/get/" \
  -H "Access-Token: $TIKTOK_ACCESS_TOKEN" \
  --data-urlencode "advertiser_id=7643153585721644371" \
  --data-urlencode "report_type=BASIC" \
  --data-urlencode "data_level=AUCTION_ADGROUP" \
  --data-urlencode 'dimensions=["adgroup_id","stat_time_day","country_code"]' \
  --data-urlencode 'metrics=["adgroup_name","campaign_id","spend","impressions","clicks","conversion"]' \
  --data-urlencode "start_date=2026-10-29" \
  --data-urlencode "end_date=2026-10-29" \
  --data-urlencode 'filtering=[{"field_name":"campaign_ids","filter_type":"IN","filter_value":"[\"1871286220402645533\"]"},{"field_name":"country_code","filter_type":"IN","filter_value":"[\"JP\",\"KR\"]"}]' \
  --data-urlencode "page_size=3"
{
  "code": 0,
  "message": "OK",
  "request_id": "b8f51f9932ba4761ad64",
  "data": {
    "list": [
      {"dimensions": {"adgroup_id": "1822048926325183510", "stat_time_day": "2026-10-29 00:00:00", "country_code": "JP"}, "metrics": {"adgroup_name": "EA_Lookalike_Payers_JP-KR-TW", "campaign_id": "1871286220402645533", "spend": "33.12", "impressions": "4158", "clicks": "24", "conversion": "4"}},
      {"dimensions": {"adgroup_id": "1822048926325183510", "stat_time_day": "2026-10-29 00:00:00", "country_code": "KR"}, "metrics": {"adgroup_name": "EA_Lookalike_Payers_JP-KR-TW", "campaign_id": "1871286220402645533", "spend": "24.70", "impressions": "3265", "clicks": "17", "conversion": "2"}},
      {"dimensions": {"adgroup_id": "1836683088316451285", "stat_time_day": "2026-10-29 00:00:00", "country_code": "JP"}, "metrics": {"adgroup_name": "EA_Interest_Gaming_JP-KR", "campaign_id": "1871286220402645533", "spend": "75.07", "impressions": "9590", "clicks": "47", "conversion": "6"}}
    ],
    "page_info": {"page": 1, "page_size": 3, "total_number": 6, "total_page": 2}
  }
}

Paging

A day of ad-level data split by country for one account is typically 10–100 rows, so page_size=1000 returns everything in one page. For longer date ranges, loop until page >= total_page:

import json
import os

import requests

BASE = "https://business-api.huydata.com/open_api/v1.3"
HEADERS = {"Access-Token": os.environ["TIKTOK_ACCESS_TOKEN"]}

def fetch_report(advertiser_id: str, start_date: str, end_date: str) -> list[dict]:
    params = {
        "advertiser_id": advertiser_id,
        "report_type": "BASIC",
        "data_level": "AUCTION_AD",
        "dimensions": json.dumps(["ad_id", "stat_time_day", "country_code"]),
        "metrics": json.dumps(["campaign_id", "campaign_name", "adgroup_id", "adgroup_name", "ad_name",
                               "spend", "impressions", "clicks", "conversion", "purchase", "total_purchase_value"]),
        "start_date": start_date,
        "end_date": end_date,
        "page_size": 1000,
        "page": 1,
    }
    rows = []
    while True:
        body = requests.get(f"{BASE}/report/integrated/get/", headers=HEADERS, params=params, timeout=60).json()
        if body["code"] != 0:
            raise RuntimeError(f"{body['code']}: {body['message']} (request_id={body['request_id']})")
        data = body["data"]
        rows.extend(data["list"])
        if data["page_info"]["page"] >= data["page_info"]["total_page"]:
            return rows
        params["page"] += 1

total_number is the total number of rows across all pages, total_page the number of pages (always at least 1, even when list is empty). Requesting a page beyond total_page returns an empty list, not an error.

Data freshness and the attribution window

Availability

Report dates are UTC days. The data for date D becomes available at 00:10 UTC on D + 1. The latest available report date is therefore always yesterday (UTC). A date range that extends past yesterday is silently clipped: the unavailable days simply produce no rows and code is still 0.

{"code": 0, "message": "OK", "request_id": "df023713e87a45d98dc5", "data": {"list": [], "page_info": {"page": 1, "page_size": 10, "total_number": 0, "total_page": 1}}}

The earliest report date is 2026-06-30. Dates before it are clipped the same way.

Attribution window: 3 days

Spend, impressions, clicks and video metrics are final as soon as a date becomes available. Installs (conversion/app_install), purchases and purchase value are not. TikTok attributes installs and purchases to the ad for up to 3 days after the impression, so the values for a report date keep increasing until 3 days after that date, when they become final.

The same request — account totals for report date 2026-10-27 — issued on four different days:

Pulled on (UTC) Age of the date spend impressions clicks conversion purchase total_purchase_value
2026-10-28 D+1 1216.74 239539 1510 267 11 236.09
2026-10-29 D+2 1216.74 239539 1510 286 11 280.36
2026-10-30 D+3 1216.74 239539 1510 296 12 326.18
2026-11-05 later 1216.74 239539 1510 296 12 326.18

Roughly 90 % of the final installs are visible on D+1, 97 % on D+2 and 100 % from D+3. Purchases and purchase value mature more slowly (about 80 % of the value on D+1 and 95 % on D+2); small purchase counts can stay flat for a day and then step up, as the purchase column above shows. Because counts are whole numbers, a row with few installs may move by exactly 1 between two reads, or not at all.

What this means for a daily pull:

  1. Each day after 00:10 UTC, pull yesterday (D-1) — it is new.
  2. Also re-pull the three most recent report dates (D-1, D-2, D-3) and replace what you stored earlier for those dates. Those are the dates whose conversion, app_install, cost_per_conversion, conversion_rate, purchase and total_purchase_value may still have changed.
  3. Dates older than D-3 do not change; there is no need to pull them again.

Because the API reports the current state of each date, there is no parameter to request "the values as of yesterday"; store the pull date with your rows if you need to reconstruct what was visible when.

Errors specific to Reporting

All are returned with HTTP 200 and code 40001:

Situation message
report_type missing or not BASIC report_type is required and must be BASIC in this sandbox.
data_level missing or misspelled data_level must be one of AUCTION_ADVERTISER, AUCTION_CAMPAIGN, AUCTION_ADGROUP, AUCTION_AD.
dimensions missing Parameter 'dimensions' is required.
id dimension missing dimensions must include ad_id when data_level=AUCTION_AD.
unknown dimension Unsupported dimension 'age'. Supported: ad_id, stat_time_day, country_code.
unknown metric (e.g. installs) Unsupported metric 'installs'.
attribute metric at the wrong level Name/id metrics are not available at AUCTION_ADVERTISER level. / adgroup/ad metrics are not available at AUCTION_CAMPAIGN level. / ad_name is not available at AUCTION_ADGROUP level.
no dates and no lifetime=true start_date and end_date are required unless lifetime=true.
wrong date format start_date and end_date must use the format YYYY-MM-DD.
end_date before start_date end_date must be on or after start_date.
filtering not a list of objects filtering must be a JSON list of {field_name, filter_type, filter_value}.
unknown field_name Unsupported filter field_name 'adgroup_id'. Supported: campaign_ids, adgroup_ids, ad_ids, country_code
unknown filter_type Unsupported filter_type 'EQ'. Use IN or NOT_IN.
order_field that is not a numeric metric order_field 'campaign_name' is not a numeric metric.
order_field metric missing from metrics order_field 'spend' must also be included in metrics.
order_type other than ASC/DESC order_type must be ASC or DESC.

Example:

{
  "code": 40001,
  "message": "dimensions must include ad_id when data_level=AUCTION_AD.",
  "request_id": "ccd5fbd11e534ab59400",
  "data": {}
}