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 |
|---|---|
Users |
|
Teams |
|
Accreditations |
|
Regions |
|
Forms |
|
Assets |
|
Equipment |
|
JobTemplates |
|
Jobs |
|
Requests |
|
Trips |
|
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:
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=jobTemplateNavigation Properties
Navigation properties allow you to expand related entities directly in OData queries, without manual joins. Common navigation properties include:
Jobs →
jobTemplate,assets,photoMetadata,checkedInHistory,mediaRequests →
assets,regions,photoMetadata,mediaUsers →
teams,accreditations,regionsAssets →
photoMetadata,media
Example:
{{gruntify-reporting-server}}/v5/odata/workspaces/{{workspace}}/jobs?$expand=jobTemplate,assetsNew 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:
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" }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 |
|---|---|---|
| Yes | See filtering guidance below |
| Yes | New in v5. Navigation properties and complex types are non-sortable |
| Yes | Required for efficient paging |
| Yes | Supported; use |
| Yes | Supported on most entity sets |
| Yes | Project specific fields to reduce payload size |
| Yes | Expand navigation properties to retrieve related entities |
Filtering ($filter)
The $filter option is supported with the following operators:
eq— Equalsgt— Greater thange— Greater than or equallt— Less thanle— Less than or equaland— Logical ANDor— 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 descNon-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=100Do 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/$countTo include a count with your query results, append ?$count=true:
/requests?$count=true&$top=10Projection ($select)
Use $select to retrieve only specific fields, reducing payload size and improving performance:
/users?$select=firstName,lastName,status
/jobs?$select=id,reference,status,createdAtExpansion ($expand)
Use $expand to retrieve related entities through navigation properties:
/jobs?$expand=jobTemplate
/requests?$expand=assets,photoMetadata
/users?$expand=teamsExpansion can be combined with $select to project specific fields on related entities:
/jobs?$expand=jobTemplate($select=id,name)&$select=id,referencePaging
For large datasets, pagination is essential to avoid timeouts and excessive data transfer. Follow this guidance:
Set a page size using
$top(recommended: 100-200 records per page)Use the returned
@odata.nextLinkto fetch subsequent pagesStop when there is no
@odata.nextLinkin the response
Example
Initial request:
{{gruntify-reporting-server}}/v5/odata/workspaces/{{workspace}}/requests?$top=100Response (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=100When 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.NameAfter (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