OData Reporting Service V5

OData Reporting Service V5

Professional Business


Overview

The Gruntify Reporting Service v5 is the current, production-ready implementation of OData reporting for Gruntify workspaces. This service provides a comprehensive, standards-compliant interface for querying workspace data through OData 4.0.

Important Versioning Clarification: The version number "v5" refers to the Gruntify Reporting Service version, not the OData standard version. Gruntify Reporting Service v5 implements the OData 4.0 standard as defined by OASIS. This distinction is important when reviewing OData specifications and documentation.

Deprecation Notice

The previous Gruntify Reporting Service v4.3 is now deprecated and will be retired in a future release. If you are currently using v4.3, plan to migrate your reports and integrations to v5. See the Migrating from v4.3 section for guidance.


Service Root URL

To access the Gruntify Reporting Service v5, use the following URL structure:

{{gruntify-reporting-server}}/v5/odata/workspaces/{{workspace}}/

Where:

  • {{gruntify-reporting-server}} — The reporting server URL for your instance, found in Gruntify under Settings > Workspace

  • {{workspace}} — Your workspace identifier

Example:

https://reporting.gruntify.com/v5/odata/workspaces/acme_city_services/

Authentication

Gruntify Reporting Service v5 uses Basic Authentication with your Gruntify user credentials.

Do NOT use Microsoft Single Sign On (SSO) credentials for API authentication. Use your standard Gruntify username and password. If your account is SSO-only, contact your workspace administrator for API credentials.

When making requests, include the Authorization header with base64-encoded credentials (this is done for you when using tools like Power BI or Excel):

Authorization: Basic base64(username:password)

Entity URLs

The v5 service exposes the following entity sets. Use these URLs to query data from your workspace.

Entity Name

URL Path

Entity Name

URL Path

Users

/users

Teams

/teams

Accreditations

/accreditations

Regions

/regions

Forms

/forms

Assets

/assets

Equipment

/equipment

JobTemplates

/jobtemplates

Jobs

/jobs

Requests

/requests

Trips

/trips

ResourceUsage

/resourceusage

Example queries:

{{gruntify-reporting-server}}/v5/odata/workspaces/{{workspace}}/users {{gruntify-reporting-server}}/v5/odata/workspaces/{{workspace}}/requests?$top=10 {{gruntify-reporting-server}}/v5/odata/workspaces/{{workspace}}/jobs?$filter=status eq 'Completed'

Schema Overview

The Gruntify Reporting Service v5 schema represents workspace entities in a normalized, relational structure designed for reporting and analytics. Below is a diagram of the complete v5 schema:

db1e7806-b13f-4375-9dfb-62a4ca161d5f.png

Key Characteristics

  • Flatter Entity Structure — Entities expose more fields at the top level, reducing the need for deeply nested object navigation

  • Navigation Properties — Relationships between entities are expressed through OData navigation properties, enabling efficient joins without manual key matching

  • Comprehensive Entity Coverage — All major workspace data types are represented, including new entities introduced in v5


Key Schema Changes from v4.3

If you are migrating from Gruntify Reporting Service v4.3, be aware of the following structural and functional changes:

Entity Flattening

Entities in v5 have a flatter structure than v4.3. More fields are exposed at the top level, reducing the number of nested objects:

v4.3 Example (nested):

{ "Id": "job-123", "JobTemplate": { "Id": "template-456", "Name": "Maintenance Work" } }

v5 Example (flatter):

{ "Id": "job-123", "JobTemplateId": "template-456", "JobTemplateName": "Maintenance Work" }

You can still navigate the full Job Template entity using the navigation property:

/jobs('job-123')?$expand=jobTemplate

Navigation Properties

Navigation properties allow you to expand related entities directly in OData queries, without manual joins. Common navigation properties include:

  • JobsjobTemplate, assets, photoMetadata, checkedInHistory, media

  • Requestsassets, regions, photoMetadata, media

  • Usersteams, accreditations, regions

  • AssetsphotoMetadata, media

Example:

{{gruntify-reporting-server}}/v5/odata/workspaces/{{workspace}}/jobs?$expand=jobTemplate,assets

New Entities

v5 introduces or substantially revises the following entities:

  • Trips — Work trip records with associated requests and jobs

  • Equipment — Equipment inventory and assignments

  • PhotoMetadata — Detailed metadata for photos, available as a navigation property on Requests, Jobs, and Assets

Form Data Handling

Form data in v5 is available in two formats:

  1. Structured Format (formData) — An OpenType property containing form field values as key-value pairs, useful for direct access to specific fields

    "formData": { "TextField-8ubq": "Sample Text", "Segmented-hv5u": "Yes" }
  2. Flat Format (flatFormData) — An array of objects with controlId, path, and value, useful for aggregation and filtering

    "flatFormData": [ { "controlId": "TextField-8ubq", "path": "TextField-8ubq", "stringValue": "Sample Text" }, { "controlId": "Segmented-hv5u", "path": "Segmented-hv5u", "stringValue": "Yes" } ]

formData cannot be filtered directly on Assets, Jobs, or Requests. Use flatFormData for OData queries that need to filter on form data values.

Location Data

Location data in v5 uses the NetTopologySuite Point type with the following properties:

  • x — Longitude coordinate

  • y — Latitude coordinate

  • z — Altitude (where available)

  • srid — Spatial reference system identifier

Additional convenience fields include:

  • wktGeometry — Well-Known Text representation of the geometry

  • geoJsonGeometry — GeoJSON representation of the geometry

