The Power BI export is a read-only data feed that Power BI pulls from on each refresh. It serves these datasets as JSON: totals per simulation, totals per coach, daily activity, one row per learner attempt, and one row per transcript message. An owner or admin of an organization workspace on the Enterprise plan sets it up by creating an API key and pasting a ready-made Power Query snippet into Power BI.
Before you start
- The organization's plan must be Enterprise. devlin.ai can also turn the export on for an individual organization. On any other plan the panel shows a Power BI export card with a View plans button in place of the controls.
- You must be an owner or admin of the organization. Members cannot open the organization's Integrations section. See Members, roles, invitations and the activity log.
- The controls are in an organization's settings only. The Integrations page of a personal workspace has no Power BI panel. See Personal and organization workspaces.
- A key gives whoever holds it read access to the organization's results, including what learners wrote and any learner identity that was collected. Treat it like a password.
- You need Power BI Desktop to paste the snippet into, and the Power BI service if you want scheduled refresh.
Steps
Create a key:
- Make the organization your active workspace (Settings → Workspaces lists your workspaces and switches to the one you pick), then open Integrations in the settings sidebar.
- Under API keys, type a name for the key that says what will use it. The name can be up to 100 characters.
- Select Create key.
- A banner shows the full key with a copy button. Copy it and store it somewhere safe before you dismiss the banner. The key is shown this one time only. devlin.ai does not keep a readable copy, so it cannot be shown again or recovered.
An organization can have up to 5 active keys. When that many exist, creating another fails with "Limit of 5 active keys reached. Revoke one first."
Connect Power BI, following the instructions under Connect Power BI in the same panel:
- Under Connect Power BI, select a dataset:
simulations,coaches,activity,attemptsortranscripts. The snippet below the buttons changes to match. Copy it with the copy button on the snippet. - In Power BI Desktop, the panel directs you to Get Data, then Blank Query, then Advanced Editor. Paste the snippet there.
- In the snippet, replace
YOUR_API_KEYwith the key you copied. - If Power BI asks how to connect, choose Anonymous. The key inside the query is what authenticates the request.
- Optional: the snippet's
StartDateline sets the earliest data to pull and starts at 2020-01-01. Set a later date to pull less history. - Repeat for each dataset you want, one query per dataset.
- Schedule refresh in the Power BI service.
Revoke a key:
- In the API keys list, find the key. Each entry shows the name, the first characters of the key (keys start with
dvlk_), the date it was created, and the date it was last used or "never used". - Select Revoke, then confirm with Revoke key in the Revoke this key? dialog.
Creating and revoking a key are both recorded in the organization's activity log with the key's name. See Members, roles, invitations and the activity log.
A revoked key stops working immediately and leaves the list. Keys do not expire, and a key cannot be edited or regenerated. A key belongs to the organization, not to the person who created it: it keeps working after that person leaves the organization or changes role, until an owner or admin revokes it. To rotate a key, create a new one, update the queries in Power BI, then revoke the old one.
Result
Each query loads one table. The snippet requests the dataset page by page until the feed reports no further page, then combines the pages. When a dataset has no rows for the range, the query still returns an empty table with the dataset's columns, so later steps in your model keep working.
Every refresh pulls the whole range again, from StartDate to the moment of the refresh.
The feed is read-only. Nothing in Power BI can change the workspace.
What the datasets leave out
Session counts, attempt rows and transcript rows leave out:
- Designer test runs.
- Sessions where the learner never sent a message.
- The replaced part of a voice session that dropped and was resumed. The resumed session is the one that counts.
Evaluation counts and scores leave out evaluations that belong to a designer test run or to the replaced part of a resumed voice session.
The credits columns of simulations, coaches and activity are counted from the workspace's usage charges, not from the sessions, so they are not reduced by these rules.
No dataset contains evaluator submissions or results. To get them, see Exporting results, transcripts and evaluations.
The attempts and transcripts datasets cover simulations only. Coaches appear as totals in coaches and as a daily count in activity.
Datasets and columns
Times are ISO timestamps. A column described as empty holds a null value.
simulations
One row per simulation in the workspace, including simulations with no activity in the range. Counts cover the range the query asks for.
| Column | Meaning |
|---|---|
simulation_id |
The simulation's ID. Join to attempts and transcripts on this column. |
name |
The simulation's name. |
status |
The simulation's status. |
sessions |
Learner sessions that started in the range. |
completions |
Those sessions that have ended. |
unique_learners |
Distinct learners among those sessions, counted by learner ID, or by browser session where there is no learner ID. |
evals |
Evaluations created in the range. This follows the evaluation's time, not the session's start time. |
pass_rate |
The share of scored evaluations that passed, as a whole percent. Empty when no evaluation in the range was scored. Feedback-only evaluations are not counted as scored. |
avg_score |
The average score percent of scored evaluations. Empty when none was scored. |
credits |
Credits charged to the simulation in the range. |
last_activity |
When the most recent counted session in the range started. Empty when there was none. |
coaches
One row per coach in the workspace, including coaches with no activity in the range.
| Column | Meaning |
|---|---|
coach_id |
The coach's ID. |
name |
The coach's name. |
status |
The coach's status. |
sessions |
Coach sessions that started in the range. |
unique_learners |
Distinct learners among those sessions, counted the same way as for simulations. |
credits |
Credits charged to the coach in the range. |
last_activity |
When the most recent counted session in the range started. Empty when there was none. |
activity
One row per day for the whole workspace. A day with no sessions, evaluations or credit usage has no row. This dataset comes back in a single response.
| Column | Meaning |
|---|---|
bucket_start |
The start of the day. |
sessions |
Simulation sessions that started that day. |
completions |
Those sessions that have ended. |
coach_sessions |
Coach sessions that started that day. |
evals |
Evaluations created that day. |
pass_count |
Evaluations created that day that passed. |
avg_score |
The average score percent of that day's scored evaluations. Empty when none was scored. |
credits |
Credits the workspace used that day, counted from its usage charges, not only learner sessions. |
attempts
One row per learner attempt at a simulation, oldest first. The range applies to when the attempt started.
| Column | Meaning |
|---|---|
conversation_id |
The attempt's ID. Join to transcripts on this column. |
simulation_id |
The simulation's ID. |
simulation_name |
The simulation's name. |
session_id |
The learner's browser session. |
learner_id |
The learner ID stored with the attempt. |
learner_identifier |
The identifier the learner entered or the course passed in. Empty if none was collected, or after the workspace's retention window cleared it. |
learner_attributes |
The attempt's learner identity field values as one piece of JSON text. Empty if none were collected, or after the workspace's retention window cleared them. Parse it in Power Query to get one column per field. |
started_at |
When the attempt started. |
ended_at |
When the attempt ended. Empty if it has not ended. |
mode |
text or voice. |
completed |
True when the attempt has ended. |
credits |
Credits charged to the attempt. |
eval_pass |
Whether the attempt's most recent evaluation passed. Empty when there is no evaluation or it was feedback-only. |
eval_score |
The score percent of the most recent evaluation, rounded to a whole number. Empty when there is no evaluation or it was feedback-only. |
eval_pass and eval_score are the AI's result. A reviewer's adjustment from human review is not applied.
The organization's learner identity visibility setting does not hide the learner identity columns in this feed. In a workspace with a retention window, learner_id, learner_identifier and learner_attributes are emptied on attempts older than the window. Only owners and admins can create a key, and they always see learner identity. See Collecting learner identity.
transcripts
One row per stored message in a simulation attempt, oldest first. The range applies to when the message was sent. To get the learner, the simulation's name, the mode or the evaluation for a message, join to attempts on conversation_id.
| Column | Meaning |
|---|---|
message_id |
The message's ID. |
conversation_id |
The attempt the message belongs to. |
simulation_id |
The simulation's ID. |
role |
user for the learner, assistant for the character. |
content |
The text of the message. |
created_at |
When the message was sent. |
A workspace's retention window deletes old messages, so they stop appearing in transcripts while the attempt can still be counted elsewhere. See Data privacy and retention.
Date range
Each request takes an optional from and to, both ISO dates. The snippet always sends from with the value of StartDate and leaves to out, which means up to now. A request with no from gets the 365 days before to, so if you write your own query, send from or older rows will drop out of your model as they age past that window.
Limits
- Each key can make 60 requests per minute. A request above that gets
Too many requestswith aRetry-Afterheader that says how many seconds to wait. Each page of a dataset is one request. - The feed sets no row limit of its own.
simulations,coaches,attemptsandtranscriptsarrive as more pages, andactivityarrives in one response.
If the plan changes
The feed checks the organization's plan on every request. When the organization is no longer on a plan that includes the export, requests are refused straight away and scheduled refreshes fail. The keys are not revoked. The panel lists them under Existing API keys so you can revoke them, and you cannot create new ones. If the organization returns to a plan that includes the export, keys that were not revoked work again.
Errors a refresh can show
The feed answers a failed request with a short JSON error, which Power BI reports as a failed web request.
| Status and error | What it means |
|---|---|
401 Unauthorized |
The request has no key, the key is mistyped, or it is not a key this feed knows. Check that YOUR_API_KEY was replaced with the whole key. |
403 Unauthorized |
The key was revoked, or the organization's plan no longer includes the export. |
429 Too many requests |
The key passed its per-minute limit, or too many requests with a bad key came from the same network address. Wait and refresh again. |
400 Unknown dataset |
The dataset name in the URL is not one of the datasets listed above. |
400 from must be before to |
StartDate (or a from you added) is later than to, or later than now when to is left out. |
400 from and to must be valid ISO dates |
StartDate (or a from or to you added) is not a valid date. |
400 Invalid cursor |
The page marker was altered. Use the snippet as copied. |
500 Internal server error |
The request failed on the devlin.ai side. Refresh again. |
In the settings panel, "Could not load Power BI settings. Refresh to try again." means the key list did not load. Reload the page.