Skills
Endpoints for managing the skills (capabilities) attached to an Assistant: list, add, get, update, and remove a skill, plus read a skill's driver descriptor.
Every skills route is gated by ai.verify (AI enabled on the tenant AND the
caller having AI access). The write routes (POST/PUT/DELETE) additionally
require permission.assistant.write on the looked-up Assistant. There is no
BYOK gate on these routes.
A skill's behavior is supplied by a registered skill driver. The type field is
a driver id, and each skill serializes an embedded inf:driver descriptor whose
name and description are i18n message keys (not resolved strings). The
drivers registered in this build are informerExpert, apiRequest,
simpleFunction, highcharts, magic-visual, app, printTemplate,
websiteSearch, quickbooks, salesforce, and informer.
GET /api/assistants/{id}/skills
List all skills for an Assistant.
Authentication: Required (AI access via ai.verify)
Response:
A HAL collection { start, count, total } embedding inf:assistant-skill rows.
Each skill eager-loads the id and name of any linked Dataset, Report,
Template, Query, or Datasource (left outer joins, so absent links serialize as
null), and embeds its inf:driver descriptor.
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/skills"
}
},
"start": 0,
"count": 2,
"total": 2,
"_embedded": {
"inf:assistant-skill": [
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/skills/00000000-0000-4000-8000-000000000002"
}
},
"id": "00000000-0000-4000-8000-000000000002",
"type": "informerExpert",
"name": "Informer Expert",
"description": "Answers questions about using Informer.",
"data": null,
"assistantId": "00000000-0000-4000-8000-000000000001",
"datasetId": null,
"reportId": null,
"queryId": null,
"datasourceId": null,
"integrationId": null,
"templateId": null,
"jobId": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"dataset": null,
"report": null,
"template": null,
"query": null,
"datasource": null,
"job": null,
"integration": null,
"_embedded": {
"inf:driver": {
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/skills/00000000-0000-4000-8000-000000000002/driver"
}
},
"id": "informerExpert",
"name": "assistant:informer_expert",
"description": "assistant:informer_expert_description",
"image": "/images/icons/assistant.svg",
"editorComponent": {}
}
}
},
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/skills/00000000-0000-4000-8000-000000000003"
}
},
"id": "00000000-0000-4000-8000-000000000003",
"type": "informerExpert",
"name": "Scratch Skill",
"description": null,
"data": null,
"assistantId": "00000000-0000-4000-8000-000000000001",
"datasetId": null,
"reportId": null,
"queryId": null,
"datasourceId": null,
"integrationId": null,
"templateId": null,
"jobId": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"dataset": null,
"report": null,
"template": null,
"query": null,
"datasource": null,
"job": null,
"integration": null,
"_embedded": {
"inf:driver": {
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/skills/00000000-0000-4000-8000-000000000003/driver"
}
},
"id": "informerExpert",
"name": "assistant:informer_expert",
"description": "assistant:informer_expert_description",
"image": "/images/icons/assistant.svg",
"editorComponent": {}
}
}
}
]
}
}
POST /api/assistants/{id}/skills
Add a skill to an Assistant.
Authentication: Required (AI access via ai.verify)
Permission: assistant:write
Request Body:
The payload is stripUnknown, so unrecognized fields are dropped rather than
rejected. The assistantId is taken from the URL.
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Skill-driver id (e.g. informerExpert, apiRequest, simpleFunction, websiteSearch). Must be a registered driver. |
name | string | No | Skill name |
description | string | No | Skill description |
data | object | No | Driver configuration (default {}) |
datasetId | string | No | Associated Dataset id |
datasourceId | string | No | Associated Datasource id |
reportId | string | No | Associated Report id |
queryId | string | No | Associated Query id |
templateId | string | No | Associated Template id |
integrationId | string | No | Associated Integration id |
type must be a registered driver idThe skill type is validated against the registered skill drivers. Values such
as dataset-query or web-search are not real types and are rejected. Use one
of the driver ids listed above.
There is no jobId input. It exists as a column but is not part of the
create/update schema.
Example Request:
{
"type": "informerExpert",
"name": "Informer Help",
"description": "Explains how to use Informer features."
}
Response:
Responds 201 Created with the created skill (including its embedded
inf:driver) and a Location header. The Location uses the Assistant's
natural id, not its UUID.
{
"type": "informerExpert",
"name": "Informer Help",
"description": "Explains how to use Informer features."
}
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/admin%3Aorder-desk-assistant/skills/00000000-0000-4000-8000-000000000002"
}
},
"id": "00000000-0000-4000-8000-000000000002",
"tenant": "acme",
"assistantId": "00000000-0000-4000-8000-000000000001",
"type": "informerExpert",
"name": "Informer Help",
"description": "Explains how to use Informer features.",
"data": {},
"updatedAt": "2026-01-15T16:20:00.000Z",
"createdAt": "2026-01-15T16:20:00.000Z",
"datasetId": null,
"reportId": null,
"queryId": null,
"datasourceId": null,
"templateId": null,
"jobId": null,
"integrationId": null,
"_embedded": {
"inf:driver": {
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/admin%3Aorder-desk-assistant/skills/00000000-0000-4000-8000-000000000002/driver"
}
},
"id": "informerExpert",
"name": "assistant:informer_expert",
"description": "assistant:informer_expert_description",
"image": "/images/icons/assistant.svg",
"editorComponent": {}
}
}
}
GET /api/assistants/{id}/skills/{skillId}
Get a single skill, scoped to the Assistant.
Authentication: Required (AI access via ai.verify)
Response:
Responds 200 with the single inf:assistant-skill, including its embedded
inf:driver descriptor.
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/skills/00000000-0000-4000-8000-000000000002"
}
},
"items": [
{
"id": "00000000-0000-4000-8000-000000000002",
"type": "informerExpert",
"name": "Informer Help",
"description": "Explains how to use Informer features.",
"data": {},
"assistantId": "00000000-0000-4000-8000-000000000001",
"datasetId": null,
"reportId": null,
"queryId": null,
"datasourceId": null,
"integrationId": null,
"templateId": null,
"jobId": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"job": null,
"integration": null,
"template": null,
"datasource": null,
"query": null,
"report": null,
"dataset": null
}
],
"start": 0,
"count": 1,
"total": 1
}
PUT /api/assistants/{id}/skills/{skillId}
Update a skill. Runs in a database transaction.
Authentication: Required (AI access via ai.verify)
Permission: assistant:write
Request Body:
Every field is optional. Most accept null to clear (name allows null;
description allows null and the empty string). Same fields as POST, minus
type.
| Field | Type | Description |
|---|---|---|
name | string | null | Skill name; null clears it |
description | string | null | Skill description; null or "" clears it |
data | object | Driver configuration |
datasetId | string | null | Associated Dataset id |
datasourceId | string | null | Associated Datasource id |
reportId | string | null | Associated Report id |
queryId | string | null | Associated Query id |
templateId | string | null | Associated Template id |
integrationId | string | null | Associated Integration id |
Example Request:
{
"name": "Informer Expert Help",
"description": "Answers detailed questions about Informer."
}
Response:
Responds 200 with the updated skill.
{
"name": "Informer Expert Help",
"description": "Answers detailed questions about Informer."
}
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/skills/00000000-0000-4000-8000-000000000002"
}
},
"id": "00000000-0000-4000-8000-000000000002",
"type": "informerExpert",
"name": "Informer Expert Help",
"description": "Answers detailed questions about Informer.",
"data": {},
"assistantId": "00000000-0000-4000-8000-000000000001",
"datasetId": null,
"reportId": null,
"queryId": null,
"datasourceId": null,
"integrationId": null,
"templateId": null,
"jobId": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"job": null,
"integration": null,
"template": null,
"datasource": null,
"query": null,
"report": null,
"dataset": null,
"_embedded": {
"inf:driver": {
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/skills/00000000-0000-4000-8000-000000000002/driver"
}
},
"id": "informerExpert",
"name": "assistant:informer_expert",
"description": "assistant:informer_expert_description",
"image": "/images/icons/assistant.svg",
"editorComponent": {}
}
}
}
DELETE /api/assistants/{id}/skills/{skillId}
Remove a skill from an Assistant. Runs in a database transaction.
Authentication: Required (AI access via ai.verify)
Permission: assistant:write
Response:
Responds 200 with an empty body (Informer convention), not 204.
GET /api/assistants/{id}/skills/{skillId}/driver
Get the skill's driver descriptor.
Authentication: Required (AI access via ai.verify)
Response:
The raw driver descriptor (skill.driver()): { id, name, description, image, editorComponent? }. The name and description are i18n message keys, not
resolved strings. Answers 404 if the skill is missing or belongs to a
different Assistant.
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/skills/00000000-0000-4000-8000-000000000002/driver"
}
},
"id": "informerExpert",
"name": "assistant:informer_expert",
"description": "assistant:informer_expert_description",
"image": "/images/icons/assistant.svg",
"editorComponent": {}
}