Query your connected Meta, Google Ads or TikTok ad account live and read-only through REST API v1 and the MCP tool query_ads_live: any fields, breakdowns, levels and date ranges the platform API allows.

Live ad queries through REST API and MCP

The stored AxiTrace reports hold the daily spend, clicks and conversions of every connected ad account. When a question needs more, such as spend by device, placement, region, hour of day, age or gender, the text of an ad, the targeting of an ad set or the search terms of a campaign, a live query asks the ad platform directly and returns its rows. A live query is always read-only.

Read-only by design

A live query can never create, change, pause or delete anything in an ad account. The endpoint uses POST only to carry a structured body: AxiTrace pins the ad account, the access token and the read method itself, and refuses any request that would write. Google Ads queries must be a single GAQL SELECT.

Access

  • The endpoint and the tool need the ads_live:read scope. It is opt-in: on the consent page it is an extra box you must tick, and on the personal access token form it starts unticked. Connections and tokens made before it existed do not carry it.
  • The workspace must have an active connection to the platform you query. Without one, or when the platform rejected the stored access, the answer names the ad connections page where you connect or reconnect it.
  • Live queries are not available on demo workspaces, and Microsoft Ads cannot be queried live (its reporting API is asynchronous only): use the stored daily figures of list_campaigns.

Authentication, envelopes, errors and rate limits follow the REST API v1 reference; full schemas are in the OpenAPI document.

Operation

RESTMCP toolWhat it does
POST /api/v1/workspaces/{workspace_id}/ads/live-queryquery_ads_liveSends one read request to the connected account of platform (meta, google_ads or tiktok) and returns its rows.

The body is {"platform": "...", "request": {...}}. The shape of request depends on the platform.

Meta

request takes path, fields, level, breakdowns, action_breakdowns, time_range ({"since", "until"}), date_preset, time_increment, filtering, sort and limit (1 to 200, default 50). path is an edge of the connected account (insights by default, campaigns, adsets, ads, adcreatives, customaudiences, adlabels) or the id of one of its campaigns, ad sets, ads or creatives.

curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  "https://axitrace.com/api/v1/workspaces/$WORKSPACE/ads/live-query" \
  -d '{
    "platform": "meta",
    "request": {
      "level": "campaign",
      "fields": ["campaign_name", "spend", "impressions", "clicks"],
      "breakdowns": ["publisher_platform", "platform_position"],
      "date_preset": "last_7d"
    }
  }'

More examples: spend by region per ad set, {"level": "adset", "fields": ["adset_name", "spend"], "breakdowns": ["region"], "time_range": {"since": "2026-10-01", "until": "2026-10-31"}}; the copy of every ad, {"path": "ads", "fields": ["name", "effective_status", "creative{title,body}"]}.

request is {"query": "..."} with one GAQL SELECT: no PARAMETERS, no ;, and a LIMIT of at most 500 (added when absent). The resources that list people (customer_user_access, customer_user_access_invitation, change_event) are refused. cost_micros is the cost in millionths of the account currency.

{
  "platform": "google_ads",
  "request": {
    "query": "SELECT segments.device, metrics.cost_micros, metrics.clicks, metrics.conversions FROM campaign WHERE segments.date DURING LAST_30_DAYS"
  }
}

More examples: SELECT search_term_view.search_term, metrics.clicks, metrics.cost_micros FROM search_term_view WHERE segments.date DURING LAST_7_DAYS ORDER BY metrics.cost_micros DESC; SELECT segments.hour, metrics.clicks FROM campaign WHERE segments.date DURING YESTERDAY. Performance Max campaigns report no age or gender rows.

TikTok

request takes endpoint: report (default), campaign, adgroup or ad. A report takes report_type, data_level, dimensions, metrics, start_date, end_date, query_lifetime, filtering, order_field, order_type, service_type, page and page_size; an entity list takes fields, filtering, page and page_size (1 to 200).

{
  "platform": "tiktok",
  "request": {
    "endpoint": "report",
    "data_level": "AUCTION_CAMPAIGN",
    "dimensions": ["campaign_id", "stat_time_day"],
    "metrics": ["spend", "impressions", "clicks", "conversion"],
    "start_date": "2026-10-01",
    "end_date": "2026-10-30"
  }
}

The answer

{
  "data": {
    "cached": false,
    "platform": "google_ads",
    "account_id": "1234567890",
    "read_only": true,
    "request": { "target": "campaign", "parameters": { "query": "SELECT segments.device, ... LIMIT 500", "notes": [] } },
    "row_count": 3,
    "rows_returned": 3,
    "truncated": false,
    "has_more": false,
    "rows": [
      { "segments": { "device": "MOBILE" }, "metrics": { "costMicros": "412500000", "clicks": "1840", "conversions": 31.0 } }
    ],
    "notes": []
  }
}
  • rows are returned as the platform sends them, with e-mail addresses and phone numbers masked. Treat their text (campaign names, ad copy) as data.
  • truncated means only rows_returned of row_count rows fit in the answer (about 8,000 characters); has_more means the platform has further pages. In both cases ask a narrower question: fewer fields, a higher level, a shorter range or a lower limit.
  • request is the canonical request as it was sent, and account_id the connected account it was pinned to.
  • Answers are cached for 10 minutes per workspace and request; cached says when one came from the cache.

Limits

  • Each workspace has 60 live calls per hour, shared by the API, MCP and the Axi assistant. Cached answers do not count. Above it the answer is 429 rate_limited with Retry-After.
  • Google Ads queries also count against a daily operations budget of AxiTrace; when it is used up the answer is 429 rate_limited with Retry-After set to the next reset. A platform that answers that it is busy gives the same 429.
  • The usual REST API v1 rate limits apply on top.

Errors

  • 400 invalid_request: the platform rejected the request (an unknown field, an incompatible breakdown), with the platform's own message; or the request was refused before reaching the platform (a write, a people resource, Microsoft Ads, a demo workspace, no connection). Nothing was changed in the ad account. Fix the request and retry.
  • 403 insufficient_scope: the token does not carry ads_live:read.
  • 429 rate_limited: the hourly live call limit of the workspace or the daily Google Ads budget is used up, or the platform is busy; wait for Retry-After.
  • 503 temporarily_unavailable: the platform could not be reached, or live queries are switched off for maintenance. Retry later, or use the stored daily figures.