Перейти к содержанию

Полное описание API

1 Основная информация

Система предоставляет программный интерфейс (публичный API) для интеграции с внешними системами, скриптами и другими инструментами. Публичный API позволяет автоматизировать получение ключевых метаданных платформы.

Публичный API разделён на две базовые поверхности:

Поверхность Базовый путь Модули Аудитория
Публичный RMD API /rmd-api/v1 rmd-api Внешние интеграции, AI-агенты
Публичный DF API /df-api/v1 df-api (витрины, подключения, группы измерений, таблицы фактов, связи, сводный экспорт РПИ) Внешние интеграции, AI-агенты

Базовые принципы, применяемые ко всем вызовам публичного API:

Принцип Описание
Версионирование в URL Публичный API версионируется через путь URL (/v1/). Внутри одной мажорной версии контракт расширяется аддитивно — новые опциональные поля могут появляться, существующие не удаляются и не переименовываются
Версионирование данных Каждый эндпоинт, работающий с РПИ, таблицами фактов, витринами или подключениями, привязан к версии проекта
Read-only Публичный API не изменяет данных, не выполняет запросов в подключённых СУБД и не раскрывает учётных данных СУБД
Контроль лицензии Весь публичный API доступен только при действующей лицензии вызывающей компании
Аудит Каждая попытка аутентификации в публичном API — успешная или неуспешная — записывается в журнал аудита

Базовый URL зависит от среды развертывания:

Среда Базовый URL
On-Premise https://${YOUR_SERVER_HOST}/api
Cloud https://api.[URL системы в облаке]

Примечание: ${YOUR_SERVER_HOST} — это адрес вашего сервера, указанный в переменной окружения SERVER_HOST.

Для всех запросов к API требуется передача заголовка с API-ключом:

Заголовок Тип Обязательный Описание
X-Api-Key string Да Ваш API-ключ, полученный при создании

2 Аутентификация и авторизация

2.1 API-ключ

Публичный API использует долгоживущие API-ключи, генерируемые через управление пользователями. У каждого пользователя в любой момент времени активно не более одного ключа; генерация нового замещает предыдущий. Plaintext ключа показывается оператору один раз и не сохраняется — в таблице api_key хранится только bcrypt-хэш.

ApiKeyGuard (применён ко всем эндпоинтам rmd-api/v1 и df-api/v1) выполняет следующие проверки в указанном порядке на каждом запросе:

  1. Наличие API-ключа. Если заголовок X-Api-Key отсутствует → 401 API_KEY.KEY_MISSING.

  2. Валидность API-ключа. Переданный ключ bcrypt-сравнивается с каждым сохранённым хэшем; при несовпадении → 401 API_KEY.INVALID_KEY.

  3. Статус пользователя. Если найденный пользователь не в статусе ENABLED → 403 API_KEY.ACCOUNT_LOCKED.

  4. IP-фильтрация. IP клиента (из X-Forwarded-For, иначе из соединения) проверяется по белому и чёрному спискам компании. Заблокировано → 403 API_KEY.IP_BLOCKED.

  5. Наличие компании. Если у пользователя нет компании → 403 API.NOT_AVAILABLE_WITHOUT_VALID_LICENSE.

  6. Действующая лицензия. Вызывается LicenseService.checkLimitedAndThrow(companyId). При сбое → 403 API.NOT_AVAILABLE_WITHOUT_VALID_LICENSE. См. раздел 5.

  7. Аудит. Запись об успехе или неудаче записывается в журнал аудита (тип API_ACCESS, действие API_ACCESS_SUCCESSFUL / API_ACCESS_FAILED).

2.2 Роли

Публичный API доступен только на чтение для всех ролей — RolesGuard к нему не применяется, поскольку каждая операция — чтение. Роль пользователя по-прежнему важна для аутентификации ApiKeyGuard (пользователь должен быть в статусе ENABLED).

2.3 IP-фильтрация

IP-фильтрация реализована в CompanyService.checkIp(user, ip) и вызывается на каждом запросе публичного API в составе ApiKeyGuard.

Компания может включить белый список IP, чёрный список IP или оба. Каждый список поддерживает либо точные IPv4-адреса, либо CIDR-диапазоны. При включённом белом списке отклоняются запросы с IP, не входящих в список; при включённом чёрном — запросы с IP, входящих в список. Неуспешные проверки IP пишутся в журнал аудита как API_ACCESS / API_ACCESS_FAILED.

2.4 Throttling

Лимит запросов на API-ключ для публичного API находится в стадии реализации. После реализации успешные ответы будут содержать заголовки X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, а превышение лимита будет возвращать 429 Too Many Requests с кодом RATE_LIMIT_EXCEEDED.

2.5 Контроль лицензии

