Skip to main content

Models

Looking for the product view?
The Help Center explains this surface as users see it: Choosing the right model.

Endpoints for managing AI models and for running one-off calls against a model. A model is either canonical (it points at a Provider plus a provider-side model identifier) or an alias (it references another model via referencesId and inherits that model's provider and capabilities).

Listing and reading models is open to any authenticated user. Creating, updating, and deleting models require permission.ai.manage (superuser). None of these routes require the AI module to be enabled on the tenant.

GET /api/models​

List the tenant's models.

Authentication: Required (no permission gate)

Query Parameters:

ParameterTypeDefaultDescription
chatbooleanfalseKeep only chat-capable models. Alias models inherit the referenced model's chat flag.
includeInternalbooleanfalseInclude internal/system models. Excluded by default.

Response:

A HAL-wrapped collection: a top-level { start, count, total } envelope with the models under _embedded["inf:model"]. It is not a hand-shaped document and there is no inf:model key at the document root. Canonical models eager-load their provider; alias models eager-load referencedModel.

List modelsGET /api/models
GET /api/models has no permission gate (any authenticated user). The body is an eu.collection: { items, start, count, total }, not a hand-shaped HAL doc. By default internal models are excluded; pass ?includeInternal=true to include them and ?chat=true to keep only chat-capable models (alias models inherit the referenced model’s chat flag).
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/models"
}
},
"start": 0,
"count": 5,
"total": 5,
"_embedded": {
"inf:model": [
{
"_links": {
"self": {
"href": "https://informer.example.com/api/models/00000000-0000-4000-8000-000000000001"
}
},
"naturalId": "go_advanced",
"permissions": {},
"promptPpm": null,
"completionPpm": null,
"cacheReadPpm": null,
"cacheWriteShortPpm": null,
"cacheWriteLongPpm": null,
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000001",
"providerId": null,
"referencesId": null,
"name": "go_advanced",
"slug": "go_advanced",
"model": null,
"options": null,
"chat": false,
"moderated": false,
"contextWindow": 200000,
"maxOutputTokens": null,
"instructions": null,
"description": null,
"rates": null,
"managed": true,
"internal": false,
"deprecatedAt": null,
"web": false,
"attachments": false,
"generateImage": false,
"createEmbeddings": false,
"score": null,
"pricingTier": null,
"badges": null,
"tier": null,
"customized": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"referencedModel": null,
"provider": null
},
{
"_links": {
"self": {
"href": "https://informer.example.com/api/models/00000000-0000-4000-8000-000000000002"
}
},
"naturalId": "go_everyday",
"permissions": {},
"promptPpm": null,
"completionPpm": null,
"cacheReadPpm": null,
"cacheWriteShortPpm": null,
"cacheWriteLongPpm": null,
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000002",
"providerId": null,
"referencesId": null,
"name": "go_everyday",
"slug": "go_everyday",
"model": null,
"options": null,
"chat": false,
"moderated": false,
"contextWindow": 200000,
"maxOutputTokens": null,
"instructions": null,
"description": null,
"rates": null,
"managed": true,
"internal": false,
"deprecatedAt": null,
"web": false,
"attachments": false,
"generateImage": false,
"createEmbeddings": false,
"score": null,
"pricingTier": null,
"badges": null,
"tier": null,
"customized": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"referencedModel": null,
"provider": null
},
{
"_links": {
"self": {
"href": "https://informer.example.com/api/models/00000000-0000-4000-8000-000000000003"
}
},
"naturalId": "informer-basic",
"permissions": {},
"promptPpm": 0.4,
"completionPpm": 1.6,
"cacheReadPpm": null,
"cacheWriteShortPpm": null,
"cacheWriteLongPpm": null,
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000003",
"providerId": "00000000-0000-4000-8000-000000000004",
"referencesId": null,
"name": "Informer Basic",
"slug": "informer-basic",
"model": "gpt-4.1",
"options": null,
"chat": true,
"moderated": false,
"contextWindow": 200000,
"maxOutputTokens": null,
"instructions": null,
"description": null,
"rates": null,
"managed": true,
"internal": false,
"deprecatedAt": null,
"web": false,
"attachments": false,
"generateImage": false,
"createEmbeddings": false,
"score": null,
"pricingTier": null,
"badges": null,
"tier": null,
"customized": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"referencedModel": null,
"provider": {
"permissions": {},
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000004",
"name": "OpenAI",
"slug": "openai",
"type": "openai",
"key": null,
"managed": true,
"internal": false,
"settings": null,
"data": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z"
}
},
"… 2 more items (5 total) — omitted from docs"
]
}
}
Captured from the API examples test suite; ids and timestamps are normalized.

