DocumentationStatisticsBI Integration

BI Integration

You can read the Statistics API from a reporting tool. This page shows two ways: Power BI with a Power Query script, and Prometheus with a scrape job.

Pick your environment and the hosts on this page update to match.


Power BI

Power BI reads the API through a Power Query script. The first query reads one page, the second reads every page and combines them.

Integration Script (Power Query M)

The script below is a Power Query function. It requests a token, reads one page of /analytics for a date range and returns a record with totalPages and the rows as a table in rows. Create a blank query in Power BI Desktop under Get data, open the Advanced Editor, paste the script, and name the query GetStatisticsPage.

(page as number) =>
let
  client_id = "your-client-id",
  client_secret = "your-client-secret",
  token_url = "https://identity-v2.metaforce.net/connect/token",
  scope = "api.external",
  start_date = "2026-09-01T00:00:00Z",
  to_date = "2026-09-07T23:59:59Z",

  Body = Text.ToBinary("grant_type=client_credentials" &
      "&client_id=" & client_id &
      "&client_secret=" & client_secret &
      "&scope=" & scope),
  TokenResponse = Json.Document(Web.Contents(token_url,
      [Content = Body, Headers = [#"Content-Type" = "application/x-www-form-urlencoded"]])),
  AccessToken = TokenResponse[access_token],

  ApiResponse = Json.Document(Web.Contents("https://api.statistics-v2.metaforce.net/analytics",
      [
          Query = [
              pageSize = "1000",
              pageNumber = Number.ToText(page),
              startDate = start_date,
              toDate = to_date
          ],
          Headers = [Authorization = "Bearer " & AccessToken]
      ])),
  Data = ApiResponse[data],
  Table1 = Table.FromList(Data, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
  Expanded = Table.ExpandRecordColumn(Table1, "Column1",
      {"event", "system", "date", "hour", "template", "source", "distribution", "environment", "area", "count", "eventDetail"},
      {"event", "system", "date", "hour", "template", "source", "distribution", "environment", "area", "count", "eventDetail"})
in [totalPages = ApiResponse[totalPages], rows = Expanded]

Set start_date and to_date to the range you want to report on. Keep the range short, see Best Practices.

Read every page

The function returns one page. The first call tells you how many pages exist in totalPages, so a second blank query can call the function for every page and combine the tables:

let
    Pages = List.Numbers(1, GetStatisticsPage(1)[totalPages]),
    Tables = List.Transform(Pages, each GetStatisticsPage(_)[rows]),
    Combined = Table.Combine(Tables)
in Combined

Load Combined into your report and build visuals on count, template, date and hour. A range without events gives an empty table. A company with no statistics data at all gets 404, which Power BI reports as an error for the query.

Note: Power BI Desktop stores the client secret inside the query, so anyone who has the report file can read it. Keep the file private.


Prometheus

The /analytics/prometheus endpoint returns the text format that Prometheus scrapes. It needs a bearer token, which Prometheus can fetch itself with the client credentials flow. This job is for Prometheus 3:

scrape_configs:
- job_name: docgen-statistics
  scheme: https
  metrics_path: /analytics/prometheus
  scrape_interval: 2m
  fallback_scrape_protocol: PrometheusText0.0.4
  oauth2:
    client_id: your-client-id
    client_secret: your-client-secret
    token_url: https://identity-v2.metaforce.net/connect/token
    scopes: [api.external]
  static_configs:
    - targets: ['api.statistics-v2.metaforce.net']
  • fallback_scrape_protocol is needed because the endpoint sends no Content-Type header, and Prometheus 3 refuses a scrape without one. Prometheus 2 falls back to the text format on its own, so leave the line out there.
  • Keep scrape_interval under five minutes. By default Prometheus looks back only five minutes for a value, so a longer interval leaves gaps in your graphs.
  • Without a startDate the endpoint counts events from today at 00:00 UTC, so the values are today’s totals so far and start again from zero at midnight UTC. Add params: { startDate: [...] } to the job to use another start.
  • Each combination becomes one series named <event>_event_count, see API Endpoints.