ApiKeyGuard вызывает LicenseService.checkLimitedAndThrow после аутентификации и IP-фильтра. Вся поверхность публичного API отклоняется при отсутствии действующей лицензии. Возвращаемая ошибка одинакова независимо от конкретной причины: 403 Forbidden с кодом API.NOT_AVAILABLE_WITHOUT_VALID_LICENSE. См. раздел 5 для условий и порядка восстановления.

2.6 Транспортная безопасность

Все эндпоинты публичного API должны обслуживаться по HTTPS с TLS 1.2 или выше. Шаблон on-premises-развёртывания поднимает nginx с терминированием TLS перед бэкендом; сам бэкенд слушает обычный HTTP внутри доверенной сети.

API-ключи хранятся как bcrypt-хэши и никогда не возвращаются в ответах. Полный список полей, не возвращаемых ответами, см. в разделе 6.

3 Общие соглашения по запросам и ответам

3.1 Формат запроса

Свойство Значение
Content-Type application/json для JSON-тел
Charset UTF-8
Заголовок аутентификации X-Api-Key:
Язык Опциональный Accept-Language; query-параметр language имеет приоритет

3.2 Пагинация

List-эндпоинты используют единую форму пагинации. Параметры query:

Параметр Тип По умолчанию Описание
page integer 1 Номер страницы (нумерация с 1)
pageSize integer 20 Максимум 100 на публичном API
Параметры фильтра разные Конкретные фильтры на эндпоинт (описаны inline)

Конверт ответа (list-эндпоинты DF API):

{ "data_marts": [ /* items */ ], "pagination": { "page": 1, "pageSize": 20, "total": 45, "total_pages": 3 } }

Конверт ответа (list-эндпоинты RMD API):

{ "measures": [ /* items */ ], "pagination": { "total": 42, "page": 1, "pageSize": 20, "totalPages": 3 } }

3.3 Локализация

Ответы публичного API учитывают query-параметр language (ru или en). Локализуются только описательные текстовые значения (метки статусов, типов, выпадающих списков); ключи JSON всегда на английском.

3.4 Временные метки

Все временные метки в ответах используют формат ISO 8601 (YYYY-MM-DDTHH:MM:SSZ).

3.5 Форматы вывода

Публичный RMD API и эндпоинты модели данных / экспорта РПИ публичного DF API поддерживают ?format=json (по умолчанию) и ?format=xlsx. При xlsx тело ответа имеет вид { "downloadUrl": "<подписанная ссылка S3, действует 15 минут>" }. Эндпоинты витрин и подключений в DF API возвращают только JSON. Некорректное значение format на эндпоинте DF API возвращает 400 Bad Request с кодом DF_API.INVALID_FORMAT.

4 Обработка ошибок

Публичный API использует единый JSON-конверт:

{ "error": { "code": "string", "message": "string", "details": {} } }

Стандартные HTTP-коды:

Код Значение
200 Успех
400 Bad Request — нарушение валидации, параметра или бизнес-правила
401 Unauthorized — отсутствует или некорректен API-ключ
403 Forbidden — IP заблокирован, учётка заблокирована, лицензия невалидна
404 Not Found — ресурс не существует или недоступен вызывающему
429 Too Many Requests — превышен лимит (планируется)
500 Internal Server Error

Полный каталог кодов — в разделе 10.

5 Проверка лицензии

Проверка лицензии — единственная точка контроля, решающая, разрешён ли публичный API-доступ компании. Она вызывается ApiKeyGuard после аутентификации и IP-фильтра.

LicenseService.checkLimitedAndThrow(companyId) выбрасывает 403 Forbidden при выполнении любого из условий для компании вызывающего:

Условие Описание
У компании отсутствует запись лицензии license равен null
Тип лицензии — NO_LICENSE Заглушка, назначаемая по умолчанию до активации
Статус лицензии — INVALID Истекла, не была валидирована или отозвана
Статус лицензии — SUSPENDED Превышены лимиты лицензии (пользователи, проекты, версии)

Публичный API мапит все эти условия в одну ошибку, чтобы не раскрывать детали состояния лицензии:

HTTP Код Тело
403 API.NOT_AVAILABLE_WITHOUT_VALID_LICENSE { "error": { "code": "API.NOT_AVAILABLE_WITHOUT_VALID_LICENSE", "message": "API is not available without a valid license", "details": {} } }

Неуспешная попытка доступа из-за невалидной лицензии записывается в журнал аудита (тип API_ACCESS, действие API_ACCESS_FAILED).

Чтобы восстановить доступ к API, администратор компании (или, в облачных инсталляциях, Super Admin) должен загрузить действующую лицензию через экран управления лицензиями и удостовериться, что компания не выходит за лимиты по пользователям, проектам и версиям соответствующего тарифа.

6 Ограничения безопасности