Model properties:

FieldTypeDescription
idstring (UUID)Model id
naturalIdstringStable natural identifier
namestringDisplay name
slugstringURL-safe identifier
descriptionstring | nullModel description
providerIdstring (UUID) | nullOwning Provider (canonical models)
referencesIdstring (UUID) | nullBase model id (alias models)
modelstring | nullProvider's model identifier
chatbooleanSupports chat completions
webbooleanCan access web content
generateImagebooleanCan generate images
attachmentsbooleanSupports file attachments
createEmbeddingsbooleanCan create embeddings
effortOverrideboolean | nullAdmin override for the reasoning-effort dial: true or false pins it, null (the default) lets the provider driver decide from the model id
supportsEffortbooleanRead-only. Whether a chat on this model may set an effort level: the override when set, otherwise the driver's answer for the canonical model. A tier alias may pin its own; a plain alias mirrors its base model's
moderatedbooleanContent moderation enabled
tierstring | nullBudget tier: everyday, advanced, strategic
pricingTierstring | nullCost category: Low, Medium, High, Very High
contextWindowinteger | nullMaximum context tokens
maxOutputTokensinteger | nullMaximum output tokens
promptPpmnumber | nullCost per million prompt tokens
completionPpmnumber | nullCost per million completion tokens
cacheReadPpmnumber | nullCost per million cached read tokens
cacheWriteShortPpmnumber | nullCost per million short-term cache writes
cacheWriteLongPpmnumber | nullCost per million long-term cache writes
ratesobject | nullNamed provider fee rates that do not fit the per-million columns (for example webSearchPer1k, imagePerUnit, longContext), delivered by model sync from the License Manager. A fee may be { value, charged }, where charged: false meters it at full rate but never debits it
scoreinteger | nullQuality/capability score
badgesarray | nullDisplay badges
instructionsstring | nullSystem instructions
optionsobject | nullProvider-specific options
managedbooleanSystem-managed (License Manager controlled)
internalbooleanInternal/system-only model
customizedbooleanWhether a managed model has been customized
deprecatedAtdate | nullDeprecation date (null if active)
providerobject | nullEager-loaded Provider (canonical models)
referencedModelobject | nullEager-loaded base model (alias models)

Alias models:

Alias models reference another model via referencesId. They:

  • Inherit capabilities from the referenced model.
  • Can override name, slug, instructions, and options.
  • Take their providerId and model from the referenced model via a database trigger, so those are never sent when creating an alias.

POST /api/models​

Create a model (canonical or alias).

Authentication: permission.ai.manage

Pre-blocks: permission.ai.manage

The payload is an XOR. If referencesId is present it is treated as an alias payload and only { referencesId, name, slug, instructions, options } are kept; every other field is stripped. Otherwise it is a canonical payload requiring { providerId, model, name }. Both referencesId and providerId must be UUIDs.

Request Body (canonical):

FieldTypeRequiredDescription
providerIdstring (UUID)YesOwning Provider
modelstringYesProvider's model identifier
namestringYesDisplay name
slugstringNoURL-safe id (defaults to model)
descriptionstringNoModel description
chatbooleanNoSupports chat
webbooleanNoWeb access
generateImagebooleanNoImage generation
attachmentsbooleanNoFile attachment support
createEmbeddingsbooleanNoEmbedding generation
effortOverrideboolean | nullNoOverride for the reasoning-effort dial; omit or send null to let the provider driver decide
moderatedbooleanNoContent moderation
tierstringNoeveryday, advanced, strategic
pricingTierstringNoLow, Medium, High, Very High
contextWindowintegerNoMax context tokens
maxOutputTokensintegerNoMax output tokens
promptPpmnumberNoPrompt cost per million tokens
completionPpmnumberNoCompletion cost per million tokens
cacheReadPpmnumberNoCache read cost per million
cacheWriteShortPpmnumberNoShort cache write cost per million
cacheWriteLongPpmnumberNoLong cache write cost per million
scoreintegerNoQuality score
instructionsstringNoSystem instructions
optionsobjectNoProvider-specific options
deprecatedAtdateNoDeprecation date

