Skip to main content

Files & References

Endpoints for managing the files attached to an Assistant and the Assistant-to-Assistant references that point one Assistant at another.

Every route on this page is gated by ai.verify (AI enabled on the tenant AND the caller having AI access). Entities are resolved through the read_access model scope: assistant.lookup for the Assistant, and assistant.lookupFile (the File assistant scope, which requires an assistant_file link) for an attached file. The file-attach and file-update mutations require permission.assistant.write; detaching a file requires permission.assistant.edit.

Files

GET /api/assistants/{id}/files

List the files attached to an Assistant.

Authentication: AI access (ai.verify)

Response:

A HAL collection embedding inf:file: the File rows behind the assistant_file links (the File objects, not the join rows). Each embedded file carries an inf:file-contents (./contents) link.

List files attached to an assistantGET /api/assistants/00000000-0000-4000-8000-000000000001/files
GET /api/assistants/{id}/files is a HAL collection embedding inf:file: the File rows behind the assistant_file links (not the join rows). Each embedded file carries an inf:file-contents (./contents) link. Requires AI access (ai.verify).
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/files"
}
},
"start": 0,
"count": 2,
"total": 2,
"_embedded": {
"inf:file": [
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/files/00000000-0000-4000-8000-000000000002"
},
"inf:file-contents": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/files/00000000-0000-4000-8000-000000000002/contents"
}
},
"extension": "md",
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000002",
"filename": "q4-forecast.md",
"embedded": true,
"contentType": "text/markdown",
"lobId": null,
"role": "DOCUMENT",
"description": "Quarterly revenue forecast notes.",
"data": {},
"createdById": null,
"letterheadId": null,
"jobActionAttachmentId": null,
"jobActionId": null,
"oauthClientId": null,
"assistantId": null,
"directory": false,
"indexed": false,
"indexingStartedAt": null,
"indexingErroredAt": null,
"indexingErrorMessage": null,
"indexedAt": null,
"parentId": null,
"libraryId": null,
"remoteId": null,
"remoteUrl": null,
"size": null,
"modifiedAt": null,
"messageId": null,
"chatId": null,
"expiresAt": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"ownerId": null,
"templateId": null,
"integrationId": null
},
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/files/00000000-0000-4000-8000-000000000003"
},
"inf:file-contents": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/files/00000000-0000-4000-8000-000000000003/contents"
}
},
"extension": "md",
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000003",
"filename": "scratch-notes.md",
"embedded": true,
"contentType": "text/markdown",
"lobId": null,
"role": "DOCUMENT",
"description": null,
"data": {},
"createdById": null,
"letterheadId": null,
"jobActionAttachmentId": null,
"jobActionId": null,
"oauthClientId": null,
"assistantId": null,
"directory": false,
"indexed": false,
"indexingStartedAt": null,
"indexingErroredAt": null,
"indexingErrorMessage": null,
"indexedAt": null,
"parentId": null,
"libraryId": null,
"remoteId": null,
"remoteUrl": null,
"size": null,
"modifiedAt": null,
"messageId": null,
"chatId": null,
"expiresAt": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"ownerId": null,
"templateId": null,
"integrationId": null
}
]
}
}
Captured from the API examples test suite; ids and timestamps are normalized.

POST /api/assistants/{id}/files

Attach already-existing Library files to an Assistant. This route does not perform an upload: it creates assistant_file rows linking the named Library files to the Assistant (for any not yet linked). Direct uploads go through POST /api/assistants/{id}/files/_upload instead.

Authentication: AI access (ai.verify)

Pre-blocks: assistant.lookup, permission.assistant.write

Request Body:

FieldTypeRequiredDescription
libraryIdstringYesThe Library that owns the files
fileIdsarray of stringYesFile ids to attach (.single(), so a bare string is also accepted)

There is no uploadId or name field.

Example Request:

{
"libraryId": "00000000-0000-4000-8000-000000000010",
"fileIds": ["00000000-0000-4000-8000-000000000011"]
}

Response:

Responds 200 with an empty body (Informer convention), not 201. The handler returns nothing.