Следующие поля никогда не включаются в ответы публичного API:

Поле Причина
password Учётные данные подключения к СУБД и пароль пользователя
ssl_certificate, caCertificateFileName, clientCertificateFileName Сертификатный материал
ssl_key, clientPrivateKeyFileName Закрытые ключи
token, apiKey, key JWT, refresh-токены, API-ключи, сессионные токены
connection_string Может содержать встроенные учётные данные
signature (сущность License) HMAC лицензии; никогда не возвращается клиенту
Любые пользовательские поля учётных данных Чувствительные значения, заданные пользователем

Идентификаторы, намеренно раскрываемые как несекретный контекст:

Поле Причина допуска
username (подключение СУБД) Имя пользователя СУБД — необходимо для построения SQL, не является секретом
host, port, database, schema Сетевые координаты, известные любому, у кого есть доступ на чтение модели данных

Шифрование данных в покое:

Поле Хранилище Шифр
API-ключ api_key.key bcrypt
Пароль удалённой СУБД remote_db.password AES (ключ управляется приложением)
SSL-файлы удалённой СУБД объектное хранилище (MinIO/S3) server-side encryption
Подпись лицензии license.signature HMAC; проверяется, не возвращается

7 Публичный RMD API (rmd-api/v1)

Базовый путь: /rmd-api/v1. Аутентификация: X-Api-Key. Все эндпоинты — read-only и контролируются лицензией компании (раздел 5).

7.1 Список проектов

GET /projects

Параметры query: page, pageSize, format.

Ответ (200 OK):

{ "projects": [ { "id": 12, "name": "Sales Analytics", "description": "Production sales warehouse" } ], "pagination": { "total": 1, "page": 1, "pageSize": 20, "totalPages": 1 } }

7.2 Список версий

GET /projects/{id}/versions

Параметры query: page, pageSize, format.

{ "versions": [ { "id": 33, "name": "Q4 2025", "is_global": true } ], "pagination": { "total": 1, "page": 1, "pageSize": 20, "totalPages": 1 } }

is_global означает опубликованную версию проекта.

7.3 Получение показателей

GET /projects/{id}/versions/{versionId}/measures

Параметры query: language, format, page, pageSize.

{ "measures": [ { "row_number": 1, "group": "Revenue", "block": "Sales", "measure_name": "Total revenue", "measure_description": "Gross revenue across all channels", "original_source_type": "Database", "original_source": { "connection": "Production PostgreSQL", "db": "analytics_db", "schema": "public", "table": "fact_sales", "column": "amount" }, "display_data_type": "Numeric", "measure_type": "base", "formula": null, "status": "Active" } ], "pagination": { "total": 42, "page": 1, "pageSize": 20, "totalPages": 3 } }

Состав возвращаемых ключей соответствует колоночной раскладке РПИ (metricsIdToKeyMap в сервисе). Поля select возвращаются как локализованные подписи; формульные поля содержат ссылки, заменённые с числовых ID на читаемые имена; поля select_db (источник) — структурированный объект с разрешёнными именем подключения, базой данных, схемой, таблицей и колонкой.

При запросе format=xlsx тело ответа имеет вид { "downloadUrl": "<подписанная ссылка S3, действует 15 минут>" }.

7.4 Получение измерений

GET /projects/{id}/versions/{versionId}/dimensions

Возвращает строки измерений в том же конверте, с раскладкой колонок измерений (measurementIdToKeyMap). Параметры query: language, format, page, pageSize.

{ "dimensions": [ { "row_number": 1, "group": "Customer", "block": "Profile", "dimension_name": "Customer name", "dimension_type": "primary", "dimension_group": "Customers", "display_data_type": "Text", "source_data_type": "VARCHAR(255)", "status": "Active" } ], "pagination": { "total": 18, "page": 1, "pageSize": 20, "totalPages": 1 } }

7.5 Получение фактов

GET /projects/{id}/versions/{versionId}/facts

Возвращает строки фактов (factsIdToKeyMap). Параметры query: language, format, page, pageSize.

{ "facts": [ { "row_number": 1, "group": "Sales", "block": "Orders", "fact_name": "Order line", "fact_description": "An individual line item on a sales order", "original_source_type": "Database", "original_source": { "connection": "Production PostgreSQL", "db": "analytics_db", "schema": "public", "table": "fact_order_line", "column": null }, "fact_type": "primary" } ], "pagination": { "total": 6, "page": 1, "pageSize": 20, "totalPages": 1 } }

7.6 Получение полного РПИ

GET /projects/{id}/versions/{versionId}/rmd

Возвращает показатели, измерения и факты в одном payload, страничит каждую секцию независимо.