Example (canonical):

{
"providerId": "00000000-0000-4000-8000-000000000001",
"model": "claude-3-5-sonnet-20241022",
"name": "Claude 3.5 Sonnet",
"slug": "claude-3-5-sonnet",
"chat": true,
"tier": "advanced",
"contextWindow": 200000,
"promptPpm": 3.0,
"completionPpm": 15.0
}

Response:

Responds 200 with the created model. The handler returns the new row directly, so there is no 201 status and no Location header.

Create a canonical modelPOST /api/models
Canonical payload requires { providerId (uuid), model, name }; slug defaults to `model`. Capability flags (chat/web/generateImage/attachments/createEmbeddings) and pricing/tier fields are optional. Requires permission.ai.manage. Responds 200 with the created Model (no 201, no Location header).
Request body
{
"providerId": "00000000-0000-4000-8000-000000000001",
"model": "claude-3-5-sonnet-20241022",
"name": "Claude 3.5 Sonnet",
"slug": "claude-3-5-sonnet",
"chat": true,
"tier": "advanced",
"contextWindow": 200000,
"promptPpm": 3,
"completionPpm": 15
}
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/models"
}
},
"naturalId": "claude-35-sonnet",
"permissions": {},
"promptPpm": 3,
"completionPpm": 15,
"cacheReadPpm": null,
"cacheWriteShortPpm": null,
"cacheWriteLongPpm": null,
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000002",
"web": false,
"attachments": false,
"generateImage": false,
"createEmbeddings": false,
"customized": false,
"name": "Claude 3.5 Sonnet",
"slug": "claude-35-sonnet",
"chat": true,
"tier": "advanced",
"contextWindow": 200000,
"providerId": "00000000-0000-4000-8000-000000000001",
"model": "claude-3-5-sonnet-20241022",
"referencesId": null,
"updatedAt": "2026-01-15T16:20:00.000Z",
"createdAt": "2026-01-15T16:20:00.000Z",
"options": null,
"instructions": null,
"moderated": false,
"internal": false,
"description": null,
"deprecatedAt": null,
"managed": false,
"score": null,
"pricingTier": null,
"badges": null,
"maxOutputTokens": null,
"rates": null
}
Captured from the API examples test suite; ids and timestamps are normalized.

Request Body (alias):

FieldTypeRequiredDescription
referencesIdstring (UUID)YesBase model id to reference
namestringYesDisplay name for the alias
slugstringYesURL-safe identifier
instructionsstringNoOverride instructions
optionsobjectNoOverride options

Example (alias):

{
"referencesId": "00000000-0000-4000-8000-000000000002",
"name": "Strategic Assistant",
"slug": "strategic-assistant",
"instructions": "Focus on strategic analysis"
}

Response:

Responds 200 with the created alias. Its providerId and model are filled in from the referenced model by a database trigger.

Create an alias modelPOST /api/models
Alias payload (referencesId present) only permits { referencesId (uuid, required), name (required), slug (required), instructions?, options? }; every other field is stripped. The alias’s providerId/model are filled by a DB trigger from the referenced model, so they are not sent here.
Request body
{
"referencesId": "00000000-0000-4000-8000-000000000001",
"name": "Strategic Assistant",
"slug": "strategic-assistant",
"instructions": "Focus on strategic analysis"
}
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/models"
}
},
"naturalId": "strategic-assistant",
"permissions": {},
"promptPpm": 15,
"completionPpm": 75,
"cacheReadPpm": null,
"cacheWriteShortPpm": null,
"cacheWriteLongPpm": null,
"tenant": "acme",
"id": "00000000-0000-4000-8000-000000000002",
"web": false,
"attachments": false,
"generateImage": false,
"createEmbeddings": false,
"customized": false,
"name": "Strategic Assistant",
"slug": "strategic-assistant",
"instructions": null,
"referencesId": "00000000-0000-4000-8000-000000000001",
"model": "claude-opus-4-20250514",
"updatedAt": "2026-01-15T16:20:00.000Z",
"createdAt": "2026-01-15T16:20:00.000Z",
"providerId": "00000000-0000-4000-8000-000000000003",
"options": null,
"moderated": false,
"chat": true,
"internal": false,
"contextWindow": 200000,
"description": null,
"deprecatedAt": null,
"managed": false,
"score": 95,
"pricingTier": "Very High",
"badges": null,
"maxOutputTokens": 16384,
"tier": "strategic",
"rates": null
}
Captured from the API examples test suite; ids and timestamps are normalized.

