Skip to main content

Sharing & Ownership

Endpoints for managing Toolkit ownership and per-principal shares, plus the Toolkit driver lookup.

Every route on this page resolves the Toolkit through the toolkit.lookup server method, which calls ai.verify() internally. AI must therefore be enabled on the tenant for any of these routes to resolve the Toolkit at all, not just the owner routes (which also list an explicit ai.verify pre-block).

Ownership

GET /api/toolkits/{id}/owner

Get the owner of a Toolkit.

Authentication: Required (AI enabled on the tenant)

Pre-blocks: toolkit.lookup, ai.verify

Response:

The owner is a Principal. The matching inf:user (or inf:team for a team-owned Toolkit) is embedded. This is a Principal HAL resource, not the flat { ownerId, ownerType } object.

Get a toolkit's ownerGET /api/toolkits/00000000-0000-4000-8000-000000000001/owner
The owner is a Principal; the matching inf:user (or inf:team) is embedded. The flat { ownerId, ownerType } shape is not what this route returns.
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/toolkits/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.

PUT /api/toolkits/{id}/owner

Transfer Toolkit ownership to another Principal.

Authentication: Required (AI enabled on the tenant)

Permission: toolkit:changeOwner (admin on the Toolkit), plus a change-owner-to-team check (data-wizard of the target team). A superuser satisfies both.

Request Body:

The payload is the new owner's Principal row, looked up with Principal.find({ where: payload }). Pass the principal id in id, not an ownerId field. A team principal id is the team id (for example marketing); a user principal id is the username. A payload that matches no Principal answers 400.

FieldTypeRequiredDescription
idstringYesPrincipal id of the new owner (team id or username)

Example Request:

{
"id": "marketing"
}

Response:

Responds 200 with the updated Toolkit. Transferring re-addresses the Toolkit: its naturalId becomes <newOwner>:<slug> (for example marketing:order-desk-tools), and the response carries a Location header.

Transfer toolkit ownershipPUT /api/toolkits/00000000-0000-4000-8000-000000000001/owner
The payload is the new owner’s PRINCIPAL row: { "id": "<principalId>" } (a team id or a username), NOT { "ownerId" }. Permission: toolkit:changeOwner. Transferring re-addresses the toolkit (naturalId becomes "<newOwner>:<slug>") and sets a Location header.
Request body
{
"id": "marketing"
}
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/toolkits/00000000-0000-4000-8000-000000000001"
},
"inf:toolkit-share": {
"href": "https://informer.example.com/api/toolkits/00000000-0000-4000-8000-000000000001/shares/{principalId}",
"templated": true
},
"inf:favorite": {
"href": "https://informer.example.com/api/toolkits/00000000-0000-4000-8000-000000000001/favorite"
},
"inf:toolkit-owner": {
"href": "https://informer.example.com/api/toolkits/marketing%3Aorder-desk-tools/owner"
},
"inf:toolkit-shares": {
"href": "https://informer.example.com/api/toolkits/marketing%3Aorder-desk-tools/shares"
},
"inf:toolkit-tools": {
"href": "https://informer.example.com/api/toolkits/marketing%3Aorder-desk-tools/tools"
},
"inf:toolkit-discover": {
"href": "https://informer.example.com/api/toolkits/00000000-0000-4000-8000-000000000001/discover"
}
},
"naturalId": "marketing:order-desk-tools",
"allowUserInstances": true,
"executionLocation": "server",
"canManageTools": true,
"permissions": {
"write": true,
"edit": true,
"delete": true,
"share": true,
"assignTags": true,
"changeOwner": true
},
"id": "00000000-0000-4000-8000-000000000001",
"name": "Order Desk Tools",
"slug": "order-desk-tools",
"type": "custom",
"description": "Custom API tools for the Order Desk app",
"instructions": null,
"ownerId": "marketing",
"shared": false,
"folderId": null,
"config": null,
"integrationId": null,
"source": null,
"sourceId": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"integration": null,
"_embedded": {
"inf:driver": {
"_links": {
"self": {
"href": "https://informer.example.com/api/toolkits/00000000-0000-4000-8000-000000000001/driver"
}
},
"id": "custom",
"name": "Integration Toolkit",
"description": "Create API tools that call external services via an Integration",
"image": "/images/icons/toolkit-server.svg",
"viewComponent": "customToolkitView",
"executionLocation": "server",
"allowUserInstances": true,
"canManageTools": true,
"supportsIntegration": true,
"editorComponent": {}
}
}
}
Captured from the API examples test suite; ids and timestamps are normalized.

