Skip to main content

Ownership

Every Query has an ownerId that points at a Principal: either a user (whose Principal id is its username) or a team (whose Principal id is the team id). The owner is part of the Query's natural id (ownerId:slug), so transferring ownership changes the natural id.

These two routes read the current owner and transfer ownership to a different Principal.

GET /api/queries/{id}/owner

Resolve a Query's ownerId to a Principal and return it as HAL.

Authentication: Required

Path Parameters:

ParameterTypeDescription
idstringQuery UUID or natural id (ownerId:slug)

Response:

A HAL Principal body: a flat { id, userId, teamId, tenant } envelope whose matching subtype is embedded under _embedded. A user-owned Query embeds inf:user (and teamId is null); a team-owned Query embeds inf:team (and userId is null). Whichever subtype matches is embedded; the other rel is absent. This is not the flat { username, displayName, email, avatar } (user) or { name, slug, memberCount } (team) object.

Get a query owner (user-owned)GET /api/queries/00000000-0000-4000-8000-000000000001/owner
GET /api/queries/{id}/owner resolves the query’s ownerId to a Principal and returns it as HAL. For a user-owned query the matching `inf:user` is embedded under `_embedded` (the `inf:team` rel is absent). `{id}` accepts the UUID or the natural id (ownerId:slug).
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/queries/00000000-0000-4000-8000-000000000001/owner"
}
},
"id": "admin",
"userId": "admin",
"teamId": null,
"tenant": "acme",
"_embedded": {
"inf:user": {
"_links": {
"self": {
"href": "https://informer.example.com/api/users/admin"
},
"inf:memberships": {
"href": "https://informer.example.com/api/users/admin/memberships"
},
"inf:avatar-upload": {
"href": "https://informer.example.com/api/users/admin/_upload/{uploadId}/avatar-upload",
"templated": true
},
"inf:password": {
"href": "https://informer.example.com/api/users/admin/password"
},
"inf:feed": {
"href": "https://informer.example.com/api/users/admin/feed"
},
"inf:viewed-feed": {
"href": "https://informer.example.com/api/users/admin/_markFeedViewed"
},
"inf:superuser": {
"href": "https://informer.example.com/api/users/admin/superuser"
}
},
"permissions": {
"changeDomain": false,
"changeProfile": true,
"changePassword": true,
"delete": false,
"edit": true,
"reassign": true,
"superuser": true,
"enable": true,
"changeTheme": true,
"lock": true,
"setGlobalPermissions": true,
"manageLogin": true
},
"domain": "local",
"username": "admin",
"displayName": "acme Administrator",
"familyName": "Administrator",
"givenName": "acme",
"middleName": null,
"email": null,
"data": null,
"superuser": true,
"timezone": "America/New_York",
"settings": {
"log": {
"log": false,
"info": false,
"warn": false,
"debug": false,
"error": true,
"remote": false
}
},
"enabled": true,
"source": null,
"sourceId": null,
"lastViewedFeed": null,
"tenant": "acme",
"globalPermissions": {
"ai": false,
"jobCreation": true,
"viewAllTeams": true,
"viewAllUsers": true,
"painlessScriptCreation": true
},
"userFields": {},
"locked": false,
"lockedAt": null,
"loginAttempts": 0,
"passwordSetAt": "2026-01-15T16:20:00.000Z",
"passwordExpiresAt": "2026-01-15T16:20:00.000Z",
"forgotPasswordRequestTime": null,
"mfa": null,
"mfaConfig": {},
"aiMessage": null,
"aiConsent": false,
"hasSharedDatasources": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"initials": "EA",
"colorIndex": 4,
"avatarColor": {
"background": "#81C784",
"text": "#1B5E20"
},
"managesPassword": true
}
}
}
Captured from the API examples test suite; ids and timestamps are normalized.

For a team-owned Query the matching inf:team Principal is embedded instead.

Get a query owner (team-owned)GET /api/queries/00000000-0000-4000-8000-000000000001/owner
After a team transfer, GET /api/queries/{id}/owner embeds the matching `inf:team` Principal (the `inf:user` rel is absent).
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/queries/00000000-0000-4000-8000-000000000001/owner"
}
},
"id": "analytics",
"userId": null,
"teamId": "analytics",
"tenant": "acme",
"_embedded": {
"inf:team": {
"_links": {
"self": {
"href": "https://informer.example.com/api/teams/analytics"
}
},
"permissions": {
"addComment": true,
"addMember": true,
"delete": true,
"removeMember": true,
"editMemberRole": true,
"write": true,
"reassign": true,
"assignOwnership": true
},
"id": "analytics",
"name": "Analytics Team",
"description": "Data analytics and reporting team",
"domain": "local",
"data": null,
"icon": null,
"materialIcon": null,
"color": null,
"defaultRole": null,
"source": null,
"sourceId": null,
"lastViewedFeed": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"_changes": null,
"tenant": "acme"
}
}
}
Captured from the API examples test suite; ids and timestamps are normalized.