{ "measures": [ /* см. 7.3 */ ], "dimensions":[ /* см. 7.4 */ ], "facts": [ /* см. 7.5 */ ], "pagination": { "measures": { "total": 42, "page": 1, "pageSize": 20, "totalPages": 3 }, "dimensions": { "total": 18, "page": 1, "pageSize": 20, "totalPages": 1 }, "facts": { "total": 6, "page": 1, "pageSize": 20, "totalPages": 1 } } }

При format=xlsx показатели и измерения объединяются в одну книгу с колонкой type, различающей строки.

8 Публичный DF API (df-api/v1)

Базовый путь: /df-api/v1. Аутентификация: X-Api-Key. Все эндпоинты — read-only.

DF API сгруппирован в шесть логических областей: витрины, подключения, группы измерений, таблицы фактов, связи и сводный экспорт РПИ. Эндпоинты витрин и подключений возвращают только JSON; эндпоинты групп измерений, таблиц фактов, связей и сводного экспорта дополнительно поддерживают ?format=xlsx (см. раздел 3.5).

8.1 Список витрин

GET /projects/{project_id}/versions/{version_id}/data-marts

Параметры query:

Параметр Тип Описание
page, pageSize, language См. раздел 3
type string Фильтр по типу витрины: with_grouping, without_grouping, with_grouping_and_pivoting
merge_type string Фильтр по типу слияния: union, join
search string Поиск без учёта регистра по подстроке в имени и описании

Ответ (200 OK):

{ "data_marts": [ { "id": "57", "name": "Monthly Sales Mart", "description": "Aggregated by month and region", "owner": "Pavel Shalavin", "created_at": "2026-04-15T08:30:00Z", "type": "with_grouping", "merge_type": "union", "source_fact_table_count": 2, "has_physical_view": true } ], "pagination": { "page": 1, "pageSize": 20, "total": 45, "total_pages": 3 } }

8.2 Получение деталей витрины

GET /projects/{project_id}/versions/{version_id}/data-marts/{data_mart_id}

Возвращает полную конфигурацию витрины.

{ "id": "57", "name": "Monthly Sales Mart", "description": "Aggregated by month and region", "owner": "Pavel Shalavin", "created_at": "2026-04-15T08:30:00Z", "type": "with_grouping", "merge_type": "union", "source_fact_tables": [ { "id": "11", "name": "fact_sales", "description": "Primary sales facts" } ], "selected_measures": [ { "instance_id": "204", "measure_id": "501", "measure_name": "Total revenue", "description": "Gross revenue", "formula": "SUM([Amount])", "data_type": "Numeric", "display_name": "Revenue", "aggregation_configuration": { "type": "default", "group_by_fields": [] }, "source_fact_table_id": "11" } ], "selected_facts": [ { "fact_id": "611", "fact_name": "Order line", "data_type": "Numeric", "display_name": "Order line", "include_in_result": true, "filter_condition": null, "source_fact_table_id": "11" } ], "selected_dimensions": [ { "dimension_id": "722", "dimension_name": "Region", "description": "Geographic region", "data_type": "Text", "display_name": "Region", "include_in_result": true, "filter_condition": null, "source_fact_table_id": "11", "source_dimension_group_id": "9", "source_dimension_group_name": "Geography" } ], "physical_view": { "exists": false, "type": null, "database": null, "schema": null, "name": null, "created_at": null } }

Для транспонированных витрин (type = "with_grouping_and_pivoting") ответ дополнительно содержит selected_measure_attributes, в котором неявный ключ транспонирования Measure name всегда добавлен в начало:

"selected_measure_attributes": [ { "attribute_id": "3", "attribute_name": "Measure name" }, { "attribute_id": "27", "attribute_name": "Measure description" } ]

Семантика полей:

Поле Примечания
merge_type null для витрин, не объединяющих несколько таблиц фактов
instance_id Уникальный идентификатор экземпляра показателя
aggregation_configuration.type default, none, custom или global
aggregation_configuration.group_by_fields Идентификаторы column-value полей группировки показателя
include_in_result false — элемент используется только для фильтрации, не попадает в проекцию
filter_condition Выражение фильтра с заменой column-value-ссылок на имена; null, если фильтра нет
source_dimension_group_id / source_dimension_group_name Разрешаются по модели данных, даже если группа измерений не указана явно в атрибутах витрины

8.3 Получение метаданных физического представления

GET /projects/{project_id}/versions/{version_id}/data-marts/{data_mart_id}/view

Возвращает метаданные физического объекта, материализованного DataForge для витрины. Подключение к целевой СУБД не выполняется.

При наличии физического представления:

{ "exists": true, "type": "materialized_view", "database": "analytics_db", "schema": "marts", "name": "monthly_sales", "created_at": "2026-04-21T09:00:00Z", "connection": { "id": "3", "name": "Production PostgreSQL", "db_type": "postgres" } }

При отсутствии:

