Two Minute Reports Logo
Data

Run query

Run a data query across accounts and connectors and return the aggregated result rows.
POST /teams/{teamId}/data/run-query

Runs a data query across one or more accounts and returns the aggregated rows. You specify the accounts to pull from, the dimensions to group by, the metrics to aggregate, a date range, and optional filters and sort. Accounts from different connectors can be combined in a single query.

Authentication: Bearer token (an API key) · Permission:data:read · Team permission:data.query · Rate limit: 15 / minute and 500 / hour

The key holder's role must include Query data over MCP and the API. Every standard role except Viewer includes it. The key holder must also have a seat in the team.

This endpoint is expensive and long-running. The query runs synchronously: the request blocks until the result is ready. At this time, a request that takes more than about 60 seconds can stop before the query finishes. You then get HTTP 504, and the response body is not JSON. Keep each query small: for many accounts or a long date range, split the query by account or by date range. Because queries are expensive, the route has a tight rate limit of 15 requests per minute and 500 per hour (lower than the default 120 / 60s). Set a generous client timeout, avoid sending queries in a tight loop, and don't retry a slow query until the previous one has returned.

Path parameters

teamId
string · uuid v7 required
The ID of the team that owns the accounts being queried.

Field IDs

There are two types of field ID:

  • Common fields work across connectors and have no prefix, for example date, campaign_name, impressions, clicks, conversions and amount_spent. For spend, use amount_spent. It maps to each ad connector's own spend field. There is no common cost field. Ad sets and ad groups use the same common fields: ad_group_id and ad_group_name.
  • Connector fields belong to one connector and start with its ID, for example ga4_sessions. GA4 sessions and new users are connector fields: ga4_sessions, ga4_new_users.

List connector fields returns connector field IDs without the prefix. Add <connectorId>_ before you use them here. For example, adset_id from fads becomes fads_adset_id.

The API checks every field ID in dimensions, metrics, filters and sort before the query runs. An unknown ID gives a 400 error that lists each unknown ID. If you send a connector field without its prefix, the error message shows the correct ID.

To find field IDs, use the field explorer.

Request body

accounts
string[] required
The accounts to query, 1–100 entries. Each account ID is prefixed with its connector ID followed by an underscore (for example gadw_1234567890 for a Google Ads account). Accounts from different connectors can be mixed in one query. An ID that does not start with a known connector prefix is rejected.
dimensions
string[]
Field IDs to group rows by. Up to 50. Omit for a single, fully-aggregated row.
metrics
string[]
Field IDs to aggregate. Up to 50.
dateRange
string | object
The reporting window. Either a preset string or a custom object. Defaults to last_7_days when omitted.Presets:today, yesterday, last_7_days, last_30_days, this_month, last_month, last_3_months, last_6_months, last_year, this_year.Custom object:{ "startDate": "YYYY-MM-DD", "endDate": "YYYY-MM-DD" }. Both dates are required and must be in YYYY-MM-DD format.
sort
object[]
Sort order, up to 20 entries. Each entry is { "fieldId": string, "direction": "asc" | "desc" }.
filters
object[]
Filters to apply, up to 50 entries. Each entry is { "fieldId": string, "operator": string, "value": string }. operator is one of equals, notEquals, contains, notContains, greaterThan, lesserThan. value is always a string.
dataOptions
object
Options that change the returned rows. All keys are optional. An unknown key gives a 400 error.
  • blankValuesToZero (boolean): returns every requested field on every row. A blank metric becomes 0 and a blank dimension becomes null. Default false: a blank field is not in the row.
  • includeDataWithoutInsights (boolean): Facebook Ads and GA4 only. Default false.
    • Facebook Ads: also returns campaigns, ad sets and ads that have no data in the date range. This can return many rows.
    • GA4: also returns rows where every metric is zero.
  • currency (string): a 3-letter ISO 4217 code, for example USD. Converts currency metrics to this currency on connectors that support conversion. Default: the currency of each account.
