# Overview reports

> The API operations about overview reports, each with its input, its output and an example.

The operations about overview reports. Each one is a `POST` with a JSON object as its body: [Making a request](/docs/api#start) has the rules they share.

## Filtered bot traffic

`POST /api/v1/overview.bots` · Read

How many requests to one site were recognised as automated and left out of every other number, by reason (crawlers, scripts, automated browsers, referrer spam, datacenter networks and so on), next to the requests that were recorded. Get the siteId from sites.list first. These are requests, not visitors, and they are counted per whole UTC hour, so the period is widened to whole hours; the answer says which in hours. It takes no filters, because a filtered request has nothing to filter by, and it has no comparison: compare, cfrom and cto are accepted and ignored. share and shareOfRequests are fractions from 0 to 1 of filtered plus recorded requests. Answers 402 workspace_locked while the workspace's dashboards are locked.

Needs a token with the Read permission. Answers 402 while the dashboards of the workspace are locked.

### Input

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `siteId` | string | required | The site id, from sites.list. |
| `range` | "today" \| "yesterday" \| "30m" \| "12h" \| "24h" \| "week" \| "7d" \| "30d" \| "60d" \| "90d" \| "mtd" \| "ytd" \| "12mo" \| "all" \| "custom" | optional | The period to report on: one of today, yesterday, 30m, 12h, 24h, week, 7d, 30d, 60d, 90d, mtd, ytd, 12mo, all. Left out, the workspace's default range is used (30d unless it was changed). For exact dates send from and to and leave range out (custom is accepted with them and means the same). A preset together with dates answers 400. |
| `from` | string | optional | First day of a custom period, YYYY-MM-DD in the site's time zone. Send it together with to: one without the other answers 400, and so does a day that does not exist or a from after to. A day after today is read as today; window in the answer shows the period that was used. |
| `to` | string | optional | Last day of a custom period, inclusive, YYYY-MM-DD in the site's time zone. Send it together with from. |
| `compare` | "prev" \| "week" \| "month" \| "quarter" \| "year" \| "custom" \| "off" | optional | Accepted and ignored: this report has no comparison. |
| `cfrom` | string | optional | Accepted and ignored: this report has no comparison. |
| `cto` | string | optional | Accepted and ignored: this report has no comparison. |

### Output

| Field | Type | Present | Description |
| --- | --- | --- | --- |
| `serverNow` | number | always | The clock the period was resolved with: the start of the next whole minute, milliseconds since 1970 UTC. |
| `serverTime` | number | always | When the answer was built, milliseconds since 1970 UTC. |
| `hours` | object | always | The period that was counted, widened to whole UTC hours: from and to in milliseconds since 1970 UTC, to exclusive. |
| `filtered` | number | always | Requests that were recognised as automated and not recorded. |
| `accepted` | number | always | Requests that were recorded as hits in the same hours. |
| `share` | number \| null | always | filtered divided by filtered plus accepted, a fraction from 0 to 1. Null when there was no request at all. |
| `rows` | array of object | always | One row per reason a request was filtered out, only reasons with hits. reason is the key, label its readable name, hits the number of requests and shareOfRequests their part of filtered plus accepted. |

### Example

**curl**

```bash
curl -s -X POST https://clearsaga.com/api/v1/overview.bots \
  -H "Authorization: Bearer $CLEARSAGA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"siteId":"site_abc123def456"}'
```

**CLI**

```bash
clearsaga overview bots --input '{"siteId":"site_abc123def456"}'
```

**MCP**

```text
Tool: overview_bots
Arguments: {"siteId":"site_abc123def456"}
```

Run `clearsaga help overview bots` for one flag per field.

## Breakdown by dimension

`POST /api/v1/overview.breakdown` · Read

One breakdown list of a site for a period: the top values of a dimension with their visitors, visits, share and credited revenue. dimension is one of page, entry_page, exit_page, referrer, channel, ai_tool, hostname, country, region, city, browser, os, device. Get the siteId from sites.list first. It pages by offset: limit rows (8 unless set, 100 at most) starting at offset, and totalRows is the number of rows there are. Only the first 1000 rows can be reached, so offset plus limit may not be more than 1000 (400 otherwise). Rows are sorted by visitors, most first, unless sort and dir say otherwise; search keeps the rows whose label contains the text. share is the row's visitors divided by scopeVisitors, a fraction from 0 to 1. On page and hostname dimensions one visitor can be in several rows, so shares add up to more than 1. Visits without a value are left out of referrer, ai_tool, region and city (omittedVisitors counts their visitors) and are one row with an empty key elsewhere. revenue is the revenue credited to the row in minor units (cents), or null; exit_page never has any. The key of a row is the value the matching filter takes when filterable is true. Every filter applies; with a conversion filter each row also carries baseVisitors and conversionRate. The comparison is not used. Answers 402 workspace_locked while the workspace's dashboards are locked.

Needs a token with the Read permission. Answers 402 while the dashboards of the workspace are locked.

### Input

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `siteId` | string | required | The site id, from sites.list. |
| `range` | "today" \| "yesterday" \| "30m" \| "12h" \| "24h" \| "week" \| "7d" \| "30d" \| "60d" \| "90d" \| "mtd" \| "ytd" \| "12mo" \| "all" \| "custom" | optional | The period to report on: one of today, yesterday, 30m, 12h, 24h, week, 7d, 30d, 60d, 90d, mtd, ytd, 12mo, all. Left out, the workspace's default range is used (30d unless it was changed). For exact dates send from and to and leave range out (custom is accepted with them and means the same). A preset together with dates answers 400. |
| `from` | string | optional | First day of a custom period, YYYY-MM-DD in the site's time zone. Send it together with to: one without the other answers 400, and so does a day that does not exist or a from after to. A day after today is read as today; window in the answer shows the period that was used. |
| `to` | string | optional | Last day of a custom period, inclusive, YYYY-MM-DD in the site's time zone. Send it together with from. |
| `compare` | "prev" \| "week" \| "month" \| "quarter" \| "year" \| "custom" \| "off" | optional | What the period is compared with: prev (the period just before, the default), week, month, quarter or year earlier, custom (cfrom and cto are then required), or off for no comparison. The range all never has a comparison. |
| `cfrom` | string | optional | First day of a custom comparison period, YYYY-MM-DD. Required with compare set to custom, where a day that does not exist or a cfrom after cto answers 400. |
| `cto` | string | optional | Last day of a custom comparison period, inclusive, YYYY-MM-DD. Required with compare set to custom. |
| `filters` | object | optional | Narrow the numbers to matching traffic. An object such as { "country": "us", "path.has": "pricing" }. A plain key means "is"; a key ending in .not means "is not" and a key ending in .has means "contains". Filters are joined with AND. At most 10 keys, of which at most 3 may end in .has. Default: `{}`. [The filter keys are listed under Filters.](/docs/api#filters) |
| `dimension` | "page" \| "entry_page" \| "exit_page" \| "referrer" \| "channel" \| "ai_tool" \| "hostname" \| "country" \| "region" \| "city" \| "browser" \| "os" \| "device" | required | What to group by: page, entry_page (first page of a visit), exit_page (last page), referrer (referring site), channel, ai_tool, hostname, country, region, city, browser, os or device. |
| `limit` | integer, 1 to 100 | optional | Rows per page, 1 to 100. 8 when left out. |
| `offset` | integer, 0 to 1000 | optional | Rows to skip, 0 to 1000. offset plus limit may not be more than 1000. |
| `search` | string, 1 to 100 characters | optional | Keep only rows whose label contains this text, ignoring case. 1 to 100 characters. |
| `sort` | "visitors" \| "visits" \| "views" \| "revenue" \| "label" | optional | What to order the rows by: visitors (the default), visits, views, revenue or label. views works for page and hostname, and revenue only for a dimension that is credited with revenue on a site with orders; otherwise the rows are ordered by visitors. |
| `dir` | "asc" \| "desc" | optional | asc or desc. Left out: desc, or asc when sorting by label. |

### Output

| Field | Type | Present | Description |
| --- | --- | --- | --- |
| `serverNow` | number | always | The clock the period was resolved with: the start of the next whole minute, milliseconds since 1970 UTC. |
| `serverTime` | number | always | When the answer was built, milliseconds since 1970 UTC. |
| `window` | object | always | The period the numbers cover: from and to in milliseconds since 1970 UTC (to is exclusive), the time zone, a label and the bucket size. |
| `compare` | object \| null | always | The comparison period in the same form, or null when there is none. |
| `rawFrom` | number \| null | always | The earliest time detailed data is kept from, or null when nothing was trimmed. |
| `truncated` | boolean | always | True when a filtered answer could only cover the part of the period that still has detailed data. |
| `dimension` | "page" \| "entry_page" \| "exit_page" \| "referrer" \| "channel" \| "ai_tool" \| "hostname" \| "country" \| "region" \| "city" \| "browser" \| "os" \| "device" | always | The dimension that was asked for. |
| `totalRows` | number | always | The number of rows after the search, before the page was cut. Page with limit and offset until offset reaches it; only the first 1,000 rows can be reached. |
| `scopeVisitors` | number | always | The visitors of the whole period with the filters applied. share of each row is measured against it. |
| `tabVisitors` | number | always | The distinct visitors behind all rows of this dimension, whatever the search. |
| `omittedVisitors` | number | always | Visitors of visits the dimension leaves out for having no value: no referrer, no AI tool, no known region or city. |
| `rows` | array of object | always | One row per value. key is the value a filter of this dimension takes (only when filterable is true) and label is its readable name. visitors and visits are counts; views is there for the page and hostname dimensions. share is visitors divided by scopeVisitors, a fraction from 0 to 1; on dimensions where one visitor can be in several rows the shares add up to more than 1. revenue is the revenue credited to the row as { minor, currency } in minor units (cents), or null when nothing was credited. parents names the country and region of a region or city row. With a conversion filter, baseVisitors is the row's visitors without that filter and conversionRate the share of them who converted. href is a link to the page or site, and icon is the key of the icon the dashboard draws. |

### Example

**curl**

```bash
curl -s -X POST https://clearsaga.com/api/v1/overview.breakdown \
  -H "Authorization: Bearer $CLEARSAGA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"siteId":"site_abc123def456","dimension":"page"}'
```

**CLI**

```bash
clearsaga overview breakdown --input '{"siteId":"site_abc123def456","dimension":"page"}'
```

**MCP**

```text
Tool: overview_breakdown
Arguments: {"siteId":"site_abc123def456","dimension":"page"}
```

Run `clearsaga help overview breakdown` for one flag per field.

## Conversions by hour

`POST /api/v1/overview.conversionPeak` · Read

When conversions happen: a grid of 7 weekdays by 24 hours in the site's time zone with the number of conversions in each cell, and their total. Row 0 is Monday. Get the siteId from sites.list first. A conversion is a completion of an enabled conversion goal (mode goals). A site without an enabled goal counts every custom event instead (mode events). With a conversion filter only the completions of that goal are counted. The other filters apply as everywhere. There is no comparison: compare, cfrom and cto change nothing in the numbers. Answers 402 workspace_locked while the workspace's dashboards are locked.

Needs a token with the Read permission. Answers 402 while the dashboards of the workspace are locked.

### Input

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `siteId` | string | required | The site id, from sites.list. |
| `range` | "today" \| "yesterday" \| "30m" \| "12h" \| "24h" \| "week" \| "7d" \| "30d" \| "60d" \| "90d" \| "mtd" \| "ytd" \| "12mo" \| "all" \| "custom" | optional | The period to report on: one of today, yesterday, 30m, 12h, 24h, week, 7d, 30d, 60d, 90d, mtd, ytd, 12mo, all. Left out, the workspace's default range is used (30d unless it was changed). For exact dates send from and to and leave range out (custom is accepted with them and means the same). A preset together with dates answers 400. |
| `from` | string | optional | First day of a custom period, YYYY-MM-DD in the site's time zone. Send it together with to: one without the other answers 400, and so does a day that does not exist or a from after to. A day after today is read as today; window in the answer shows the period that was used. |
| `to` | string | optional | Last day of a custom period, inclusive, YYYY-MM-DD in the site's time zone. Send it together with from. |
| `compare` | "prev" \| "week" \| "month" \| "quarter" \| "year" \| "custom" \| "off" | optional | What the period is compared with: prev (the period just before, the default), week, month, quarter or year earlier, custom (cfrom and cto are then required), or off for no comparison. The range all never has a comparison. |
| `cfrom` | string | optional | First day of a custom comparison period, YYYY-MM-DD. Required with compare set to custom, where a day that does not exist or a cfrom after cto answers 400. |
| `cto` | string | optional | Last day of a custom comparison period, inclusive, YYYY-MM-DD. Required with compare set to custom. |
| `filters` | object | optional | Narrow the numbers to matching traffic. An object such as { "country": "us", "path.has": "pricing" }. A plain key means "is"; a key ending in .not means "is not" and a key ending in .has means "contains". Filters are joined with AND. At most 10 keys, of which at most 3 may end in .has. Default: `{}`. [The filter keys are listed under Filters.](/docs/api#filters) |

### Output

| Field | Type | Present | Description |
| --- | --- | --- | --- |
| `serverNow` | number | always | The clock the period was resolved with: the start of the next whole minute, milliseconds since 1970 UTC. |
| `serverTime` | number | always | When the answer was built, milliseconds since 1970 UTC. |
| `window` | object | always | The period the numbers cover: from and to in milliseconds since 1970 UTC (to is exclusive), the time zone, a label and the bucket size. |
| `compare` | object \| null | always | The comparison period in the same form, or null when there is none. |
| `rawFrom` | number \| null | always | The earliest time detailed data is kept from, or null when nothing was trimmed. |
| `truncated` | boolean | always | True when a filtered answer could only cover the part of the period that still has detailed data. |
| `total` | number | always | All conversions of the period: the sum of the matrix. |
| `matrix` | array of array of number | always | Seven rows of 24 numbers: conversions per weekday and hour in the site's time zone. Row 0 is Monday and column 0 is the hour from midnight to one. |
| `mode` | "goals" \| "events" | always | What was counted. goals: completions of the enabled conversion goals. events: every custom event, because the site has no enabled goal. |

### Example

**curl**

```bash
curl -s -X POST https://clearsaga.com/api/v1/overview.conversionPeak \
  -H "Authorization: Bearer $CLEARSAGA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"siteId":"site_abc123def456"}'
```

**CLI**

```bash
clearsaga overview conversionPeak --input '{"siteId":"site_abc123def456"}'
```

**MCP**

```text
Tool: overview_conversion_peak
Arguments: {"siteId":"site_abc123def456"}
```

Run `clearsaga help overview conversionPeak` for one flag per field.

## Headline numbers

`POST /api/v1/overview.kpis` · Read

The headline numbers of one site for a period: visitors, visits, page views, bounce rate, average session time, conversion rate, revenue and revenue per visitor. It answers the same numbers for the comparison period (previous) and the change between the two (delta). Get the siteId from sites.list first. A visitor is counted once per day, so visitors over several days is the sum of the daily counts. Rates are fractions from 0 to 1 and session time is in seconds. Money is in minor units (cents) of revenue.currency; amounts in other currencies are listed in revenue.otherCurrencies and never added in. conversionRate is the share of visitors who completed any enabled conversion goal on the day of their visit; it is null when the site has no enabled goal. revenue and revenuePerVisitor are null when the site never recorded an order. Without filters revenue is net of refunds; with filters it is the gross revenue credited to the matching visits. With a conversion filter, visitors are the visitors who completed that goal and conversion gives their share of all visitors. previous and delta are null when compare is off or the range is all. Answers 402 workspace_locked while the workspace's dashboards are locked.

Needs a token with the Read permission. Answers 402 while the dashboards of the workspace are locked.

### Input

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `siteId` | string | required | The site id, from sites.list. |
| `range` | "today" \| "yesterday" \| "30m" \| "12h" \| "24h" \| "week" \| "7d" \| "30d" \| "60d" \| "90d" \| "mtd" \| "ytd" \| "12mo" \| "all" \| "custom" | optional | The period to report on: one of today, yesterday, 30m, 12h, 24h, week, 7d, 30d, 60d, 90d, mtd, ytd, 12mo, all. Left out, the workspace's default range is used (30d unless it was changed). For exact dates send from and to and leave range out (custom is accepted with them and means the same). A preset together with dates answers 400. |
| `from` | string | optional | First day of a custom period, YYYY-MM-DD in the site's time zone. Send it together with to: one without the other answers 400, and so does a day that does not exist or a from after to. A day after today is read as today; window in the answer shows the period that was used. |
| `to` | string | optional | Last day of a custom period, inclusive, YYYY-MM-DD in the site's time zone. Send it together with from. |
| `compare` | "prev" \| "week" \| "month" \| "quarter" \| "year" \| "custom" \| "off" | optional | What the period is compared with: prev (the period just before, the default), week, month, quarter or year earlier, custom (cfrom and cto are then required), or off for no comparison. The range all never has a comparison. |
| `cfrom` | string | optional | First day of a custom comparison period, YYYY-MM-DD. Required with compare set to custom, where a day that does not exist or a cfrom after cto answers 400. |
| `cto` | string | optional | Last day of a custom comparison period, inclusive, YYYY-MM-DD. Required with compare set to custom. |
| `filters` | object | optional | Narrow the numbers to matching traffic. An object such as { "country": "us", "path.has": "pricing" }. A plain key means "is"; a key ending in .not means "is not" and a key ending in .has means "contains". Filters are joined with AND. At most 10 keys, of which at most 3 may end in .has. Default: `{}`. [The filter keys are listed under Filters.](/docs/api#filters) |

### Output

| Field | Type | Present | Description |
| --- | --- | --- | --- |
| `serverNow` | number | always | The clock the period was resolved with: the start of the next whole minute, milliseconds since 1970 UTC. |
| `serverTime` | number | always | When the answer was built, milliseconds since 1970 UTC. |
| `window` | object | always | The period the numbers cover: from and to in milliseconds since 1970 UTC (to is exclusive), the time zone, a label and the bucket size. |
| `compare` | object \| null | always | The comparison period in the same form, or null when there is none. |
| `rawFrom` | number \| null | always | The earliest time detailed data is kept from, or null when nothing was trimmed. |
| `truncated` | boolean | always | True when a filtered answer could only cover the part of the period that still has detailed data. |
| `current` | object | always | The totals of the period. visitors, visits and views are counts. bounceRate and conversionRate are fractions from 0 to 1. sessionTimeSec is seconds. goalConverters is the number of visitors who completed any enabled conversion goal. revenue is the revenue tile (amounts in minor units of revenue.currency) or null when the site never had an order. revenuePerVisitor is revenue.netMinor divided by visitors, in the same minor units, or null when revenue is null. conversion is only present with a conversion filter. |
| `previous` | object \| null | always | The same totals for the comparison period, or null when there is no comparison. |
| `delta` | object \| null | always | The change from previous to current as a fraction (0.25 means up 25 percent), per number. A value is null when there is nothing to compare with. The whole field is null without a comparison. |
| `filterLabels` | object | always | A readable name for the value of each filter that has one, for example the country name for a country code. |

### Example

**curl**

```bash
curl -s -X POST https://clearsaga.com/api/v1/overview.kpis \
  -H "Authorization: Bearer $CLEARSAGA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"siteId":"site_abc123def456"}'
```

**CLI**

```bash
clearsaga overview kpis --input '{"siteId":"site_abc123def456"}'
```

**MCP**

```text
Tool: overview_kpis
Arguments: {"siteId":"site_abc123def456"}
```

Run `clearsaga help overview kpis` for one flag per field.

## Pages not found

`POST /api/v1/overview.missingPages` · Read

The paths of one site that answered "not found" in a period, most hits first, each with the page that most often linked to it. Get the siteId from sites.list first. A site only has these when its tracker reports missing pages; sites.get says so in has404Tracking. It pages by offset: limit rows (8 unless set, 100 at most) starting at offset, and totalRows is the number of paths there are; offset plus limit may not be more than 1000. search keeps the paths that contain the text. A hit on a missing page is not a page view, so the path, event, prop and conversion filters are ignored here; the hostname filter and the filters about the visit (source, place, device, campaign tags) apply. The comparison is not used. Answers 402 workspace_locked while the workspace's dashboards are locked.

Needs a token with the Read permission. Answers 402 while the dashboards of the workspace are locked.

### Input

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `siteId` | string | required | The site id, from sites.list. |
| `range` | "today" \| "yesterday" \| "30m" \| "12h" \| "24h" \| "week" \| "7d" \| "30d" \| "60d" \| "90d" \| "mtd" \| "ytd" \| "12mo" \| "all" \| "custom" | optional | The period to report on: one of today, yesterday, 30m, 12h, 24h, week, 7d, 30d, 60d, 90d, mtd, ytd, 12mo, all. Left out, the workspace's default range is used (30d unless it was changed). For exact dates send from and to and leave range out (custom is accepted with them and means the same). A preset together with dates answers 400. |
| `from` | string | optional | First day of a custom period, YYYY-MM-DD in the site's time zone. Send it together with to: one without the other answers 400, and so does a day that does not exist or a from after to. A day after today is read as today; window in the answer shows the period that was used. |
| `to` | string | optional | Last day of a custom period, inclusive, YYYY-MM-DD in the site's time zone. Send it together with from. |
| `compare` | "prev" \| "week" \| "month" \| "quarter" \| "year" \| "custom" \| "off" | optional | What the period is compared with: prev (the period just before, the default), week, month, quarter or year earlier, custom (cfrom and cto are then required), or off for no comparison. The range all never has a comparison. |
| `cfrom` | string | optional | First day of a custom comparison period, YYYY-MM-DD. Required with compare set to custom, where a day that does not exist or a cfrom after cto answers 400. |
| `cto` | string | optional | Last day of a custom comparison period, inclusive, YYYY-MM-DD. Required with compare set to custom. |
| `filters` | object | optional | Narrow the numbers to matching traffic. An object such as { "country": "us", "path.has": "pricing" }. A plain key means "is"; a key ending in .not means "is not" and a key ending in .has means "contains". Filters are joined with AND. At most 10 keys, of which at most 3 may end in .has. Default: `{}`. [The filter keys are listed under Filters.](/docs/api#filters) |
| `limit` | integer, 1 to 100 | optional | Rows per page, 1 to 100. 8 when left out. |
| `offset` | integer, 0 to 1000 | optional | Rows to skip, 0 to 1000. offset plus limit may not be more than 1000. |
| `search` | string, 1 to 100 characters | optional | Keep only paths that contain this text, ignoring case. 1 to 100 characters. |

### Output

| Field | Type | Present | Description |
| --- | --- | --- | --- |
| `serverNow` | number | always | The clock the period was resolved with: the start of the next whole minute, milliseconds since 1970 UTC. |
| `serverTime` | number | always | When the answer was built, milliseconds since 1970 UTC. |
| `window` | object | always | The period the numbers cover: from and to in milliseconds since 1970 UTC (to is exclusive), the time zone, a label and the bucket size. |
| `compare` | object \| null | always | The comparison period in the same form, or null when there is none. |
| `rawFrom` | number \| null | always | The earliest time detailed data is kept from, or null when nothing was trimmed. |
| `truncated` | boolean | always | True when a filtered answer could only cover the part of the period that still has detailed data. |
| `totalRows` | number | always | The number of paths that match the search. Page with limit and offset until offset reaches it. |
| `totalHits` | number | always | All "not found" hits on those paths in the period. |
| `rows` | array of object | always | One row per path that answered "not found", most hits first. topFrom is the page that most often linked to it (null when none is known), topFromHits how often it did, and fromCount the number of distinct pages that did. |

### Example

**curl**

```bash
curl -s -X POST https://clearsaga.com/api/v1/overview.missingPages \
  -H "Authorization: Bearer $CLEARSAGA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"siteId":"site_abc123def456"}'
```

**CLI**

```bash
clearsaga overview missingPages --input '{"siteId":"site_abc123def456"}'
```

**MCP**

```text
Tool: overview_missing_pages
Arguments: {"siteId":"site_abc123def456"}
```

Run `clearsaga help overview missingPages` for one flag per field.

## Traffic over time

`POST /api/v1/overview.timeseries` · Read

The main chart of one site: visitors, visits, page views, bounce rate, session time, revenue, orders and goal converters per bucket of the period, and the same for the comparison period. Get the siteId from sites.list first. The bucket size follows the period and is named in window.granularity: minutes for 30m, hours up to two days, days up to about three months, then weeks or months. compareBuckets lines up with buckets by position, not by time, and is null when compare is off or the range is all. A visitor who is active in two buckets is counted in both, so with buckets shorter than a day the visitors of the buckets add up to more than the visitors of overview.kpis. Rates are fractions from 0 to 1 and session time is in seconds. revenue per bucket is in minor units (cents) of the currency overview.kpis names: the money taken in the bucket without filters, the revenue credited to the matching visits with them, and null when the site never had an order. Every filter applies. Answers 402 workspace_locked while the workspace's dashboards are locked.

Needs a token with the Read permission. Answers 402 while the dashboards of the workspace are locked.

### Input

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `siteId` | string | required | The site id, from sites.list. |
| `range` | "today" \| "yesterday" \| "30m" \| "12h" \| "24h" \| "week" \| "7d" \| "30d" \| "60d" \| "90d" \| "mtd" \| "ytd" \| "12mo" \| "all" \| "custom" | optional | The period to report on: one of today, yesterday, 30m, 12h, 24h, week, 7d, 30d, 60d, 90d, mtd, ytd, 12mo, all. Left out, the workspace's default range is used (30d unless it was changed). For exact dates send from and to and leave range out (custom is accepted with them and means the same). A preset together with dates answers 400. |
| `from` | string | optional | First day of a custom period, YYYY-MM-DD in the site's time zone. Send it together with to: one without the other answers 400, and so does a day that does not exist or a from after to. A day after today is read as today; window in the answer shows the period that was used. |
| `to` | string | optional | Last day of a custom period, inclusive, YYYY-MM-DD in the site's time zone. Send it together with from. |
| `compare` | "prev" \| "week" \| "month" \| "quarter" \| "year" \| "custom" \| "off" | optional | What the period is compared with: prev (the period just before, the default), week, month, quarter or year earlier, custom (cfrom and cto are then required), or off for no comparison. The range all never has a comparison. |
| `cfrom` | string | optional | First day of a custom comparison period, YYYY-MM-DD. Required with compare set to custom, where a day that does not exist or a cfrom after cto answers 400. |
| `cto` | string | optional | Last day of a custom comparison period, inclusive, YYYY-MM-DD. Required with compare set to custom. |
| `filters` | object | optional | Narrow the numbers to matching traffic. An object such as { "country": "us", "path.has": "pricing" }. A plain key means "is"; a key ending in .not means "is not" and a key ending in .has means "contains". Filters are joined with AND. At most 10 keys, of which at most 3 may end in .has. Default: `{}`. [The filter keys are listed under Filters.](/docs/api#filters) |

### Output

| Field | Type | Present | Description |
| --- | --- | --- | --- |
| `serverNow` | number | always | The clock the period was resolved with: the start of the next whole minute, milliseconds since 1970 UTC. |
| `serverTime` | number | always | When the answer was built, milliseconds since 1970 UTC. |
| `window` | object | always | The period the numbers cover: from and to in milliseconds since 1970 UTC (to is exclusive), the time zone, a label and the bucket size. |
| `compare` | object \| null | always | The comparison period in the same form, or null when there is none. |
| `rawFrom` | number \| null | always | The earliest time detailed data is kept from, or null when nothing was trimmed. |
| `truncated` | boolean | always | True when a filtered answer could only cover the part of the period that still has detailed data. |
| `buckets` | array of object | always | One point per bucket of the period, oldest first. The bucket size is window.granularity. start and end are the edges of the bucket in milliseconds since 1970 UTC (end is exclusive) and partial is true while the bucket is still running. visitors, visits and views are counts, bounceRate is a fraction from 0 to 1 and sessionTimeSec is seconds, both null when no visit viewed a page. revenue is the money taken in the bucket in minor units (cents) of the currency overview.kpis names, null when the site never had an order, and orders is the number of orders. goalConverters is the number of visitors of the bucket who completed any enabled conversion goal. |
| `compareBuckets` | array of object \| null | always | The same points for the comparison period over its own buckets, oldest first, or null when there is no comparison. Line the two lists up by position, not by time. |

### Example

**curl**

```bash
curl -s -X POST https://clearsaga.com/api/v1/overview.timeseries \
  -H "Authorization: Bearer $CLEARSAGA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"siteId":"site_abc123def456"}'
```

**CLI**

```bash
clearsaga overview timeseries --input '{"siteId":"site_abc123def456"}'
```

**MCP**

```text
Tool: overview_timeseries
Arguments: {"siteId":"site_abc123def456"}
```

Run `clearsaga help overview timeseries` for one flag per field.