PUT /api/queries/{id}/owner

Transfer ownership of a Query to a different user or team.

Authentication: Required

Permission: query:write on the Query (Designer for ad-hoc, Data Wizard for embedded; superusers pass).

Path Parameters:

ParameterTypeDescription
idstringQuery UUID or natural id (ownerId:slug)

Request Body:

The route has no Joi payload validation. The entire payload is passed straight to the Principal lookup as its where clause, so the only reliable key is id, set to the target Principal's id.

FieldTypeRequiredDescription
idstringYesTarget Principal id. A user's id is its username; a team's id is the team id.
Use id, not username

A user's Principal id is its username, so the transfer target always goes in id. There is no username column on Principal, so a { "username": "..." } payload is unreliable. A payload that resolves to no Principal answers 400.

Example Request (transfer to a user):

{
"id": "annie.larson"
}

Example Request (transfer to a team):

{
"id": "analytics"
}

Response:

Responds 200 (not 201) with the updated Query and a Location header pointing at the Query's new natural-id lookup. The response body is the full updated Query: its ownerId, naturalId, and _links now reflect the new owner. The natural id changes from oldOwner:slug to newOwner:slug.

Transfer a query to a userPUT /api/queries/00000000-0000-4000-8000-000000000001/owner
PUT /api/queries/{id}/owner with { id: “<username>” } (a user’s Principal id is its username). The whole payload is the lookup `where`, so use `id`, not the `username` key the older docs showed. Requires query:write (Designer/Data Wizard; superusers pass). Returns 200 (not 201) with the updated Query and a Location header; the query’s naturalId changes to newOwner:slug. Records a queryAssigned activity.
Request body
{
"id": "annie.larson"
}
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/queries/00000000-0000-4000-8000-000000000001"
},
"inf:run": {
"href": "https://informer.example.com/api/queries/annie.larson%3Asales-analysis-query/_run{?progress}",
"templated": true
},
"inf:benchmark": {
"href": "https://informer.example.com/api/queries/annie.larson%3Asales-analysis-query/_benchmark{?progress}",
"templated": true
},
"inf:execute": {
"href": "https://informer.example.com/api/queries/annie.larson%3Asales-analysis-query/_execute{?output,limit,pretty,timezone,applyFormatting}",
"templated": true
},
"inf:comments": {
"href": "https://informer.example.com/api/queries/00000000-0000-4000-8000-000000000001/comments"
},
"inf:dataset": {
"href": "https://informer.example.com/api/queries/annie.larson%3Asales-analysis-query/dataset"
},
"inf:query-shares": {
"href": "https://informer.example.com/api/queries/00000000-0000-4000-8000-000000000001/shares"
},
"inf:query-share": {
"href": "https://informer.example.com/api/queries/00000000-0000-4000-8000-000000000001/shares/{principalId}",
"templated": true
},
"inf:draft": {
"href": "https://informer.example.com/api/queries/annie.larson%3Asales-analysis-query/draft"
},
"inf:query-tags": {
"href": "https://informer.example.com/api/queries/00000000-0000-4000-8000-000000000001/tags"
},
"inf:favorite": {
"href": "https://informer.example.com/api/queries/00000000-0000-4000-8000-000000000001/favorite"
},
"inf:query-tag": {
"href": "https://informer.example.com/api/queries/00000000-0000-4000-8000-000000000001/tags/{tagId}",
"templated": true
},
"inf:export-bundle": {
"href": "https://informer.example.com/api/queries/00000000-0000-4000-8000-000000000001/_export"
},
"edit": {
"href": "https://informer.example.com/api/queries/annie.larson%3Asales-analysis-query/_edit"
},
"inf:owner": {
"href": "https://informer.example.com/api/queries/00000000-0000-4000-8000-000000000001/owner"
},
"inf:user-settings": {
"href": "https://informer.example.com/api/queries/annie.larson%3Asales-analysis-query/settings"
},
"inf:input-templates": {
"href": "https://informer.example.com/api/queries/annie.larson%3Asales-analysis-query/input-templates{?dataType,wildcard}",
"templated": true
}
},
"naturalId": "annie.larson:sales-analysis-query",
"fields": null,
"permissions": {
"assignTags": true,
"changeOwner": true,
"copy": true,
"delete": true,
"edit": true,
"rename": true,
"run": false,
"share": true,
"write": true
},
"id": "00000000-0000-4000-8000-000000000001",
"tenant": "acme",
"ownerId": "annie.larson",
"slug": "sales-analysis-query",
"name": "Sales Analysis Query",
"description": null,
"shared": false,
"embedded": false,
"source": null,
"sourceId": null,
"settings": {},
"inputs": null,
"language": "informer",
"flow": null,
"payload": {
"fields": [],
"groupBy": [],
"distinct": false
},
"defnUpdatedAt": null,
"limit": -1,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"datasourceId": null,
"editingId": null,
"folderId": null,
"datasource": null,
"_embedded": {
"inf:query-language": {
"_links": {
"self": {
"href": "https://informer.example.com/api/query-languages/informer"
}
},
"id": "informer",
"name": "common:ad_hoc_query",
"description": "query-languages:ad_hoc.description",
"image": "/assets/query-languages/images/query-designer.svg",
"color": "blue",
"preProcessors": [
"iqlTclPredicateValidationProcessor",
"resolveLinkRefProcessor",
"iqlPayloadFieldPermissionEvaluator",
"… 8 more items (11 total) — omitted from docs"
]
}
}
}
Captured from the API examples test suite; ids and timestamps are normalized.

