Skip to content

Connecting your BI tool

The feed is standard OData v4, so most BI and ETL tools consume it without any custom code. Point the connector at the service root, give it a bearer token, and let it read $metadata to map the schema.

What every tool needs

SettingValue
Service root / URLhttps://<your-api-host>/api/ticketinghub/odata/v1
AuthAuthorization: Bearer <token> header
Token endpointhttps://<identity-host>/connect/token
Grantclient_credentials, scope ticketinghub-api
OData versionv4

The service root sits on the same host as your other ADITUS APIs, so whatever network path, proxy exception or firewall rule already lets your tooling reach those covers this too.

The catch with every tool below: the token is valid for one hour, and none of these connectors know how to run a client_credentials flow on their own. Whatever tool you use, something has to fetch the token before the refresh runs — a pipeline step, a small script, or a secret your orchestrator rotates.

Power BI

Use Get Data → OData feed, then supply the token as a header in the advanced editor:

let
    Token = "...",   // fetched by your refresh pipeline, not hard-coded
    Source = OData.Feed(
        "https://<your-api-host>/api/ticketinghub/odata/v1",
        null,
        [ Headers = [ Authorization = "Bearer " & Token ],
          Implementation = "2.0" ]
    )
in
    Source

Power Query folds $select and $filter into the request, so removing columns and filtering rows in the query editor genuinely reduces what is transferred. Do both before loading — this is where the 10 KB-per-row figure bites.

Because the status columns are plain strings rather than OData enum types, they arrive as ordinary text and every connector handles them without special configuration. Model them as dimension columns and use Column values to build the lookup tables.

Power BI's scheduled refresh cannot itself perform the token flow. Most teams land the data in a warehouse with a pipeline and point Power BI at that instead, which also gives them history.

Tableau

Tableau's OData connector expects a URL it can call directly. In practice the same token problem applies, so the common patterns are:

  • Extract to a warehouse or file with a pipeline, then connect Tableau to that. Recommended.
  • Use Tableau's Web Data Connector with a small script that fetches the token.

Azure Data Factory / Synapse

ADF has a first-class OData linked service. The usual shape:

  1. A Web activity calls the token endpoint with the four form fields.
  2. A Copy activity with an OData source uses @activity('GetToken').output.access_token in an Authorization header.
  3. Set the sink to Parquet or your warehouse table.

ADF follows @odata.nextLink automatically, so paging needs no configuration.

Fivetran, Airbyte and similar

Use the generic OData or HTTP/REST source. Configure:

  • Base URL: https://<your-api-host>/api/ticketinghub/odata/v1
  • Auth: bearer token, refreshed by the connector's OAuth2 client-credentials support if it has one
  • Streams: Tickets, TicketUsages, StatisticGroups, Surveys
  • Pagination: follow @odata.nextLink
  • Incremental cursor: LastRefreshedAt for TicketUsages and Surveys only

dbt and modelling

Once the four datasets are landed, the modelling is straightforward — and the traps are documented rather than discovered:

  • Stage each dataset one-to-one, applying SaleIsTest eq false at extract or stage.
  • Build a ticket fact from Tickets, keeping CurrencyShort next to every measure.
  • Build a usage fact from TicketUsages; remember it is scans, not people.
  • Treat StatisticGroups as a bridge table, not a dimension — the many-to-many is the whole point.
  • Treat Surveys at selection grain, aggregating to answer or submission grain in a model above it.
  • Seed the token sets from Column values as small lookup tables, so a status you have never seen before shows up as an unmatched key rather than disappearing.

Getting the numbers right lists every rule these models need to encode.