Run query
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.
data:read · Rate limit: 30 / 60s500. Because of this, the route has a tight rate limit of 30 requests per 60 seconds (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
Request body
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.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.{ "fieldId": string, "direction": "asc" | "desc" }.{ "fieldId": string, "operator": string, "value": string }. operator is one of equals, notEquals, contains, notContains, greaterThan, lesserThan. value is always a string.accounts— use your enabled account IDs from List all accounts or List connector accounts with?status=enabled. Account IDs should include the connector prefix - see the full list on the Connectors reference.dimensions,metrics, and filter/sortfieldIds — browse every available field (and the shared common fields) in the Field Explorer.
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": ["cost", "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": ["cost", "clicks"],
"dateRange": "last_30_days"
}'
A single account over an explicit startDate–endDate window.
{
"accounts": ["gadw_1234567890"],
"dimensions": ["date", "campaign_name"],
"metrics": ["impressions", "cost"],
"dateRange": { "startDate": "2026-05-01", "endDate": "2026-05-31" }
}
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"],
"dimensions": ["date", "campaign_name"],
"metrics": ["impressions", "cost"],
"dateRange": { "startDate": "2026-05-01", "endDate": "2026-05-31" }
}'
Group by campaign, keep only campaigns whose name contains Brand, and sort by cost descending.
{
"accounts": ["gadw_1234567890", "fads_act_9876543210"],
"dimensions": ["campaign_name"],
"metrics": ["cost", "clicks", "conversions"],
"dateRange": "last_3_months",
"filters": [
{ "fieldId": "campaign_name", "operator": "contains", "value": "Brand" },
{ "fieldId": "cost", "operator": "greaterThan", "value": "100" }
],
"sort": [
{ "fieldId": "cost", "direction": "desc" }
]
}
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": ["cost", "clicks", "conversions"],
"dateRange": "last_3_months",
"filters": [
{ "fieldId": "campaign_name", "operator": "contains", "value": "Brand" },
{ "fieldId": "cost", "operator": "greaterThan", "value": "100" }
],
"sort": [
{ "fieldId": "cost", "direction": "desc" }
]
}'
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.
Rows for the "Filters & sort" example above.
{
"success": true,
"data": [
{ "campaign_name": "Brand - Search", "cost": 1820.45, "clicks": 5421, "conversions": 132 },
{ "campaign_name": "Brand - Display", "cost": 640.10, "clicks": 2210, "conversions": 38 },
{ "campaign_name": "Brand - Retargeting", "cost": 305.77, "clicks": 980, "conversions": 21 }
]
}
An account ID without a valid connector prefix (or an empty/oversized accounts array) is rejected.
{
"success": false,
"error": {
"code": "BAD_REQUEST",
"message": "accounts.0: Account ID must start with one of the following prefixes: ga, gadw, fads, ga4, ..."
}
}
The caller is authenticated but is not at least an editor on the team.
{
"success": false,
"error": { "code": "FORBIDDEN", "message": "You do not have permission to perform this action" }
}
Returned when the upstream query fails or does not finish within ~5 minutes. The message is generic.
{
"success": false,
"error": { "code": "INTERNAL_SERVER_ERROR", "message": "An unexpected error occurred" }
}