Attach existing library files to an assistantPOST /api/assistants/00000000-0000-4000-8000-000000000001/files
POST /api/assistants/{id}/files payload is { libraryId, fileIds } (NOT { uploadId, name } — the .md guessed wrong). It ATTACHES already-existing Library files to the assistant, creating assistant_file rows for any not yet linked. fileIds is an array of File ids (.single(), so a bare string is also accepted). The handler returns nothing, so the status is 200 with an EMPTY body (Informer convention), NOT 201. Requires permission.assistant.write. Direct uploads use POST /files/_upload instead.
Request body
{
"libraryId": "00000000-0000-4000-8000-000000000002",
"fileIds": [
"00000000-0000-4000-8000-000000000003"
]
}
Response · 200 · no body
Captured from the API examples test suite; ids and timestamps are normalized.

POST /api/assistants/{id}/files/_upload

Upload a file directly to an Assistant and compute its embeddings.

Authentication: AI access (ai.verify)

Pre-blocks: assistant.lookup, permission.assistant.write

Content-Type: multipart/form-data

Response:

The stored file. This route does file IO and embedding generation against live services, so it is not captured here.


GET /api/assistants/{id}/files/{file}

Get a single attached file. The {file} path param is the File id, resolved via assistant.lookupFile (the File assistant scope, which requires an assistant_file link).

Authentication: AI access (ai.verify)

Response:

The raw File row with an inf:file-contents (./contents) link.

Get an attached fileGET /api/assistants/00000000-0000-4000-8000-000000000001/files/00000000-0000-4000-8000-000000000002
GET /api/assistants/{id}/files/{file} resolves the File via assistant.lookupFile (File `assistant` scope, which requires an assistant_file link) and returns the raw File row with an inf:file-contents (./contents) link. The {file} path param is the File id. Requires AI access (ai.verify).
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/files/00000000-0000-4000-8000-000000000002"
},
"inf:file-contents": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/files/00000000-0000-4000-8000-000000000002/contents"
}
},
"extension": "md",
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000002",
"filename": "q4-forecast.md",
"embedded": true,
"contentType": "text/markdown",
"lobId": null,
"role": "DOCUMENT",
"description": "Quarterly revenue forecast notes.",
"data": {},
"createdById": null,
"letterheadId": null,
"jobActionAttachmentId": null,
"jobActionId": null,
"oauthClientId": null,
"assistantId": null,
"directory": false,
"indexed": false,
"indexingStartedAt": null,
"indexingErroredAt": null,
"indexingErrorMessage": null,
"indexedAt": null,
"parentId": null,
"libraryId": null,
"remoteId": null,
"remoteUrl": null,
"size": null,
"modifiedAt": null,
"messageId": null,
"chatId": null,
"expiresAt": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"ownerId": null,
"templateId": null,
"integrationId": null
}
Captured from the API examples test suite; ids and timestamps are normalized.

PUT /api/assistants/{id}/files/{file}

Update an attached file's metadata. There is no Joi payload schema; the route is a db.update against the File model (matched on id plus embedded: true). Send File columns such as filename or description.

Authentication: AI access (ai.verify)

Pre-blocks: assistant.lookupFile, permission.assistant.write

Example Request:

{ "description": "Updated quarterly revenue forecast notes." }

Response:

Responds 200 with the updated File.

Update an attached filePUT /api/assistants/00000000-0000-4000-8000-000000000001/files/00000000-0000-4000-8000-000000000002
PUT /api/assistants/{id}/files/{file} has NO joi payload schema; it is a db.update against the File model (where id + embedded:true) and returns the updated File (200). Send File columns such as `filename` or `description`. Requires permission.assistant.write.
Request body
{
"description": "Updated quarterly revenue forecast notes."
}
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/files/00000000-0000-4000-8000-000000000002"
},
"inf:file-contents": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/files/00000000-0000-4000-8000-000000000002/contents"
}
},
"extension": "md",
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000002",
"filename": "q4-forecast.md",
"embedded": true,
"contentType": "text/markdown",
"lobId": null,
"role": "DOCUMENT",
"description": "Updated quarterly revenue forecast notes.",
"data": {},
"createdById": null,
"letterheadId": null,
"jobActionAttachmentId": null,
"jobActionId": null,
"oauthClientId": null,
"assistantId": null,
"directory": false,
"indexed": false,
"indexingStartedAt": null,
"indexingErroredAt": null,
"indexingErrorMessage": null,
"indexedAt": null,
"parentId": null,
"libraryId": null,
"remoteId": null,
"remoteUrl": null,
"size": null,
"modifiedAt": null,
"messageId": null,
"chatId": null,
"expiresAt": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"ownerId": null,
"templateId": null,
"integrationId": null
}
Captured from the API examples test suite; ids and timestamps are normalized.

