All Integrations

OData & Power BI Integration

Pull live Standard Time® data into Power BI, Excel, Tableau, or any OData-compatible tool. No export files, no scheduled syncs — your dashboards refresh directly from your shop floor time logs, projects, expenses, and inventory on demand.


What You Can Do with OData

Standard Time® exposes a live OData 4.0 REST feed that any modern BI tool can connect to directly. Instead of exporting a CSV and importing it into a dashboard tool, you point Power BI (or Excel, or Tableau) at the OData endpoint, and it reads fresh data every time you hit Refresh.

Architecture diagram showing Standard Time® data flowing through the OData API to Power BI, Excel, Tableau, Power Automate, and Python
Standard Time® data → OData API → any OData 4.0 consumer, all through the same HTTPS endpoint

Eleven entity sets are available. Each maps to a separate Power BI table you can join to build rich cross-entity reports:

TimeLogs
Time entries — who, what project, when, how long, billable status, and cost
Projects
Work orders / jobs — status, dates, client, rates, quoted cost, folder
ProjectTasks
Tasks — estimated vs. actual hours, cost, % complete, due date
Subprojects
Nested project phases with their own rates and quoted costs
Users
Employees — name, workgroup, role, billing rates, hire date
Clients
Customers — contacts, addresses, tax rate, payment terms
Expenses
Material usage, mileage, out-of-pocket costs per project
Inventory
Parts catalog — qty in stock, costs, SKU, reorder triggers
Categories
Time log / expense categories with per-category billing rates
Invoices
Invoice records — amounts, terms, paid status, balance due
BillingRates
Per-user, per-project, and per-category rate overrides

Install Power BI Desktop

Power BI Desktop is a free Windows app from Microsoft. The Microsoft Store version updates automatically and is the recommended path for most users.

  1. Open the Microsoft Store.
    Click the Start menu and search for Microsoft Store, then open it. Alternatively, press Win + S and type Microsoft Store.
  2. Search for Power BI Desktop.
    In the Store search box, type Power BI Desktop and press Enter. Select the result published by Microsoft Corporation.
  3. Click Install.
    The app is free to download. Installation takes a few minutes. Sign in with your Microsoft or work account when prompted — a free account is sufficient for building and viewing reports locally.
  4. Launch Power BI Desktop.
    After installation, open Power BI Desktop from the Start menu. You will see a splash screen followed by a blank report canvas. You are ready to connect to the Standard Time® OData feed.
Sharing dashboards with colleagues: Power BI Desktop is free for local reports. To publish and share dashboards through the Power BI web service, a Power BI Pro license ($10/user/month) is required. The queries on this page work identically in both the free and Pro versions.

Generate Your API Key

Each call to the OData feed must include an API key in the request header. You generate this key once inside Standard Time® and then paste it into every Power BI query you create.

  1. Open the View menu in Standard Time®.
    In the top menu bar, click View. Scroll down to find the Generate API Key menu item. Standard Time View menu open with Generate API Key item highlighted
  2. Generate or copy your key.
    The API Key dialog shows your current key. If you have never generated a key before, click Generate. The key is a long alphanumeric string. Click anywhere on the key to select it, then copy it to your clipboard — you will paste it into each Power BI M query in the next section. API key dialog showing the generated key with Generate and Revoke buttons
Keep the key private: The API key grants read access to your Standard Time® data. Treat it like a password — do not post it in public repositories or share it outside your team. If a key is ever compromised, return to this dialog and click Revoke to invalidate it, then generate a new one.

Your Customer ID (CID)

Every OData URL also requires your Customer ID (cid), which identifies your account on the server. Your CID is a long alphanumeric string unique to your Standard Time® subscription — it is not a short number. You can find it in Help → About or by asking your Standard Time® administrator. In the query examples below, the placeholder cid=1000 is used — replace it with your actual CID before connecting.


Connect Power BI — Step by Step

