> For the complete documentation index, see [llms.txt](https://docs.graspil.com/ru/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.graspil.com/ru/api/reports.md).

# Конструктор отчетов и дашбордов

Методы для построения аналитических отчётов — те же отчёты, что вы видите в личном кабинете в разделе [«Конструктор отчётов»](/ru/app/reports.md), но через API. Удобно, если вы хотите получать графики и таблицы по своим данным в собственной системе (внутренней аналитике, дашборде, чат-боте с отчётами и т.д.) без захода в личный кабинет.

{% hint style="info" %}
Методы конструктора отчётов доступны только на тарифе **Premium**.
{% endhint %}

### Как это работает вкратце

1. Отчёт строится по событиям, которые вы отправляете в Graspil (см. [Список событий](/ru/app/reports/events.md)). Чтобы понять, какие события и поля доступны для отчёта по вашему боту, используйте методы `events`, `event-fields` и `utm-labels` — они подсказывают, что можно подставить в фильтры и отчёт.
2. Сам отчёт описывается одним JSON-объектом `report_config` — в нём указано, что считать (какое событие, какая агрегация), как фильтровать и как группировать. Ниже подробно расписан его формат — это тот же формат, что использует визуальный конструктор отчётов в личном кабинете.
3. Прежде чем сохранять отчёт, его можно «прогнать» вхолостую методом `preview` — посмотреть первые строки результата и убедиться, что всё посчиталось так, как вы хотели.
4. Когда отчёт готов — сохраните его методом `save`. Сохранённые отчёты можно получить списком через `list`.

### Авторизация

Если ваш API-ключ привязан к одному боту (обычный ключ из раздела «Мои боты» — см. [Авторизацию](/ru/api/auth.md)) — ничего дополнительно указывать не нужно, все методы применяются к этому боту.

Если вы используете ключ из раздела [«API-ключи»](https://app.graspil.com/api-keys), выданный сразу на несколько ботов или на все ваши боты, в каждом запросе нужно явно указать, какого бота он касается — заголовком `Resource-Key` либо полем (для `POST`) или параметром (для `GET`) `resource_key`. Значение — публичный ключ бота: часть до двоеточия в API-ключе бота, который вы видите в разделе «Мои боты» рядом с иконкой ключа (формат `ключ_бота:api_key`).

{% hint style="info" %}
Методы `save` и `list` работают только с пользовательским ключом из раздела «API-ключи» — обычный ключ одного бота для них не подходит.
{% endhint %}

### Формат ответа

Успешный ответ:

{% code overflow="wrap" %}

```json
{ "ok": true, "data": { ... } }
```

{% endcode %}

Ответ с ошибкой:

{% code overflow="wrap" %}

```json
{ "ok": false, "error": "...", "error_code": 400 }
```

{% endcode %}

***

## Конфигурация отчёта (`report_config`)

Это главный объект, который описывает отчёт. Его передают в методы `preview` и `save`, и его же возвращают сохранённые отчёты. Состоит из двух частей: `source_request` (что и как считать) и `settings` (период):

{% code overflow="wrap" %}

```json
{
  "source_request": {
    "type": "trends",
    "type_chart": "line",
    "requests": [ ... ],
    "filters": null,
    "separators": [ ... ]
  },
  "settings": {
    "params": {
      ":date_from": "2026-01-01 00:00:00",
      ":date_to": "2026-01-31 23:59:59"
    }
  }
}
```

{% endcode %}

| Поле              | Описание                                                                                                                                        |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `source_request`  | Что и как считать — тип отчёта (`type` / `type_chart`), события, фильтры, группировки. Описано ниже                                             |
| `settings.params` | Период, за который строится отчёт. Ресурс (бот) подставляется автоматически по вашему ключу — указывать `:resource_key` самостоятельно не нужно |

| Параметр `settings.params` | Тип    | Обязательный | Описание                                     |
| -------------------------- | ------ | ------------ | -------------------------------------------- |
| `:date_from`               | string | да           | Начало периода, формат `YYYY-MM-DD HH:MM:SS` |
| `:date_to`                 | string | да           | Конец периода, формат `YYYY-MM-DD HH:MM:SS`  |

### Типы отчётов (`source_request.type` / `type_chart`)

| `type`      | `type_chart` | Что показывает                                                                                         | Когда использовать                                                                    |
| ----------- | ------------ | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------- |
| `trends`    | `line`       | Динамику показателя по дням — график «событие/пользователи во времени»                                 | Самый частый тип: «сколько событий/пользователей было каждый день»                    |
| `trends`    | `table`      | То же самое, но в виде таблицы, а не графика. У таблицы более короткий набор значений `agr` — см. ниже | Когда нужны точные числа по дням, а не картинка                                       |
| `list`      | `list`       | Список сырых строк из таблицы событий (или другой таблицы), без агрегации                              | Когда нужен список конкретных событий, а не сводная цифра — например, журнал действий |
| `funnels`   | `funnels`    | Воронку: сколько пользователей прошли цепочку событий шаг за шагом                                     | «Сколько из тех, кто открыл карточку товара, дошли до оплаты»                         |
| `retention` | `retention`  | Ретеншен: вернулись ли пользователи и сделали повторное действие через N дней                          | «Сколько пользователей, оплативших один раз, оплатили снова через неделю»             |

Дальше в зависимости от `type` заполняются разные поля `source_request` — они описаны в соответствующих разделах ниже.

***

## Тренды и таблицы (`type: "trends"`)

| Поле         | Тип         | Обязательный | Описание                                                                                            |
| ------------ | ----------- | ------------ | --------------------------------------------------------------------------------------------------- |
| `requests`   | array       | да           | Один или несколько показателей на одном графике/таблице — см. «Показатель (`requests`)» ниже        |
| `filters`    | array\|null | нет          | Общий фильтр, применяется ко всем показателям сразу — см. «Фильтры» ниже                            |
| `separators` | array       | нет          | Разбивка показателя на несколько линий/строк по какому-то полю — см. «Разбивка (`separators`)» ниже |

### Показатель (`requests`)

Каждый элемент массива `requests` — это один показатель (одна линия на графике/строка в таблице):

{% code overflow="wrap" %}

```json
{
  "type": "trend",
  "event_id": 5,
  "event_name": "purchase",
  "label": "Покупки",
  "agr": "total",
  "filters": null
}
```

{% endcode %}

| Поле         | Тип         | Обязательный | Описание                                                                                   |
| ------------ | ----------- | ------------ | ------------------------------------------------------------------------------------------ |
| `type`       | string      | да           | Всегда `"trend"`                                                                           |
| `event_id`   | int\|null   | нет          | ID события, которое считаем (см. метод `events` ниже). `null` — считать вообще все события |
| `event_name` | string      | да           | Название события — просто для удобства чтения, на расчёт не влияет                         |
| `label`      | string      | нет          | Подпись показателя, которая будет в результате (например, название линии на графике)       |
| `agr`        | string      | да           | Как агрегировать — см. таблицу ниже                                                        |
| `filters`    | array\|null | нет          | Фильтр именно для этого показателя (в дополнение к общему `source_request.filters`)        |

#### Агрегации (`agr`)

Допустимые значения зависят от `type_chart`.

**`type_chart: "table"`:**

| Значение     | Что считает                                                 |
| ------------ | ----------------------------------------------------------- |
| `total`      | Общее количество событий                                    |
| `total_uniq` | Количество уникальных пользователей, у которых было событие |
| `avg`        | Среднее количество событий на одного пользователя           |
| `min`        | Минимальное количество событий на одного пользователя       |
| `max`        | Максимальное количество событий на одного пользователя      |
| `median`     | Медианное количество событий на одного пользователя         |

**`type_chart: "line"`, `"bar"`, `"area"`, `"pie"` и т.д. (любой график):**

| Значение                    | Что считает                                                         |
| --------------------------- | ------------------------------------------------------------------- |
| `total`                     | Общее количество событий                                            |
| `total_uniq_user_id`        | Количество уникальных пользователей, у которых было событие         |
| `total_uniq_session_id`     | Количество уникальных сессий с этим событием                        |
| `total_uniq_app_session_id` | Количество уникальных сессий в Mini App с этим событием             |
| `avg_user_id`               | Среднее количество событий на одного пользователя                   |
| `min_user_id`               | Минимальное количество событий на одного пользователя               |
| `max_user_id`               | Максимальное количество событий на одного пользователя              |
| `median_user_id`            | Медианное количество событий на одного пользователя                 |
| `property_sum`              | Сумма числового поля события (`agr_field`) — например, сумма продаж |
| `property_avg`              | Среднее значение числового поля события                             |
| `property_min`              | Минимальное значение числового поля события                         |
| `property_max`              | Максимальное значение числового поля события                        |
| `property_median`           | Медианное значение числового поля события                           |

{% hint style="warning" %}
Не смешивайте эти два набора. Запрос с `type_chart: "table"` и `agr: "total_uniq_user_id"` вернёт ошибку `Unsupported aggregation`. Для таблиц используйте короткую форму (`total_uniq`).
{% endhint %}

Для агрегаций `property_*` дополнительно обязателен параметр `agr_field` — какое поле агрегировать. Доступны два значения:

* `events.value_int` — «сырое» значение как оно было отправлено в `value_num`, без перевода в обычные единицы и без конвертации валют. Для денежных событий это минимальные единицы валюты (например, копейки для RUB)
* `events.value_amount` — то же значение, но переведённое в обычные единицы (рубли вместо копеек) и сконвертированное по курсу в валюту, установленную в [профиле](https://app.graspil.com/profile) владельца ключа

{% hint style="warning" %}
Если считаете деньги (сумму продаж, выручку и т.п.) — используйте `agr_field: "events.value_amount"`. С `events.value_int` итоговая сумма для денежных событий обычно будет казаться завышенной в 100 раз (или больше, если единица события — не копейка/цент).
{% endhint %}

**Пример:** сумма продаж по дням, в валюте профиля:

{% code overflow="wrap" %}

```json
{ "type": "trend", "event_id": 5, "event_name": "purchase", "label": "Выручка", "agr": "property_sum", "agr_field": "events.value_amount" }
```

{% endcode %}

### Фильтры

Фильтры сужают набор событий, которые попадают в расчёт. Указываются как вложенный массив `[оператор, ...аргументы]` — в том же стиле, что и фильтры аудитории в [API рассылок](/ru/api/broadcasts.md), только поля берутся из таблицы событий (узнать доступные поля — метод `event-fields` ниже).

* Логика: `["and", условие1, условие2, ...]`, `["or", ...]`
* Сравнение: `["=", "поле", значение]`, `["!=", ...]`, `[">", ...]`, `["<", ...]`, `[">=", ...]`, `["<=", ...]`
* Список значений: `["in", "поле", [значение1, значение2, ...]]`
* Диапазон: `["between", "поле", от, до]`

**Пример:** только покупки на сумму от 1000:

{% code overflow="wrap" %}

```json
[">=", "events.value_int", 1000]
```

{% endcode %}

{% hint style="warning" %}
Одно условие — это **плоский** массив `[оператор, поле, значение]`. Не оборачивайте его в дополнительный массив (`[[">=", "events.value_int", 1000]]` — неверно, API вернёт ошибку "expected a single condition, got a nested array"). Для нескольких условий явно комбинируйте их через `["and", ...]` / `["or", ...]` — просто список условий без `"and"`/`"or"` тоже невалиден.
{% endhint %}

{% hint style="info" %}
Период (`:date_from`/`:date_to`) и ваш бот подставляются в фильтр автоматически — добавлять их вручную не нужно.
{% endhint %}

### Разбивка (`separators`)

Разбивка показывает один и тот же показатель отдельно по каждому значению выбранного поля — например, отдельная линия на графике для каждого значения кастомного свойства события.

{% code overflow="wrap" %}

```json
"separators": [
  { "property": "events.properties.plan_name" }
]
```

{% endcode %}

Можно указать сразу несколько `separators` — тогда разбивка будет по комбинации значений всех полей.

{% hint style="warning" %}
Элементы `separators` — это объекты с полем `property` из фиксированного списка (`events.*`-колонки, либо любое поле с префиксом `events.properties.*` / `user.*` / `user.custom_fields.*`). Голая строка вроде `"utm_source"` невалидна и вернёт ошибку `Wrong separator property`.

Для разбивки **по UTM-source/medium/campaign** не используйте `separators` — значения UTM не выведены как обычные поля `events.properties.*`, они лежат за внутренними id-колонками (`events.f_param_id_*`), которые обрабатывает отдельный UTM-механизм отчётов. Используйте `type_chart: "utm_trends"` / `"utm_table"` — см. "Разбивка по UTM" ниже, именно это использует визуальный конструктор отчётов для UTM-разбивок.
{% endhint %}

***

## Разбивка по UTM (`type_chart: "utm_trends"` / `"utm_table"`)

Отдельный тип отчёта для разбивки показателя по UTM-метке (source/medium/campaign) без выбора конкретных значений метки заранее — например, «продажи по дням в разрезе UTM-метки».

| `type_chart` | Что показывает                                                                                          |
| ------------ | ------------------------------------------------------------------------------------------------------- |
| `utm_trends` | График во времени, одна линия на каждую комбинацию UTM (аналог `line`)                                  |
| `utm_table`  | Плоская сводная таблица, одна строка на каждую комбинацию UTM, без разбивки по времени (аналог `table`) |

{% code overflow="wrap" %}

```json
{
  "source_request": {
    "type": "trends",
    "type_chart": "utm_trends",
    "requests": [
      { "type": "trend", "event_id": 28, "event_name": "Sale", "label": "",
        "agr": "property_sum", "filters": [] }
    ],
    "filters": null,
    "separators": [],
    "granularity": "day",
    "breakdown_limit": 25,
    "row_limit": 100
  },
  "settings": { "params": { ":date_from": "2026-06-01 00:00:00", ":date_to": "2026-06-29 23:59:59" } }
}
```

{% endcode %}

| Поле              | Тип    | Обязательно | Описание                                                                                                                                                                   |
| ----------------- | ------ | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `requests`        | array  | да          | Тот же формат, что и в обычных trends — но `agr: "property_sum"` автоматически суммирует денежное поле события (с конвертацией валют); `agr_field` не нужен и игнорируется |
| `breakdown_limit` | int    | нет         | Максимум комбинаций UTM в ответе (5–500, по умолчанию `25`) — какие именно комбинации попадут в разбивку, выбирается автоматически, указывать их не нужно                  |
| `row_limit`       | int    | нет         | Максимум строк в ответе (1–5000, по умолчанию `100`)                                                                                                                       |
| `granularity`     | string | нет         | Шаг бакетов для `utm_trends`, например `day` — для `utm_table` игнорируется                                                                                                |

{% hint style="info" %}
Если нужно отфильтровать по ОДНОМУ конкретному известному значению UTM (например, «продажи с utm\_source=vk»), а не разбить по всем сразу — это обычное условие `filters` в отчёте `trends`/`line`, а не разбивка по UTM. Сначала уточните точное значение через метод `utm-labels`.
{% endhint %}

***

## Список событий (`type: "list"`)

Возвращает сырые строки без агрегации — например, журнал последних событий.

| Поле      | Тип         | Обязательный | Описание                                                                                 |
| --------- | ----------- | ------------ | ---------------------------------------------------------------------------------------- |
| `table`   | string      | да           | Таблица-источник, обычно `"events"`                                                      |
| `columns` | array       | да           | Какие поля вернуть, например `["events.date", "events.user_id", "events.event_type_id"]` |
| `filters` | array\|null | нет          | Фильтр — формат как в разделе «Фильтры» выше                                             |
| `order`   | object      | нет          | Сортировка, например `{ "events.date": "desc" }`                                         |
| `limit`   | int         | нет          | Сколько строк вернуть, по умолчанию `50`, максимум `1000`                                |
| `offset`  | int         | нет          | Смещение для постраничной выгрузки                                                       |

***

## Воронка (`type: "funnels"`)

Показывает, сколько пользователей дошли от первого события воронки до последнего.

| Поле                 | Тип    | Обязательный | Описание                                                                                                               |
| -------------------- | ------ | ------------ | ---------------------------------------------------------------------------------------------------------------------- |
| `requests`           | array  | да           | Шаги воронки по порядку — каждый элемент в том же формате, что «Показатель» выше (поле `agr` не важно, обычно `total`) |
| `funnel_window`      | int    | нет          | Сколько времени даётся пользователю, чтобы пройти всю воронку                                                          |
| `funnel_window_unit` | string | нет          | Единица для `funnel_window`: `second`, `minute`, `hour`, `day`, `week`, `month`. По умолчанию — 14 дней                |
| `funnel_order_type`  | string | нет          | Насколько строго проверяется порядок шагов — см. таблицу ниже                                                          |
| `separators`         | array  | нет          | Разбивка воронки по полю, как в трендах                                                                                |

| `funnel_order_type` | Поведение                                                                                   |
| ------------------- | ------------------------------------------------------------------------------------------- |
| `ordered`           | Шаги должны идти в указанном порядке, между ними допускаются любые другие действия          |
| `strict`            | Следующий шаг должен случиться сразу после предыдущего, без посторонних действий между ними |
| `unordered`         | Порядок шагов не важен                                                                      |

**Пример** (показано содержимое `source_request`; оберните его в `report_config` вместе с `settings` — см. раздел «Конфигурация отчёта»), воронка «посмотрел товар → оплатил» с окном 30 дней:

{% code overflow="wrap" %}

```json
{
  "type": "funnels",
  "type_chart": "funnels",
  "requests": [
    { "type": "trend", "event_id": 1, "event_name": "view_item", "agr": "total" },
    { "type": "trend", "event_id": 5, "event_name": "purchase", "agr": "total" }
  ],
  "funnel_window": 30,
  "funnel_window_unit": "day",
  "funnel_order_type": "ordered"
}
```

{% endcode %}

***

## Ретеншен (`type: "retention"`)

Показывает, какая доля пользователей, выполнивших стартовое действие, вернулась и выполнила его (или другое) повторно через определённое количество дней/недель.

| Поле                        | Тип    | Обязательный | Описание                                                                                                                   |
| --------------------------- | ------ | ------------ | -------------------------------------------------------------------------------------------------------------------------- |
| `target_entity`             | object | да           | Стартовое событие — кого считаем «вошедшим в когорту». Формат: `{ "type": "event", "event_id": ..., "event_name": "..." }` |
| `returning_entity`          | object | да           | Событие, которое считается «возвращением». Тот же формат, что `target_entity`                                              |
| `retention_total_intervals` | int    | нет          | Сколько интервалов показать, по умолчанию `8`                                                                              |
| `granularity`               | string | нет          | Шаг интервала — `day` или `week`                                                                                           |
| `retention_type`            | string | нет          | Логика отбора в когорту — см. таблицу ниже                                                                                 |
| `separators`                | array  | нет          | Разбивка ретеншена по полю                                                                                                 |

| `retention_type`            | Логика                                                                                                               |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `retention_first_time`      | В когорту попадает первое за период действие, подходящее по условию (по умолчанию)                                   |
| `retention_first_time_ever` | В когорту попадает пользователь только если его самое первое действие вообще (без учёта периода) подходит по условию |
| `retention_recurring`       | Пользователь может попадать в несколько когорт — за каждый интервал, в котором выполнил стартовое действие           |

**Пример** (показано содержимое `source_request`; оберните его в полный `report_config` — см. раздел «Конфигурация отчёта»), вернулись ли пользователи, открывшие бота, чтобы открыть его снова через 8 дней:

{% code overflow="wrap" %}

```json
{
  "type": "retention",
  "type_chart": "retention",
  "granularity": "day",
  "retention_total_intervals": 8,
  "target_entity": { "type": "event", "event_id": 1, "event_name": "open_bot" },
  "returning_entity": { "type": "event", "event_id": 1, "event_name": "open_bot" }
}
```

{% endcode %}

***

## Методы

### GET /v1/reports/resources

Возвращает бота (или ботов), к которым у вашего ключа есть доступ. Полезно для ключей из раздела «API-ключи», выданных сразу на несколько ботов — чтобы узнать, какие `resource_key` доступны и какие значения подставлять в остальные методы.

`Resource-Key` для этого метода указывать не нужно.

#### Пример запроса

{% code overflow="wrap" %}

```
GET /v1/reports/resources
Api-Key: YOUR_API_KEY
```

{% endcode %}

#### Ответ

{% code overflow="wrap" %}

```json
{
  "ok": true,
  "data": [
    { "key": "abc123...", "name": "Мой бот", "type": 1 }
  ]
}
```

{% endcode %}

***

### GET /v1/reports/events

Возвращает список событий, которые можно использовать в отчёте по конкретному боту (поле `event_id` в показателях).

#### Параметры

| Параметр       | Тип    | Обязательный                                    | Описание                      |
| -------------- | ------ | ----------------------------------------------- | ----------------------------- |
| `resource_key` | string | только для ключей с доступом к нескольким ботам | См. раздел «Авторизация» выше |

#### Пример запроса

{% code overflow="wrap" %}

```
GET /v1/reports/events
Api-Key: YOUR_API_KEY
```

{% endcode %}

#### Ответ

{% code overflow="wrap" %}

```json
{
  "ok": true,
  "data": [
    { "id": 5, "name": "purchase", "category": "Покупки", "is_global": false }
  ]
}
```

{% endcode %}

***

### GET /v1/reports/event-fields

Возвращает список полей события, которые можно использовать в фильтрах (`filters`). Набор полей фиксирован и не зависит от бота или конкретного события.

#### Пример запроса

{% code overflow="wrap" %}

```
GET /v1/reports/event-fields
Api-Key: YOUR_API_KEY
```

{% endcode %}

#### Ответ

{% code overflow="wrap" %}

```json
{
  "ok": true,
  "data": [
    { "field": "events.value_int", "type": "number", "label": "Числовое значение" }
  ]
}
```

{% endcode %}

`type` — одно из: `number`, `string`, `date`.

***

### GET /v1/reports/utm-labels

Возвращает UTM-метки (источники, каналы, кампании), которые реально встречались у вашего бота — удобно, чтобы предложить пользователю выбор в фильтре, а не угадывать значения.

#### Параметры

| Параметр       | Тип    | Обязательный                                    | Описание                      |
| -------------- | ------ | ----------------------------------------------- | ----------------------------- |
| `resource_key` | string | только для ключей с доступом к нескольким ботам | См. раздел «Авторизация» выше |

#### Пример запроса

{% code overflow="wrap" %}

```
GET /v1/reports/utm-labels
Api-Key: YOUR_API_KEY
```

{% endcode %}

#### Ответ

{% code overflow="wrap" %}

```json
{
  "ok": true,
  "data": {
    "sources": ["telegram", "vk"],
    "mediums": ["cpc", "social"],
    "campaigns": ["spring_sale"]
  }
}
```

{% endcode %}

***

### POST /v1/reports/preview

Прогоняет отчёт без сохранения и возвращает первые 10 строк результата — удобно, чтобы проверить, что отчёт настроен правильно, прежде чем сохранять его.

#### Параметры

| Параметр        | Тип    | Обязательный                                    | Описание                              |
| --------------- | ------ | ----------------------------------------------- | ------------------------------------- |
| `resource_key`  | string | только для ключей с доступом к нескольким ботам | См. раздел «Авторизация» выше         |
| `report_config` | object | да                                              | Конфигурация отчёта — см. раздел выше |

#### Пример запроса

{% code overflow="wrap" %}

```json
POST /v1/reports/preview
Api-Key: YOUR_API_KEY
Content-Type: application/json

{
  "report_config": {
    "source_request": {
      "type": "trends",
      "type_chart": "line",
      "requests": [
        { "type": "trend", "event_id": 5, "event_name": "purchase", "label": "Покупки", "agr": "total" }
      ]
    },
    "settings": {
      "params": { ":date_from": "2026-06-01 00:00:00", ":date_to": "2026-06-29 23:59:59" }
    }
  }
}
```

{% endcode %}

#### Ответ

{% code overflow="wrap" %}

```json
{
  "ok": true,
  "data": {
    "rows": [
      { "date": ["2026-06-01", "2026-06-02"], "total": [12, 18] }
    ],
    "total_estimate": 2
  }
}
```

{% endcode %}

{% hint style="info" %}
В превью пока не поддерживаются когортные фильтры (`in_cohort`/`not_in_cohort`).
{% endhint %}

***

### POST /v1/reports/save

Сохраняет отчёт — после этого он появляется в личном кабинете в разделе «Конструктор отчётов» и доступен через метод `list`.

{% hint style="info" %}
Работает только с пользовательским ключом из раздела «API-ключи» — у сохранённого отчёта должен быть владелец.
{% endhint %}

#### Параметры

| Параметр        | Тип    | Обязательный                                    | Описание                              |
| --------------- | ------ | ----------------------------------------------- | ------------------------------------- |
| `resource_key`  | string | только для ключей с доступом к нескольким ботам | См. раздел «Авторизация» выше         |
| `name`          | string | да                                              | Название отчёта                       |
| `report_config` | object | да                                              | Конфигурация отчёта — см. раздел выше |

#### Пример запроса

{% code overflow="wrap" %}

```json
POST /v1/reports/save
Api-Key: YOUR_API_KEY
Content-Type: application/json

{
  "name": "Покупки по дням",
  "report_config": {
    "source_request": {
      "type": "trends",
      "type_chart": "line",
      "requests": [
        { "type": "trend", "event_id": 5, "event_name": "purchase", "label": "Покупки", "agr": "total" }
      ]
    },
    "settings": {
      "params": { ":date_from": "2026-06-01 00:00:00", ":date_to": "2026-06-29 23:59:59" }
    }
  }
}
```

{% endcode %}

#### Ответ

{% code overflow="wrap" %}

```json
{ "ok": true, "data": { "uuid": "f1b2c3d4-..." } }
```

{% endcode %}

`uuid` — идентификатор сохранённого отчёта, по нему отчёт можно найти в списке (`list`) или открыть в личном кабинете.

***

### GET /v1/reports/list

Возвращает ранее сохранённые отчёты.

{% hint style="info" %}
Работает только с пользовательским ключом из раздела «API-ключи».
{% endhint %}

#### Параметры

| Параметр       | Тип    | Обязательный | Описание                                                                                               |
| -------------- | ------ | ------------ | ------------------------------------------------------------------------------------------------------ |
| `resource_key` | string | нет          | Если указан — вернутся только отчёты этого бота. Если не указан — отчёты по всем доступным ключу ботам |

#### Пример запроса

{% code overflow="wrap" %}

```
GET /v1/reports/list
Api-Key: YOUR_API_KEY
```

{% endcode %}

#### Ответ

{% code overflow="wrap" %}

```json
{
  "ok": true,
  "data": [
    { "uuid": "f1b2c3d4-...", "name": "Покупки по дням", "created_at": "2026-06-29 12:00:00", "resource_key": "abc123..." }
  ]
}
```

{% endcode %}

***

## Возможные ошибки

| Код           | Когда возникает                                                                                                                            |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `400`         | Не передан обязательный параметр (например, `report_config` или `:date_from`/`:date_to`), либо параметр неверного формата                  |
| `401`         | API-ключ не передан или недействителен                                                                                                     |
| `403`         | Метод недоступен на вашем тарифе (требуется Premium), ресурс недоступен этому ключу, либо `save`/`list` вызваны не пользовательским ключом |
| `404`         | Бот по указанному `resource_key` не найден                                                                                                 |
| `500` / `502` | Внутренняя ошибка сервера — повторите запрос позже                                                                                         |

**Пример ошибки:**

{% code overflow="wrap" %}

```json
{ "ok": false, "error": { "errors": "Premium tariff required" }, "error_code": 403 }
```

{% endcode %}
