# Analytics

Part of AppEngine API Documentation. Full index: https://appengine.appmint.io/documentation.md
## GET /analytics

**Get analytics data**

`operationId: AnalyticsController_getAnalytics`

The general analytics read. `type` selects one dashboard; omitting it returns `{ website, blog, workflow, storefront, tickets, leads, automation, users }` in one response (heavier, and `email` is only available by naming it). Unlike the per-area routes, this read carries no previous-window `comparison`.

#### Signature

```http
GET /analytics (type?: string, startDate?: string, endDate?: string) -> Analytics data
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | ORGID_REQUIRED | orgId is required | The `orgid` header is missing. | Send the `orgid` header. |
| `500` | ANALYTICS_FAILED | Failed to get analytics | The figures could not be computed. | Retry; escalate if it persists. |

Plus the standard platform errors: `401`, `403`, `429`.

#### See also

- `GET /analytics/website`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |
| `type` | query | "website" \| "blog" \| "workflow" \| "storefront" \| "tickets" \| "leads" \| "automation" \| "users" \| "email" | — | Dashboard type. Omit for all but email. |
| `metrics` | query | string[] | — |  |
| `demo` | query | boolean | — | Use demo data instead of real data |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Analytics data |
| `400` | orgId is required — The `orgid` header is missing. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | Failed to get analytics — The figures could not be computed. |

## GET /analytics/filter-options

**Get filter options**

`operationId: AnalyticsController_getFilterOptions`

Distinct sites, domains and hosts seen in web visit data over the last 90 days — what populates a dashboard's filter dropdowns. Derived from observed traffic, so a site with no visits in that window will not appear. Up to 100 of each.

#### Signature

```http
GET /analytics/filter-options () -> Filter options
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | ORGID_REQUIRED | orgId is required | The `orgid` header is missing. | Send the `orgid` header. |
| `500` | ANALYTICS_FAILED | Failed to get filter options | The figures could not be computed. | Retry; escalate if it persists. |

Plus the standard platform errors: `401`, `403`, `429`.

#### See also

- `GET /analytics/website`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Filter options |
| `400` | orgId is required — The `orgid` header is missing. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | Failed to get filter options — The figures could not be computed. |

## GET /analytics/live-view

**Get Live View**

`operationId: AnalyticsController_getLiveView`

Unique visitors on the site right now, with real-time aggregated metrics. `minutes` sets how far back "now" reaches — a wider window shows more people but stops being live.

Built from the web-visit timeseries, so a visitor appears only once their first event has been recorded. Bots, scanners and probes are never recorded, so they never appear here. Refreshed about every 15 seconds; up to 500 visitors, most recently seen first.

#### Signature

```http
GET /analytics/live-view (minutes?: integer) -> Current visitors and metrics
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | ORGID_REQUIRED | orgId is required | The `orgid` header is missing. | Send the `orgid` header. |
| `500` | ANALYTICS_FAILED | Failed to get live view | The figures could not be computed. | Retry; escalate if it persists. |

Plus the standard platform errors: `401`, `403`, `429`.

#### See also

- `GET /analytics/live-view/{deviceId}/journey`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `minutes` | query | integer | — | Window in minutes, default 15, minimum 1. Wider is less "live". |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Current visitors and metrics |
| `400` | orgId is required — The `orgid` header is missing. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | Failed to get live view — The figures could not be computed. |

## GET /analytics/live-view/{deviceId}/journey

**Get a visitor journey**

`operationId: AnalyticsController_getLiveViewJourney`

The full timeline for one visitor — every page and event in order. `deviceId` identifies a browser, not a person: the same human on a phone and a laptop is two device ids, and a cleared browser is a new one. Newest event first, at most 500 (`limit`, default 100). Refreshed about every 15 seconds, like Live View.

#### Signature

```http
GET /analytics/live-view/{deviceId}/journey (deviceId: string, limit?: integer) -> The journey
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | ORGID_REQUIRED | orgId is required | The `orgid` header is missing. | Send the `orgid` header. |
| `500` | ANALYTICS_FAILED | Failed to get device journey | The figures could not be computed. | Retry; escalate if it persists. |

Plus the standard platform errors: `401`, `403`, `429`.

#### See also

- `GET /analytics/live-view`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `deviceId` | path | string | yes | Device identifier from Live View. |
| `limit` | query | integer | — |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The journey |
| `400` | orgId is required — The `orgid` header is missing. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | Failed to get device journey — The figures could not be computed. |