{ "exists": false, "type": null, "database": null, "schema": null, "name": null, "created_at": null, "connection": null }

type принимает одно из значений regular_view, materialized_view, table.

8.4 Генерация SQL-скрипта

POST /projects/{project_id}/versions/{version_id}/data-marts/{data_mart_id}/generate-sql

Генерирует выражение SQL SELECT. SQL только формируется и возвращается — он не выполняется.

Опциональное тело запроса:

{ "limit": 100, "offset": 0 }

Параметр Тип Описание
limit integer (>0) Добавляет ограничение строк в синтаксисе диалекта (LIMIT n OFFSET m для PostgreSQL/ClickHouse, OFFSET m ROWS FETCH NEXT n ROWS ONLY для MS SQL). offset без limit игнорируется
offset integer (≥0) Смещение строк; имеет смысл вместе с limit

Для MS SQL, если в SQL отсутствует ORDER BY, сервис добавляет ORDER BY (SELECT NULL) для синтаксической валидности OFFSET … FETCH NEXT.

Ответ (200 OK):

{ "sql_script": "SELECT ...\nFROM ...\nGROUP BY ...\nLIMIT 100 OFFSET 0", "target_db_type": "postgres", "validation_errors": [] }

Если генерация SQL завершается ошибкой (повреждённые формулы или отсутствие привязок), ответ остаётся HTTP 200, а сбой описывается в validation_errors:

{ "sql_script": "", "target_db_type": null, "validation_errors": [ { "code": "SQL_GENERATION_FAILED", "message": "Measure 'Revenue' references an unresolved field" } ] }

Такая форма позволяет клиенту отличить «витрина не может сейчас сформировать SQL» от «витрины не существует» (которая возвращает 404).

8.5 Список подключений

GET /projects/{project_id}/versions/{version_id}/connections

Параметры query:

Параметр Тип Описание
page, pageSize, language См. раздел 3
db_type string Фильтр по типу СУБД: postgresql, clickhouse, sqlserver
status string Фильтр по статусу: active, inactive, never_verified, failed

Ответ (200 OK):

{ "connections": [ { "id": "1", "name": "Production PostgreSQL", "db_type": "postgresql", "host": "db.production.company.com", "port": 5432, "database": "analytics_db", "schema": "public", "username": "analytics_user", "status": "active", "last_updated_at": "2026-04-15T08:30:00Z" }, { "id": "2", "name": "Legacy SQL Server", "db_type": "sqlserver", "host": "sqlserver.legacy.company.com", "port": 1433, "database": "legacy_warehouse", "schema": null, "username": "etl_service", "status": "active", "last_updated_at": "2026-04-14T10:00:00Z" } ], "pagination": { "page": 1, "pageSize": 20, "total": 8, "total_pages": 1 } }

Замечания:

  • schema возвращается только для PostgreSQL. Для MS SQL Server схема включается в имя таблицы в других местах системы; для ClickHouse вместо схемы используется имя базы данных.

  • status рассчитывается из внутреннего состояния. Приоритет имеет never_verified — без отметки об успешном обновлении система не может утверждать состояние. failed соответствует внутреннему UPDATE_ERROR. inactive соответствует DISABLED. В остальных случаях статус — active.

8.6 Получение деталей подключения

GET /projects/{project_id}/versions/{version_id}/connections/{connection_id}

Параметры query:

Параметр Тип По умолчанию Описание
language string en Локализация
include_db_schema boolean false При true облегчённый массив db_tables заменяется полным объектом db_schema

Ответ (200 OK) — include_db_schema=false:

{ "id": "1", "name": "Production PostgreSQL", "db_type": "postgresql", "host": "db.production.company.com", "port": 5432, "database": "analytics_db", "schema": "public", "username": "analytics_user", "status": "active", "last_updated_at": "2026-04-15T08:30:00Z", "db_tables": [ { "name": "fact_sales" }, { "name": "dim_customer" } ] }

Ответ (200 OK) — include_db_schema=true:

{ "id": "1", "name": "Production PostgreSQL", "db_type": "postgresql", "host": "db.production.company.com", "port": 5432, "database": "analytics_db", "schema": "public", "username": "analytics_user", "status": "active", "last_updated_at": "2026-04-15T08:30:00Z", "db_schema": { "tables": [ { "table_name": "fact_sales", "schema": "public", "columns": [ { "column_name": "sale_id", "data_type": "int" }, { "column_name": "sale_date", "data_type": "datetime" }, { "column_name": "amount", "data_type": "decimal(18,2)" } ] } ] } }

8.7 Получение схемы подключения

GET /projects/{project_id}/versions/{version_id}/connections/{connection_id}/schema

Возвращает только закешированную схему (таблицы и колонки) подключения.

