Skip to main content
Ce guide présente un exemple de bout en bout de lecture de /v1 dans Power BI. Il couvre le modèle de connectivité Power Query (M), un modèle sémantique en étoile construit sur /v1/activities, l’actualisation incrémentielle, ainsi que les cas où il convient d’utiliser les jeux de données en préversion reporting pour les résultats de phishing par personne. Les exemples utilisent l’hôte de production américain (https://api.us-east-1.livingsecurity.ai/v1). Pour une organisation située dans l’UE, utilisez https://api.eu-west-1.livingsecurity.ai/v1 à la fois dans Fn_FetchAll et Fn_GetJson, puis associez les identifiants de la source de données à cet hôte. Consultez Régions. Ce guide utilise des identifiants Basic stockés avec une clé d’API. Vous n’avez pas besoin d’un client OAuth. Consultez Authentification pour les choix d’identifiants, et Developer Hub pour l’accès et la configuration.

À quoi sert cet exemple

Utilisez-le lorsque vous devez :
  • Charger les points de terminaison de liste /v1 dans un jeu de données Power BI avec une pagination par curseur correcte et une nouvelle tentative en cas de limite de débit.
  • Créer un modèle sémantique dans lequel les mesures (« entités actives », « activités par entité active ») sont dimensionnelles plutôt que comptées à partir d’une table à plat.
  • Faire passer une actualisation Power BI planifiée d’un parcours complet de l’historique à une petite fenêtre quotidienne grâce à l’actualisation incrémentielle.
  • Choisir la bonne granularité pour le phishing : totaux de campagne (opérationnel) ou résultats par personne et événements typés (préversion reporting).

Prérequis

  • Une clé d’API disposant des autorisations requises par vos requêtes :
    • Exemple opérationnel : activity:read, entity:read et simulation:read.
    • Phishing par personne via les jeux de données de reporting : reporting:read. Consultez Clés d’API.
  • Power BI Desktop, ou un espace de travail Power BI / Fabric dans lequel vous pouvez créer un modèle sémantique et planifier une actualisation.

Choisir la bonne granularité

/v1 expose deux surfaces liées pour le phishing. Elles ne sont pas interchangeables. Les exemples de requêtes Power BI ci-dessous appellent les routes opérationnelles (/v1/simulations, /v1/simulations/{id}/results, /v1/activities, /v1/entities). Pour le reporting de phishing par personne, privilégiez la famille reporting en préversion ci-dessous. Une clé disposant uniquement de reporting:read ne peut pas appeler /v1/simulation_results opérationnel (l’API renvoie 403).

Échelle de difficulté

La difficulté d’une simulation est un entier de 1 à 5 présent sur /v1/simulations (difficulty_level), /v1/simulation_results (difficulty_level), les propriétés /v1/activities (difficulty_tier) et /v1/reporting/simulation_events (difficulty_tier). 1 est le niveau le plus facile et 5 le plus difficile. Les simulations adaptatives et progressives n’ont pas de valeur unique au niveau de la campagne ; /v1/simulations.difficulty_level vaut donc null, alors que difficulty_level par destinataire sur les résultats peut tout de même être défini. Pour faire correspondre ces valeurs aux exports hérités faible/moyen/élevé, considérez 1–2 comme faible, 3 comme moyen et 4–5 comme élevé.
Ne créez pas de nouvelles intégrations BI reposant sur des appels réseau non documentés du Tableau de bord ou sur l’ancienne présentation générale de l’API publique /api/v1 organisée. Authentifiez-vous auprès de l’hôte /v1 régional de l’organisation avec une clé d’API Developer Hub. Consultez Régions.

Modèle de connectivité (Power Query)

Quatre règles sous-tendent chaque requête de l’exemple. Chacune est imposée par le service Power BI et ne relève pas de préférences de style.
Placez tout ce qui est dynamique dans RelativePath et Query. Le premier argument de Web.Contents doit être une chaîne littérale qui se termine à la racine /v1 régionale de l’organisation :
  • US : https://api.us-east-1.livingsecurity.ai/v1
  • UE : https://api.eu-west-1.livingsecurity.ai/v1
Les appelants transmettent ensuite uniquement la ressource ("simulations", et non "v1/simulations"). Ne collez pas un hôte US pour une organisation de l’UE.Si le premier argument est construit par concaténation de chaînes, le service Power BI ne peut pas identifier statiquement la source de données et l’actualisation planifiée échoue avec une erreur de « source de données dynamique », même si la requête fonctionne dans Power BI Desktop.
Lorsque Power BI vous demande les identifiants de la source de données /v1, choisissez Basic et collez la clé d’API comme nom d’utilisateur. Saisissez un espace réservé tel que x dans le champ Mot de passe. Le service Power BI refuse un mot de passe vide, même si l’API ignore ce champ. L’inverse (clé comme mot de passe avec un nom d’utilisateur fictif) fonctionne également.N’ajoutez pas d’en-tête Authorization dans M. Cela fonctionne sur votre poste, mais intègre ensuite la clé dans le fichier de requête et entre en conflit avec l’actualisation planifiée.
GET /v1 est authentifié : il renvoie 200 avec une clé valide et 401 sans clé. Pointez la source de données vers …/v1 et ne sautez pas le test — une bonne clé est enregistrée, alors qu’une clé révoquée ou mal formée échoue immédiatement.D’anciens exemples utilisaient l’hôte seul comme source de données et indiquaient de sauter le test, car GET / renvoie toujours 404. Redirigez ces modèles vers …/v1.
La taille de page par défaut de chaque point de terminaison de liste /v1 est de 25. Conserver la valeur par défaut multiplie le nombre de requêtes pour les mêmes données. Les valeurs de requête doivent être du texte — limit = "500" en M, et non limit = 500.

Fonction de pagination partagée

Chaque requête de l’exemple appelle une unique fonction Fn_FetchAll qui parcourt next_page_token jusqu’à ce qu’il soit null (consultez pagination). Ses propriétés notables :
  • URL de base /v1 statique, RelativePath et Query dynamiques. Requis pour l’actualisation planifiée et pour le test des identifiants.
  • ManualStatusHandling = {429} avec une nouvelle tentative bornée. La fonction lit Retry-After lorsque Power Query l’expose, sinon attend 30 secondes, et abandonne après 5 réponses 429 consécutives avec une erreur explicite plutôt que de boucler jusqu’à l’expiration de l’actualisation. 5xx n’est volontairement pas retenté — une erreur de serveur doit remonter, et non produire silencieusement un jeu de données partiel.
  • Timeout de 60 secondes. Les pages répondent généralement en bien moins d’une seconde ; une minute de silence signifie donc que la requête est perdue.
  • Binary.Buffer avant Json.Document. Sans mise en mémoire tampon, le moteur mashup peut redemander le flux de réponse s’il le lit plus d’une fois.
  • baseQuery est transmis sans modification à chaque itération. Les jetons de page sont des curseurs opaques et signés, liés à l’organisation, aux identifiants, à la version du contrat et à l’empreinte des filtres et du tri. Modifier un filtre en cours de parcours est rejeté comme jeton invalide, au lieu de repartir de la première page.
Fn_FetchAll.pq — base and call shape

Requêtes typées par point de terminaison

Tout consommateur de Fn_FetchAll suit la même structure : appeler le point de terminaison, projeter une liste fixe de colonnes, supprimer le discriminant object et typer les horodatages en datetimezone afin que les mesures de date ne soient pas décalées silencieusement par le fuseau horaire de la capacité d’actualisation.
Une liste de colonnes explicite sur Table.FromRecords maintient la stabilité du schéma lorsqu’un point de terminaison renvoie zéro ligne. Un Table.FromRecords({}) seul produit une table sans colonne, et toutes les étapes suivantes échouent faute de champs.

Excel

Le même Power Query (M) s’exécute dans Récupérer et transformer d’Excel — c’est le même moteur que Power BI Desktop. Utilisez-le lorsque vous souhaitez un tableau dans une feuille de calcul plutôt qu’un modèle sémantique. Dans Excel pour Windows (Microsoft 365, Excel 2024, 2021, 2019 ou 2016) :
  1. Données → Obtenir des données → À partir d’autres sources → Requête vide.
  2. Dans l’Éditeur Power Query, Accueil → Éditeur avancé. Collez d’abord Fn_FetchAll, puis renommez cette requête Fn_FetchAll (Paramètres de la requête → Nom, ou clic droit dans le volet Requêtes → Renommer).
  3. Répétez l’opération pour Fn_GetJson, puis pour chaque requête de rapport.
  4. Accueil → Fermer et charger → Fermer et charger dans… ouvre la boîte de dialogue Importer les données. Choisissez Créer uniquement une connexion pour Fn_FetchAll et Fn_GetJson (ce sont des fonctions, pas des tables). Choisissez Tableau pour chaque requête de rapport que vous souhaitez placer dans une feuille de calcul.
  5. Lors de la première actualisation, choisissez Basic : la clé d’API comme Nom d’utilisateur, un espace réservé tel que x comme Mot de passe. Excel stocke un seul jeu d’identifiants par URL de source de données ; les requêtes suivantes qui ciblent le même hôte /v1 le réutilisent.
Fermer et charger dans… peut être grisé la première fois que vous créez une requête dans un classeur. Utilisez Fermer et charger, puis dans Excel sélectionnez Données → Requêtes et connexions, faites un clic droit sur la requête et choisissez Charger dans. Microsoft documente cette procédure pour ce cas.
Vous ne pouvez pas envoyer Living-Security-Version depuis Power Query sur une source authentifiée — c’est la même restriction que pour Power BI. Épinglez le compte de service ou transmettez api_version dans l’enregistrement de la requête. Consultez Versions du contrat et identifiants stockés. Requêtes de rapport prêtes à l’emploi (correspondances de colonnes et écarts par rapport à l’export d’un fournisseur précédent) :

Conformité par personne

Inscriptions aux formations à la granularité personne × affectation.

Journal du phishing par e-mail

Interactions de phishing au niveau de l’événement, sur les 12 derniers mois.

Utilisateurs les plus vulnérables

Synthèse par personne sur 12 mois des clics, des identifiants saisis et des signalements.

Jeux de données de reporting en préversion (phishing par personne)

La famille de reporting en préversion fournit des jeux de données pour le phishing par personne. Elle nécessite reporting:read et un accès au reporting pour votre organisation. Utilisez le catalogue de jeux de données ci-dessous pour consulter ses schémas et ses politiques de données. Découvrez le catalogue en direct :
Chaque jeu de données déclare sa granularité, sa clé primaire, ses jointures, son filigrane, sa politique de correction et de suppression.

simulation_results

  • Chemin : GET /v1/reporting/simulation_results
  • Granularité : entité × simulation
  • Filtres : simulation, entity, updated_after, ainsi que limit / page_token
  • Objet transmis : reporting.simulation_result
  • Clés de jointure : entity_id, simulation_id
ReportingSimulationResults.pq (sketch)
Utilisez updated_after comme filigrane inférieur inclusif lorsque vous actualisez les partitions récentes. Les dimensions de résultat modifiables sont réécrites sur place sous le même id.

simulation_events

  • Chemin : GET /v1/reporting/simulation_events
  • Granularité : un fait typé par interaction observée
  • Filtres : simulation, entity, event_type, occurred_after, ainsi que limit / page_token
  • Objet transmis : reporting.simulation_event
  • Types d’événement : jetons publics fermés tels que simulation.delivered, simulation.opened, simulation.link_clicked, simulation.credentials_submitted, simulation.reported — et non les types d’activité phishing.simulation.* bruts de ClickHouse
  • Appareil : device_type est la classe dérivée (les jetons observés incluent desktop, mobile, tablet, unknown). user_agent brut n’est pas présent sur /v1. L’adresse IP brute n’est jamais présente sur /v1 (jamais conservée ; uniquement ip_hash salé).
ReportingSimulationEvents.pq (sketch)
Utilisez occurred_after pour les chargements incrémentiels d’événements. Les faits sont en ajout seul ; les arrivées tardives sont de nouvelles lignes.

entities

  • Chemin : GET /v1/reporting/entities
  • Granularité : une ligne actuelle par entité
  • Filtres : type, updated_after, ainsi que limit / page_token
  • Objet transmis : reporting.entity
  • Clé de jointure : id / entity_id (même valeur)
Associez les faits de phishing aux personnes avec reporting.simulation_results.entity_id = reporting.entities.id. GET /v1/entities opérationnel reste sur entity:read et relève d’une autre autorisation.
ReportingEntities.pq

entity_versions et cohort_memberships

Ces deux jeux de données présentent une exception nommée, limitée à l’état actuel :
Aucune table faisant autorité pour l’historique des versions ou des appartenances n’existe. Ce jeu de données projette la ligne actuelle sous la forme d’un intervalle ouvert (valid_to est null, is_current est true). valid_from vaut created_at ou à défaut updated_at pour les versions d’entités, et l’heure d’observation de la requête pour les appartenances aux cohortes. Les intervalles historiques fermés ne sont pas fabriqués.
  • entity_versions : GET /v1/reporting/entity_versions. Mêmes filtres que entities. valid_from vaut created_at ou à défaut updated_at. Une entité dont les deux horodatages sont null est omise.
  • cohort_memberships : GET /v1/reporting/cohort_memberships. Filtres : cohort, entity, updated_after. updated_at correspond à la dernière mise à jour de la Cohorte, afin que l’actualisation incrémentielle reste fiable. valid_from est l’heure d’observation de la requête. Jointure de entity_id à reporting.entities.id.
ReportingEntityVersions.pq
ReportingCohortMemberships.pq

Modèle sémantique en étoile sur /v1/activities

/v1/activities est le flux d’événements horodatés de l’organisation. Il ne comporte aucune mesure numérique — chaque quantité d’un rapport correspond à un nombre de lignes — ce qui fait du schéma en étoile un choix naturel.
  • Activities est le fait d’événement à sa granularité réelle. Une ligne par activité. Les participants y sont supprimés et reconstruits dans leur propre table.
  • ActivityParticipants existe parce que les participants relèvent véritablement d’une relation un-à-plusieurs, avec des rôles tels que actor et target. Les aplatir dans Activities dupliquerait les lignes d’activité (gonflant chaque décompte) ou supprimerait les participants supplémentaires. La relation avec Activities est la seule relation bidirectionnelle du modèle ; ainsi, un segment d’entité atteint la table de faits.
  • Entities est la dimension qui nomme les participants. Les lignes de participants d’une activité contiennent entity_id et un rôle, mais pas de nom d’affichage.
  • Dates est générée en M (aucun appel d’API) et désignée comme table de dates du modèle. C’est ce qui rend valides les fonctions d’intelligence temporelle DAX (DATESINPERIOD, DATEADD). Les colonnes de nom de mois et de jour de la semaine déclarent sortByColumn sur leurs jumelles numériques afin que les visuels ne trient pas les mois par ordre alphabétique.
Toutes les mesures sont explicites (le modèle définit discourageImplicitMeasures) : total des activités, entités actives, activités par entité active, jours avec activité et moyenne quotidienne glissante sur 7 jours.

Structure de la table pont

ActivityParticipants parcourt /v1/activities et développe le tableau participants en une ligne par participant :
ActivityParticipants.pq
ActivityParticipants parcourt /v1/activities de manière indépendante plutôt que de référencer la requête Activities. Dans Power BI, deux requêtes chargées sous forme de deux tables effectuent chacune leur propre lecture au moment de l’actualisation. Les garder indépendantes permet au service d’actualiser en parallèle les partitions des deux tables.

Actualisation incrémentielle

Les deux tables de faits (Activities et ActivityParticipants) déclarent une politique d’actualisation incrémentielle Power BI : conserver 5 ans de partitions annuelles, réimporter les 14 derniers jours à chaque actualisation. Le mécanisme repose sur une paire de paramètres DateTime, RangeStart et RangeEnd, que le service Power BI relie à chaque partition au moment de l’actualisation. Chaque requête de faits intègre ces paramètres dans les filtres start_date et end_date de l’API ; le volume de requêtes par partition est donc proportionnel à la partition, et non à l’historique total. La requête élargit la fenêtre de l’API d’une minute de chaque côté et réapplique localement la borne semi-ouverte exacte [RangeStart, RangeEnd), de sorte que l’exactitude des partitions ne dépend pas du fait que le serveur traite ses bornes comme inclusives ou exclusives.
Activities.pq — the fold that makes incremental refresh work
La première actualisation après un déploiement applique la politique : un chargement historique complet, lent. Chaque actualisation suivante ne concerne que la fenêtre incrémentielle. Mesure sur un jeu de données d’environ 158 000 activités et 2 300 entités :
Le point de terminaison REST d’actualisation classique de Power BI (POST .../refreshes avec uniquement notifyOption) ignore silencieusement les politiques d’actualisation et effectue un parcours complet à chaque fois. Pour appliquer la politique via l’API REST, utilisez l’actualisation améliorée : envoyez type, commitMode et applyRefreshPolicy dans le corps de la requête. Les actualisations déclenchées par le planificateur du service Power BI appliquent toujours les politiques — cette particularité est propre à l’appel REST.
La fenêtre de 14 jours est volontairement généreuse. L’ingestion des activités ne se fait pas uniquement en ajout à l’instant présent : les rattrapages des connecteurs déposent des événements avec des horodatages passés. Une fenêtre de 1 à 2 jours les manquerait définitivement.

Élargir la fenêtre d’actualisation dans l’API

GET /v1/activities accepte les filtres start_date et end_date dans lesquels les paramètres Power BI sont intégrés, en filtrant event_ts entre les bornes. Entities est une dimension ; cet exemple l’actualise donc entièrement à chaque fois plutôt que de manière incrémentielle. Les jeux de données de reporting utilisent leurs propres filigranes (updated_after, occurred_after) au lieu de la fenêtre de dates des activités.

Limites de débit pendant l’actualisation

/v1 applique des budgets distincts par clé et par IP (consultez limites de débit). Respectez 429 + Retry-After ; ne codez pas en dur un budget de requêtes dans votre modèle. Deux propriétés des actualisations Power BI sont importantes :
  • Le parcours d’une seule table est séquentiel. Chaque requête de page a besoin du jeton de la page précédente ; une table est donc limitée par la latence, quelle que soit la taille de page.
  • Les actualisations simultanées de tables se cumulent. Plusieurs grandes tables actualisées en parallèle constituent le cas qui atteint le plafond, et c’est pourquoi le chemin de nouvelle tentative 429 dans Fn_FetchAll est important. Privilégiez un nombre réduit de tables en parallèle plutôt que de supposer une simultanéité illimitée.
La nouvelle tentative a été éprouvée face à un limiteur réellement saturé. Une actualisation exécutée pendant qu’une charge parallèle maintenait volontairement la clé à son plafond s’est tout de même terminée et a produit les mêmes nombres de lignes qu’une référence sans contention — les nouvelles tentatives ont renvoyé des pages complètes, sans lacunes.

Versions du contrat et identifiants stockés

/v1 accepte un en-tête de requête Living-Security-Version pour épingler une version publiée du contrat (consultez Démarrage rapide de l’API). Power Query ne peut pas envoyer cet en-tête lorsque la source de données utilise des identifiants stockés — seules les sources de données anonymes autorisent des en-têtes personnalisés. Son ajout fait échouer une actualisation avec le message suivant :
Conservez la clé dans les identifiants stockés de Power BI et omettez l’en-tête personnalisé. En l’absence de version explicite dans la requête, l’API utilise la valeur contract_version épinglée du compte de service, ou la dernière version publiée si aucune version n’est épinglée. Confirmez la version du contrat du compte auprès de votre administrateur d’API avant de publier une actualisation. Consultez le journal des modifications de l’API pour connaître les versions prises en charge. Si une actualisation se comporte de manière inattendue, inspectez l’en-tête de réponse Living-Security-Version de l’API pour voir quel contrat a réellement servi la requête.

Actualiser et vérifier votre modèle

Publiez le modèle sémantique dans votre espace de travail Power BI, associez ses identifiants stockés à la source /v1 régionale, et exécutez une actualisation avant d’activer une planification. Examinez l’historique des actualisations pour détecter les échecs ou les lectures incomplètes. Comparez les nombres de lignes avec une lecture indépendante de l’API utilisant les mêmes filtres. Le guide de pagination inclut des exemples Python et cURL pour lire un jeu de résultats complet. Une actualisation qui ne lit que la première page peut sembler réussie sur un petit jeu de données ; comparez les nombres avant de vous fier au rapport.

Choix de modélisation

  • Les totaux de campagne et les résultats par personne n’ont pas la même granularité. SimulationResults appelle GET /v1/simulations/{id}/results (un GET par exécution). Pour le phishing par personne, ajoutez des requêtes pour GET /v1/reporting/simulation_results et GET /v1/reporting/simulation_events (ou GET /v1/simulation_results opérationnel si vous disposez déjà de simulation:read).
  • vectors sur /v1/simulations est aplati en une chaîne séparée par des virgules. Une colonne de type liste ne peut pas servir de véritable dimension de segment. Si une page de rapport doit filtrer par vecteur, ajoutez une table pont simulation-vecteur.

Étapes suivantes

Developer Hub

Créez un compte de service et une clé d’API pour Power BI.

Démarrage rapide de l'API

Authentifiez les requêtes /v1 avec l’authentification Basic.

Pagination

L’enveloppe de liste, les jetons de curseur et la stabilité des filtres tout au long d’un parcours.

Limites de débit

Budgets par clé et par IP, contrat 429 et conseils de nouvelle tentative.