## GET /analytics/website

**Get website analytics**

`operationId: AnalyticsController_getWebsiteAnalytics`

Traffic and engagement across the org's sites over a date range.

Every dashboard is computed twice — for the requested window and for the window of the same length just before it — and returned with `period` (the window used) and `comparison: { startDate, endDate, overview }`, where each numeric `overview` figure gets `{ previous, changePercent, direction: up|down|flat, sentiment: good|bad|neutral }`. `changePercent` is `null` when the previous value was 0. Without dates the window is the last 30 days.

Cached for about five minutes: a reload inside that window returns the same figures.

#### Signature

```http
GET /analytics/website (startDate?: string, endDate?: string) -> Website analytics with the previous-window comparison
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `500` | ANALYTICS_FAILED | Failed to get website analytics | The figures could not be computed — or the `orgid` header is missing (the handler reports that as this 500, not a 400). | Check the `orgid` header; otherwise retry and escalate if it persists. |

Plus the standard platform errors: `401`, `403`, `429`.

#### See also

- `GET /analytics`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |
| `type` | query | "website" \| "blog" \| "workflow" \| "storefront" \| "tickets" \| "leads" \| "automation" \| "users" \| "email" | — |  |
| `metrics` | query | string[] | — |  |
| `demo` | query | boolean | — | Use demo data instead of real data |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Website analytics with the previous-window comparison |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | Failed to get website analytics — The figures could not be computed — or the `orgid` header is missing (the handler reports that as this 500, not a 400). |

## GET /analytics/blog

**Get blog analytics**

`operationId: AnalyticsController_getBlogAnalytics`

Post readership and engagement. A visit counts as a view of a post when the last segment of its URL is one of the org’s post slugs (the post’s `name` when it has no slug) — whatever prefix the site gives posts (`/blog/`, `/news/`, …). `topPosts` are the ten most-viewed posts in the range; `overview.totalViews` counts every post view in the range. Category and author figures come from the posts themselves.

Every dashboard is computed twice — for the requested window and for the window of the same length just before it — and returned with `period` (the window used) and `comparison: { startDate, endDate, overview }`, where each numeric `overview` figure gets `{ previous, changePercent, direction: up|down|flat, sentiment: good|bad|neutral }`. `changePercent` is `null` when the previous value was 0. Without dates the window is the last 30 days.

Cached for about five minutes: a reload inside that window returns the same figures.

#### Signature

```http
GET /analytics/blog (startDate?: string, endDate?: string) -> Blog analytics with the previous-window comparison
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `500` | ANALYTICS_FAILED | Failed to get blog analytics | The figures could not be computed — or the `orgid` header is missing (the handler reports that as this 500, not a 400). | Check the `orgid` header; otherwise retry and escalate if it persists. |

Plus the standard platform errors: `401`, `403`, `429`.

#### See also

- `GET /analytics`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |
| `type` | query | "website" \| "blog" \| "workflow" \| "storefront" \| "tickets" \| "leads" \| "automation" \| "users" \| "email" | — |  |
| `metrics` | query | string[] | — |  |
| `demo` | query | boolean | — | Use demo data instead of real data |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Blog analytics with the previous-window comparison |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | Failed to get blog analytics — The figures could not be computed — or the `orgid` header is missing (the handler reports that as this 500, not a 400). |

## GET /analytics/workflow

**Get workflow analytics**

`operationId: AnalyticsController_getWorkflowAnalytics`

Pipeline throughput and stage timings from the workflow engine.

Every dashboard is computed twice — for the requested window and for the window of the same length just before it — and returned with `period` (the window used) and `comparison: { startDate, endDate, overview }`, where each numeric `overview` figure gets `{ previous, changePercent, direction: up|down|flat, sentiment: good|bad|neutral }`. `changePercent` is `null` when the previous value was 0. Without dates the window is the last 30 days.

Cached for about five minutes: a reload inside that window returns the same figures.

#### Signature