{ "id": "1", "name": "Production PostgreSQL", "db_type": "postgresql", "last_updated_at": "2026-04-15T08:30:00Z", "schema": { "tables": [ { "table_name": "fact_sales", "schema": "public", "columns": [ { "column_name": "sale_id", "data_type": "int" }, { "column_name": "sale_date", "data_type": "datetime" } ] } ] } }

Возвращаемая схема — закешированный снимок, снятый при настройке подключения или ручном обновлении. Он не отражает изменения целевой СУБД в реальном времени. Поле last_updated_at фиксирует момент снятия снимка.

8.8 Список групп измерений

GET /projects/{project_id}/versions/{version_id}/dimension-groups

Возвращает группы измерений (справочники) текущей версии проекта с их первичным ключом, составом измерений и идентификаторами таблиц фактов, ссылающихся на группу.

Параметры query: page, pageSize, language, format.

Ответ (200 OK):

{ "dimension_groups": [ { "id": "9", "name": "Geography", "description": "Geographic regions and countries", "primary_key": { "db": "analytics_db", "schema": "public", "table": "dim_geography", "column": "region_id" }, "dimensions": [ { "id": "722", "name": "Region", "level": 1, "data_type": "Text", "physical_column": "region_name" }, { "id": "723", "name": "Country", "level": 2, "data_type": "Text", "physical_column": "country_code" } ], "related_fact_tables": ["11", "14"], "created_at": "2026-04-15T08:30:00Z" } ], "pagination": { "page": 1, "pageSize": 20, "total": 12, "total_pages": 1 } }

Поле Примечания
primary_key null, если у группы не разрешён физический ключ. db и schema могут быть null для типов источников, не разделяющих их (например, ClickHouse)
dimensions Члены группы, упорядочены по уровню иерархии. data_type — локализованный отображаемый тип; physical_column — имя колонки в исходной таблице
related_fact_tables Строковые ID таблиц фактов, ссылающихся на группу; полная конфигурация доступна через 8.10 / 8.11

При format=xlsx ответ — { "downloadUrl": "<подписанная ссылка S3>" }, книга содержит один лист Dimension Groups со строками списка.

8.9 Получение деталей группы измерений

GET /projects/{project_id}/versions/{version_id}/dimension-groups/{dimension_group_id}

Возвращает полную конфигурацию одной группы измерений, включая связанные таблицы фактов с колонками внешних ключей.

Параметры query: language, format.

Ответ (200 OK):

{ "id": "9", "name": "Geography", "description": "Geographic regions and countries", "primary_key": { "db": "analytics_db", "schema": "public", "table": "dim_geography", "column": "region_id" }, "related_fact_tables": [ { "fact_table_id": "11", "fact_table_name": "fact_sales", "foreign_key_column": "region_id" }, { "fact_table_id": "14", "fact_table_name": "fact_inventory", "foreign_key_column": "region_id" } ], "created_at": "2026-04-15T08:30:00Z", "updated_at": "2026-04-21T11:15:00Z" }

Если группа не существует в указанной версии, API возвращает 404 Not Found с кодом DF_API.DIMENSION_GROUP_NOT_FOUND.

8.10 Список таблиц фактов

GET /projects/{project_id}/versions/{version_id}/fact-tables

Возвращает таблицы фактов текущей версии проекта со счётчиками элементов.

Параметры query: page, pageSize, language, format.

Ответ (200 OK):

{ "fact_tables": [ { "id": "11", "name": "fact_sales", "description": "Primary sales facts", "owner": "Pavel Shalavin", "created_at": "2026-04-15T08:30:00Z", "measures_count": 5, "dimensions_count": 3, "facts_count": 2, "verification_filters_count": 2, "related_dimension_groups_count": 1 } ], "pagination": { "page": 1, "pageSize": 20, "total": 6, "total_pages": 1 } }

dimensions_count учитывает только измерения, добавленные непосредственно в таблицу фактов (т. е. не входящие ни в одну группу измерений). Измерения, унаследованные через группы, доступны через related_dimension_groups_count и через эндпоинт деталей.

При format=xlsx книга содержит один лист Fact Tables.

8.11 Получение деталей таблицы фактов

GET /projects/{project_id}/versions/{version_id}/fact-tables/{fact_table_id}

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

Параметры query:

Параметр Тип По умолчанию Описание
language string en Локализация
include_dependencies boolean false При true каждая мера несёт рекурсивное дерево dependencies, разрешающее ссылки формулы до целевых мер
format string json json или xlsx

Ответ (200 OK):