Shares

A share grants a Principal access to a Toolkit at a given access level. The PUT is an upsert keyed on the URL's principalId; DELETE removes the share.

GET /api/toolkits/{id}/shares

List a Toolkit's shares.

Authentication: Required (AI enabled on the tenant)

Pre-blocks: toolkit.lookup

Response:

A HAL collection whose rows are enriched Principal details, built from a SQL join and filtered to accessLevel > 0. Each row carries the Principal type ("User" or "Team"), a display name, and either team icon/color or user avatar data, alongside the share's toolkitId, principalId, and accessLevel. Each row links to inf:toolkit-share. This is not the raw toolkit_share columns.

List a toolkit's sharesGET /api/toolkits/00000000-0000-4000-8000-000000000001/shares
A HAL collection whose rows are enriched principal details (type "User"/"Team", display name, team icon/color or user avatar data), built from a SQL join and filtered to accessLevel > 0. Each row links to inf:toolkit-share. This is not the raw toolkit_share columns.
Response · 200
[
{
"toolkitId": "00000000-0000-4000-8000-000000000001",
"principalId": "marketing",
"accessLevel": 2,
"id": "marketing",
"teamId": "marketing",
"name": "Marketing",
"materialIcon": "campaign",
"icon": null,
"color": "purple",
"username": null,
"displayName": null,
"email": null,
"avatarUpdatedAt": null,
"type": "Team"
}
]
Captured from the API examples test suite; ids and timestamps are normalized.

GET /api/toolkits/{id}/shares/{principalId}

Get a single share.

Authentication: Required (AI enabled on the tenant)

Pre-blocks: toolkit.lookup

Response:

Returns one ToolkitShare (toolkitId, principalId, accessLevel, plus timestamps).

Get a single shareGET /api/toolkits/00000000-0000-4000-8000-000000000001/shares/marketing
Returns one ToolkitShare (toolkitId, principalId, accessLevel). A missing share 404s ("Share not found").
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/toolkits/00000000-0000-4000-8000-000000000001/shares/marketing"
}
},
"id": "00000000-0000-4000-8000-000000000002",
"tenant": "acme",
"toolkitId": "00000000-0000-4000-8000-000000000001",
"principalId": "marketing",
"accessLevel": 2,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z"
}
Captured from the API examples test suite; ids and timestamps are normalized.
Missing share answers 404

A Principal with no share on this Toolkit yields 404 Not Found with the message Share not found.

Get a share that does not existGET /api/toolkits/00000000-0000-4000-8000-000000000001/shares/nobody
A principal with no share on this toolkit yields 404 "Share not found".
Response · 404
{
"statusCode": 404,
"error": "Not Found",
"message": "Share not found"
}
Captured from the API examples test suite; ids and timestamps are normalized.

PUT /api/toolkits/{id}/shares/{principalId}

Create or update a share. This is an upsert: repeat the PUT to change the access level for the same Principal.

Authentication: Required (AI enabled on the tenant)

Permission: toolkit:share

Request Body:

The principalId is taken from the URL (a user username or a team id). To remove a share, use DELETE rather than an access level of 0.

FieldTypeRequiredDescription
accessLevelintegerNoAccess level (integer >= 1, default 1)

Example Request:

{
"accessLevel": 2
}

Response:

Responds 200 with the saved ToolkitShare, not 201.

Share a toolkit with a principalPUT /api/toolkits/00000000-0000-4000-8000-000000000001/shares/marketing
Upsert: repeat the PUT to change accessLevel. Payload is { accessLevel } (integer >= 1, default 1; use DELETE to remove, not accessLevel 0). principalId is a user username or a team id, taken from the URL. Returns the saved ToolkitShare with status 200 (NOT 201). Permission: toolkit:share.
Request body
{
"accessLevel": 2
}
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/toolkits/00000000-0000-4000-8000-000000000001/shares/marketing"
}
},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000002",
"toolkitId": "00000000-0000-4000-8000-000000000001",
"principalId": "marketing",
"accessLevel": 2,
"updatedAt": "2026-01-15T16:20:00.000Z",
"createdAt": "2026-01-15T16:20:00.000Z"
}
Captured from the API examples test suite; ids and timestamps are normalized.

