Chats
Endpoints for managing AI chat conversations and the models a chat can run on.
Chat CRUD needs only a normal authenticated user; read access is enforced by the
read_access model scope rather than a permission, so list and lookup routes
return only the chats the caller may see. Sending a message (and a few related
live-AI routes) additionally require AI access via ai.verify.
GET /api/chats
List chats as a paged envelope, ordered by pinned status then last update time. Embedded chats (created internally for libraries and apps) are always excluded.
Authentication: Required
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 20 | Results per page (1-200) |
offset | integer | 0 | Pagination offset |
appBuilder | boolean | - | When set, filters to (or away from) App Builder chats |
Response:
A paged envelope { total, limit, offset, results } (with a HAL _links.self),
not a bare array. Each row is a lightweight column subset with its model
eager-loaded; it carries appId, appBuilder, and schedule, and there is no
directory field. Supports ETags.
{
"_links": {
"self": {
"href": "https://informer.example.com/api/chats"
}
},
"total": 2,
"limit": 20,
"offset": 0,
"results": [
{
"permissions": {},
"id": "00000000-0000-4000-8000-000000000001",
"name": "Scratch Chat",
"autoRename": true,
"stale": true,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"modelId": "00000000-0000-4000-8000-000000000002",
"tier": null,
"ownerAssistantId": null,
"primaryAssistantId": null,
"web": null,
"outputSize": null,
"pinned": false,
"appId": null,
"appBuilder": false,
"schedule": null,
"model": {
"naturalId": "acme-custom-opus",
"permissions": {},
"promptPpm": null,
"completionPpm": null,
"cacheReadPpm": null,
"cacheWriteShortPpm": null,
"cacheWriteLongPpm": null,
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000002",
"providerId": "00000000-0000-4000-8000-000000000003",
"referencesId": null,
"name": "Acme Custom Opus",
"slug": "acme-custom-opus",
"model": "claude-opus-4",
"options": null,
"chat": true,
"moderated": false,
"contextWindow": 200000,
"maxOutputTokens": null,
"instructions": null,
"description": null,
"managed": false,
"internal": false,
"deprecatedAt": null,
"web": false,
"attachments": false,
"generateImage": false,
"createEmbeddings": false,
"score": 100,
"pricingTier": null,
"badges": null,
"tier": "strategic",
"customized": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"provider": {
"permissions": {},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000003",
"name": "Anthropic",
"slug": "anthropic-1",
"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"
}
}
},
{
"permissions": {},
"id": "00000000-0000-4000-8000-000000000004",
"name": "Order Desk Analysis",
"autoRename": true,
"stale": true,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"modelId": "00000000-0000-4000-8000-000000000002",
"tier": "strategic",
"ownerAssistantId": null,
"primaryAssistantId": null,
"web": null,
"outputSize": "medium",
"pinned": false,
"appId": null,
"appBuilder": false,
"schedule": null,
"model": {
"naturalId": "acme-custom-opus",
"permissions": {},
"promptPpm": null,
"completionPpm": null,
"cacheReadPpm": null,
"cacheWriteShortPpm": null,
"cacheWriteLongPpm": null,
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000002",
"providerId": "00000000-0000-4000-8000-000000000003",
"referencesId": null,
"name": "Acme Custom Opus",
"slug": "acme-custom-opus",
"model": "claude-opus-4",
"options": null,
"chat": true,
"moderated": false,
"contextWindow": 200000,
"maxOutputTokens": null,
"instructions": null,
"description": null,
"managed": false,
"internal": false,
"deprecatedAt": null,
"web": false,
"attachments": false,
"generateImage": false,
"createEmbeddings": false,
"score": 100,
"pricingTier": null,
"badges": null,
"tier": "strategic",
"customized": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"provider": {
"permissions": {},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000003",
"name": "Anthropic",
"slug": "anthropic-1",
"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"
}
}
}
]
}
GET /api/chats-list
List chats as a flat array ordered by last update time. This is the legacy compatibility endpoint: same chat shape as the paged route's rows, but with no pagination envelope. Embedded chats are excluded.
Authentication: Required
Response:
[
{
"permissions": {},
"id": "00000000-0000-4000-8000-000000000001",
"name": "Scratch Chat",
"username": "admin",
"instructions": null,
"web": null,
"helpCenter": false,
"informerApi": false,
"appBuilder": false,
"outputSize": null,
"error": null,
"stale": true,
"modelId": "00000000-0000-4000-8000-000000000002",
"tier": null,
"autoRename": true,
"autoRenamedAt": null,
"autosuggest": false,
"ownerAssistantId": null,
"primaryAssistantId": null,
"appId": null,
"datasetId": null,
"reportId": null,
"templateId": null,
"queryId": null,
"visualId": null,
"datasourceId": null,
"jobId": null,
"memoryRequestedAt": null,
"memoryRequestedReason": null,
"pinned": false,
"embedded": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"schedule": null,
"model": {
"naturalId": "acme-custom-opus",
"permissions": {},
"promptPpm": null,
"completionPpm": null,
"cacheReadPpm": null,
"cacheWriteShortPpm": null,
"cacheWriteLongPpm": null,
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000002",
"providerId": "00000000-0000-4000-8000-000000000003",
"referencesId": null,
"name": "Acme Custom Opus",
"slug": "acme-custom-opus",
"model": "claude-opus-4",
"options": null,
"chat": true,
"moderated": false,
"contextWindow": 200000,
"maxOutputTokens": null,
"instructions": null,
"description": null,
"managed": false,
"internal": false,
"deprecatedAt": null,
"web": false,
"attachments": false,
"generateImage": false,
"createEmbeddings": false,
"score": 100,
"pricingTier": null,
"badges": null,
"tier": "strategic",
"customized": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"provider": {
"permissions": {},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000003",
"name": "Anthropic",
"slug": "anthropic-1",
"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"
}
}
},
{
"permissions": {},
"id": "00000000-0000-4000-8000-000000000004",
"name": "Order Desk Analysis",
"username": "admin",
"instructions": null,
"web": null,
"helpCenter": false,
"informerApi": false,
"appBuilder": false,
"outputSize": "medium",
"error": null,
"stale": true,
"modelId": "00000000-0000-4000-8000-000000000002",
"tier": "strategic",
"autoRename": true,
"autoRenamedAt": null,
"autosuggest": false,
"ownerAssistantId": null,
"primaryAssistantId": null,
"appId": null,
"datasetId": null,
"reportId": null,
"templateId": null,
"queryId": null,
"visualId": null,
"datasourceId": null,
"jobId": null,
"memoryRequestedAt": null,
"memoryRequestedReason": null,
"pinned": false,
"embedded": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"schedule": null,
"model": {
"naturalId": "acme-custom-opus",
"permissions": {},
"promptPpm": null,
"completionPpm": null,
"cacheReadPpm": null,
"cacheWriteShortPpm": null,
"cacheWriteLongPpm": null,
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000002",
"providerId": "00000000-0000-4000-8000-000000000003",
"referencesId": null,
"name": "Acme Custom Opus",
"slug": "acme-custom-opus",
"model": "claude-opus-4",
"options": null,
"chat": true,
"moderated": false,
"contextWindow": 200000,
"maxOutputTokens": null,
"instructions": null,
"description": null,
"managed": false,
"internal": false,
"deprecatedAt": null,
"web": false,
"attachments": false,
"generateImage": false,
"createEmbeddings": false,
"score": 100,
"pricingTier": null,
"badges": null,
"tier": "strategic",
"customized": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"provider": {
"permissions": {},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000003",
"name": "Anthropic",
"slug": "anthropic-1",
"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"
}
}
}
]
POST /api/chats
Create a chat. This route only writes database rows; it does not call a model provider, so no streaming happens here.
Authentication: Required
Pre-blocks: ai.verify (AI enabled on the tenant AND the caller has AI access)
Request Body:
The payload is stripUnknown, so unrecognized fields are dropped rather than
rejected.
| Field | Type | Required | Description |
|---|---|---|---|
modelId | string | Yes | Model id; validated against an existing Model (unknown id answers 400) |
name | string | null | No | Chat name (null for auto-generated) |
tier | string | null | No | Model tier alias |
ownerAssistantId | string | null | No | Assistant that owns the chat |
primaryAssistantId | string | null | No | Primary assistant for the chat |
assistantIds | array | No | Assistant ids to associate |
datasetIds | array | No | Dataset ids to associate |
libraryIds | array | No | Library ids to associate |
instructions | string | No | Custom instructions |
messages | array | No | Initial messages (default []) |
web | boolean | No | Enable web access (default false) |
helpCenter | boolean | No | Enable Help Center context (default false) |
informerApi | boolean | No | Enable the Informer API tool (default false) |
pinned | boolean | No | Pin to top (default false) |
outputSize | string | No | small, medium, or large (default medium) |
appBuilder is server-derived from the resolved model and is stripped from the
payload, so a client cannot self-grant it.
Example Request:
{
"name": "Sales Analysis",
"modelId": "00000000-0000-4000-8000-000000000001",
"tier": "strategic",
"messages": [],
"web": false,
"outputSize": "medium"
}
Response:
Responds 200 with the created chat (the handler returns the row directly; it
does not use .created(), so the status is 200, not 201). Runs in a database
transaction.
{
"name": "Sales Analysis",
"modelId": "00000000-0000-4000-8000-000000000001",
"tier": "strategic",
"messages": [],
"web": false,
"outputSize": "medium"
}
{
"_links": {
"self": {
"href": "https://informer.example.com/api/chats"
},
"inf:messages": {
"href": "https://informer.example.com/api/chats/messages"
},
"inf:chat-schedule": {
"href": "https://informer.example.com/api/chats/schedule"
},
"inf:chat-object": {
"href": "https://informer.example.com/api/chats/_object"
}
},
"permissions": {},
"id": "00000000-0000-4000-8000-000000000002",
"autosuggest": false,
"embedded": false,
"tenant": "acme",
"name": "Sales Analysis",
"modelId": "00000000-0000-4000-8000-000000000001",
"tier": "strategic",
"web": false,
"outputSize": "medium",
"helpCenter": false,
"informerApi": false,
"pinned": false,
"appBuilder": false,
"updatedAt": "2026-01-15T16:20:00.000Z",
"createdAt": "2026-01-15T16:20:00.000Z",
"username": "admin",
"instructions": null,
"error": null,
"stale": true,
"autoRename": true,
"autoRenamedAt": null,
"ownerAssistantId": null,
"datasetId": null,
"reportId": null,
"templateId": null,
"queryId": null,
"visualId": null,
"datasourceId": null,
"jobId": null,
"primaryAssistantId": null,
"memoryRequestedAt": null,
"memoryRequestedReason": null,
"appId": null,
"messages": []
}
GET /api/chats/{id}
Retrieve a chat with the detail the UI needs.
Authentication: Required
Pre-blocks: chat.lookupForUi(params.id)
Response:
The chat columns plus the eager-loaded model, the assistantIds,
datasetIds, and libraryIds association arrays, UI-shaped messages, and a
memories array. File attachments are not included here; that loading is
reserved for the submission and explain lookups. Supports a Last-Modified
header.
{
"_links": {
"self": {
"href": "https://informer.example.com/api/chats/00000000-0000-4000-8000-000000000001"
},
"inf:messages": {
"href": "https://informer.example.com/api/chats/00000000-0000-4000-8000-000000000001/messages"
},
"inf:chat-clear": {
"href": "https://informer.example.com/api/chats/00000000-0000-4000-8000-000000000001/_clear"
},
"inf:chat-schedule": {
"href": "https://informer.example.com/api/chats/00000000-0000-4000-8000-000000000001/schedule"
},
"inf:chat-object": {
"href": "https://informer.example.com/api/chats/00000000-0000-4000-8000-000000000001/_object"
}
},
"permissions": {},
"id": "00000000-0000-4000-8000-000000000001",
"name": "Sales Analysis",
"username": "admin",
"instructions": null,
"web": false,
"helpCenter": false,
"informerApi": false,
"appBuilder": false,
"outputSize": "medium",
"error": null,
"stale": true,
"modelId": "00000000-0000-4000-8000-000000000002",
"tier": "strategic",
"autoRename": true,
"autoRenamedAt": null,
"autosuggest": false,
"ownerAssistantId": null,
"primaryAssistantId": null,
"appId": null,
"datasetId": null,
"reportId": null,
"templateId": null,
"queryId": null,
"visualId": null,
"datasourceId": null,
"jobId": null,
"memoryRequestedAt": null,
"memoryRequestedReason": null,
"pinned": false,
"embedded": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"schedule": null,
"model": {
"naturalId": "acme-custom-opus",
"permissions": {},
"promptPpm": null,
"completionPpm": null,
"cacheReadPpm": null,
"cacheWriteShortPpm": null,
"cacheWriteLongPpm": null,
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000002",
"providerId": "00000000-0000-4000-8000-000000000003",
"referencesId": null,
"name": "Acme Custom Opus",
"slug": "acme-custom-opus",
"model": "claude-opus-4",
"options": null,
"chat": true,
"moderated": false,
"contextWindow": 200000,
"maxOutputTokens": null,
"instructions": null,
"description": null,
"managed": false,
"internal": false,
"deprecatedAt": null,
"web": false,
"attachments": false,
"generateImage": false,
"createEmbeddings": false,
"score": 100,
"pricingTier": null,
"badges": null,
"tier": "strategic",
"customized": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"provider": {
"permissions": {},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000003",
"name": "Anthropic",
"slug": "anthropic-1",
"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"
}
},
"chatAssistants": [],
"chatDatasets": [],
"chatLibraries": [],
"assistantIds": [],
"datasetIds": [],
"libraryIds": [],
"messages": [],
"memories": []
}
PUT /api/chats/{id}
Update chat columns and replace association sets.
Authentication: Required
Pre-blocks: chat.lookup(params.id)
Request Body:
| Field | Type | Description |
|---|---|---|
name | string | null | Chat name |
instructions | string | Custom instructions; "" or null clears the column |
modelId | string | null | Change model (re-derives the App Builder flag) |
assistantIds | array | Replace assistant associations |
datasetIds | array | Replace dataset associations |
libraryIds | array | Replace library associations |
primaryAssistantId | string | null | Set primary assistant |
ownerAssistantId | string | null | Set owner assistant |
appId | string | null | Link the chat to an App (requires app:write on that App) |
autoRename | boolean | Enable auto-renaming |
autoRenamedAt | date | null | Last auto-rename timestamp |
autosuggest | boolean | Enable auto-suggestions |
stale | boolean | Mark as stale |
web | boolean | Enable web access |
helpCenter | boolean | Enable Help Center context |
informerApi | boolean | Enable the Informer API tool |
pinned | boolean | Pin to top |
outputSize | string | small, medium, or large |
Association arrays (assistantIds/datasetIds/libraryIds) are replaced only
when provided, and each id is filtered through read_access so a caller cannot
attach an entity it may not see. appBuilder is server-controlled and stripped
from the payload. Linking to an appId the caller cannot write answers 403.
Example Request:
{
"name": "Q4 Sales Analysis",
"instructions": "Focus on quarterly revenue metrics.",
"pinned": true
}
Response:
Responds 200 with the updated chat. Runs in a database transaction.
{
"name": "Q4 Sales Analysis",
"instructions": "Focus on quarterly revenue metrics.",
"pinned": true
}
{
"_links": {
"self": {
"href": "https://informer.example.com/api/chats/00000000-0000-4000-8000-000000000001"
},
"inf:messages": {
"href": "https://informer.example.com/api/chats/00000000-0000-4000-8000-000000000001/messages"
},
"inf:chat-schedule": {
"href": "https://informer.example.com/api/chats/00000000-0000-4000-8000-000000000001/schedule"
},
"inf:chat-object": {
"href": "https://informer.example.com/api/chats/00000000-0000-4000-8000-000000000001/_object"
}
},
"permissions": {},
"id": "00000000-0000-4000-8000-000000000001",
"name": "Q4 Sales Analysis",
"username": "admin",
"instructions": "Focus on quarterly revenue metrics.",
"web": false,
"helpCenter": false,
"informerApi": false,
"appBuilder": false,
"outputSize": "medium",
"error": null,
"stale": false,
"modelId": "00000000-0000-4000-8000-000000000002",
"tier": "strategic",
"autoRename": true,
"autoRenamedAt": null,
"autosuggest": false,
"ownerAssistantId": null,
"primaryAssistantId": null,
"appId": null,
"datasetId": null,
"reportId": null,
"templateId": null,
"queryId": null,
"visualId": null,
"datasourceId": null,
"jobId": null,
"memoryRequestedAt": null,
"memoryRequestedReason": null,
"pinned": true,
"embedded": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"schedule": null,
"model": {
"naturalId": "acme-custom-opus",
"permissions": {},
"promptPpm": null,
"completionPpm": null,
"cacheReadPpm": null,
"cacheWriteShortPpm": null,
"cacheWriteLongPpm": null,
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000002",
"providerId": "00000000-0000-4000-8000-000000000003",
"referencesId": null,
"name": "Acme Custom Opus",
"slug": "acme-custom-opus",
"model": "claude-opus-4",
"options": null,
"chat": true,
"moderated": false,
"contextWindow": 200000,
"maxOutputTokens": null,
"instructions": null,
"description": null,
"managed": false,
"internal": false,
"deprecatedAt": null,
"web": false,
"attachments": false,
"generateImage": false,
"createEmbeddings": false,
"score": 100,
"pricingTier": null,
"badges": null,
"tier": "strategic",
"customized": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"provider": {
"permissions": {},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000003",
"name": "Anthropic",
"slug": "anthropic-1",
"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"
}
},
"chatAssistants": [],
"chatDatasets": [],
"chatLibraries": [],
"assistantIds": [],
"datasetIds": [],
"libraryIds": []
}
DELETE /api/chats/{id}
Delete a chat (and its messages) via the read_access scope.
Authentication: Required
Response:
Responds 200 with an empty body (Informer convention), not 204. A
non-existent id answers 404 via the route's postRemove guard.
GET /api/chat-models
List the models available for chat as a HAL collection embedding inf:model,
ordered by score.
Authentication: Required
Pre-blocks: byok (reads the signed license claim via server.ai.byok(); no License Manager round-trip)
Response:
A HAL collection under _embedded["inf:model"], filtered to chat-capable,
non-deprecated, non-internal models. The three GO tier aliases (go_everyday,
go_advanced, go_strategic) are always included and embed their referenced
base model under inf:referenced-model; other managed aliases are excluded. An
alias without its own tier inherits the base model's tier. Each inlined
provider has its key stripped. Under BYOK, models from managed providers with
no configured key are filtered out.
{
"_links": {
"self": {
"href": "https://informer.example.com/api/chat-models"
}
},
"start": 0,
"count": 46,
"total": 46,
"_embedded": {
"inf:model": [
{
"_links": {
"self": {
"href": "https://informer.example.com/api/chat-models/00000000-0000-4000-8000-000000000001"
}
},
"naturalId": "claude-opus-4",
"permissions": {},
"promptPpm": 15,
"completionPpm": 75,
"cacheReadPpm": 1.5,
"cacheWriteShortPpm": 18.75,
"cacheWriteLongPpm": 30,
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000001",
"providerId": "00000000-0000-4000-8000-000000000002",
"referencesId": null,
"name": "Claude Opus 4",
"slug": "claude-opus-4",
"model": "claude-opus-4",
"options": {},
"chat": true,
"moderated": false,
"contextWindow": 200000,
"maxOutputTokens": null,
"instructions": null,
"description": null,
"managed": true,
"internal": false,
"deprecatedAt": null,
"web": false,
"attachments": false,
"generateImage": false,
"createEmbeddings": false,
"score": null,
"pricingTier": null,
"badges": null,
"tier": "strategic",
"customized": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"referencedModel": null,
"provider": {
"permissions": {},
"id": "00000000-0000-4000-8000-000000000002",
"name": "Anthropic",
"type": "anthropic",
"managed": true
}
},
{
"_links": {
"self": {
"href": "https://informer.example.com/api/chat-models/00000000-0000-4000-8000-000000000003"
}
},
"naturalId": "claude-opus-4-1",
"permissions": {},
"promptPpm": 15,
"completionPpm": 75,
"cacheReadPpm": 1.5,
"cacheWriteShortPpm": 18.75,
"cacheWriteLongPpm": 30,
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000003",
"providerId": "00000000-0000-4000-8000-000000000002",
"referencesId": null,
"name": "Claude Opus 4.1",
"slug": "claude-opus-4-1",
"model": "claude-opus-4-1",
"options": {},
"chat": true,
"moderated": false,
"contextWindow": 200000,
"maxOutputTokens": null,
"instructions": null,
"description": null,
"managed": true,
"internal": false,
"deprecatedAt": null,
"web": false,
"attachments": false,
"generateImage": false,
"createEmbeddings": false,
"score": null,
"pricingTier": null,
"badges": null,
"tier": "strategic",
"customized": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"referencedModel": null,
"provider": {
"permissions": {},
"id": "00000000-0000-4000-8000-000000000002",
"name": "Anthropic",
"type": "anthropic",
"managed": true
}
},
{
"_links": {
"self": {
"href": "https://informer.example.com/api/chat-models/00000000-0000-4000-8000-000000000004"
}
},
"naturalId": "claude-sonnet-4-6",
"permissions": {},
"promptPpm": 3,
"completionPpm": 15,
"cacheReadPpm": 0.3,
"cacheWriteShortPpm": 3.75,
"cacheWriteLongPpm": 6,
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000004",
"providerId": "00000000-0000-4000-8000-000000000002",
"referencesId": null,
"name": "Claude Sonnet 4.6",
"slug": "claude-sonnet-4-6",
"model": "claude-sonnet-4-6",
"options": {},
"chat": true,
"moderated": false,
"contextWindow": 200000,
"maxOutputTokens": null,
"instructions": null,
"description": null,
"managed": true,
"internal": false,
"deprecatedAt": null,
"web": false,
"attachments": false,
"generateImage": false,
"createEmbeddings": false,
"score": null,
"pricingTier": null,
"badges": null,
"tier": "advanced",
"customized": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"referencedModel": null,
"provider": {
"permissions": {},
"id": "00000000-0000-4000-8000-000000000002",
"name": "Anthropic",
"type": "anthropic",
"managed": true
}
},
"… 43 more items (46 total) — omitted from docs"
]
}
}
POST /api/chats/{id}
Send a message to a chat and receive a live model response.
Authentication: Required
Pre-blocks:
chat.lookupForSubmission(params.id)- Model resolution (resolves the chat's model, allowing a tier override)
- Credit enforcement: a model with a tier runs
ai.enforceTieredLimits(tier); otherwiseai.enforceLimits(). App Builder models (keyed off the resolved model slug, not the chat'sappBuildercolumn) bypass the per-profile tier gate.
Metering: Consumes credits subject to the caller's usage profile (skipped under BYOK).
Request Body:
The payload is stripUnknown. Max payload size is 200MB (209715200 bytes).
| Field | Type | Default | Description |
|---|---|---|---|
message | object | - | The message to send |
fileIds | array | [] | File ids to attach |
uploadIds | array | [] | Upload ids to process |
tools | object | {} | Tool configuration |
functions | array | [] | Function names to enable |
toolkitIds | array | [] | Additional toolkit ids |
system | string | null | - | System prompt override |
dynamicSystem | string | null | - | Dynamic system prompt fragment |
Response:
A live model stream served as Server-Sent Events (text/event-stream); not
shown. The connection closes on the abort signal.
The credit enforcer runs in the pre-block before any streaming starts. A request
that exceeds the caller's profile cap, an entity budget, or the credit pool is
rejected with 402 Payment Required and a machine-readable code (for example
CREDIT_LIMIT, BUDGET_EXHAUSTED, HARD_CUTOFF). See the
enforcement flow.
POST /api/chats/{id}/attachments
Upload a file attachment to a chat. The file is stored in the chat's embedded library and embeddings are computed for retrieval.
Authentication: Required
Pre-blocks: chat.lookup(params.id), then upload.lookup(payload.uploadId)
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
uploadId | string | Yes | Upload id from a prior upload session |
progress | string | No | Progress identifier for upload tracking |
Response:
Responds 201 Created with the stored file. This route does file IO and
embedding generation against live services, so it is not captured here.
POST /api/chats/{id}/messages/{messageId}/_explain
Generate a step-by-step explanation of how a specific message's answer was produced, and persist it on the message.
Authentication: Required
Pre-blocks: message lookup (by messageId + chat id via read_access), then chat.lookupForExplain(params.id, params.messageId)
Request Body:
| Field | Type | Default | Description |
|---|---|---|---|
tools | object | {} | Tool configuration |
functions | array | [] | Function names to enable |
system | string | null | - | System prompt override |
Response:
A live model stream served as Server-Sent Events (text/event-stream); not
shown. The explanation text is saved to the message when the stream finishes.
POST /api/chats/{id}/_summarize
Summarize a chat's messages into memory segments. Each segment of messages is turned into a Memory.
Authentication: Required
Pre-blocks: chat.lookup(params.id)
Request Body:
| Field | Type | Default | Description |
|---|---|---|---|
segmentSize | integer | 20 | Messages per segment (1-100) |
modelId | string | null | - | Override the summarization model |
A chat with no messages answers 400. The response reports
{ success, chatId, chatName, totalMessages, segmentSize, totalSegments, summaries, createdAt },
where each summaries entry carries either the created memory's createdAt or
an error message for that segment.
Response:
Each segment is summarized by a live model, so this route is not captured here.
GET /api/chats/{id}/files/{fileId}/{filename}
Retrieve the contents of a chat attachment.
Authentication: Required
Pre-blocks: ai.verify, then file lookup
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | Chat id |
fileId | string | File id |
filename | string | Original filename |
The file lookup matches on the chat id, the ATTACHMENT role, and the
requesting user's ownerId, so a caller can only read their own chat's
attachments.
Response:
The file bytes with an appropriate Content-Type header (binary, not shown).
GET /api/chats/{id}/images/{fileId}
Retrieve an image attachment from a chat. Typically used as an externally resolvable image URL while an assistant analyzes or reads files.
Authentication: Required
Pre-blocks: file lookup (404 when the image is not found)
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | Chat id |
fileId | string | Image file id |
The lookup is scoped to the chat id, the ATTACHMENT role, and the requesting
user's ownerId.
Response:
The image bytes with an appropriate Content-Type header (binary, not shown).