{ "id": "11", "name": "fact_sales", "description": "Primary sales facts", "owner": "Pavel Shalavin", "created_at": "2026-04-15T08:30:00Z", "updated_at": "2026-04-21T09:00:00Z", "measures": [ { "id": "501", "name": "Total revenue", "description": "Gross revenue", "formula": "SUM([Amount])", "data_type": "Numeric", "measure_type": "base", "dependencies": null } ], "dimensions": [ { "id": "801", "name": "Sale date", "description": "Calendar date of the sale", "data_type": "Date", "physical_column": "sale_date", "is_from_dimension_group": false, "dimension_group_id": null } ], "facts": [ { "id": "611", "name": "Order line", "description": null, "data_type": "Numeric", "fact_type": "primary", "formula": null, "physical_column": "amount" } ], "dimension_groups": [ { "id": "9", "name": "Geography", "description": "Geographic regions and countries", "primary_key": { "db": "analytics_db", "schema": "public", "table": "dim_geography", "column": "region_id" }, "foreign_key": { "db": "analytics_db", "schema": "public", "table": "fact_sales", "column": "region_id" } } ], "verification_filters": [ { "id": "301", "name": "Valid sales only", "description": "Excludes test and cancelled orders", "conditions": "[Status] != 'cancelled'", "is_valid": true, "invalid_reason": null } ] }

Поле Примечания
measure_type base (источник напрямую) или calculated (производный по формуле)
fact_type primary, derived или constant
is_from_dimension_group true — измерение унаследовано из связанной группы; false — задано прямо в таблице фактов
dependencies Присутствует и заполняется только при include_dependencies=true. Узел содержит id, name, type, formula и рекурсивный массив dependencies
verification_filters[].is_valid false, если выражение фильтра не разрешается (отсутствующая ссылка, ошибка синтаксиса). invalid_reason несёт локализованное объяснение

При format=xlsx книга содержит пять листов: Measures, Dimensions, Facts, Dimension Groups, Verification Filters.

Если таблица фактов не существует в указанной версии, API возвращает 404 Not Found с кодом DF_API.FACT_TABLE_NOT_FOUND.

8.12 Список связей

GET /projects/{project_id}/versions/{version_id}/relationships

Возвращает связи внешних ключей между таблицами фактов и группами измерений в текущей версии проекта.

Параметры query:

Параметр Тип Описание
page, pageSize, language См. раздел 3
fact_table_id integer Фильтр: связи с указанной таблицей фактов в качестве источника
dimension_group_id integer Фильтр: связи с указанной группой измерений в качестве цели
format string json или xlsx

Ответ (200 OK):

{ "relationships": [ { "id": "1101", "source_fact_table": { "id": "11", "name": "fact_sales" }, "target_dimension_group": { "id": "9", "name": "Geography" }, "foreign_key": { "db": "analytics_db", "schema": "public", "table": "fact_sales", "column": "region_id" }, "primary_key": { "db": "analytics_db", "schema": "public", "table": "dim_geography", "column": "region_id" }, "relationship_type": "many_to_one", "created_at": "2026-04-15T08:30:00Z" } ], "pagination": { "page": 1, "pageSize": 20, "total": 4, "total_pages": 1 } }

relationship_type описывает кратность от источника (таблицы фактов) к цели (группе измерений). foreign_key и primary_key могут быть null, если соответствующий маппинг неполный; в этом случае связь видна, но не пригодна для построения SQL-join'а.

8.13 Получение деталей связи

GET /projects/{project_id}/versions/{version_id}/relationships/{relationship_id}

Возвращает одну связь с описательными полями обеих сторон.

Параметры query: language, format.

Ответ (200 OK):

{ "id": "1101", "source_fact_table": { "id": "11", "name": "fact_sales", "description": "Primary sales facts" }, "target_dimension_group": { "id": "9", "name": "Geography", "description": "Geographic regions and countries", "primary_key": { "db": "analytics_db", "schema": "public", "table": "dim_geography", "column": "region_id" } }, "foreign_key": { "db": "analytics_db", "schema": "public", "table": "fact_sales", "column": "region_id" }, "primary_key": { "db": "analytics_db", "schema": "public", "table": "dim_geography", "column": "region_id" }, "relationship_type": "many_to_one", "created_at": "2026-04-15T08:30:00Z", "updated_at": "2026-04-21T11:15:00Z" }

Если связь не существует в указанной версии, API возвращает 404 Not Found с кодом DF_API.RELATIONSHIP_NOT_FOUND.

8.14 Сводный экспорт РПИ

GET /projects/{project_id}/versions/{version_id}/rmd

Возвращает полный снимок метаданных версии проекта — содержимое РПИ (показатели, измерения, факты) и модели данных (группы измерений, таблицы фактов, связи) — в одном payload плюс отметку времени exported_at. Предназначен для внешних каталогов и полной синхронизации состояния.

Параметры query: language, format.

Ответ (200 OK):