```http
GET /analytics/workflow (startDate?: string, endDate?: string) -> Workflow analytics with the previous-window comparison
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `500` | ANALYTICS_FAILED | Failed to get workflow analytics | The figures could not be computed — or the `orgid` header is missing (the handler reports that as this 500, not a 400). | Check the `orgid` header; otherwise retry and escalate if it persists. |

Plus the standard platform errors: `401`, `403`, `429`.

#### See also

- `GET /analytics`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |
| `type` | query | "website" \| "blog" \| "workflow" \| "storefront" \| "tickets" \| "leads" \| "automation" \| "users" \| "email" | — |  |
| `metrics` | query | string[] | — |  |
| `demo` | query | boolean | — | Use demo data instead of real data |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Workflow analytics with the previous-window comparison |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | Failed to get workflow analytics — The figures could not be computed — or the `orgid` header is missing (the handler reports that as this 500, not a 400). |

## GET /analytics/storefront

**Get storefront analytics**

`operationId: AnalyticsController_getStorefrontAnalytics`

Orders, revenue and conversion for the storefront.

Every dashboard is computed twice — for the requested window and for the window of the same length just before it — and returned with `period` (the window used) and `comparison: { startDate, endDate, overview }`, where each numeric `overview` figure gets `{ previous, changePercent, direction: up|down|flat, sentiment: good|bad|neutral }`. `changePercent` is `null` when the previous value was 0. Without dates the window is the last 30 days.

Cached for about five minutes: a reload inside that window returns the same figures.

#### Signature

```http
GET /analytics/storefront (startDate?: string, endDate?: string) -> Storefront analytics with the previous-window comparison
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `500` | ANALYTICS_FAILED | Failed to get storefront analytics | The figures could not be computed — or the `orgid` header is missing (the handler reports that as this 500, not a 400). | Check the `orgid` header; otherwise retry and escalate if it persists. |

Plus the standard platform errors: `401`, `403`, `429`.

#### See also

- `GET /analytics`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |
| `type` | query | "website" \| "blog" \| "workflow" \| "storefront" \| "tickets" \| "leads" \| "automation" \| "users" \| "email" | — |  |
| `metrics` | query | string[] | — |  |
| `demo` | query | boolean | — | Use demo data instead of real data |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Storefront analytics with the previous-window comparison |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | Failed to get storefront analytics — The figures could not be computed — or the `orgid` header is missing (the handler reports that as this 500, not a 400). |

## POST /analytics/storefront/orders

**Get the order dashboard**

`operationId: AnalyticsController_getOrderDashboard`

Order analytics with a richer selector than the query-string dashboards: `period` picks a named window (`today`, `week`, `month`, `year`), or give explicit dates. `recentLimit` caps how many recent orders come back alongside the aggregates.

A POST because of the body, not because it changes anything — it is a read.

#### Signature

