View as Markdown

v1 to v2 Migration

BDA v2 replaces the v1 report, segment, and data endpoints with one query endpoint. Instead of saving a custom report or segment first and pulling data from it afterwards, you describe the whole report — data set, date range, dimensions, metrics, filters, sorting — in a single POST /query request.

This page maps every v1 concept to its v2 equivalent. The complete v2 reference is the official API docs.

What Changed

v1 v2
Base URL https://api-gateway.ezoic.com/bdaservices/ https://api-gateway.ezoic.com/gateway/bdaservices/v2/
Authentication ?developerKey= query parameter X-API-Key header
Report definitions Saved server-side (predefined reports, custom reports, segments) Sent inline with every query
Field naming PascalCase (DomainId, StartDate) snake_case (domain_id, start_date)
Errors Mixed formats One JSON envelope with a machine-readable code and field-level details

Your existing API key works on both versions — no key changes are needed. v2 accepts the key only in the X-API-Key header; the ?developerKey= query parameter is rejected.

Endpoint Mapping

v1 endpoint v2 equivalent
GET getdomains/ GET /domains
GET getcolumns/ GET /columns — now includes each column's type, unit, description, and which data sets it belongs to.
POST getdata/ POST /query
POST getCustomData/ POST /query
GET getreports/, GET getreport/ None. Predefined reports are gone; send the equivalent query directly.
GET getcustomreports/, POST createcustomreport/ None. There are no saved reports; store your query definitions in your own code or config.
GET getsegments/, POST createsegment/ None. Segments are replaced by inline filters on POST /query.
GET getfilters/, GET getmultifilters/, GET getmultifiltertypes/ GET /columns — filter on any column directly; there is no separate filter catalog.
GET /data-sets (new): lists the queryable data sets.
GET /date-range (new): the earliest and latest dates with data.

Request Field Mapping

getdata and getCustomData requests translate to POST /query like this:

v1 field v2 field Notes
data_set New, required. Most v1 reports correspond to the pageview data set. Use GET /data-sets for the options.
StartDate / EndDate date_range.start_date / date_range.end_date Always required in v2 — there are no report-level default date ranges.
DimensionColumns dimensions A plain list of column names; drop the { "Data": ..., "Type": ... } wrappers.
MetricColumns metrics Same — a plain list of column names.
DateGrouping (DAILY / WEEKLY / MONTHLY) Group by a time dimension instead: report_day, report_week, or report_month.
SegmentIds filters Express the segment's conditions inline. See Segments Become Filters.
Filters filters Operations are lowercase words: GREATERgreater_than, GREATER_OR_EQUALgreater_than_or_equal, and so on.
Order (ColumnNumber) sort Sort by column name, not index: { "column": "revenue", "direction": "desc" }.
StartItem offset
MaxItems limit Defaults to 100, max 100,000.
DomainId domain_id Still optional; omit to query all your sites.
Platform (EZOIC / ORIG / ALL) platform (ezoic / original / all)
UrlParams / UrlFragments url_options.query_params / url_options.fragments Lowercase values include / exclude. v2 adds url_options.case_normalization.
RevenueDecimalPlaces v2 returns full-precision numbers; round client-side.

Before and After

A v1 getCustomData request:

POST /bdaservices/getCustomData/
{
  "StartItem": 0,
  "MaxItems": 10,
  "Platform": "ALL",
  "DomainId": 9999,
  "StartDate": "2026-07-24",
  "EndDate": "2026-07-30",
  "DimensionColumns": [{ "Data": "report_day", "Type": "string" }],
  "MetricColumns": [
    { "Data": "visits", "Type": "number" },
    { "Data": "revenue", "Type": "number" },
    { "Data": "epmv", "Type": "number" }
  ],
  "Order": { "ColumnNumber": 0, "Direction": "DESC" },
  "Filters": [
    { "Type": "INCLUDE", "FilterKey": "epmv", "OperationId": "GREATER", "FilterValue": "3" }
  ]
}

The same report in v2:

curl -X POST "https://api-gateway.ezoic.com/gateway/bdaservices/v2/query" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
  "data_set": "pageview",
  "date_range": { "start_date": "2026-07-24", "end_date": "2026-07-30" },
  "dimensions": ["report_day"],
  "metrics": ["visits", "revenue", "epmv"],
  "filters": [
    { "column": "epmv", "operator": "greater_than", "value": 3 }
  ],
  "sort": [{ "column": "report_day", "direction": "desc" }],
  "limit": 10,
  "offset": 0,
  "domain_id": 9999,
  "platform": "all"
}'
import requests

url = "https://api-gateway.ezoic.com/gateway/bdaservices/v2/query"
headers = {"X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json"}
payload = """{
  "data_set": "pageview",
  "date_range": { "start_date": "2026-07-24", "end_date": "2026-07-30" },
  "dimensions": ["report_day"],
  "metrics": ["visits", "revenue", "epmv"],
  "filters": [
    { "column": "epmv", "operator": "greater_than", "value": 3 }
  ],
  "sort": [{ "column": "report_day", "direction": "desc" }],
  "limit": 10,
  "offset": 0,
  "domain_id": 9999,
  "platform": "all"
}"""

response = requests.post(url, headers=headers, data=payload)
print(response.json())
<?php
$ch = curl_init("https://api-gateway.ezoic.com/gateway/bdaservices/v2/query");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-API-Key: YOUR_API_KEY", "Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
  "data_set": "pageview",
  "date_range": { "start_date": "2026-07-24", "end_date": "2026-07-30" },
  "dimensions": ["report_day"],
  "metrics": ["visits", "revenue", "epmv"],
  "filters": [
    { "column": "epmv", "operator": "greater_than", "value": 3 }
  ],
  "sort": [{ "column": "report_day", "direction": "desc" }],
  "limit": 10,
  "offset": 0,
  "domain_id": 9999,
  "platform": "all"
}');
$response = curl_exec($ch);
curl_close($ch);
echo $response;

The response is rows keyed by your requested columns, plus the total match count for pagination:

{
  "rows": [
    { "report_day": "2026-07-30", "visits": 1200, "revenue": 15.4321, "epmv": 12.8618 }
  ],
  "total_rows": 7
}

Segments Become Filters

In v1 you created a segment once with createsegment, then referenced its id in SegmentIds. In v2 the segment's conditions go straight into the query's filters. Every filter in the list must match; use an any_of group where matching any one condition is enough.

The v1 segment "epmv of 100 or more, from the US or Canada":

POST /bdaservices/createsegment/
{
  "SegmentName": "High EPMV US and Canada",
  "SegmentFilters": {
    "21": { "FilterIntOperationId": "GREATER_OR_EQUAL", "FilterValue": "100" }
  },
  "SegmentMultiFilters": {
    "1": { "FilterValues": ["US", "CA"] }
  }
}

becomes two inline filters in v2 — no ids, no separate create step:

"filters": [
  { "column": "epmv", "operator": "greater_than_or_equal", "value": 100 },
  { "column": "country", "operator": "in", "values": ["US", "CA"] }
]

You don't have to translate your existing segments by hand. In the BDA web UI, open the segment picker, click the three-dot menu next to a segment, and choose Copy for API — it copies the segment's conditions as a ready-to-paste v2 filters array:

Any column from GET /columns is filterable, so v1's filter, multifilter, and multifilter-type catalogs have no v2 counterpart.

Saved Custom Reports

v2 has no server-side saved reports. If your integration created reports with createcustomreport and pulled them by id, keep the query JSON wherever you keep configuration and send it with each request. Report-level default date ranges (like BASE_LAST_7) are gone too — compute the dates when you build the query.

Errors

Every v2 error uses the same envelope, with a machine-readable code (unauthorized, forbidden, not_found, validation_error, concurrent_request_limit, rate_limit_exceeded, upstream_error, internal_error) and, on validation errors, field-level details:

{
  "error": {
    "code": "validation_error",
    "message": "the query has 1 problem(s)",
    "details": [
      { "field": "metrics[0]", "message": "unknown column 'revanue'; did you mean 'revenue'?" }
    ]
  }
}