Example:

"location": { "x": 153.073083, "y": -27.542646, "z": null, "srid": 4326 }, "wktGeometry": "POINT (153.073083 -27.542646)", "geoJsonGeometry": "{\"type\":\"Point\",\"coordinates\":[153.073083,-27.542646]}"

Query Feature Support

  • $count — Supported on most entity sets to retrieve record counts

  • $orderby — Now supported in v5 (was not available in v4.3). Some properties are non-sortable, including navigation properties and complex types


Query Options

The Gruntify Reporting Service v5 supports the following OData query options:

Query Option

Supported

Notes

Query Option

Supported

Notes

$filter

Yes

See filtering guidance below

$orderby

Yes

New in v5. Navigation properties and complex types are non-sortable

$top

Yes

Required for efficient paging

$skip

Yes

Supported; use @odata.nextLink from responses instead

$count

Yes

Supported on most entity sets

$select

Yes

Project specific fields to reduce payload size

$expand

Yes

Expand navigation properties to retrieve related entities

Filtering ($filter)

The $filter option is supported with the following operators:

  • eq — Equals

  • gt — Greater than

  • ge — Greater than or equal

  • lt — Less than

  • le — Less than or equal

  • and — Logical AND

  • or — Logical OR

Important Limitation: Form data cannot be filtered directly on the formData property when querying Assets, Jobs, or Requests. To filter on form data, use flatFormData:

# This will NOT work on Assets, Jobs, or Requests: /requests?$filter=formData/TextField-8ubq eq 'value' # Use flatFormData instead: /requests?$filter=flatFormData/any(item: item/controlId eq 'TextField-8ubq' and item/value eq 'Sample Text')

Sorting ($orderby)

Sorting is supported in v5 and was not available in v4.3. Specify fields to sort by, with optional asc (default) or desc:

/jobs?$orderby=createdAt desc /requests?$orderby=status asc, createdAt desc

Non-sortable properties include:

  • Navigation properties (e.g., jobTemplate)

  • Complex types (e.g., formData, location)

Paging ($top and $skip)

Use $top to limit the number of records returned and $skip to offset results:

/requests?$top=100&$skip=0 /requests?$top=100&$skip=100

Do not construct your own pagination links using $skip. Always use the @odata.nextLink value returned in responses to ensure compatibility with future changes to the API.

Counting ($count)

To retrieve the count of records without fetching the full dataset:

/jobs/$count

To include a count with your query results, append ?$count=true:

/requests?$count=true&$top=10

Projection ($select)

Use $select to retrieve only specific fields, reducing payload size and improving performance:

/users?$select=firstName,lastName,status /jobs?$select=id,reference,status,createdAt

Expansion ($expand)

Use $expand to retrieve related entities through navigation properties:

/jobs?$expand=jobTemplate /requests?$expand=assets,photoMetadata /users?$expand=teams

Expansion can be combined with $select to project specific fields on related entities:

/jobs?$expand=jobTemplate($select=id,name)&$select=id,reference

Paging

For large datasets, pagination is essential to avoid timeouts and excessive data transfer. Follow this guidance:

  1. Set a page size using $top (recommended: 100-200 records per page)

  2. Use the returned @odata.nextLink to fetch subsequent pages

  3. Stop when there is no @odata.nextLink in the response

Example

Initial request:

{{gruntify-reporting-server}}/v5/odata/workspaces/{{workspace}}/requests?$top=100

Response (partial):

{ "@odata.context": "{{gruntify-reporting-server}}/v5/odata/workspaces/{{workspace}}/$metadata#Requests", "@odata.nextLink": "{{gruntify-reporting-server}}/v5/odata/workspaces/{{workspace}}/requests?$top=100&$skip=100", "value": [ { ... }, { ... } ] }

Use the @odata.nextLink URL to fetch the next page:

{{gruntify-reporting-server}}/v5/odata/workspaces/{{workspace}}/requests?$top=100&$skip=100

When there are no more records, the response will not include @odata.nextLink:

{ "@odata.context": "{{gruntify-reporting-server}}/v5/odata/workspaces/{{workspace}}/$metadata#Requests", "value": [ { ... } ] }

The format of @odata.nextLink is subject to change. Always use the provided link instead of constructing your own.


Migrating from v4.3

If you have existing reports or integrations using Gruntify Reporting Service v4.3, follow these migration steps:

Step 1: Update Service Root URL

Change the version segment in your OData URL from v4.3 to v5:

Before:

https://reporting.gruntify.com/v4.3/odata/workspaces/acme_city_services/

After:

https://reporting.gruntify.com/v5/odata/workspaces/acme_city_services/

Step 2: Review Field References

The v5 schema is flatter than v4.3. Update field references to use top-level properties where available:

Before (v4.3, nested):

formData/TextField-8ubq JobTemplate.Name

After (v5, flatter):

flatFormData (for form data queries) JobTemplateName (if only the name is needed)

Step 3: Leverage Navigation Properties

Instead of manually joining entities by ID, use navigation properties to simplify your queries:

Before (v4.3 manual join):

/jobs?$filter=JobTemplateId eq 'template-123' # Then manually fetch JobTemplate by Id /jobtemplates('template-123')

After (v5 with navigation):

/jobs?$expand=jobTemplate&$filter=jobTemplate/name eq 'Maintenance Work'

Step 4: Test Sorting and Filtering

v5 supports $orderby and more sophisticated filtering. Review your existing reports and consider applying sorting or improved filters where beneficial.


Related Content