GET /api/models/{id}​

Retrieve a single model.

Authentication: Required (no permission gate)

Pre-blocks: model.lookup

The id may be a UUID or a slug. Canonical models return their eager-loaded provider; alias models return referencedModel.

Response:

Get a modelGET /api/models/00000000-0000-4000-8000-000000000001
GET /api/models/{id} resolves via the model.lookup pre (id may be a uuid or a slug). No permission gate. Returns the Model with its eager-loaded provider.
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/models/00000000-0000-4000-8000-000000000001"
}
},
"naturalId": "claude-opus-4",
"permissions": {},
"promptPpm": 15,
"completionPpm": 75,
"cacheReadPpm": null,
"cacheWriteShortPpm": null,
"cacheWriteLongPpm": null,
"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-20250514",
"options": null,
"chat": true,
"moderated": false,
"contextWindow": 200000,
"maxOutputTokens": 16384,
"instructions": null,
"description": null,
"rates": null,
"managed": false,
"internal": false,
"deprecatedAt": null,
"web": false,
"attachments": false,
"generateImage": false,
"createEmbeddings": false,
"score": 95,
"pricingTier": "Very High",
"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-000000000002",
"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.

PUT /api/models/{id}​

Update a model.

Authentication: permission.ai.manage

Pre-blocks: permission.ai.manage, then model.lookup

Unknown fields are stripped. providerId, model, and referencesId can be sent but are ignored for non-managed edits. Returns the updated model.

Request Body:

The same optional fields as the canonical create payload, minus the identity fields above.

Example:

{ "description": "Updated description", "score": 90 }

Response:

Responds 200 with the updated model.

Update a modelPUT /api/models/00000000-0000-4000-8000-000000000001
PUT /api/models/{id} pre-blocks are permission.ai.manage THEN model.lookup. Unknown fields are stripped; providerId/model/referencesId can be sent but are ignored for non-managed edits. Managed models are read-only (403) outside the tier-alias carve-outs. Returns the updated Model.
Request body
{
"description": "Updated description",
"score": 90
}
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/models/00000000-0000-4000-8000-000000000001"
}
},
"naturalId": "claude-opus-4",
"permissions": {},
"promptPpm": 15,
"completionPpm": 75,
"cacheReadPpm": null,
"cacheWriteShortPpm": null,
"cacheWriteLongPpm": null,
"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-20250514",
"options": null,
"chat": true,
"moderated": false,
"contextWindow": 200000,
"maxOutputTokens": 16384,
"instructions": null,
"description": "Updated description",
"rates": null,
"managed": false,
"internal": false,
"deprecatedAt": null,
"web": false,
"attachments": false,
"generateImage": false,
"createEmbeddings": false,
"score": 90,
"pricingTier": "Very High",
"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-000000000002",
"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.
Managed models are read-only

Managed models (those controlled by License Manager) reject edits with 403, except for the tier-alias customization carve-outs and the effortOverride field, which an admin owns on every managed row. Send effortOverride on its own (true, false, or null for auto) and the write is allowed on any managed model, alias or canonical; the License Manager sync never touches it. Send it alongside any other field and the whole request is a 403.

A plain alias follows its base model

On a model that is not managed, a plain alias (one with referencesId and no tier) rejects effortOverride with a 400: the sync_model_from_reference trigger mirrors the base model's capabilities onto it on every write, so an override written there would not survive. Set it on the base model instead. Managed rows never reach this check — the managed rule above settles them first.


DELETE /api/models/{id}​

Delete a model.

Authentication: permission.ai.manage

Pre-blocks: permission.ai.manage, then model.lookup

Response:

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

Delete a modelDELETE /api/models/00000000-0000-4000-8000-000000000001
DELETE /api/models/{id} requires permission.ai.manage. The handler destroys the row and returns nothing, so the response is 200 with an EMPTY body (Informer convention), NOT 204. Managed models cannot be deleted (403).
Response · 200 · no body
Captured from the API examples test suite; ids and timestamps are normalized.
Managed models cannot be deleted

Deleting a managed model answers 403. Deleting a canonical model may orphan alias models that reference it.