{ "project": { "id": "12", "name": "Sales Analytics", "description": "Production sales warehouse" }, "version": { "id": "33", "name": "Q4 2025", "is_global": true }, "measures": [ /* такая же форма строк, как в 7.3 */ ], "dimensions": [ /* такая же форма строк, как в 7.4 */ ], "facts": [ /* такая же форма строк, как в 7.5 */ ], "dimension_groups": [ /* такая же форма строк, как в 8.8 */ ], "fact_tables": [ /* такая же форма строк, как в 8.10 */ ], "relationships": [ /* такая же форма строк, как в 8.12 */ ], "exported_at": "2026-05-05T08:30:00Z" }

При format=xlsx книга содержит шесть листов — Measures, Dimensions, Facts, Dimension Groups, Fact Tables, Relationships — а тело ответа имеет вид { "downloadUrl": "<подписанная ссылка S3>" }.

Этот эндпоинт — публичный аналог унаследованного rmd-api/v1 /rmd (7.6), расширенный сущностями модели данных. Любой из эндпоинтов можно использовать для содержимого РПИ; модель данных раскрывает только эндпоинт DF API.

9 Журналирование аудита

События аутентификации в публичном API записываются с типом, действием, актором, IP-источником, целевым объектом и свободным полем what:

Событие Тип Действие Триггер
Успешная аутентификация в API API_ACCESS API_ACCESS_SUCCESSFUL Запрос публичного API прошёл все проверки ApiKeyGuard
Неуспешная аутентификация в API API_ACCESS API_ACCESS_FAILED Учётка заблокирована, IP заблокирован или лицензия невалидна

Поля журнала аудита:

Поле Значение
type Категория события (API_ACCESS)
action Конкретное действие в категории
who Email актора (владелец API-ключа)
from_where IP клиента (учитывается X-Forwarded-For)
where Имя компании
what Группа эндпоинтов (RmdApi v1 / DfApi v1)
before, after Diff для событий изменения (не используется в read-only API)

Срок хранения журнала задаётся настройками компании; записи доступны на экране Audit Log пользователям с ролью Company Admin или Super Admin. События аудита внутреннего API (вход в UI, управление лицензиями и т. п.) описаны в главе 8.

10 Справочник кодов ошибок

В таблице сведены коды ошибок публичного API.

Код HTTP Поверхность Описание
API_KEY.KEY_MISSING 401 оба Заголовок X-Api-Key не передан
API_KEY.INVALID_KEY 401 оба API-ключ не соответствует ни одному сохранённому
API_KEY.INVALID_ENCRYPTED_API_KEY 400 оба Зашифрованный payload ключа не удалось декодировать
API_KEY.AUTH_FAILED 401 оба Общий сбой аутентификации
API_KEY.ACCOUNT_LOCKED 403 оба Пользователь не в статусе ENABLED
API_KEY.IP_BLOCKED 403 оба IP клиента в чёрном списке или вне белого списка
API.NOT_AVAILABLE_WITHOUT_VALID_LICENSE 403 оба У компании нет действующей лицензии
PROJECT.NOT_FOUND 404 rmd-api Проект не существует или недоступен
VERSION.NOT_FOUND 404 rmd-api Версия не существует или недоступна
DF_API.INVALID_PARAMETER 400 df-api Параметр пути или query не прошёл валидацию
DF_API.PAGE_SIZE_EXCEEDED 400 df-api pageSize превышает 100
DF_API.INVALID_TYPE 400 df-api Некорректное значение фильтра type для витрин
DF_API.INVALID_MERGE_TYPE 400 df-api Некорректное значение фильтра merge_type для витрин
DF_API.INVALID_DB_TYPE 400 df-api Некорректное значение фильтра db_type для подключений
DF_API.INVALID_STATUS 400 df-api Некорректное значение фильтра status для подключений
DF_API.INVALID_FORMAT 400 df-api format отличается от json и xlsx
DF_API.PROJECT_NOT_FOUND 404 df-api Проект не существует или недоступен
DF_API.VERSION_NOT_FOUND 404 df-api Версия не существует или недоступна
DF_API.DATA_MART_NOT_FOUND 404 df-api Витрина не существует в указанной версии
DF_API.CONNECTION_NOT_FOUND 404 df-api Подключение не существует в указанной версии
DF_API.DIMENSION_GROUP_NOT_FOUND 404 df-api Группа измерений не существует в указанной версии
DF_API.FACT_TABLE_NOT_FOUND 404 df-api Таблица фактов не существует в указанной версии
DF_API.RELATIONSHIP_NOT_FOUND 404 df-api Связь не существует в указанной версии
SQL_GENERATION_FAILED 200 (в validation_errors) df-api Витрина не может сейчас сформировать SQL
RATE_LIMIT_EXCEEDED 429 оба Превышена квота запросов на ключ (планируется)
INTERNAL_ERROR 500 оба Непредвиденная ошибка сервера