Related Resources
There are two ways to work with data related to a resource:
- Embed it in the response with the
?include=query parameter — good for reading related data alongside the parent in one request. - Access it under a nested URL — good for operating on the relationship or paging through a large related collection.
Tourfold does not use a JSON:API-style relationships / included envelope. Included data is
embedded inline in the resource it belongs to.
Embedding related data with ?include=​
?include= is opt-in: related data is only present when you ask for it. The value is a list of
named embeddable resources, and which names are valid is defined per endpoint and documented in
the OpenAPI specification — there is no universal include catalog.
It is available on selected read endpoints, not all of them.
Example: device current state​
GET /api/v2/devices/{device_id} and GET /api/v2/devices accept ?include=current_state. The
materialized state is embedded as a current_state field on the device, present only when
requested:
curl "https://api.tourfold.com/api/v2/devices/a1b2c3d4-e5f6-4a1b-8c9d-123456789abc?include=current_state" \
-H "Authorization: Bearer YOUR_TOKEN"
{
"id": "a1b2c3d4-e5f6-4a1b-8c9d-123456789abc",
"kind": "TOURFOLD_APP",
"device_model": "iPhone 15",
"provisioning_state": "PROVISIONED",
"lock_version": 3,
"current_state": {
"last_received_at": "2024-01-15T10:29:00Z",
"location": { "latitude": 48.2038, "longitude": 16.3698 }
}
}
Without ?include=current_state, the current_state field is simply absent.
Example: custom-object relations​
Custom-object instances contain their own dynamic properties under data; related instances are
not embedded as made-up relationship attributes. Read an equipment instance with its definition
slug and instance ID:
curl "https://api.tourfold.com/api/v2/custom-objects/instances/equipment/6f3d2a10-0000-4000-8000-000000000101" \
-H "Authorization: Bearer YOUR_TOKEN"
{
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"slug": "equipment",
"title": "Equipment",
"type": "object"
},
"data": {
"id": "6f3d2a10-0000-4000-8000-000000000101",
"created_at": "2026-03-01T08:00:00Z",
"updated_at": "2026-03-01T08:00:00Z",
"name": "Rooftop Unit RTU-17",
"asset_tag": "AFS-RTU-17",
"operational": true
},
"display_value": "Rooftop Unit RTU-17",
"lock_version": 0
}
To read its related maintenance requests, use the relation slug declared in the custom-object relation:
curl "https://api.tourfold.com/api/v2/custom-objects/instances/equipment/6f3d2a10-0000-4000-8000-000000000101/associated/maintenance_requests" \
-H "Authorization: Bearer YOUR_TOKEN"
The response is the standard custom-object items + schema + page envelope. For filtering,
sorting, paginating, or traversing several custom-object relations in one read, use the
read-only GraphQL API.
Nested resource URLs​
Related collections are also addressable directly. Real examples:
# Maintenance requests associated with one equipment instance
GET /api/v2/custom-objects/instances/equipment/{instance_id}/associated/maintenance_requests
# A user's skills (whole-set; see Creating & Updating Resources for PUT semantics)
GET /api/v2/users/{user_id}/skills
PUT /api/v2/users/{user_id}/skills
# A user's tags
GET /api/v2/users/{user_id}/tags
Collection shapes and pagination capabilities are declared per operation. Paginated collections
follow the standard items + page envelope; the custom-object association endpoint returns the
same envelope for its complete related set. See
Pagination, Sorting & Filtering.
When to embed vs. use a nested URL​
Use ?include= when:
- You need a bit of related data for display alongside the parent.
- You want to avoid a second round-trip.
Use the nested URL when:
- You need to page through a large related collection.
- You want to operate on the relationship (replace a user's skills, list associated custom-object instances).
Keep ?include= lists minimal — each included resource adds work and response size.
Error handling​
Errors are RFC 9457 problem documents (see Errors):
{
"type": "https://problems.tourfold.com/not-found",
"title": "Resource not found",
"detail": "No record with id 'a1b2c3d4-e5f6-4a1b-8c9d-123456789abc' exists"
}