DELETE /api/toolkits/{id}/shares/{principalId}

Remove a share.

Authentication: Required (AI enabled on the tenant)

Permission: toolkit:share

Response:

Responds 200 with an empty body (Informer db.remove convention), not 204.

Remove a shareDELETE /api/toolkits/00000000-0000-4000-8000-000000000001/shares/marketing
Responds 200 with an EMPTY body (Informer/db.remove convention), NOT 204. Permission: toolkit:share.
Response · 200 · no body
Captured from the API examples test suite; ids and timestamps are normalized.

Access Levels

LevelNamePermissions
1ReadView Toolkit, use tools in chats
2WriteEdit Toolkit, manage tools, configure settings
3AdminFull control, change ownership, manage shares

GET /api/toolkits/{id}/driver

Get the driver singleton for a Toolkit, selected by the Toolkit's type.

Authentication: Required (AI enabled on the tenant)

Pre-blocks: toolkit.lookup

Response:

The driver singleton's plain-data fields. Driver methods are functions and drop out of JSON, so the response carries only the data fields: id, name, description, image, viewComponent, executionLocation, allowUserInstances, canManageTools, and supportsIntegration.

Get a toolkit's driverGET /api/toolkits/00000000-0000-4000-8000-000000000001/driver
Returns the toolkit driver singleton for the toolkit’s `type`. Driver methods are functions and drop out of JSON; the response carries the driver’s plain-data fields (id, name, description, image, viewComponent, executionLocation, allowUserInstances, canManageTools, supportsIntegration).
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/toolkits/00000000-0000-4000-8000-000000000001/driver"
}
},
"id": "custom",
"name": "Integration Toolkit",
"description": "Create API tools that call external services via an Integration",
"image": "/images/icons/toolkit-server.svg",
"viewComponent": "customToolkitView",
"executionLocation": "server",
"allowUserInstances": true,
"canManageTools": true,
"supportsIntegration": true,
"editorComponent": {}
}
Captured from the API examples test suite; ids and timestamps are normalized.

Favorite

The current user's favorite flag on a toolkit.

GET /api/toolkits/{id}/favorite

Read the current user's favorite status.

Get toolkit favorite statusGET /api/toolkits/admin:order-tools/favorite
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/toolkits/admin%3Aorder-tools/favorite"
}
},
"permissions": {},
"id": "00000000-0000-4000-8000-000000000001",
"principalId": "admin",
"reportId": null,
"datasetId": null,
"queryId": null,
"datasourceId": null,
"jobId": null,
"assistantId": null,
"templateId": null,
"libraryId": null,
"appId": null,
"integrationId": null,
"toolkitId": "00000000-0000-4000-8000-000000000002",
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme"
}
Captured from the API examples test suite; ids and timestamps are normalized.

PUT /api/toolkits/{id}/favorite

Mark the toolkit as a favorite.

Mark a toolkit as favoritePUT /api/toolkits/admin:order-tools/favorite
PUT /api/toolkits/{id}/favorite flags the toolkit as a favorite for the current user.
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/toolkits/admin%3Aorder-tools/favorite"
}
},
"permissions": {},
"id": "00000000-0000-4000-8000-000000000001",
"tenant": "acme",
"toolkitId": "00000000-0000-4000-8000-000000000002",
"principalId": "admin",
"reportId": null,
"datasetId": null,
"queryId": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"datasourceId": null,
"jobId": null,
"templateId": null,
"assistantId": null,
"libraryId": null,
"appId": null,
"integrationId": null
}
Captured from the API examples test suite; ids and timestamps are normalized.

DELETE /api/toolkits/{id}/favorite

Clear the favorite flag. Returns 200 with an empty body.

Clear toolkit favoriteDELETE /api/toolkits/admin:order-tools/favorite
DELETE /api/toolkits/{id}/favorite removes the current user’s favorite flag.
Response · 200 · no body
Captured from the API examples test suite; ids and timestamps are normalized.