DELETE /api/assistants/{id}/files/{file}

Detach a file from an Assistant. This is a db.remove against AssistantFile: it removes the assistant_file row but does not delete the underlying File.

Authentication: AI access (ai.verify)

Pre-blocks: assistant.lookupFile, permission.assistant.edit

Requires edit, not write

Unlike the other file mutations on this page, detaching a file requires permission.assistant.edit, not permission.assistant.write.

Response:

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

Detach a file from an assistantDELETE /api/assistants/00000000-0000-4000-8000-000000000001/files/00000000-0000-4000-8000-000000000002
DELETE /api/assistants/{id}/files/{file} is a db.remove against AssistantFile: it DETACHES the file from the assistant (removing the assistant_file row); it does not delete the underlying File. Returns 200 with an EMPTY body (Informer convention), NOT 204 as the .md claims. NOTE: this route requires permission.assistant.EDIT, not `write` as the other file mutations and the .md state.
Response · 200 · no body
Captured from the API examples test suite; ids and timestamps are normalized.

GET /api/assistants/{id}/files/{file}/contents

Download the raw contents of an attached file.

Authentication: AI access (ai.verify)

Response:

The file bytes with an appropriate Content-Type header (binary, not shown).


PUT /api/assistants/{id}/files/{file}/contents

Replace the contents of an attached file.

Authentication: AI access (ai.verify)

Content-Type: multipart/form-data

Response:

The updated File. This route accepts a binary/multipart upload, so it is not captured here.


GET /api/assistants/{id}/files/{file}/embeddings/{embeddingId}/image

Retrieve an image extracted from a file's embeddings.

Authentication: AI access (ai.verify)

Response:

The image bytes with an appropriate Content-Type header (binary, not shown).


References

References are Assistant-to-Assistant pointers: one Assistant (the source) references another (the target).

GET /api/assistants/{id}/references

List the references on an Assistant.

Authentication: AI access (ai.verify)

Response:

A HAL collection embedding inf:assistant-reference, each embedding the target inf:assistant (resolved through read_access, with its icon).

