Skip to main content

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.

List assistant skillsGET /api/assistants/00000000-0000-4000-8000-000000000001/skills
GET /api/assistants/{id}/skills is a HAL collection ({ start, count, total }) embedding inf:assistant-skill rows. Each skill eager-loads id+name of any linked dataset/report/template/query/datasource (required:false), and serializes an embedded inf:driver descriptor. Requires AI access (ai.verify).
Response · 200
{
"_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": {}
}
}
}
]
}
}
Captured from the API examples test suite; ids and timestamps are normalized.

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.

FieldTypeRequiredDescription
typestringYesSkill-driver id (e.g. informerExpert, apiRequest, simpleFunction, websiteSearch). Must be a registered driver.
namestringNoSkill name
descriptionstringNoSkill description
dataobjectNoDriver configuration (default {})
datasetIdstringNoAssociated Dataset id
datasourceIdstringNoAssociated Datasource id
reportIdstringNoAssociated Report id
queryIdstringNoAssociated Query id
templateIdstringNoAssociated Template id
integrationIdstringNoAssociated Integration id
type must be a registered driver id

The 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.

Add a skill to an assistantPOST /api/assistants/00000000-0000-4000-8000-000000000001/skills
POST /api/assistants/{id}/skills adds a skill. Payload is { type (required), name?, description?, data? (default {}), datasetId?, datasourceId?, reportId?, queryId?, templateId?, integrationId? } and is stripUnknown. `type` must be a registered skill-driver id (e.g. informerExpert, apiRequest, simpleFunction, websiteSearch); the .md’s dataset-query/web-search examples are not real types. Requires assistant:write. Responds 201 with a Location header.
Request body
{
"type": "informerExpert",
"name": "Informer Help",
"description": "Explains how to use Informer features."
}
Response · 201
{
"_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": {}
}
}
}
Captured from the API examples test suite; ids and timestamps are normalized.

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.

Get a skillGET /api/assistants/00000000-0000-4000-8000-000000000001/skills/00000000-0000-4000-8000-000000000002
GET /api/assistants/{id}/skills/{skillId} returns the single AssistantSkill (scoped to the assistant), with its embedded inf:driver descriptor. Requires AI access.
Response · 200
{
"_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
}
Captured from the API examples test suite; ids and timestamps are normalized.

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.

FieldTypeDescription
namestring | nullSkill name; null clears it
descriptionstring | nullSkill description; null or "" clears it
dataobjectDriver configuration
datasetIdstring | nullAssociated Dataset id
datasourceIdstring | nullAssociated Datasource id
reportIdstring | nullAssociated Report id
queryIdstring | nullAssociated Query id
templateIdstring | nullAssociated Template id
integrationIdstring | nullAssociated Integration id

Example Request:

{
"name": "Informer Expert Help",
"description": "Answers detailed questions about Informer."
}

Response:

Responds 200 with the updated skill.

Update a skillPUT /api/assistants/00000000-0000-4000-8000-000000000001/skills/00000000-0000-4000-8000-000000000002
PUT /api/assistants/{id}/skills/{skillId} updates the skill (db.update in a transaction). Every field is optional; most accept null to clear (name allows null; description allows null and empty string). Requires assistant:write. Returns 200 with the updated skill.
Request body
{
"name": "Informer Expert Help",
"description": "Answers detailed questions about Informer."
}
Response · 200
{
"_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": {}
}
}
}
Captured from the API examples test suite; ids and timestamps are normalized.

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.

Remove a skill from an assistantDELETE /api/assistants/00000000-0000-4000-8000-000000000001/skills/00000000-0000-4000-8000-000000000002
DELETE /api/assistants/{id}/skills/{skillId} removes the skill (db.remove in a transaction) and returns 200 with an EMPTY body (Informer convention), NOT 204 as the .md claims. Requires assistant:write.
Response · 200 · no body
Captured from the API examples test suite; ids and timestamps are normalized.

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.

Get a skill driver descriptorGET /api/assistants/00000000-0000-4000-8000-000000000001/skills/00000000-0000-4000-8000-000000000002/driver
GET /api/assistants/{id}/skills/{skillId}/driver returns the raw driver descriptor (skill.driver()): { id, name, description, image, editorComponent? }. name/description are i18n keys, not resolved strings. 404s if the skill is missing or belongs to another assistant.
Response · 200
{
"_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": {}
}
Captured from the API examples test suite; ids and timestamps are normalized.