connectorReportOptions
object
Report settings for one connector, keyed by connector ID. All keys are optional. Omit a key to use the settings of each account. You can only set a connector that has accounts in accounts. An unknown key or an unknown attribution window gives a 400 error that lists the valid values.
  • fads (Facebook Ads):
    • conversionWindow (string): attribution windows, for example ["7c", "1v"]. Values: default, incrementality, 1d_ev, 1c, 1v, 7c, 28c, 1c1v, 7c1v, 28c1v. Default ["default"]: the attribution setting of the ad account.
    • reportTimeOfStats (string): impression or conversion. Sets the date that a conversion is reported on. Default: the Meta API default.
    • useUnifiedAttributionSetting (boolean): uses the unified attribution setting of the ad account. Default false.
    • useAccountAttributionSetting (boolean): uses the default attribution setting of the ad account. Default false.
    • includeAllItems (boolean): does not filter by status. Includes active, paused, archived and deleted campaigns, ad sets and ads. Default false: the API sends no status filter, and Meta applies its default.
  • pinads (Pinterest Ads):
    • conversionWindow (string, one window). Each ID gives the click, engagement and view days: c30_e7_v1 is 30-day click, 7-day engagement and 1-day view. Values: default, c60_e60_v60, c60_e60_v30, c60_e60_v7, c60_e60_v1, c60_e30_v30, c60_e30_v7, c60_e30_v1, c60_e7_v7, c60_e7_v1, c60_e1_v1, c30_e30_v30, c30_e30_v7, c30_e30_v1, c30_e7_v7, c30_e7_v1, c30_e1_v1, c7_e7_v7, c7_e7_v1, c7_e1_v1, c1_e1_v1. Default default: 30-day click, 30-day engagement and 1-day view.
    • reportTimeOfStats (string): default or time_of_conversion.
  • snapads (Snapchat Ads): conversionWindow (string, one window). Each ID gives the view and swipe windows: 1dv_28ds is 1-day view and 28-day swipe. Values: 1hv_1ds, 1hv_7ds, 1hv_28ds, 3hv_1ds, 3hv_7ds, 3hv_28ds, 6hv_1ds, 6hv_7ds, 6hv_28ds, 1dv_1ds, 1dv_7ds, 1dv_28ds, 7dv_7ds, 7dv_28ds, 28dv_28ds. Default 1dv_28ds.
  • chatgptads (ChatGPT Ads): conversionWindow (string). Values: 30c1v, 14c1v, 7c1v, 30c, 14c, 7c. Default ["30c1v"]: 30-day click and 1-day view.
  • klaviyo (Klaviyo): isKlaviyoAttributedValuesOnly (boolean). Returns only values that Klaviyo campaigns and flows caused.
Not sure what to put in a query? Look these up first:

Request examples

Two accounts, grouped by campaign, with spend and clicks over the last 30 days.

{
  "accounts": ["gadw_1234567890", "fads_act_9876543210"],
  "dimensions": ["campaign_name"],
  "metrics": ["amount_spent", "clicks"],
  "dateRange": "last_30_days"
}
curl -X POST https://api.twominutereports.com/v1/teams/0190f8b0-1a2b-7c3d-8e4f-5a6b7c8d9e0f/data/run-query \
  -H "Authorization: Bearer tmrc_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "accounts": ["gadw_1234567890", "fads_act_9876543210"],
    "dimensions": ["campaign_name"],
    "metrics": ["amount_spent", "clicks"],
    "dateRange": "last_30_days"
  }'

Response

On success, data is an array of row objects. Each key is a requested field ID and each value is the cell value (a string or number). The set of keys matches the dimensions and metrics you requested. A field with a blank value is not in the row. To get every field on every row, set dataOptions.blankValuesToZero to true.

All rows are in one response. There is no pagination and no row limit. The limit in practice is time: a query that runs too long stops (see the warning at the top of this page). For many accounts or a long date range, split the query by account or by date range.

account_id contains the account ID without the connector prefix, for example 9876543210. To identify the connector of each row, also request data_source. It contains the connector name, for example Facebook Ads.

Rows for the "Filters and sort" example above.

{
  "success": true,
  "data": [
    { "campaign_name": "Brand - Search", "amount_spent": 1820.45, "clicks": 5421, "conversions": 132 },
    { "campaign_name": "Brand - Display", "amount_spent": 640.10, "clicks": 2210, "conversions": 38 },
    { "campaign_name": "Brand - Retargeting", "amount_spent": 305.77, "clicks": 980, "conversions": 21 }
  ]
}
Copyright © 2026