Each Standard Time® entity (TimeLogs, Projects, etc.) becomes its own table in Power BI. You add tables one at a time by creating a separate query for each. Here is the complete workflow for adding your first table.

  1. Open Power BI Desktop.
    After the splash screen closes you will see a blank report canvas — no tables, no visuals yet. Power BI Desktop showing a blank report canvas at startup
  2. On the Home ribbon, click Get Data → Blank Query.
    Open the Home tab in the ribbon. Click the Get Data dropdown arrow, then choose More… from the bottom of the list, or look for the Blank Query option directly under New Source. Power BI Home ribbon showing the New Source dropdown with Blank Query option Power BI Get Data menu with Blank Query highlighted
  3. The Power Query Editor opens with an empty query.
    A new window (the Power Query Editor) opens. You will see a query named Query1 in the left-hand Queries pane. The main area shows no data yet. Power Query Editor with a new blank query called Query1 in the Queries pane
  4. Right-click the query name → Advanced Editor.
    In the Queries pane on the left, right-click Query1. In the context menu that appears, select Advanced Editor. This opens the M formula editor where you will paste your query. Right-click context menu on Query1 in the Queries pane with Advanced Editor option highlighted
  5. Select all, then paste the M query for the entity you want.
    In the Advanced Editor, press Ctrl+A to select the existing placeholder text, then paste the M query from the Query Reference section below. Replace YOUR_API_KEY with the key you copied earlier and 1000 with your actual CID. Advanced Editor showing the Standard Time OData M query pasted in
  6. Click Done — Power BI fetches a data preview.
    After clicking Done, Power BI executes the query and shows a preview of the returned rows in the main editor area. If you see column headers and rows of data, the connection is working. Advanced Editor results showing OData data preview after clicking Done
  7. Rename the query, then Close & Apply.
    Double-click the query name in the left pane and rename it to match the entity — for example, TimeLogs. Repeat steps 2–7 for each additional entity set you need. When all queries are added, click Close & Apply on the Home ribbon to load the data into the Power BI data model. Power Query Editor showing multiple named queries with data loaded
Refreshing data: Once queries are set up, click Refresh on the Home ribbon any time you want to pull the latest data from Standard Time®. Power BI re-runs every M query and updates all tables and visuals automatically.

OData Query Reference

Each query below is a complete, paste-ready Power BI M query. Before using them:

  • Replace YOUR_API_KEY with the key you copied from Standard Time®.
  • Replace 1000 in cid=1000 with your actual Customer ID. CIDs are normally long alphanumeric strings — 1000 is a placeholder used in these examples only.
Diagram showing the parts of a Standard Time OData URL: base endpoint, entity set, customer ID, and OData filter
Each OData URL is made of four parts — base endpoint, entity set, your CID, and an optional filter expression
Grid showing all 11 Standard Time OData entity sets with descriptions
All 11 entity sets available in the Standard Time® OData feed

Supported OData Query Parameters

ParameterExampleDescription
$filter$filter=Created gt 2026-01-01T00:00:00-07:00Filter rows server-side before returning results. Supported operators: eq ne gt ge lt le and or not
$select$select=TimeLogID,Date,TimeLogDurationHoursReturn only the named columns — faster load for wide entities
$orderby$orderby=Date descSort the result set by one or more columns
$top$top=500Limit the number of rows returned (default: 1,000)
$skip$skip=1000Skip N rows — combine with $top for pagination
$count$count=trueInclude the total row count in the response metadata

TimeLogs

The core labor data table. Each row is one time entry — who worked, on what project and task, start/end times, duration in hours, billable flag, and computed cost columns. Large datasets; use the DaysBack variable to limit the date range.

