Оформление
Работа через REST API
Всё, что делается в интерфейсе, платформа умеет делать и запросом: подключить источник, собрать датасет, построить виджет, получить данные. Часть возможностей существует только здесь — перечень в разделе Ограничения.
Эта страница — про общие правила: куда обращаться, как авторизоваться, как устроены ответы и ошибки. Разбор отдельных подсистем — по ссылкам в конце.
Адрес и описание
Единого адреса у платформы нет: она ставится в контуре организации, поэтому база — это адрес вашей установки плюс /api. Дальше в примерах он записан как http://<адрес>.
Машиночитаемое описание всех методов платформа отдаёт сама, в формате OpenAPI 3:
bash
curl -s http://<адрес>/api/v3/api-docs > openapi.jsonВ текущей версии это 140 путей и 202 операции. Файл годится и для генератора клиента, и для импорта в Postman или Insomnia — отдельного SDK платформа не поставляет.
Авторизация
Все методы, кроме входа, требуют заголовок Authorization: Bearer <токен>. Токенов два вида, и они решают разные задачи.
Токен сеанса: вход логином и паролем
bash
curl -s -X POST http://<адрес>/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"reader","password":"…"}'Ответ:
json
{
"data": {
"token": "eyJhbGciOi…",
"refresh_token": "0f2c…",
"token_type": "Bearer",
"expires_in": 900
},
"success": true
}expires_in — 900 секунд, то есть пятнадцать минут. Дальше либо новый вход, либо продление через POST /api/auth/refresh с телом {"refresh_token": "…"}. POST /api/auth/logout отзывает все обновляющие токены пользователя.
Дальше в примерах токен подставляется из переменной T — положите в неё своё значение, чтобы команды можно было копировать как есть:
bash
T="eyJhbGciOi…"Права попадают в токен в момент выдачи
Токен несёт список групп пользователя таким, каким он был при входе. Добавили человека в группу — его текущий токен об этом не узнает, и запрос по-прежнему ответит 403 Доступ запрещён. Нужен новый вход. То же касается интерфейса: пользователь должен выйти и войти заново, иначе новые права не появятся.
Постоянный токен: для интеграций
Токен сеанса живёт четверть часа и для скрипта в расписании неудобен. Для постоянного доступа заводится API-токен — тот же, что выдаётся AI-агенту:
bash
curl -s -X POST http://<адрес>/api/mcp-tokens \
-H "Authorization: Bearer $T" -H "Content-Type: application/json" \
-d '{"name":"выгрузка в хранилище","description":"ночной скрипт"}'В ответе придёт строка вида dwmcp_… — она показывается один раз, сохраните её сразу.
Выпуск разрешён не всем: нужен подходящий тип учётной записи, членство в группе доступа и включённый администратором рубильник — условия перечислены в разделе Кому разрешено. Если чего-то не хватает, запрос отвечает «Выпуск и работа MCP-токенов отключены администратором платформы» или отказом по правам.
Этот токен работает не только для AI-агента
Несмотря на название, dwmcp_… принимается любым методом REST API — платформа различает вид токена по префиксу. Проверено: список виджетов и запрос данных виджета этим токеном отрабатывают штатно. Действует он от имени владельца и с его правами, приостанавливается и отзывается в профиле — выпуск и управление токенами.
Формат ответа
Успешный и неуспешный ответы имеют одинаковую оболочку — по полю success их и различают:
json
{ "data": { … }, "success": true }
{ "error": { "code": 404, "message": "Виджет не найден (id 999999)",
"timestamp": "2026-08-27T00:12:03Z" }, "success": false }Сообщение в message человекочитаемое и на русском — его можно показывать пользователю скрипта как есть. Ошибки валидации добавляют объект errors с разбором по полям:
json
{ "error": { "code": 422, "errors": { "parameters[0].primitiveType": "must not be blank" },
"message": "Ошибка валидации" }, "success": false }| Код | Когда приходит |
|---|---|
| 400 | Тело разобрано, но запрос невыполним: «Сравнить можно только с соседней стадией», «К стадии можно привязать только командное пространство» |
| 401 | Токена нет, он истёк или подпись не сходится |
| 403 | Прав не хватает — роли, типа учётной записи или членства в группе |
| 404 | Объекта с таким идентификатором нет или он в другом пространстве |
| 422 | Ошибка валидации тела: в errors перечислены поля |
| 500 | Сбой на стороне платформы. Стоит воспроизвести и передать разработке — в ответе подробностей нет, они в журнале сервиса |
Списки: страницы, фильтры, поиск
Списочные методы (/api/widget, /api/dataset, /api/data-source, /api/dashboard) устроены одинаково:
bash
curl -s -H "Authorization: Bearer $T" \
"http://<адрес>/api/widget?page=1&size=20&sort=name,asc&query=выручка"json
{ "data": { "content": [ … ],
"page": { "size": 20, "number": 1, "total_elements": 50, "total_pages": 3 } },
"success": true }Нумерация страниц списков начинается с нуля: в примере page=1 — вторая страница. У данных виджета нумерация своя, с единицы. Кроме page, size и sort списки принимают отбор:
| Параметр | Что делает |
|---|---|
query | Поиск по названию |
type | Отбор по типу объекта — например, тип виджета или тип источника |
author | Идентификатор автора |
workspaceId | Пространство, в котором искать |
createdAtFrom, createdAtTo | Диапазон по дате создания |
updatedAtFrom, updatedAtTo | То же по дате изменения |
Из чего состоит API
| Группа | Путей | О чём |
|---|---|---|
| Источники | 17 | Подключения, проверка связи, метаданные, объекты, данные, SQL-запросы, журнал обращений |
| Датасеты | 17 | Состав, схема, связи, значения полей, зависимости, настройки извлечения, RLS и CLS |
| Пользователи и группы | 12 | Учётные записи, членство, атрибуты для RLS, пароль |
| Вход и провайдеры | 12 | Логин, продление, SSO (7) и настройка внешних провайдеров (5) |
| Конвейеры | 7 | Развёртывание объектов между пространствами — Конвейеры развёртывания |
| Администрирование | 6 | Типы источников, драйверы, AI-провайдер |
| Публичные ссылки | 11 | Выпуск и отзыв ссылок на дашборд, страница зрителя — публикация по ссылке |
| Дашборды | 5 | Список, реквизиты, схема, данные |
| Пространства и перенос | 5 | Пространства, участники и роли, перенос объектов из личного в общее |
| API-токены | 5 | Выпуск, приостановка, отзыв |
| Виджеты | 4 | Список, реквизиты, данные — POST /api/widget/{id}/data |
| Уведомления | 4 | Список, счётчик непрочитанных, отметка о прочтении |
| Доступ | 3 | Права на объект для пользователя и группы |
| Запуски ETL | 3 | Состояние запуска, история, отмена |
| AI-помощник | 4 | Проверка доступа, генерация формулы, SQL и кода виджета |
| Выгрузка в файл | 4 | Задание выгрузки, его состояние, файл, пределы — выгрузка в файл |
| Рассылки | 10 | Рассылки, пауза и запуск, оценка срезов, история и письма запуска — рассылки |
| Почтовые каналы | 3 | SMTP-каналы рассылок и тестовая отправка |
| Рендер | 4 | Служебные пути страницы, которую снимает выгрузка; клиенту не нужны |
| Файлы | 2 | Загрузка и удаление файла-источника |
| Служебное | 2 | Настройки установки и словарь интерфейса |
Итого 140 путей: сумма по таблице.
Запись схемы датасета
Самый неочевидный метод API — PUT /api/dataset/{id}/schema. Он записывает всю схему датасета целиком: таблицы, поля, связи, иерархии, фильтры и параметры. Частичного обновления нет: что не прислали — то удалится.
Порядок работы всегда один: прочитать текущее состояние, изменить нужное, отправить обратно.
bash
# 1. читаем
curl -s -H "Authorization: Bearer $T" http://<адрес>/api/dataset/1413 > ds.json
# 2. правим блоки objects / fields / relations / hierarchies / filters / parameters
# 3. отправляем целиком
curl -s -X PUT -H "Authorization: Bearer $T" -H "Content-Type: application/json" \
-d @ds-new.json http://<адрес>/api/dataset/1413/schemaТело — шесть массивов:
json
{ "objects": [ … ], "fields": [ … ], "relations": [ … ],
"hierarchies": [ … ], "filters": [ … ], "parameters": [ … ] }Четыре правила, без которых запрос не пройдёт
- Новым объектам и полям нужен временный отрицательный идентификатор, а ссылки на них делаются по нему же: поле нового объекта указывает
"object_id": -1. Иначе — «Object id is required (use a negative temp id for new objects)». - У производных полей нельзя присылать
formula: она собирается платформой изderivation. Иначе — «formula у производного поля генерируется из derivation и не принимается». - Тип поля не меняется: обычное поле нельзя превратить в вычисляемое и наоборот — «Field kind cannot change (calculated ↔ physical)». Нужно новое поле.
- Ссылки на несуществующие идентификаторы (например,
sort_by_field_idот другого датасета) отвечают «Поле датасета не найдено (id …)».
Параметр в теле задаётся так — обратите внимание, что default_value строковое, а область значений лежит в domain:
json
{ "name": "Скидка", "primitive_type": "number", "default_value": "10",
"domain": { "kind": "range", "min": "0", "max": "50", "step": "1" }, "order": 0 }kind бывает any, list (со списком values) и range. Что параметр делает при просмотре — Параметры.
Типовые операции
Примеры ниже сняты с работающей установки 27.08 — их можно повторить, подставив свой адрес и токен. Полный список полей у каждого метода — в openapi.json.
Подключить источник и проверить связь:
bash
curl -s -X POST http://<адрес>/api/data-source/check \
-H "Authorization: Bearer $T" -H "Content-Type: application/json" \
-d '{"type":"clickhouse","settings":{"host":"clickhouse","port":8123,"http_port":8123,
"username":"reader","password":"…","db":"sales","use_ssh":false}}'
curl -s -X POST http://<адрес>/api/data-source \
-H "Authorization: Bearer $T" -H "Content-Type: application/json" \
-d '{"name":"Продажи","type":"clickhouse","settings":{ … }}'Создать датасет поверх источника (workspace_id — пространство, live: true — прямой запрос):
bash
curl -s -X POST http://<адрес>/api/dataset \
-H "Authorization: Bearer $T" -H "Content-Type: application/json" \
-d '{"name":"Продажи: витрина","workspace_id":5,"live":true,"data_source_ids":[1363]}'Дальше в датасет пишется схема — Запись схемы датасета.
Создать виджет: полки задаются массивами rows (категории), series, columns (меры); у каждого поля — sql с выражением и свой id, на который ссылается сортировка.
bash
curl -s -X POST http://<адрес>/api/widget \
-H "Authorization: Bearer $T" -H "Content-Type: application/json" \
-d '{ "name":"Топ городов","type":"bar","dataset_id":1413,
"rows":[{"id":"r1","alias":"Город","field":"city","table":"customers",
"sql":"[customers.city]","settings":{}}],
"columns":[{"id":"c1","alias":"Выручка","field":"amount","table":"orders",
"sql":"SUM([orders.amount])","settings":{}}],
"series":[],"filters":[],"sorts":[{"field_id":"c1","direction":"desc"}] }'Вычисляемые поля датасета нужно передавать самому
Если на полке стоит вычисляемое поле датасета (ссылка без точки — [unit_price], а не [orders.amount]), в теле запроса должен быть блок calculated_fields с его определением:
json
"calculated_fields": [
{ "id": "135267", "name": "unit_price", "alias": "Цена за единицу",
"primitive_type": "float", "sql": "[orders.amount] / [orders.quantity]" }
]Платформа не подставляет определения из датасета сама: без этого блока и создание, и выборка отвечают «Определение вычисляемого поля не найдено: …». Идентификатор, имя и формулу берут из GET /api/dataset/{id}, из блока fields — это те поля, у которых заполнено formula, а object_id пустой.
Получить данные виджета — тем же телом, что и при создании, плюс при необходимости фильтры и значения параметров:
bash
curl -s -X POST http://<адрес>/api/widget/1531/data \
-H "Authorization: Bearer $T" -H "Content-Type: application/json" \
-d '{ "type":"bar", "rows":[ … ], "columns":[ … ], "series":[], "sorts":[],
"filters":[{"sql":"[customers.city]","op":"in","values":["Казань"],
"value_type":"string"}],
"parameters":{"Скидка":50} }'Ответ — плоские строки, где ключи совпадают с id полей на полках:
json
{ "data": { "kind": "flat",
"rows": [ { "r1": "Казань", "c1": 40708500.0 } ],
"page": { "page": 1, "pageSize": 20, "hasMore": false } },
"success": true }У показателя (KPI) форма ответа другая — "kind": "kpi" и объект row вместо массива.
Условия отбора складываются по «И»
Фильтры из тела запроса платформа соединяет с сохранёнными фильтрами виджета — все условия действуют одновременно. Взаимоисключающие условия по одному полю дают пустой результат: это тот же механизм, что и у фильтров дашборда.
Выпустить публичную ссылку на дашборд: реестр ссылок — GET|POST /api/dashboard/{id}/share-links, правка и отзыв — PUT|DELETE /api/dashboard/{id}/share-links/{linkId}, приостановка и возобновление — .../suspend и .../activate, смена адреса — .../rotate. Сторона зрителя живёт под /api/public/link/{token}: сама ссылка, /dashboard, /widget/{id}, /widget/{id}/data, /dataset/{id}/field-values и /unlock для ссылки с паролем. Ответ /unlock даёт подтверждение, которое дальше передаётся заголовком X-Share-Grant. Разбор — Публикация по ссылке.
Запустить синхронизацию и следить за ней: запуски датасета — /api/datasets/{id}/extracts, состояние и история конкретного запуска — /api/etl-jobs/{jobId} и /api/etl-jobs/{jobId}/history, отмена — /api/etl-jobs/{jobId}/cancel. Что происходит внутри — Синхронизация и ETL, шаги запуска — журнал запуска.
Что доступно только через API
Разовая подстановка параметра, просмотр от имени другого пользователя и пределы выгрузки в интерфейсе не представлены — они делаются только запросом. Полный перечень с ссылками на разборы, а заодно список значений, которые задаются только настройками установки, — ограничения текущей версии.
Что дальше
- Конвейеры развёртывания — перенос источников, датасетов и виджетов между контурами разработки, теста и эксплуатации.
- AI-помощник и MCP — тот же продукт для языковой модели: 90 инструментов поверх этого же API.
- Справочник инструментов MCP — что именно умеет агент.