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.
{
"_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
}
}
}
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.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Principal 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.
{
"id": "marketing"
}
{
"_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": {}
}
}
}
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.
[
{
"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"
}
]
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).
{
"_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"
}
A Principal with no share on this Toolkit yields 404 Not Found with the
message Share not found.
{
"statusCode": 404,
"error": "Not Found",
"message": "Share not found"
}
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.
| Field | Type | Required | Description |
|---|---|---|---|
accessLevel | integer | No | Access level (integer >= 1, default 1) |
Example Request:
{
"accessLevel": 2
}
Response:
Responds 200 with the saved ToolkitShare, not 201.
{
"accessLevel": 2
}
{
"_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"
}
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.
Access Levels
| Level | Name | Permissions |
|---|---|---|
| 1 | Read | View Toolkit, use tools in chats |
| 2 | Write | Edit Toolkit, manage tools, configure settings |
| 3 | Admin | Full 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.
{
"_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": {}
}
Favorite
The current user's favorite flag on a toolkit.
GET /api/toolkits/{id}/favorite
Read the current user's favorite status.
{
"_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"
}
PUT /api/toolkits/{id}/favorite
Mark the toolkit as a favorite.
{
"_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
}
DELETE /api/toolkits/{id}/favorite
Clear the favorite flag. Returns 200 with an empty body.