let
    // Fetch time logs created in the last N days.
    // Set DaysBack = 9999 to load all records (slower on large accounts).
    DaysBack = 14,

    // Build an ISO 8601 DateTimeOffset string that includes your local UTC offset,
    // e.g. "2026-06-07T00:00:00-07:00". The OData feed compares this against Created.
    Cutoff = DateTimeZone.ToText(
        DateTimeZone.LocalNow() - #duration(DaysBack, 0, 0, 0),
        "yyyy-MM-ddTHH:mm:sszzz"
    ),

    Source = OData.Feed(
        "https://stcloud67.com/odata/TimeLogs?cid=1000&$filter=Created gt " & Cutoff,
        null,
        [Headers = [#"X-Api-Key" = "YOUR_API_KEY"]]
    )
in
    Source

Projects

Work orders and jobs — status, priority, start/finish dates, billing type, quoted cost, and folder. Join to TimeLogs on ProjectID to group hours by job.

let
    DaysBack = 30,

    Cutoff = DateTimeZone.ToText(
        DateTimeZone.LocalNow() - #duration(DaysBack, 0, 0, 0),
        "yyyy-MM-ddTHH:mm:sszzz"
    ),

    Source = OData.Feed(
        "https://stcloud67.com/odata/Projects?cid=1000&$filter=Created gt " & Cutoff,
        null,
        [Headers = [#"X-Api-Key" = "YOUR_API_KEY"]]
    )
in
    Source

ProjectTasks

Task-level data: estimated duration, actual hours logged, remaining hours, cost estimates vs. actuals, percent complete, and due dates. Join to Projects on ProjectID and to TimeLogs on ProjectTaskID.

let
    DaysBack = 30,

    Cutoff = DateTimeZone.ToText(
        DateTimeZone.LocalNow() - #duration(DaysBack, 0, 0, 0),
        "yyyy-MM-ddTHH:mm:sszzz"
    ),

    Source = OData.Feed(
        "https://stcloud67.com/odata/ProjectTasks?cid=1000&$filter=Created gt " & Cutoff,
        null,
        [Headers = [#"X-Api-Key" = "YOUR_API_KEY"]]
    )
in
    Source

Subprojects

Nested project phases and subassemblies. Small table — no date filter needed. Join to Projects on ProjectID.

let
    Source = OData.Feed(
        "https://stcloud67.com/odata/Subprojects?cid=1000",
        null,
        [Headers = [#"X-Api-Key" = "YOUR_API_KEY"]]
    )
in
    Source

Users

Employee roster — full name, email, workgroup, department, role, billing rates, and hire date. Join to TimeLogs on UserID to get employee names on time log rows.

let
    Source = OData.Feed(
        "https://stcloud67.com/odata/Users?cid=1000",
        null,
        [Headers = [#"X-Api-Key" = "YOUR_API_KEY"]]
    )
in
    Source

Clients

Customer records — company name, main and billing contacts, addresses, tax rate, and payment terms. Join to Projects on ClientID for customer-level job reports.

let
    Source = OData.Feed(
        "https://stcloud67.com/odata/Clients?cid=1000",
        null,
        [Headers = [#"X-Api-Key" = "YOUR_API_KEY"]]
    )
in
    Source

Expenses

Material usage, out-of-pocket costs, and mileage records. Created automatically when inventory barcodes are scanned. Combine with TimeLogs for full job cost (labor + materials). Larger tables benefit from a date filter.

let
    DaysBack = 90,

    Cutoff = DateTimeZone.ToText(
        DateTimeZone.LocalNow() - #duration(DaysBack, 0, 0, 0),
        "yyyy-MM-ddTHH:mm:sszzz"
    ),

    Source = OData.Feed(
        "https://stcloud67.com/odata/Expenses?cid=1000&$filter=Created gt " & Cutoff,
        null,
        [Headers = [#"X-Api-Key" = "YOUR_API_KEY"]]
    )
in
    Source

Inventory

Parts catalog — names, SKUs, current stock quantities, unit costs, reorder rules, vendor names. Useful for dashboards tracking stock levels and cost-of-goods data alongside labor.

let
    Source = OData.Feed(
        "https://stcloud67.com/odata/Inventory?cid=1000",
        null,
        [Headers = [#"X-Api-Key" = "YOUR_API_KEY"]]
    )
in
    Source

Categories

Time log and expense categories (e.g., Machining, Assembly, Inspection). Each has optional client and salary rate overrides. Join to TimeLogs on CategoryID.

let
    Source = OData.Feed(
        "https://stcloud67.com/odata/Categories?cid=1000",
        null,
        [Headers = [#"X-Api-Key" = "YOUR_API_KEY"]]
    )
in
    Source

Invoices

Invoice records — date sent, due date, subtotal, tax, total amount, amount paid, balance due, and paid-in-full flag. Join to Clients on ClientID for receivables dashboards.

let
    Source = OData.Feed(
        "https://stcloud67.com/odata/Invoices?cid=1000",
        null,
        [Headers = [#"X-Api-Key" = "YOUR_API_KEY"]]
    )
in
    Source

BillingRates

Per-user, per-project, and per-category billing rate overrides with effective date ranges. Useful for auditing rate changes and building blended-rate calculations in DAX.

let
    Source = OData.Feed(
        "https://stcloud67.com/odata/BillingRates?cid=1000",
        null,
        [Headers = [#"X-Api-Key" = "YOUR_API_KEY"]]
    )
in
    Source

Define Table Relationships

After loading your tables, switch to the Model view (the icon that looks like three connected boxes on the left rail) to define how the tables join. Power BI sometimes auto-detects relationships based on column names — review and correct any it creates automatically.

Power BI Model view showing multiple Standard Time tables with relationship lines between them

To create or edit a relationship, drag a column from one table onto the matching column in another, or double-click an existing relationship line to open the Edit Relationship dialog.

Power BI Edit Relationship dialog showing the column mapping between two tables

Recommended Relationships

From table (many side)ColumnTo table (one side)Column
TimeLogsUserIDUsersUserID
TimeLogsProjectIDProjectsProjectID
TimeLogsClientIDClientsClientID
TimeLogsProjectTaskIDProjectTasksTaskID
TimeLogsCategoryIDCategoriesCategoryID
TimeLogsSubsystemIDSubprojectsSubsystemID
ExpensesUserIDUsersUserID
ExpensesProjectIDProjectsProjectID
ExpensesClientIDClientsClientID
ProjectsClientIDClientsClientID
ProjectTasksProjectIDProjectsProjectID
InvoicesClientIDClientsClientID
InvoicesProjectIDProjectsProjectID
BillingRatesUserIDUsersUserID
BillingRatesProjectIDProjectsProjectID
Cardinality: All relationships above are many-to-one. TimeLogs is the central fact table; Users, Projects, Clients, ProjectTasks, and Categories are dimension tables. This star-schema layout gives DAX the best performance for aggregations across large time log datasets.

Build DAX Measures

After defining relationships, add calculated measures to the TimeLogs or Expenses table for use in charts and cards. To add a measure, right-click the target table in the Fields pane → New measure, then type the DAX formula.

Power BI table showing a DAX formula for Total Hours being entered in the formula bar

Starter DAX Measures

Total Hours — sum of all logged hours across the current filter context:

Total Hours = SUM(TimeLogs[TimeLogDurationHours])

Billable Hours — hours where the Billable flag is true:

Billable Hours = CALCULATE(SUM(TimeLogs[TimeLogDurationHours]), TimeLogs[Billable] = TRUE())

Total Labor Cost — sum of the computed client-side cost field:

Total Labor Cost = SUM(TimeLogs[TimeLogCostClient])

Total Material Cost — sum of expense amounts:

Total Material Cost = SUM(Expenses[ExpenseAmount])

Total Job Cost — labor plus materials combined:

Total Job Cost = [Total Labor Cost] + [Total Material Cost]

Utilization % — billable hours as a percentage of total hours (useful for resource dashboards):

Utilization % = DIVIDE([Billable Hours], [Total Hours], 0)

Hours Last 7 Days — rolling window measure for trend sparklines:

Hours Last 7 Days =
CALCULATE(
    [Total Hours],
    DATESINPERIOD(TimeLogs[Date], TODAY(), -7, DAY)
)

Sample Reports & Dashboards

Once your tables, relationships, and measures are set up, you can build any report by dragging fields from the Fields pane onto the canvas and switching visual types in the Visualizations pane.

Power BI Report view with multiple tables and data showing Standard Time time log data

Common starter visuals for Standard Time® data:

  • Bar chart — Hours by Project: drag ProjectName to Axis, Total Hours to Values
  • Line chart — Daily hours trend: drag TimeLogs[Date] to Axis (set to Day), Total Hours to Values
  • Donut chart — Billable vs. Non-billable: drag TimeLogs[Billable] to Legend, Total Hours to Values
  • Matrix — Hours by Employee and Week: drag Users[FullName] to Rows, TimeLogs[Date] (Week) to Columns, Total Hours to Values
  • KPI cards: drop Total Hours, Billable Hours, Total Labor Cost, and Utilization % onto card visuals
  • Table — Job cost summary: drag ProjectName, Total Hours, Total Labor Cost, Total Material Cost, Total Job Cost
Power BI dashboard showing time and utilization charts from Standard Time data
Scheduling automatic refresh: If you publish your report to the Power BI web service, you can configure a Scheduled Refresh in the dataset settings — Power BI will re-query the Standard Time® OData endpoint at your chosen interval (up to 8 times per day on Pro) and update all report consumers automatically.

Beyond Power BI

The Standard Time® OData feed is a standard HTTP REST API. Any application that can send an authenticated GET request can consume it — Power BI is just the most common starting point. The same API key, CID, and URL patterns work identically in:

Microsoft Excel

Use Data → Get Data → From OData Feed. Paste the entity URL and add the X-Api-Key header in the connection settings. Results land in a Power Query table you can refresh on demand.

Tableau

Connect via Connect → To a Server → OData. Enter the endpoint URL, set the authentication header, and choose the entity sets to pull. Tableau handles pagination automatically.

Grafana

Use the Infinity data source plugin with type set to JSON and the OData URL as the endpoint. Add X-Api-Key as a custom header. Good for real-time shop floor dashboards on wall-mounted displays.

Power Automate

Use an HTTP action with the OData URL, GET method, and X-Api-Key header. Parse the returned JSON with Parse JSON and feed the results into downstream steps — Teams notifications, SharePoint lists, or email summaries.

Python / pandas

A simple requests.get(url, headers={"X-Api-Key": key}) call returns JSON. Parse response.json()["value"] directly into a pandas DataFrame for custom analysis, ML pipelines, or ETL jobs.

R

Use httr::GET(url, httr::add_headers("X-Api-Key" = key)) and parse the response with jsonlite::fromJSON. The odata CRAN package also provides a native OData client for R.

Azure Data Factory

Add an OData linked service pointing to the Standard Time® endpoint. ADF handles pagination natively and can load data into Azure SQL, Data Lake, or Synapse Analytics on a schedule.

Postman / curl

Use Postman or curl to explore the API, test filters, and prototype queries before building full integrations. Add the X-Api-Key header and call any entity URL to inspect the raw JSON response.

OData is a published standard: OData 4.0 is an OASIS open standard (ISO/IEC 20802). Any tool that advertises OData 4.0 compatibility will work with the Standard Time® feed out of the box — no custom connectors or plugins required beyond authentication.

Related guides:
Build Four Dashboards in Power BI — step-by-step recipes for shop floor time, project budget, full job cost, and inventory health dashboards using these same OData queries.
OData Schema Reference — every entity set, every column name, OData type, and FK relationship in one place.
Google Sheets IntegrationQuickBooks Online IntegrationAll Integrations
Back to Integrations

Ready to Build Live Dashboards from Your Shop Floor?

Start a free 30-day trial and connect Power BI, Excel, or any OData tool to your real Standard Time® data.

View Pricing Contact Us