Batch API
The Batch API lets you execute multiple analytics queries in a single HTTP request. This is useful when building dashboards or reports that need data from several endpoints simultaneously.
Endpoint
POST /api/v1/batch
Request format
{
"queries": [
{
"id": "overview",
"endpoint": "/stats/overview",
"params": {
"account_id": "my-site",
"period": "30d"
}
},
{
"id": "pages",
"endpoint": "/stats/pages",
"params": {
"account_id": "my-site",
"period": "30d",
"page_size": 10
}
},
{
"id": "sources",
"endpoint": "/stats/sources",
"params": {
"account_id": "my-site",
"period": "30d"
},
"depends_on": ["overview"]
}
],
"options": {
"fail_fast": false,
"parallel_limit": 5,
"include_timing": true
}
}
Query fields
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique identifier for this query (alphanumeric) |
endpoint | string | Yes | Analytics endpoint path (must start with /stats/) |
params | object | Yes | Parameters for the endpoint |
depends_on | string[] | No | Query IDs that must complete before this one runs |
Options
| Option | Default | Description |
|---|---|---|
fail_fast | false | Stop execution on first error |
parallel_limit | 5 | Maximum concurrent queries (1-10) |
include_timing | true | Include execution time per query |
Multi-account timezone handling
Each query resolves date filters using its own account's timezone. So a batch containing one query for account_id=acme (Europe/Madrid) and another for account_id=partner (America/New_York) will interpret period=30d correctly for each site — no need to pre-resolve dates on your side or coerce all queries to UTC.
This is important when you're building a multi-site dashboard: the today / this_month / 30d presets each expand against the specific site they target, matching how the data is stored in ClickHouse (each hit is bucketed by the account's local date at ingest). See Date periods and account timezone for the full rule.
Supported endpoints
All /stats/ endpoints are available:
/stats/overview— Traffic overview/stats/pages— Pages report/stats/sources— Traffic sources/stats/mediums— UTM mediums/stats/campaigns— UTM campaigns/stats/terms— UTM terms/stats/referrers— Referrers/stats/geo/countries— Geographic data/stats/devices— Device types/stats/browsers— Browsers/stats/operating-systems— Operating systems/stats/conversions— Conversions/stats/microconversions— Microconversions/stats/funnel— Funnel analysis/stats/landing-pages— Landing pages/stats/channels— Channel groups
Response format
{
"batch_id": "uuid",
"status": "completed",
"results": {
"overview": {
"status": "success",
"data": { },
"timing_ms": 45
},
"pages": {
"status": "success",
"data": { },
"timing_ms": 32
},
"sources": {
"status": "success",
"data": { },
"timing_ms": 28
}
},
"meta": {
"total_queries": 3,
"successful": 3,
"failed": 0,
"skipped": 0,
"total_timing_ms": 105
}
}
Query statuses
| Status | Description |
|---|---|
success | Query completed successfully |
error | Query failed (see error field) |
skipped | Skipped because a dependency failed |
Validation endpoint
Validate your batch request without executing it:
POST /api/v1/batch/validate
Returns the planned execution order and parallel groups:
{
"valid": true,
"query_count": 3,
"execution_order": ["overview", "pages", "sources"],
"parallel_groups": [["overview", "pages"], ["sources"]]
}
Limits
- Maximum 50 queries per batch
- All query IDs must be unique
- Circular dependencies are not allowed
For agents: fan out without spending requests
A batch is one HTTP request and one rate-limit slot, no matter how many queries it carries. For an agent assembling a report, that turns a dozen round trips into one:
- Dry-run first.
POST /batch/validatereturns the execution order and the parallel groups without running anything, so you can check a generated plan before spending the request. - Express ordering, don't serialise.
depends_onlets the API run everything it can in parallel while still respecting your dependencies. - Cap concurrency with
parallel_limit(1–10) when you are querying many sites at once. - Read
timing_msper query (include_timing) to find the expensive part of a report. - Handle partial failure. With
fail_fast: falseyou get per-querystatus, so one bad query does not lose the whole batch. Dependants of a failed query come back asskipped.
Batch covers /stats/* endpoints. For configuration reads (sites, segments, alerts), issue normal requests.
Related
- For AI Agents — the full agent integration guide
- Multi-Dimensional Query — one query with several dimensions, as an alternative to several batched queries
- Rate Limits
- Error codes