Skip to main content
Это руководство — сквозной пример чтения /v1 в Power BI. Оно охватывает шаблон подключения на Power Query (M), семантическую модель по схеме «звезда», построенную на /v1/activities, инкрементальное обновление, а также случаи, когда следует использовать предварительные наборы данных reporting для получения результатов фишинга по отдельным сотрудникам. В примерах используется производственный хост для США (https://api.us-east-1.livingsecurity.ai/v1). Для организации из ЕС используйте https://api.eu-west-1.livingsecurity.ai/v1 в Fn_FetchAll и Fn_GetJson, а затем привяжите учётные данные источника данных к этому хосту. См. Regions. В этом руководстве используются сохранённые учётные данные Basic с ключом API. Клиент OAuth не требуется. Варианты учётных данных описаны в разделе Authentication, а сведения о доступе и настройке — в Developer Hub.

Для чего предназначен этот пример

Используйте его, когда необходимо:
  • Загрузить списочные конечные точки /v1 в набор данных Power BI с корректной постраничной навигацией на основе курсора и повторными попытками при превышении лимита запросов.
  • Построить семантическую модель, в которой меры («активные сущности», «действия на одну активную сущность») являются многомерными, а не подсчитываются по плоской таблице.
  • Перевести плановое обновление Power BI с полного прохода по всей истории на небольшое ежедневное окно с помощью инкрементального обновления.
  • Выбрать подходящую детализацию данных о фишинге: итоги по кампаниям (операционные) или результаты по отдельным сотрудникам и типизированные события (предварительная версия reporting).

Предварительные требования

  • Ключ API с разрешениями, необходимыми для ваших запросов:
    • Операционный пример: activity:read, entity:read и simulation:read.
    • Данные о фишинге по отдельным сотрудникам через наборы данных reporting: reporting:read. См. API keys.
  • Power BI Desktop или рабочая область Power BI / Fabric, в которой можно создать семантическую модель и настроить расписание обновления.

Выбор подходящей детализации

/v1 предоставляет две связанные области данных о фишинге. Они не взаимозаменяемы. Приведённые ниже примеры запросов Power BI обращаются к операционным маршрутам (/v1/simulations, /v1/simulations/{id}/results, /v1/activities, /v1/entities). Для отчётности по фишингу на уровне отдельных сотрудников предпочтительно использовать семейство предварительных маршрутов reporting, описанное ниже. Ключ, которому предоставлено только reporting:read, не может вызывать операционный /v1/simulation_results (API возвращает 403).

Шкала сложности

Сложность симуляции — целое число от 1 до 5 в свойствах /v1/simulations (difficulty_level), /v1/simulation_results (difficulty_level), /v1/activities (difficulty_tier) и /v1/reporting/simulation_events (difficulty_tier). 1 — самый лёгкий уровень, 5 — самый сложный. У адаптивных и прогрессивных симуляций нет единого значения на уровне кампании, поэтому /v1/simulations.difficulty_level равно null, при этом difficulty_level для отдельного получателя в результатах всё равно может быть задано. Для сопоставления с прежними экспортами low/medium/high считайте 1–2 низким, 3 средним, а 4–5 — высоким.
Не создавайте новые интеграции для BI на основе недокументированных сетевых вызовов Панели управления или устаревшего кураторского обзора Public API /api/v1. Выполняйте аутентификацию на региональном хосте /v1 вашей организации с помощью ключа API из Developer Hub. См. Regions.

Шаблон подключения (Power Query)

В основе каждого запроса в примере лежат четыре правила. Каждое из них продиктовано службой Power BI, а не стилистическими предпочтениями.
Всё динамическое поместите в RelativePath и Query. Первый аргумент Web.Contents должен быть строковым литералом, заканчивающимся на корне регионального /v1 вашей организации:
  • США: https://api.us-east-1.livingsecurity.ai/v1
  • ЕС: https://api.eu-west-1.livingsecurity.ai/v1
Затем вызывающий код передаёт только ресурс ("simulations", а не "v1/simulations"). Не вставляйте хост для США для организации из ЕС.Если первый аргумент формируется конкатенацией строк, служба Power BI не может статически определить источник данных, и плановое обновление завершается ошибкой «dynamic data source», хотя в Power BI Desktop запрос работает.
Когда Power BI запрашивает учётные данные для источника данных /v1, выберите Basic и вставьте ключ API в поле username. В поле Пароль введите заполнитель, например x. Служба Power BI отклоняет пустой пароль, хотя API это поле игнорирует. Вариант с ключом в качестве пароля и заполнителем в качестве имени пользователя также работает.Не добавляйте заголовок Authorization в M. Он работает на вашем компьютере, но затем встраивает ключ в файл запроса и конфликтует с плановым обновлением.
GET /v1 требует аутентификации: он возвращает 200 при действительном ключе и 401 без него. Укажите в качестве источника данных …/v1 и не пропускайте проверку — корректный ключ сохраняется, а отозванный или неверно сформированный сразу вызывает ошибку.В прежних примерах в качестве источника данных использовался голый хост, а проверку предлагалось пропустить, так как GET / всегда возвращает 404. Перенастройте такие модели на …/v1.
Размер страницы по умолчанию для каждой списочной конечной точки /v1 равен 25. Если оставить значение по умолчанию, число запросов для тех же данных многократно возрастёт. Значения запроса должны быть текстовыми — limit = "500" в M, а не limit = 500.

Общая функция постраничной навигации

Каждый запрос в примере вызывает единую функцию Fn_FetchAll, которая проходит по next_page_token, пока оно не станет null (см. pagination). Её основные свойства:
  • Статический базовый URL /v1, динамические RelativePath и Query. Необходимо для планового обновления и для проверки учётных данных.
  • ManualStatusHandling = {429} с ограниченным числом повторных попыток. Функция считывает Retry-After, если Power Query его предоставляет, в противном случае ждёт 30 секунд и после 5 подряд полученных ответов 429 завершается с явной ошибкой, а не зацикливается до истечения времени обновления. Для 5xx повторные попытки намеренно не выполняются — ошибка сервера должна быть видна, а не приводить к тихому формированию неполного набора данных.
  • Timeout 60 секунд. Страницы обычно отвечают значительно быстрее чем за секунду, поэтому минута молчания означает, что запрос не выполняется.
  • Binary.Buffer перед Json.Document. Без буферизации механизм mashup может повторно запросить поток ответа, если прочитает его более одного раза.
  • baseQuery передаётся без изменений на каждой итерации. Токены страниц — непрозрачные подписанные курсоры, привязанные к организации, учётным данным, версии контракта и отпечатку фильтров и сортировки. Изменение фильтра в ходе прохода отклоняется как недействительный токен, а не перезапускается с первой страницы.
Fn_FetchAll.pq — base and call shape

Типизированные запросы для каждой конечной точки

Каждый потребитель Fn_FetchAll следует одной схеме: вызвать конечную точку, спроецировать фиксированный список столбцов, удалить дискриминатор object и привести временные метки к типу datetimezone, чтобы значения дат в мерах не смещались незаметно из-за часового пояса ёмкости обновления.
Явный список столбцов в Table.FromRecords сохраняет стабильность схемы, когда конечная точка возвращает ноль строк. Простой Table.FromRecords({}) даёт таблицу без столбцов, и все последующие шаги завершаются ошибкой из-за отсутствующих полей.

Excel

Тот же Power Query (M) работает в Get & Transform в Excel — это тот же механизм, что и в Power BI Desktop. Используйте этот вариант, когда вам нужна таблица на листе вместо семантической модели. В Excel для Windows (Microsoft 365, Excel 2024, 2021, 2019 или 2016):
  1. Data → Get Data → From Other Sources → Blank Query.
  2. В Power Query Editor выберите Главная страница → Расширенный редактор. Сначала вставьте Fn_FetchAll, затем переименуйте этот запрос в Fn_FetchAll (Query Settings → Name или щёлкните правой кнопкой мыши в области Queries и выберите Rename).
  3. Повторите для Fn_GetJson, а затем для каждого запроса отчёта.
  4. Главная страница → Close & Load → Close & Load To… открывает диалоговое окно Import Data. Выберите Only Create Connection для Fn_FetchAll и Fn_GetJson (это функции, а не таблицы). Выберите Table для каждого запроса отчёта, который нужно разместить на листе.
  5. При первом обновлении выберите Basic: ключ API в поле User name, а заполнитель, например x, в поле Пароль. Excel хранит одни учётные данные на URL источника данных; последующие запросы к тому же хосту /v1 используют их повторно.
Close & Load To… может быть недоступна (затемнена) при первом создании запроса в книге. Используйте Close & Load, затем в Excel выберите Data → Queries & Connections, щёлкните запрос правой кнопкой мыши и выберите Load To. Корпорация Майкрософт документирует этот путь именно для такого случая.
Отправить Living-Security-Version из Power Query для источника с аутентификацией невозможно — это то же ограничение, что и в Power BI. Закрепите версию за сервисной учётной записью или передайте api_version в записи запроса. См. Contract versions and stored credentials. Готовые запросы отчётов (сопоставление столбцов и отличия от экспорта предыдущего поставщика):

Per-person compliance

Зачисления на обучение с детализацией «сотрудник × назначение».

Email phishing log

Фишинговые взаимодействия на уровне событий за последние 12 месяцев.

Most susceptible users

Сводка по каждому сотруднику за 12 месяцев: переходы по ссылкам, ввод учётных данных и сообщения о фишинге.

Предварительные наборы данных reporting (фишинг по отдельным сотрудникам)

Семейство предварительных наборов данных reporting предоставляет наборы данных о фишинге по отдельным сотрудникам. Для него требуется reporting:read и доступ к отчётности для вашей организации. Используйте приведённый ниже каталог наборов данных, чтобы изучить их схемы и политики данных. Получите актуальный каталог:
Каждый набор данных объявляет детализацию, первичный ключ, соединения, водяной знак, политику коррекции и политику удаления.

simulation_results

  • Путь: GET /v1/reporting/simulation_results
  • Детализация: сущность × симуляция
  • Фильтры: simulation, entity, updated_after, а также limit / page_token
  • Объект передачи: reporting.simulation_result
  • Ключи соединения: entity_id, simulation_id
ReportingSimulationResults.pq (sketch)
Используйте updated_after как включающий нижний водяной знак при обновлении последних партиций. Изменяемые измерения результатов пересчитываются на месте под тем же id.

simulation_events

  • Путь: GET /v1/reporting/simulation_events
  • Детализация: один типизированный факт на каждое зафиксированное взаимодействие
  • Фильтры: simulation, entity, event_type, occurred_after, а также limit / page_token
  • Объект передачи: reporting.simulation_event
  • Типы событий: закрытый набор публичных токенов, например simulation.delivered, simulation.opened, simulation.link_clicked, simulation.credentials_submitted, simulation.reported — а не необработанные типы активности ClickHouse phishing.simulation.*
  • Устройство: device_type — производный класс (среди наблюдаемых токенов — desktop, mobile, tablet, unknown). Необработанный user_agent отсутствует в /v1. Необработанный IP-адрес никогда не попадает в /v1 (не сохраняется; только ip_hash с солью).
ReportingSimulationEvents.pq (sketch)
Используйте occurred_after для инкрементальной загрузки событий. Факты только добавляются; поздно поступившие данные становятся новыми строками.

entities

  • Путь: GET /v1/reporting/entities
  • Детализация: одна текущая строка на сущность
  • Фильтры: type, updated_after, а также limit / page_token
  • Объект передачи: reporting.entity
  • Ключ соединения: id / entity_id (одно и то же значение)
Соединяйте факты фишинга с сотрудниками с помощью reporting.simulation_results.entity_id = reporting.entities.id. Операционный GET /v1/entities остаётся на entity:read и требует другого разрешения.
ReportingEntities.pq

entity_versions и cohort_memberships

Эти два набора данных имеют именованное исключение «только текущие данные»:
Авторитетной таблицы истории версий или членства не существует. Этот набор данных отображает текущую строку как один открытый интервал (valid_to равно null, is_current равно true). valid_from — это created_at, а при его отсутствии updated_at для версий сущностей и время наблюдения запроса для членства в когортах. Закрытые исторические интервалы не создаются искусственно.
  • entity_versions: GET /v1/reporting/entity_versions. Те же фильтры, что и у entities. valid_from — это created_at, а при его отсутствии updated_at. Сущность, у которой обе временные метки равны null, пропускается.
  • cohort_memberships: GET /v1/reporting/cohort_memberships. Фильтры: cohort, entity, updated_after. updated_at — время последнего обновления когорты, благодаря чему инкрементальное обновление остаётся корректным. valid_from — время наблюдения запроса. Соедините entity_id с reporting.entities.id.
ReportingEntityVersions.pq
ReportingCohortMemberships.pq

Семантическая модель «звезда» на /v1/activities

/v1/activities — это поток событий организации с временными метками. В нём нет числовых мер — каждая величина в отчёте представляет собой количество строк, — что делает схему «звезда» естественным выбором.
  • Activities — таблица фактов событий с истинной детализацией. Одна строка на активность. Участники здесь отбрасываются и воссоздаются в виде отдельной таблицы.
  • ActivityParticipants существует потому, что участники на самом деле связаны отношением «один ко многим» и имеют роли, такие как actor и target. Разворачивание в плоскую структуру на Activities привело бы либо к дублированию строк активности (завышению каждого подсчёта), либо к потере дополнительных участников. Связь с Activities — единственная двунаправленная связь в модели, поэтому срез по сущности доходит до таблицы фактов.
  • Entities — измерение, которое называет участников. Строки участников в активности содержат entity_id и роль, но не отображаемое имя.
  • Dates создаётся в M (без обращений к API) и помечается как таблица дат модели. Именно это делает допустимой аналитику времени в DAX (DATESINPERIOD, DATEADD). Столбцы с названиями месяцев и дней недели объявляют sortByColumn на своих числовых двойниках, чтобы визуальные элементы не сортировали месяцы по алфавиту.
Все меры явные (в модели задано discourageImplicitMeasures): общее число активностей, активные сущности, активности на одну активную сущность, дни с активностью и 7-дневное скользящее среднее за день.

Структура таблицы-моста

ActivityParticipants проходит по /v1/activities и разворачивает массив participants в одну строку на участника:
ActivityParticipants.pq
ActivityParticipants проходит по /v1/activities независимо, а не ссылается на запрос Activities. В Power BI два запроса, загруженные как две таблицы, при обновлении получают данные независимо. Их независимость позволяет службе обновлять партиции обеих таблиц параллельно.

Инкрементальное обновление

Обе таблицы с детализацией фактов (Activities и ActivityParticipants) объявляют политику инкрементального обновления Power BI: хранить 5 лет годовых партиций и повторно импортировать последние 14 дней при каждом обновлении. Механизм основан на паре параметров DateTime, RangeStart и RangeEnd, которые служба Power BI переопределяет для каждой партиции во время обновления. Каждый запрос фактов подставляет эти параметры в фильтры API start_date и end_date, поэтому объём запросов на уровне партиции пропорционален партиции, а не всей истории. Запрос расширяет окно API на минуту с каждой стороны и локально повторно применяет точную полуоткрытую границу [RangeStart, RangeEnd), поэтому корректность партиции не зависит от того, считает ли сервер свои границы включающими или исключающими.
Activities.pq — the fold that makes incremental refresh work
Первое обновление после развёртывания применяет политику: выполняется полная загрузка истории, это медленно. Каждое последующее обновление затрагивает только инкрементальное окно. Измерено на наборе данных из ~158 000 активностей и ~2 300 сущностей:
Классическая конечная точка REST для обновления Power BI (POST .../refreshes только с notifyOption) молча игнорирует политики обновления и каждый раз выполняет полный проход. Чтобы применить политику через REST API, используйте расширенное обновление: передайте в теле запроса type, commitMode и applyRefreshPolicy. Обновления, запущенные планировщиком службы Power BI, всегда применяют политики — эта особенность относится только к вызову REST.
14-дневное окно намеренно выбрано с запасом. Приём данных об активности не ограничивается добавлением только текущих событий: при заполнении истории коннекторами поступают события с прошлыми временными метками. Окно в 1–2 дня безвозвратно пропустило бы их.

Расширение окна обновления на стороне API

GET /v1/activities принимает фильтры start_date и end_date, в которые подставляются параметры Power BI, фильтруя event_ts между границами. Entities является измерением, поэтому в этом примере оно обновляется полностью каждый раз, а не инкрементально. Наборы данных reporting используют собственные водяные знаки (updated_after, occurred_after) вместо окна дат активностей.

Ограничения частоты запросов во время обновления

/v1 применяет отдельные лимиты для каждого ключа и каждого IP-адреса (см. rate limits). Учитывайте 429 + Retry-After; не закладывайте в модель жёстко заданный лимит запросов. Важны два свойства обновлений Power BI:
  • Проход по одной таблице выполняется последовательно. Для каждого запроса страницы нужен токен предыдущей страницы, поэтому скорость обработки одной таблицы ограничена задержкой независимо от размера страницы.
  • Параллельные обновления таблиц накладываются друг на друга. Именно одновременное обновление нескольких больших таблиц приводит к достижению предела, поэтому важен путь повторных попыток при ответе 429 в Fn_FetchAll. Лучше уменьшить число параллельных таблиц, чем рассчитывать на неограниченный параллелизм.
Механизм повторных попыток проверен на реальном насыщенном ограничителе. Обновление, которое выполнялось, пока параллельная нагрузка намеренно удерживала ключ на предельном уровне, всё равно завершилось и дало те же количества строк, что и базовое обновление без конкуренции, — повторные попытки возвращали полные страницы, без пропусков.

Версии контракта и сохранённые учётные данные

/v1 принимает заголовок запроса Living-Security-Version, чтобы закрепить опубликованную версию контракта (см. API quickstart). Power Query не может отправлять этот заголовок, если источник данных использует сохранённые учётные данные, — пользовательские заголовки допускают только анонимные источники данных. Его добавление приводит к сбою обновления со следующей ошибкой:
Храните ключ в сохранённых учётных данных Power BI и не добавляйте пользовательский заголовок. Если в запросе явно не указана версия, API использует закреплённую за сервисной учётной записью версию contract_version или последнюю опубликованную версию, если закрепления нет. Прежде чем публиковать обновление, уточните версию контракта учётной записи у администратора API. Поддерживаемые версии см. в API changelog. Если обновление начинает вести себя неожиданно, проверьте заголовок ответа API Living-Security-Version, чтобы узнать, какой контракт фактически обработал запрос.

Обновление и проверка модели

Опубликуйте семантическую модель в рабочей области Power BI, привяжите её сохранённые учётные данные к региональному источнику /v1 и выполните обновление, прежде чем включать расписание. Проверьте историю обновлений на наличие сбоев или неполного чтения. Сверьте количества строк с независимым чтением через API с теми же фильтрами. В руководстве по постраничной навигации приведены примеры на Python и cURL для чтения полного набора результатов. Обновление, читающее только первую страницу, может выглядеть успешным на небольшом наборе данных; сравните количества, прежде чем полагаться на отчёт.

Проектные решения модели

  • Итоги кампаний и результаты по отдельным сотрудникам имеют разную детализацию. SimulationResults вызывает GET /v1/simulations/{id}/results (один GET на запуск). Для данных о фишинге по отдельным сотрудникам добавьте запросы для GET /v1/reporting/simulation_results и GET /v1/reporting/simulation_events (или операционного GET /v1/simulation_results, если у вас уже есть simulation:read).
  • vectors в /v1/simulations преобразуется в строку, соединённую запятыми. Столбец типа «список» нельзя использовать в срезе как настоящее измерение. Если странице отчёта нужна фильтрация по вектору, добавьте таблицу-мост «симуляция — вектор».

Дальнейшие шаги

Developer Hub

Создайте сервисную учётную запись и ключ API для Power BI.

API quickstart

Аутентификация запросов /v1 с помощью Basic.

Pagination

Конверт списка, токены курсора и стабильность фильтров при проходе.

Rate limits

Лимиты для каждого ключа и каждого IP-адреса, контракт ответа 429 и рекомендации по повторным попыткам.