POST /api/models/{id}/_chat​

Run a chat against a model without persisting anything. Nothing is written to the database, so each request starts from the messages you send it. To save the conversation instead, see Choosing an endpoint.

Authentication: Required (AI access)

Pre-blocks: Model resolution, then credit enforcement (tiered when the model has a tier, legacy otherwise)

An unknown model id answers 404. A model row that exists but has not yet been populated by the License Manager sync answers 503 with data.code = "AI_MODEL_PENDING", which is retryable.

Metering: Consumes credits subject to the caller's usage profile (skipped under BYOK).

Request Body:

The payload is stripUnknown, so unrecognized fields are dropped rather than rejected.

FieldTypeDefaultDescription
messagesarray-Required. Messages in parts format
primaryAssistantIdstring | null-The Assistant that answers, with its full configuration
assistantIdsarray[]Assistants the model may dispatch to
toolkitIdsarray[]Additional Toolkits to enable
toolsobject{}Tool configuration
skillsobject{}Inline skill configuration, keyed by skill type
functionsarray[]Built-in function names to enable
systemstring | null-System prompt
dynamicSystemstring | null-Dynamic system prompt fragment
webSearchbooleanfalseEnable the web search function
helpCenterbooleanfalseEnable the Help Center search function
magicReportbooleanfalseSelect the Magic Report admin instructions
maxStepsnumber20Maximum tool-calling steps
outputSizestringmediumsmall, medium, or large

Datasets, knowledge files, secrets, and Toolkits are not payload fields. They reach the request through the Assistant's own configuration, so attaching an Assistant is what brings them in. Toolkits configured on the Assistant are merged with any toolkitIds you pass.

primaryAssistantId and assistantIds both resolve through read_access, so an id the caller cannot see is treated as absent. When assistantIds holds exactly one Assistant and no primaryAssistantId is given, that Assistant is promoted to the primary.

Admin instructions are selected by context: Magic Report, magic visual, Assistant, Help Center, or Copilot, in that order of precedence.

Example Request:

{
"messages": [
{ "role": "user", "parts": [{ "type": "text", "text": "Which programs have fall deadlines?" }] }
],
"primaryAssistantId": "admin:admissions-helper"
}

Response:

A live model stream served as Server-Sent Events (text/event-stream); not shown. The connection closes on the abort signal.


POST /api/models/{id}/_completion​

Generate a completion from a model, with no Assistant and no persistence.

Authentication: Required (AI access)

Pre-blocks: model.lookup(params.id)

Request Body:

The payload is stripUnknown.

FieldTypeDefaultDescription
promptstring-Required. Appended to messages as a user message
messagesarray[]Prior message context, in parts format

Sampling controls such as temperature and stop sequences are not accepted here; they belong to the model's own options. See POST /api/models.

Example Request:

{
"prompt": "Summarize the fall admissions timeline in one sentence."
}

Response:

A live model stream served as Server-Sent Events (text/event-stream), despite the endpoint's name; not shown.


POST /api/models/{id}/_object​

Generate a structured object from a model using a JSON Schema. This is the only AI endpoint that answers with a plain JSON body rather than a stream.

Authentication: Required (AI access)

Pre-blocks: model.lookup(params.id)

Request Body:

The payload is stripUnknown.

FieldTypeDefaultDescription
schemaobject-Required. JSON Schema describing the output
messagesarray-Required. Prompt messages, in parts format
outputSizestring-small, medium, or large

There is no field for an Assistant, a system prompt, or Toolkits, so an Assistant's skills never run on this route. When you need those, use _chat and read the stream.

Example Request:

{
"schema": {
"type": "object",
"properties": {
"sentiment": { "type": "string", "enum": ["positive", "negative", "neutral"] },
"confidence": { "type": "number", "minimum": 0, "maximum": 1 },
"keywords": { "type": "array", "items": { "type": "string" } }
},
"required": ["sentiment", "confidence"]
},
"messages": [
{ "role": "user", "parts": [{ "type": "text", "text": "Analyze the sentiment: 'This product is amazing!'" }] }
]
}

Response:

The generated object itself, as the entire response body, with no envelope and no HAL links. Because a live model call produces it, no captured example is shown here.

Model selection

Use advanced or strategic tier models for complex schema generation. Everyday models may struggle with intricate structures.