Reports API
A report is a high-level summary of sessions, exported as a table. The HEAT v2 API serves each report as a CSV or XLSX file that a learning record system or a spreadsheet can read.
A report definition names a set of columns. Each column reads one value from a small set of records HEAT keeps for every session, such as its date, its scenario, a trainee or a key in the session metadata. HEAT evaluates the definition when you request the download, so the file always reflects the current values. These are the same reports an instructor downloads from the Reports page of the HEAT dashboard.
A report is not a query over session data. It cannot read what the nodes of a session computed, and it cannot aggregate across sessions. Reporting is implemented by the originating session template. The template writes its key metrics into the session metadata, and a report column reads them from there. A session whose template does not do this has nothing on the session for a report to read beyond its date, scenario and users. See Assessment values in session metadata and Limitations.
For deep analysis across many sessions, build a session template that queries the sessions and produces the analysis as an artefact. See Cross-session analysis.
A report is not a raw data export either. It does not return the stored outputs of a node. Use the outputs routes in the HEAT v2 API reference for that.
Prerequisites
- A token from HEAT Auth, sent as
Authorization: Bearer <token>on every call. - The Administrator, Instructor or Developer role. Creating, updating and deleting report definitions needs Administrator or Developer.
- An offline token is accepted on every route on this page except delete, which suits a scheduled export job.
Routes
| Method | Path | Purpose |
|---|---|---|
GET | /api/v2/dashboard/reports/catalog | List the reports this environment offers |
GET | /api/v2/dashboard/reports/download | Download one report as CSV or XLSX |
GET | /api/v2/dashboard/reports/{key} | Read a full report definition |
POST | /api/v2/dashboard/reports | Create a report definition |
PUT | /api/v2/dashboard/reports/{key} | Update a report definition |
DELETE | /api/v2/dashboard/reports/{key} | Delete a report definition |
Report catalog
The catalog lists every report defined in the environment and names the default.
curl -H "Authorization: Bearer $HEAT_TOKEN" \
"https://heat.example.com/api/v2/dashboard/reports/catalog"{
"reports": [
{
"key": "session-list",
"name": "Session List",
"configurationKey": "sessionList"
}
],
"defaultReport": "session-list"
}Pass a report’s key to the download route.
Report download
The download route builds the report and returns it as a file.
curl -H "Authorization: Bearer $HEAT_TOKEN" -OJ \
"https://heat.example.com/api/v2/dashboard/reports/download?report=session-list&format=csv&from=2026-01-01&to=2026-01-31"| Parameter | Description |
|---|---|
report | Report key from the catalog. option is accepted as an alias. When the key is missing or unknown, HEAT uses the default report. |
format | xlsx (default) or csv |
from, to | Optional ISO dates. A session is included when its scenario window overlaps the range. to defaults to the end of the current day. |
userId | Optional HEAT Auth user GUID. Limits the report to sessions that user took part in, and to that user’s rows. |
The response is a file. CSV is served as text/csv and XLSX as application/vnd.openxmlformats-officedocument.spreadsheetml.sheet. The Content-Disposition filename is {fileName}_{ddMMyyyy_HH.mm}.{csv|xlsx}, where fileName comes from the report definition and defaults to SessionList.
Rows
A Dimension is the dashboard-facing result a session publishes. A report holds one row for each user of each dimension that passes the report’s filters. A dimension with no users produces one row with empty user values.
The first line of a CSV file, and the first row of an XLSX sheet, holds the column names from the report definition.
User names and email addresses are resolved from HEAT Auth when the report is built. HEAT does not store them with session results.
Report definitions
A report definition is the set of columns and filters behind one catalog entry. Read one to learn what a report contains, or create one from your own tooling.
The definition routes are the only part of the v2 API that changes how reports behave. They control which reports exist, their columns, their filters, the filename and the default report. The row model, the file formats and the download parameters are fixed.
Definitions belong to the whole environment. A change applies at once to every caller and to the Reports page of the HEAT dashboard.
curl -H "Authorization: Bearer $HEAT_TOKEN" \
"https://heat.example.com/api/v2/dashboard/reports/afv-all"Create a report with POST /api/v2/dashboard/reports. Update one with PUT /api/v2/dashboard/reports/{key}. Both take the same body.
{
"key": "afv-all",
"name": "AFV All",
"fileName": "AFV_Report",
"dimensionNameFilter": "AFV Recognition",
"setAsDefault": false,
"replaceConfiguration": true,
"columns": [
{
"columnKey": "Date",
"name": "Date",
"expression": "from",
"type": "datetime",
"format": "yyyy-MM-dd",
"source": "scenarioInstance",
"order": 1
},
{
"columnKey": "Trainee",
"name": "Trainee",
"expression": "email",
"source": "user",
"order": 2
},
{
"columnKey": "Detections",
"name": "Detections",
"expression": "reporting.kpis.detections",
"type": "numeric",
"source": "metadata",
"order": 3
}
],
"filters": [
{
"filterKey": "ScenarioName",
"expression": "scenario_type",
"value": "AFV",
"source": "metadata"
}
]
}The reporting.kpis.detections path is an example. The keys available under the metadata source depend on what the uploader and the session template write into the session metadata.
| Field | Description |
|---|---|
key | Required. The identifier used in the catalog and the download route. |
name | Required. The display name shown in the dashboard. |
configurationKey | Optional. The storage key for the definition. Derived from key when omitted, for example session-list becomes sessionList. |
fileName | Optional. The filename prefix for downloads. |
dimensionNameFilter | Optional. Limits the report to dimensions with this name. |
setAsDefault | Optional. Makes this the default report. |
replaceConfiguration | Optional, default true. On update, columns and filters missing from the body are removed. Set false to merge instead. |
columns | Required. See the columns table. |
filters | Optional. See the filters table. |
Deleting a report
DELETE /api/v2/dashboard/reports/{key} removes the report from the catalog and deletes its stored columns and filters. It returns 204 No Content.
curl -X DELETE -H "Authorization: Bearer $HEAT_TOKEN" \
"https://heat.example.com/api/v2/dashboard/reports/afv-all"An environment always keeps one report, so deleting the only report returns 409. Deleting the default report makes the first remaining report the default. An offline token cannot delete a report.
Columns
| Field | Description |
|---|---|
columnKey | Required. The storage key for the column. |
name | Required. The column heading in the file. |
source | The record the expression reads. See Sources. Defaults to dimension. |
expression | A JMESPath expression evaluated against the source. When the result is a list, the first item is used. |
type | string (default), numeric or datetime. A numeric column writes 0 when the value is missing or not a number. |
format | For datetime columns. Built from the tokens yyyy, MM, dd, HH, mm and ss. Defaults to yyyy-MM-dd HH:mm:ss. Times are written in UTC. |
order | The column position. Columns without an order follow the ordered ones. |
regex, regexGroup | Optional. Extracts part of a string result. regexGroup is a group name or index, and the first capture group is used when it is omitted. |
A datetime column accepts an ISO 8601 string or a Unix time in milliseconds.
Filters
A row is kept only when every filter passes.
| Field | Description |
|---|---|
filterKey | Required. The storage key for the filter. |
source | The record the expression reads. Defaults to dimension. |
expression | A JMESPath expression evaluated against the source. |
value | The value to match. A filter with no value is ignored. |
Strings match when the result contains value, and the comparison is case-sensitive. Numbers match when they are equal. When the expression returns a list, the filter passes if any item matches.
Sources
| Source | Content | Fields |
|---|---|---|
dimension | The dimension the row describes | id, dimensionName, nodeOutputId, sessionId, scenarioInstanceId, dashboardVersion |
scenarioInstance | The scenario run the session recorded | id, simulationId, sessionId, scenarioName, scenarioInstanceId, from, to |
metadata | The session’s metadata JSON | Set by the uploader and the session template |
user | The dimension user, resolved from HEAT Auth | userId, username, firstName, lastName, email |
dashboard | The JSON payload stored behind the dimension | Kept for reports written for the Legacy dashboard. See the note below. |
Do not use the dashboard source in a new report. It downloads the whole dashboard payload for every row each time the report is built, and the column is left empty when the payload is not a single JSON object. It exists for reports written against Legacy dashboard payloads. A supported way to read assessment values from dashboard or node data is not available today. Write the values into the session metadata instead.
Assessment values in session metadata
Session metadata is a JSON object stored with each session. It is the only place a report can read a value that the session itself produced.
A value reaches the session metadata in one of these ways.
| Route | Use it when |
|---|---|
The metadata field on the create session and update session routes of the v2 API | Your software already knows the value, for example the unit, the course or an exercise identifier |
| The session-metadata-enrich node template | A node in the session template computes a small summary, such as a score or a count. The payload is limited to 20 KB and cannot contain arrays. |
An Arbex script, through ctx.session.metadata | The template already uses Arbex to build its results |
Plan the keys with the session template. A report column then reads them with "source": "metadata" and a path such as reporting.kpis.detections.
Sessions processed before the template wrote a key have no value for it. The column is empty for those rows, or 0 for a numeric column, until the session is reprocessed.
Limitations
- A report reads fixed records for each session. Querying the contents of node outputs or dashboards across sessions is not available today.
- There is no aggregation, grouping, sorting or joining. A report always holds one row for each user of each dimension.
- The download parameters are limited to the date range, one user and the format. Any other selection is a filter in the report definition, and a filter can only test that a value contains or equals a constant.
- CSV and XLSX are the only output formats. The rows are not available as JSON.
- A report is built while the request waits, with one lookup for each session in the date range. There is no paging. Keep date ranges bounded for environments with many sessions.
- Report definitions are environment-wide. They cannot be scoped to a Project or to a caller.
Deep analysis across sessions belongs in a session template, not in a report. A template can query one trainee’s sessions or one kind of session, process the matches on the platform’s runners and store the analysis as a downloadable artefact. It can run on a schedule and publish a comparative dashboard from the same session. See Cross-session analysis.
Report definitions are stored as platform configuration under the report prefix. An operator can also read them in the Control Centre under Platform settings.
Errors
| Status | Cause |
|---|---|
400 | from is later than to, or a definition body failed validation. The response body describes the problem. |
401 | The token is missing, invalid or expired. |
403 | The caller’s role may not use the route. |
404 | The report key is unknown on a definition read, update or delete. |
409 | A report with the same key already exists on create, or the report to delete is the only one left. |
502 | HEAT could not load the session catalog. Retry the request. |