```http
POST /analytics/storefront/orders (body) -> Order analytics
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Read-only despite being a POST.

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | ORGID_REQUIRED | orgId is required | The `orgid` header is missing. | Send the `orgid` header. |
| `500` | ANALYTICS_FAILED | Failed to get order dashboard analytics | The figures could not be computed. | Retry; escalate if it persists. |

Plus the standard platform errors: `401`, `403`, `429`.

#### See also

- `GET /analytics/storefront`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The window.

```json
{
  "period": "month",
  "recentLimit": 10
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Order analytics |
| `400` | orgId is required — The `orgid` header is missing. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | Failed to get order dashboard analytics — The figures could not be computed. |

## GET /analytics/tickets

**Get ticket analytics**

`operationId: AnalyticsController_getTicketAnalytics`

Support ticket volume, resolution time and backlog.

Every dashboard is computed twice — for the requested window and for the window of the same length just before it — and returned with `period` (the window used) and `comparison: { startDate, endDate, overview }`, where each numeric `overview` figure gets `{ previous, changePercent, direction: up|down|flat, sentiment: good|bad|neutral }`. `changePercent` is `null` when the previous value was 0. Without dates the window is the last 30 days.

Cached for about five minutes: a reload inside that window returns the same figures.

#### Signature

```http
GET /analytics/tickets (startDate?: string, endDate?: string) -> Ticket analytics with the previous-window comparison
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `500` | ANALYTICS_FAILED | Failed to get ticket analytics | The figures could not be computed — or the `orgid` header is missing (the handler reports that as this 500, not a 400). | Check the `orgid` header; otherwise retry and escalate if it persists. |

Plus the standard platform errors: `401`, `403`, `429`.

#### See also

- `GET /analytics`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |
| `type` | query | "website" \| "blog" \| "workflow" \| "storefront" \| "tickets" \| "leads" \| "automation" \| "users" \| "email" | — |  |
| `metrics` | query | string[] | — |  |
| `demo` | query | boolean | — | Use demo data instead of real data |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Ticket analytics with the previous-window comparison |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | Failed to get ticket analytics — The figures could not be computed — or the `orgid` header is missing (the handler reports that as this 500, not a 400). |

## GET /analytics/attribution

**Get revenue attribution**

`operationId: AnalyticsController_getAttributionAnalytics`

Revenue by campaign source, medium and campaign, read from what the campaign page handed over at checkout (`sf_order.data.attribution`) — not a join back over visits, which are purged after six months. Cancelled, refunded and draft orders are not counted.

`bySource` and `byCampaign` also carry `sessions` from web visits (their `utmSource` / `utmCampaign`), so a source with traffic and no revenue still shows, with `revenuePerSession`. Rows sort by revenue, then sessions. `totals.coverage` is the percentage of orders that carried a source — a low number means campaign pages are not handing their source over at checkout.

Without dates the window is the last 30 days. Cached for about five minutes: a reload inside that window returns the same figures.

#### Signature

```http
GET /analytics/attribution (startDate?: string, endDate?: string) -> { period, totals, bySource, byMedium, byCampaign }
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `400` | ORGID_REQUIRED | Organization ID is required | The `orgid` header is missing. | Send the `orgid` header. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /analytics/storefront`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |
| `type` | query | "website" \| "blog" \| "workflow" \| "storefront" \| "tickets" \| "leads" \| "automation" \| "users" \| "email" | — |  |
| `metrics` | query | string[] | — |  |
| `demo` | query | boolean | — | Use demo data instead of real data |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | { period, totals, bySource, byMedium, byCampaign } |
| `400` | Organization ID is required — The `orgid` header is missing. |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

Example response:

```json
{
  "period": {
    "startDate": "2026-08-01T00:00:00.000Z",
    "endDate": "2026-08-31T00:00:00.000Z"
  },
  "totals": {
    "orders": 120,
    "revenue": 9400,
    "attributedOrders": 84,
    "attributedRevenue": 7010,
    "coverage": 70,
    "unattributedRevenue": 2390
  },
  "bySource": [
    {
      "name": "facebook",
      "orders": 40,
      "revenue": 3200,
      "customers": 36,
      "sessions": 900,
      "revenuePerSession": 3.56
    }
  ],
  "byMedium": [
    {
      "name": "cpc",
      "orders": 50,
      "revenue": 4100,
      "customers": 44
    }
  ],
  "byCampaign": [
    {
      "name": "fall-sale",
      "orders": 30,
      "revenue": 2500,
      "customers": 28,
      "sessions": 610,
      "revenuePerSession": 4.1
    }
  ]
}
```

## GET /analytics/leads

**Get leads analytics**

`operationId: AnalyticsController_getLeadsAnalytics`

Lead volume, source and conversion.

Every dashboard is computed twice — for the requested window and for the window of the same length just before it — and returned with `period` (the window used) and `comparison: { startDate, endDate, overview }`, where each numeric `overview` figure gets `{ previous, changePercent, direction: up|down|flat, sentiment: good|bad|neutral }`. `changePercent` is `null` when the previous value was 0. Without dates the window is the last 30 days.

Cached for about five minutes: a reload inside that window returns the same figures.

#### Signature

```http
GET /analytics/leads (startDate?: string, endDate?: string) -> Leads analytics with the previous-window comparison
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `500` | ANALYTICS_FAILED | Failed to get leads analytics | The figures could not be computed — or the `orgid` header is missing (the handler reports that as this 500, not a 400). | Check the `orgid` header; otherwise retry and escalate if it persists. |

Plus the standard platform errors: `401`, `403`, `429`.

#### See also

- `GET /analytics`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |
| `type` | query | "website" \| "blog" \| "workflow" \| "storefront" \| "tickets" \| "leads" \| "automation" \| "users" \| "email" | — |  |
| `metrics` | query | string[] | — |  |
| `demo` | query | boolean | — | Use demo data instead of real data |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Leads analytics with the previous-window comparison |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | Failed to get leads analytics — The figures could not be computed — or the `orgid` header is missing (the handler reports that as this 500, not a 400). |

## GET /analytics/automation

**Get automation analytics**

`operationId: AnalyticsController_getAutomationAnalytics`

Automation run counts, successes and failures.

Every dashboard is computed twice — for the requested window and for the window of the same length just before it — and returned with `period` (the window used) and `comparison: { startDate, endDate, overview }`, where each numeric `overview` figure gets `{ previous, changePercent, direction: up|down|flat, sentiment: good|bad|neutral }`. `changePercent` is `null` when the previous value was 0. Without dates the window is the last 30 days.

Cached for about five minutes: a reload inside that window returns the same figures.

#### Signature

```http
GET /analytics/automation (startDate?: string, endDate?: string) -> Automation analytics with the previous-window comparison
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `500` | ANALYTICS_FAILED | Failed to get automation analytics | The figures could not be computed — or the `orgid` header is missing (the handler reports that as this 500, not a 400). | Check the `orgid` header; otherwise retry and escalate if it persists. |

Plus the standard platform errors: `401`, `403`, `429`.

#### See also

- `GET /analytics`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |
| `type` | query | "website" \| "blog" \| "workflow" \| "storefront" \| "tickets" \| "leads" \| "automation" \| "users" \| "email" | — |  |
| `metrics` | query | string[] | — |  |
| `demo` | query | boolean | — | Use demo data instead of real data |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Automation analytics with the previous-window comparison |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | Failed to get automation analytics — The figures could not be computed — or the `orgid` header is missing (the handler reports that as this 500, not a 400). |

## GET /analytics/users

**Get user account analytics**

`operationId: AnalyticsController_getUserAccountAnalytics`

Account signups, activity and retention.

Every dashboard is computed twice — for the requested window and for the window of the same length just before it — and returned with `period` (the window used) and `comparison: { startDate, endDate, overview }`, where each numeric `overview` figure gets `{ previous, changePercent, direction: up|down|flat, sentiment: good|bad|neutral }`. `changePercent` is `null` when the previous value was 0. Without dates the window is the last 30 days.

Cached for about five minutes: a reload inside that window returns the same figures.

#### Signature

```http
GET /analytics/users (startDate?: string, endDate?: string) -> User account analytics with the previous-window comparison
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `500` | ANALYTICS_FAILED | Failed to get user account analytics | The figures could not be computed — or the `orgid` header is missing (the handler reports that as this 500, not a 400). | Check the `orgid` header; otherwise retry and escalate if it persists. |

Plus the standard platform errors: `401`, `403`, `429`.

#### See also

- `GET /analytics`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |
| `type` | query | "website" \| "blog" \| "workflow" \| "storefront" \| "tickets" \| "leads" \| "automation" \| "users" \| "email" | — |  |
| `metrics` | query | string[] | — |  |
| `demo` | query | boolean | — | Use demo data instead of real data |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | User account analytics with the previous-window comparison |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | Failed to get user account analytics — The figures could not be computed — or the `orgid` header is missing (the handler reports that as this 500, not a 400). |

## GET /analytics/email

**Get email analytics**

`operationId: AnalyticsController_getEmailAnalytics`

Email send and engagement figures.

Every dashboard is computed twice — for the requested window and for the window of the same length just before it — and returned with `period` (the window used) and `comparison: { startDate, endDate, overview }`, where each numeric `overview` figure gets `{ previous, changePercent, direction: up|down|flat, sentiment: good|bad|neutral }`. `changePercent` is `null` when the previous value was 0. Without dates the window is the last 30 days.

Cached for about five minutes: a reload inside that window returns the same figures.

#### Signature

```http
GET /analytics/email (startDate?: string, endDate?: string) -> Email analytics with the previous-window comparison
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `500` | ANALYTICS_FAILED | Failed to get email analytics | The figures could not be computed — or the `orgid` header is missing (the handler reports that as this 500, not a 400). | Check the `orgid` header; otherwise retry and escalate if it persists. |

Plus the standard platform errors: `401`, `403`, `429`.

#### See also

- `GET /analytics`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |
| `type` | query | "website" \| "blog" \| "workflow" \| "storefront" \| "tickets" \| "leads" \| "automation" \| "users" \| "email" | — |  |
| `metrics` | query | string[] | — |  |
| `demo` | query | boolean | — | Use demo data instead of real data |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Email analytics with the previous-window comparison |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | Failed to get email analytics — The figures could not be computed — or the `orgid` header is missing (the handler reports that as this 500, not a 400). |

## POST /analytics/export

**Export analytics data**

`operationId: AnalyticsController_exportAnalytics`

Returns the same figures as `GET /analytics` for the dashboard and date range, wrapped as `{ format, data, exportedAt }`. The selector travels in the **query string**, not a body. No file is produced yet: `format` is echoed back and `data` is always JSON, whatever format is asked for.

#### Signature

```http
POST /analytics/export (type?: string, startDate?: string, endDate?: string, format?: string) -> { format, data, exportedAt }
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `500` | ANALYTICS_FAILED | Failed to export analytics | The figures could not be computed — or the `orgid` header is missing (reported as this 500). | Check the `orgid` header; otherwise retry. |

Plus the standard platform errors: `401`, `403`, `429`.

#### See also

- `GET /analytics`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |
| `type` | query | "website" \| "blog" \| "workflow" \| "storefront" \| "tickets" \| "leads" \| "automation" \| "users" \| "email" | — | Dashboard. Omit for all but email. |
| `metrics` | query | string[] | — |  |
| `demo` | query | boolean | — | Use demo data instead of real data |
| `format` | query | "csv" \| "json" \| "pdf" | — | Echoed back; does not change the payload yet. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | { format, data, exportedAt } |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | Failed to export analytics — The figures could not be computed — or the `orgid` header is missing (reported as this 500). |

Example response:

```json
{
  "format": "csv",
  "data": {
    "overview": {}
  },
  "exportedAt": "2026-09-29T14:00:00.000Z"
}
```

## GET /studio-overview/{section}

**Get a Studio section overview**

`operationId: StudioOverviewController_getSection`

The finished figures one Studio dashboard renders — counts, recent records and section-specific tiles — computed on the server so the screen only draws them. Every response carries `section` and `generatedAt` beside the section's own fields. Not cached.

#### Signature

```http
GET /studio-overview/{section} (section: string, site?: string) -> { section, generatedAt, ...figures }
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

| Status | Code | Message | When | What to do |
| --- | --- | --- | --- | --- |
| `404` | UNKNOWN_SECTION | Unknown overview section "reports" | `section` is not one of the listed dashboards. | Use one of the enum values. |

Plus the standard platform errors: `401`, `403`, `429`, `500`.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `section` | path | "home" \| "account" \| "config" \| "database" \| "crm" \| "store" \| "finance" \| "logistics" \| "events" \| "community" \| "dam" \| "build-studio" \| "ai-automation" | yes | Which dashboard. |
| `site` | query | string | — | Narrows `home` and `build-studio` to one site (site name). Ignored by other sections. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | { section, generatedAt, ...figures } |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `404` | Unknown overview section "reports" — `section` is not one of the listed dashboards. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

Example response:

```json
{
  "section": "home",
  "generatedAt": "2026-09-29T14:00:00.000Z",
  "customers": 1240,
  "sites": 2,
  "activityToday": 37,
  "recentActivity": []
}
```

## GET /analytics/dashboard/all

**Get all dashboard data**

`operationId: AnalyticsController_getAllDashboardData`

Every dashboard in one response — website, blog, workflow, storefront, tickets, leads, automation, social and users. Heavier than fetching one, but it saves nine round trips when a page shows them together.

#### Signature

```http
GET /analytics/dashboard/all (startDate?: string, endDate?: string) -> All dashboards
```

#### Access

Public — no credentials required.

#### Notes

- Unauthenticated — this controller is entirely public.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `GET /analytics/dashboard/website`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | All dashboards |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /analytics/dashboard/website

**Get website analytics**

`operationId: AnalyticsController_getWebsiteAnalytics`

Traffic and engagement for the org's sites. Narrow it with `siteName`, `domain` or `host` — without one, the figures cover every site the org runs, which is rarely what a per-site view wants.

#### Signature

```http
GET /analytics/dashboard/website (startDate?: string, endDate?: string, siteName?: string, domain?: string, host?: string) -> Website analytics
```

#### Access

Public — no credentials required.

#### Notes

- Unauthenticated — this controller is entirely public.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `GET /analytics/filter-options`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |
| `siteName` | query | string | — |  |
| `domain` | query | string | — |  |
| `host` | query | string | — |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Website analytics |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /analytics/dashboard/blog

**Get blog analytics**

`operationId: AnalyticsController_getBlogAnalytics`

Post performance and readership over a date range.

#### Signature

```http
GET /analytics/dashboard/blog (startDate?: string, endDate?: string) -> Blog analytics
```

#### Access

Public — no credentials required.

#### Notes

- Unauthenticated — this controller is entirely public.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `GET /analytics/dashboard/all`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Blog analytics |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /analytics/dashboard/workflow

**Get workflow analytics**

`operationId: AnalyticsController_getWorkflowAnalytics`

Pipeline throughput and stage timings, drawn from the workflow engine.

#### Signature

```http
GET /analytics/dashboard/workflow (startDate?: string, endDate?: string) -> Workflow analytics
```

#### Access

Public — no credentials required.

#### Notes

- Unauthenticated — this controller is entirely public.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `GET /workflow/analytics/{workflowId}/wait-times`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Workflow analytics |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /analytics/dashboard/storefront

**Get storefront analytics**

`operationId: AnalyticsController_getStorefrontAnalytics`

Orders, revenue and conversion for the storefront.

#### Signature

```http
GET /analytics/dashboard/storefront (startDate?: string, endDate?: string) -> Storefront analytics
```

#### Access

Public — no credentials required.

#### Notes

- Unauthenticated — this controller is entirely public.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `GET /analytics/dashboard/all`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Storefront analytics |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /analytics/dashboard/tickets

**Get ticket analytics**

`operationId: AnalyticsController_getTicketAnalytics`

Support ticket volume, resolution time and backlog.

#### Signature

```http
GET /analytics/dashboard/tickets (startDate?: string, endDate?: string) -> Ticket analytics
```

#### Access

Public — no credentials required.

#### Notes

- Unauthenticated — this controller is entirely public.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `GET /analytics/dashboard/all`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Ticket analytics |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /analytics/dashboard/leads

**Get leads analytics**

`operationId: AnalyticsController_getLeadsAnalytics`

Lead volume, source and conversion over a date range.

#### Signature

```http
GET /analytics/dashboard/leads (startDate?: string, endDate?: string) -> Leads analytics
```

#### Access

Public — no credentials required.

#### Notes

- Unauthenticated — this controller is entirely public.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `GET /analytics/dashboard/automation`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Leads analytics |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /analytics/dashboard/automation

**Get automation analytics**

`operationId: AnalyticsController_getAutomationAnalytics`

Automation run counts, successes and failures.

#### Signature

```http
GET /analytics/dashboard/automation (startDate?: string, endDate?: string) -> Automation analytics
```

#### Access

Public — no credentials required.

#### Notes

- Unauthenticated — this controller is entirely public.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `GET /analytics/dashboard/all`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Automation analytics |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /analytics/dashboard/social

**Get social media analytics**

`operationId: AnalyticsController_getSocialMediaAnalytics`

Social reach and engagement across connected accounts.

#### Signature

```http
GET /analytics/dashboard/social (startDate?: string, endDate?: string) -> Social analytics
```

#### Access

Public — no credentials required.

#### Notes

- Unauthenticated — this controller is entirely public.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `GET /analytics/dashboard/all`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Social analytics |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /analytics/dashboard/users

**Get user account analytics**

`operationId: AnalyticsController_getUserAccountAnalytics`

Account signups, activity and retention for the org.

#### Signature

```http
GET /analytics/dashboard/users (startDate?: string, endDate?: string) -> User analytics
```

#### Access

Public — no credentials required.

#### Notes

- Unauthenticated — this controller is entirely public.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `GET /analytics/dashboard/all`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | User analytics |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /analytics/dashboard/{dashboardType}/refresh

**Refresh a dashboard**

`operationId: AnalyticsController_refreshDashboard`

Recomputes one dashboard rather than serving the cached figures. Deliberately more expensive than the plain read — call it when the numbers must be current, not on every page load.

#### Signature

```http
GET /analytics/dashboard/{dashboardType}/refresh (dashboardType: string, startDate?: string, endDate?: string) -> The refreshed dashboard
```

#### Access

Public — no credentials required.

#### Notes

- Unauthenticated — this controller is entirely public.
- Recomputes rather than reading cache.

#### Errors

Plus the standard platform errors: `429`, `500`.

#### See also

- `GET /analytics/dashboard/all`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `dashboardType` | path | string | yes | Which dashboard — `website`, `blog`, `storefront`, and so on. |
| `startDate` | query | string | — | ISO date. |
| `endDate` | query | string | — | ISO date. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The refreshed dashboard |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