List references on an assistantGET /api/assistants/00000000-0000-4000-8000-000000000001/references
GET /api/assistants/{id}/references is a HAL collection embedding inf:assistant-reference, each embedding the target inf:assistant (resolved through read_access, with its icon). References are assistant-to-assistant pointers. Requires AI access (ai.verify).
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/references"
}
},
"start": 0,
"count": 1,
"total": 1,
"_embedded": {
"inf:assistant-reference": [
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/references/00000000-0000-4000-8000-000000000002"
}
},
"id": "00000000-0000-4000-8000-000000000003",
"sourceId": "00000000-0000-4000-8000-000000000001",
"targetId": "00000000-0000-4000-8000-000000000002",
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"_embedded": {
"inf:assistant": {
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/references/00000000-0000-4000-8000-000000000002/00000000-0000-4000-8000-000000000002"
},
"inf:draft": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/draft"
},
"inf:edit": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/_edit"
},
"inf:comments": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/comments{?sort,limit}",
"templated": true
},
"inf:assistant-share": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/references/00000000-0000-4000-8000-000000000002/00000000-0000-4000-8000-000000000002/shares/{principalId}",
"templated": true
},
"inf:assistant-owner": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/owner"
},
"inf:assistant-datasets": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/datasets"
},
"inf:assistant-skills": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/skills"
},
"inf:assistant-toolkits": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/toolkits"
},
"inf:assistant-references": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/references"
},
"inf:assistant-shares": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/shares"
},
"inf:assistant-icon": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/icon"
},
"inf:assistant-secrets": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/secrets"
},
"inf:assistant-copy": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/_copy"
},
"inf:favorite": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/favorite"
},
"inf:assistant-files": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/files"
},
"inf:assistant-file-upload": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/files/_upload"
},
"inf:assistant-usage": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/usage"
},
"inf:create-image": {
"href": "https://informer.example.com/api/assistants/admin%3Asupport-assistant/_create-image"
},
"inf:chat-external": {
"href": "https://informer.example.com/assistants/admin%3Asupport-assistant/chat"
}
},
"naturalId": "admin:support-assistant",
"searchName": "support assistant",
"permissions": {
"chat": true,
"edit": true,
"share": true,
"delete": true,
"write": true,
"changeOwner": true,
"copy": true,
"rename": true,
"assignTags": true
},
"id": "00000000-0000-4000-8000-000000000002",
"name": "Support Assistant",
"description": "Handles customer support inquiries.",
"slug": "support-assistant",
"ownerId": "admin",
"welcome": null,
"modelId": "00000000-0000-4000-8000-000000000004",
"instructions": null,
"suggestions": null,
"token": null,
"data": null,
"source": null,
"sourceId": null,
"folderId": null,
"editingId": null,
"shared": false,
"embedded": false,
"dispatcher": false,
"libraryId": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"icon": null,
"model": {
"naturalId": "go_everyday",
"permissions": {},
"promptPpm": null,
"completionPpm": null,
"cacheReadPpm": null,
"cacheWriteShortPpm": null,
"cacheWriteLongPpm": null,
"id": "00000000-0000-4000-8000-000000000004",
"model": null,
"slug": "go_everyday",
"provider": {
"permissions": {},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000005",
"name": "Anthropic",
"slug": "anthropic",
"type": "anthropic",
"key": null,
"managed": true,
"internal": false,
"settings": null,
"data": null,
"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.

POST /api/assistants/{id}/references

Add a reference from this Assistant to another.

Authentication: AI access (ai.verify)

Pre-blocks: assistant.lookup, permission.assistant.write

Request Body:

The payload is stripUnknown, so unrecognized fields are dropped.

FieldTypeRequiredDescription
targetIdstringYesThe id of another Assistant to reference

There is no targetType or description field. targetId must be a different Assistant's id: references are Assistant-to-Assistant, and a self-reference answers 400.

Example Request:

{ "targetId": "00000000-0000-4000-8000-000000000020" }

Response:

Responds 201 Created with a Location header. The body is the raw AssistantReference row (id, sourceId, targetId, timestamps), not HAL-shaped.

Add a reference to an assistantPOST /api/assistants/00000000-0000-4000-8000-000000000001/references
POST /api/assistants/{id}/references payload is { targetId } ONLY (joi { targetId } with stripUnknown — there is no targetType or description as the .md lists). targetId must be ANOTHER assistant's id; references are assistant-to-assistant and self-references 400. Responds 201 with a Location header; the body is the raw AssistantReference row (id, sourceId, targetId, timestamps), not HAL-shaped. Requires permission.assistant.write.
Request body
{
"targetId": "00000000-0000-4000-8000-000000000002"
}
Response · 201
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/admin%3Asales-assistant/references/00000000-0000-4000-8000-000000000002"
}
},
"id": "00000000-0000-4000-8000-000000000003",
"tenant": "acme",
"sourceId": "00000000-0000-4000-8000-000000000001",
"targetId": "00000000-0000-4000-8000-000000000002",
"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.

GET /api/assistants/{id}/references/{targetId}

Get a single reference. The {targetId} path param is the referenced Assistant's id; the row is looked up by sourceId plus targetId.

Authentication: AI access (ai.verify)

Response:

One AssistantReference row.

Get a single referenceGET /api/assistants/00000000-0000-4000-8000-000000000001/references/00000000-0000-4000-8000-000000000002
GET /api/assistants/{id}/references/{targetId} returns one AssistantReference (db.query keyed by sourceId + targetId). The {targetId} path param is the referenced assistant id.
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/00000000-0000-4000-8000-000000000001/references/00000000-0000-4000-8000-000000000002"
}
},
"items": [
{
"id": "00000000-0000-4000-8000-000000000003",
"sourceId": "00000000-0000-4000-8000-000000000001",
"targetId": "00000000-0000-4000-8000-000000000002",
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme"
}
],
"start": 0,
"count": 1,
"total": 1
}
Captured from the API examples test suite; ids and timestamps are normalized.

DELETE /api/assistants/{id}/references/{targetId}

Remove a reference from an Assistant. This is a db.remove against AssistantReference.

Authentication: AI access (ai.verify)

Pre-blocks: assistant.lookup, permission.assistant.write

Response:

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

Remove a reference from an assistantDELETE /api/assistants/00000000-0000-4000-8000-000000000001/references/00000000-0000-4000-8000-000000000002
DELETE /api/assistants/{id}/references/{targetId} is a db.remove against AssistantReference. Returns 200 with an EMPTY body (Informer convention), NOT 204 as the .md claims. Requires permission.assistant.write.
Response · 200 · no body
Captured from the API examples test suite; ids and timestamps are normalized.