Transferring to a team uses the team's Principal id; the natural id becomes teamId:slug.

Transfer a query to a teamPUT /api/queries/00000000-0000-4000-8000-000000000001/owner
Team transfer uses the team’s Principal id: { id: “<teamId>” }. The response is the updated Query; its natural id becomes <teamId>:slug.
Request body
{
"id": "analytics"
}
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/queries/00000000-0000-4000-8000-000000000001"
},
"inf:run": {
"href": "https://informer.example.com/api/queries/analytics%3Arevenue-query/_run{?progress}",
"templated": true
},
"inf:benchmark": {
"href": "https://informer.example.com/api/queries/analytics%3Arevenue-query/_benchmark{?progress}",
"templated": true
},
"inf:execute": {
"href": "https://informer.example.com/api/queries/analytics%3Arevenue-query/_execute{?output,limit,pretty,timezone,applyFormatting}",
"templated": true
},
"inf:comments": {
"href": "https://informer.example.com/api/queries/00000000-0000-4000-8000-000000000001/comments"
},
"inf:dataset": {
"href": "https://informer.example.com/api/queries/analytics%3Arevenue-query/dataset"
},
"inf:query-shares": {
"href": "https://informer.example.com/api/queries/00000000-0000-4000-8000-000000000001/shares"
},
"inf:query-share": {
"href": "https://informer.example.com/api/queries/00000000-0000-4000-8000-000000000001/shares/{principalId}",
"templated": true
},
"inf:draft": {
"href": "https://informer.example.com/api/queries/analytics%3Arevenue-query/draft"
},
"inf:query-tags": {
"href": "https://informer.example.com/api/queries/00000000-0000-4000-8000-000000000001/tags"
},
"inf:favorite": {
"href": "https://informer.example.com/api/queries/00000000-0000-4000-8000-000000000001/favorite"
},
"inf:query-tag": {
"href": "https://informer.example.com/api/queries/00000000-0000-4000-8000-000000000001/tags/{tagId}",
"templated": true
},
"inf:export-bundle": {
"href": "https://informer.example.com/api/queries/00000000-0000-4000-8000-000000000001/_export"
},
"edit": {
"href": "https://informer.example.com/api/queries/analytics%3Arevenue-query/_edit"
},
"inf:owner": {
"href": "https://informer.example.com/api/queries/00000000-0000-4000-8000-000000000001/owner"
},
"inf:user-settings": {
"href": "https://informer.example.com/api/queries/analytics%3Arevenue-query/settings"
},
"inf:input-templates": {
"href": "https://informer.example.com/api/queries/analytics%3Arevenue-query/input-templates{?dataType,wildcard}",
"templated": true
}
},
"naturalId": "analytics:revenue-query",
"fields": null,
"permissions": {
"assignTags": true,
"changeOwner": true,
"copy": true,
"delete": true,
"edit": true,
"rename": true,
"run": false,
"share": true,
"write": true
},
"id": "00000000-0000-4000-8000-000000000001",
"tenant": "acme",
"ownerId": "analytics",
"slug": "revenue-query",
"name": "Revenue Query",
"description": null,
"shared": false,
"embedded": false,
"source": null,
"sourceId": null,
"settings": {},
"inputs": null,
"language": "informer",
"flow": null,
"payload": {
"fields": [],
"groupBy": [],
"distinct": false
},
"defnUpdatedAt": null,
"limit": -1,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"datasourceId": null,
"editingId": null,
"folderId": null,
"datasource": null,
"_embedded": {
"inf:query-language": {
"_links": {
"self": {
"href": "https://informer.example.com/api/query-languages/informer"
}
},
"id": "informer",
"name": "common:ad_hoc_query",
"description": "query-languages:ad_hoc.description",
"image": "/assets/query-languages/images/query-designer.svg",
"color": "blue",
"preProcessors": [
"iqlTclPredicateValidationProcessor",
"resolveLinkRefProcessor",
"iqlPayloadFieldPermissionEvaluator",
"… 8 more items (11 total) — omitted from docs"
]
}
}
}
Captured from the API examples test suite; ids and timestamps are normalized.
Activity tracking

Transferring ownership records a queryAssigned Activity entry.

Natural id changes

Because the owner is part of the natural id, a transfer changes it from oldOwner:slug to newOwner:slug. References that use the natural id need to be updated; references that use the Query UUID are stable across transfers.