# AI capabilities

These operations read documents and make media with models: parse a PDF into markdown, generate images, speech or video, transcribe audio, answer a question about an image or a video, and submit many requests at once as an offline batch. They spend your Workspace's own model budget, so the whole family is agency-only — a client collaborator is refused every operation in it. Bytes are never inlined: a response names a stored file, and `GET /v1/api/ai/assets/{key}` hands it over.

Generated from contract version `1.0.0` — the same document [`/v1/api/openapi.json`](/api/openapi/) serves.

## Prerequisites

- An API key in `x-api-key`, or a browser session cookie
- `X-Organization-Id` naming the workspace to act in, unless the session already has an active one
- The base URL for your deployment, `https://server.hlix.ai` by default

## Operations

| Method | Path | Operation |
| --- | --- | --- |
| `GET` | `/v1/api/ai/assets/{key}` | [Fetch one stored AI artifact](#fetch-one-stored-ai-artifact) |
| `POST` | `/v1/api/ai/batches` | [Submit a batch of offline requests](#submit-a-batch-of-offline-requests) |
| `GET` | `/v1/api/ai/batches/{id}` | [Read one batch and a page of its items](#read-one-batch-and-a-page-of-its-items) |
| `POST` | `/v1/api/ai/batches/{id}/poll` | [Poll one batch now](#poll-one-batch-now) |
| `GET` | `/v1/api/ai/documents` | [List recently parsed documents](#list-recently-parsed-documents) |
| `POST` | `/v1/api/ai/documents` | [Parse a document into markdown](#parse-a-document-into-markdown) |
| `GET` | `/v1/api/ai/documents/{id}` | [Read one parsed document](#read-one-parsed-document) |
| `POST` | `/v1/api/ai/media/analyze` | [Ask a question about an image or a video](#ask-a-question-about-an-image-or-a-video) |
| `POST` | `/v1/api/ai/media/images` | [Generate images](#generate-images) |
| `POST` | `/v1/api/ai/media/speech` | [Synthesize speech](#synthesize-speech) |
| `POST` | `/v1/api/ai/media/transcriptions` | [Transcribe stored audio](#transcribe-stored-audio) |
| `POST` | `/v1/api/ai/media/video` | [Submit a video generation](#submit-a-video-generation) |
| `GET` | `/v1/api/ai/media/video/{id}` | [Read one video job](#read-one-video-job) |
| `POST` | `/v1/api/ai/media/video/{id}/review` | [Record a review verdict on a generated video](#record-a-review-verdict-on-a-generated-video) |
| `POST` | `/v1/api/ai/w/{workspaceId}/chat/completions` | [Run an OpenAI-compatible chat completion on the workspace's own model budget](#run-an-openai-compatible-chat-completion-on-the-workspaces-own-model-budget) |
| `GET` | `/v1/api/ai/w/{workspaceId}/models` | [List the models a Hlix Code session may run, and the workspace default](#list-the-models-a-hlix-code-session-may-run-and-the-workspace-default) |
| `POST` | `/v1/api/ai/w/{workspaceId}/responses` | [Run an OpenAI Responses request on the workspace's own model budget](#run-an-openai-responses-request-on-the-workspaces-own-model-budget) |
| `POST` | `/v1/api/ai/w/{workspaceId}/v1/messages` | [Run an Anthropic Messages request on the workspace's own model budget](#run-an-anthropic-messages-request-on-the-workspaces-own-model-budget) |

## Fetch one stored AI artifact

`GET /v1/api/ai/assets/{key}` · operation ID `getAiAsset`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `key` | path | **yes** | string |  |
| `download` | query | no | string | Set to `1` to receive the object's own bytes instead of a JSON pointer. It only changes anything when this deployment cannot hand back a signed URL — artifacts stored locally, or a signed download link could not be issued for this request — because a signed URL is always answered as JSON. In that case the JSON body's `url` is this same route with `download=1` already appended, so following it is the normal flow; any other value, absent included, answers the JSON. |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | SignedArtifactUrl | A signed URL where this deployment can issue one, otherwise this same route with `download=1` already appended — following it returns the object's own bytes. |
| `400` | ApiError | The request named no active organization. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not entitled to this endpoint. The whole `/v1/api/ai` family is agency-only: a client collaborator is refused every operation in it, on every project. |
| `404` | ApiError | No such artifact. A key outside this workspace's own AI storage answers the same 404 — its existence is not confirmed. |
| `500` | ApiError | The download could not be prepared. |

## Submit a batch of offline requests

`POST /v1/api/ai/batches` · operation ID `submitAiBatch`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Request body** — `application/json`, `SubmitBatch` (required)

| Property | Type | Required | Notes |
| --- | --- | --- | --- |
| `endpoint` | `/v1/chat/completions` | `/v1/responses` | `/v1/messages` | `/v1/embeddings` | **yes** |  |
| `idempotencyKey` | string | **yes** | min length 1, max length 200 |
| `items` | object[] | **yes** |  |
| `kind` | `backfill` | `classification` | `enrichment` | `transcription` | `variation` | `evaluation` | **yes** |  |
| `model` | `claude-fable-5-1` | `claude-opus-5` | `claude-sonnet-5` | `claude-haiku-4-5` | `gpt-6-astra` | `gpt-5.6-sol` | `gpt-5.6-terra` | `gpt-5.6-luna` | `jev-latest` | `gemini-3.8-flash` | `gemini-embedding-2` | `grok-4.6` | `kimi-k3` | `deepseek-v4-pro` | `deepseek-v4.1-flash` | `glm-5.3` | `glm-5.3-flash` | `qwen3.8-max` | `qwen3.8-flash` | `auto` | `pareto-code` | `fable-latest` | `opus-latest` | `sonnet-latest` | `haiku-latest` | `gpt-latest` | `grok-latest` | `gemini-pro-latest` | `gemini-flash-latest` | `deepseek-pro-latest` | `deepseek-flash-latest` | `glm-latest` | `glm-flash-latest` | `kimi-latest` | `whisper-1` | `voxtral-mini-tts` | `seedream-4-5` | `veo-3-1` | **yes** |  |
| `policy` | object | **yes** |  |
| `projectId` | string | no | min length 1 |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `202` | AiBatchAccepted | Accepted. The provider holds the batch; results arrive through the poll sweep. Replaying the same `idempotencyKey` returns the first job and calls no provider. |
| `400` | ValidationError \| ApiError | The JSON body failed schema validation (`ValidationError`), or the request named no active organization (`ApiError`). |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not an owner or admin of this workspace — or a client collaborator, for whom the whole family is closed. |
| `404` | ApiError | The `projectId` names no project in this workspace. A project belonging to another workspace answers identically (`code: "project_not_found"`) — its existence is not confirmed. |
| `422` | AiInputRefused | The request was understood and refused — a blocked URL, a source that is not a parseable document, an artifact key outside this workspace, or a policy this capability will not waive. |
| `502` | AiUpstreamFailed | The AI provider could not complete the request. The provider's own message is deliberately not forwarded. |
| `503` | AiCapabilityDisabled | This capability is switched off for this deployment. |

## Read one batch and a page of its items

`GET /v1/api/ai/batches/{id}` · operation ID `getAiBatch`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `id` | path | **yes** | string |  |
| `limit` | query | no | string | How many items to return, 1–1000. Defaults to 200. Rejected rather than clamped: a substituted window is how a paging loop skips rows unnoticed. |
| `after` | query | no | string | The previous page's `nextCursor`, verbatim — the last `customId` it returned. Omit for the first page. |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | AiBatchRead | The batch and one page of its items, ordered by `customId`. An item carries the ADDRESS of its result, never the completion itself. `nextCursor` is null on the last page. |
| `400` | ValidationError \| ApiError | The query failed schema validation (`ValidationError`), or the request named no active organization (`ApiError`). |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not entitled to this endpoint. The whole `/v1/api/ai` family is agency-only: a client collaborator is refused every operation in it, on every project. |
| `404` | ApiError | No such batch in this workspace. |

## Poll one batch now

`POST /v1/api/ai/batches/{id}/poll` · operation ID `pollAiBatch`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `id` | path | **yes** | string |  |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | AiBatchPoll | The batch as of this poll. `polled` is false when it was already settled or was never submitted — no request went to the provider. The scheduled sweep is the normal path; this is the manual poke. |
| `400` | ApiError | The request named no active organization. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not entitled to this endpoint. The whole `/v1/api/ai` family is agency-only: a client collaborator is refused every operation in it, on every project. |
| `404` | ApiError | No such batch in this workspace. |
| `502` | AiUpstreamFailed | The AI provider could not complete the request. The provider's own message is deliberately not forwarded. |
| `503` | AiCapabilityDisabled | This capability is switched off for this deployment. |

## List recently parsed documents

`GET /v1/api/ai/documents` · operation ID `listAiDocuments`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `limit` | query | no | string | How many rows to return, newest first. Clamped to 200; anything unparseable falls back to 50. |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | AiDocument[] | The workspace's most recent parses, newest first. The extraction itself is not inlined — read one document for a followable address. |
| `400` | ApiError | The request named no active organization. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not entitled to this endpoint. The whole `/v1/api/ai` family is agency-only: a client collaborator is refused every operation in it, on every project. |
| `404` | ApiError | The resource does not exist, or the caller is a task-scoped credential and this endpoint is outside its allowlist. |

## Parse a document into markdown

`POST /v1/api/ai/documents` · operation ID `parseAiDocument`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Request body** — `application/json`, `ParseDocument` (required)

| Property | Type | Required | Notes |
| --- | --- | --- | --- |
| `critical` | boolean | no |  |
| `engine` | `text` | `ocr` | `native` | no | How to read the PDF. Omit unless you know: `text` (the default) converts a PDF whose words are already text. Use `ocr` when the pages are images of a document, and `native` when the meaning is in the layout or the figures rather than the words. |
| `projectId` | string | no | min length 1 |
| `scanned` | boolean | no |  |
| `source` | object | object | **yes** |  |
| `visual` | boolean | no |  |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `201` | AiDocumentParsed | The parse ran and the row is final. `reused` is true when the same bytes through the same engine had already been parsed — a lookup, not a second bill. A document declared `critical` lands `review_required`, not `succeeded`. |
| `400` | ValidationError \| ApiError | The JSON body failed schema validation (`ValidationError`), or the request named no active organization (`ApiError`). |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not entitled to this endpoint. The whole `/v1/api/ai` family is agency-only: a client collaborator is refused every operation in it, on every project. |
| `404` | ApiError | Either the `projectId` names no project in this workspace (`code: "project_not_found"`, and a project belonging to another workspace answers identically), or the parsed row could not be read back. |
| `422` | AiInputRefused | The request was understood and refused — a blocked URL, a source that is not a parseable document, an artifact key outside this workspace, or a policy this capability will not waive. |
| `502` | AiUpstreamFailed | The AI provider could not complete the request. The provider's own message is deliberately not forwarded. |
| `503` | AiCapabilityDisabled | This capability is switched off for this deployment. |

## Read one parsed document

`GET /v1/api/ai/documents/{id}` · operation ID `getAiDocument`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `id` | path | **yes** | string |  |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | AiDocumentRead | The row, plus `extractedUrl` — a followable address for the extracted markdown, or null while there is nothing to fetch. |
| `400` | ApiError | The request named no active organization. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not entitled to this endpoint. The whole `/v1/api/ai` family is agency-only: a client collaborator is refused every operation in it, on every project. |
| `404` | ApiError | No such document in this workspace. |

## Ask a question about an image or a video

`POST /v1/api/ai/media/analyze` · operation ID `analyzeAiMedia`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Request body** — `application/json`, `AnalyzeMedia` (required)

| Property | Type | Required | Notes |
| --- | --- | --- | --- |
| `kind` | `image` | `video` | **yes** |  |
| `projectId` | string | no | min length 1 |
| `question` | string | **yes** | min length 1, max length 4000 |
| `source` | object | object | **yes** |  |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | AiTextResult | The answer and what it consumed. |
| `400` | ValidationError \| ApiError | The JSON body failed schema validation (`ValidationError`), or the request named no active organization (`ApiError`). |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not entitled to this endpoint. The whole `/v1/api/ai` family is agency-only: a client collaborator is refused every operation in it, on every project. |
| `404` | ApiError | The `projectId` names no project in this workspace. A project belonging to another workspace answers identically (`code: "project_not_found"`) — its existence is not confirmed. |
| `422` | AiInputRefused | The request was understood and refused — a blocked URL, a source that is not a parseable document, an artifact key outside this workspace, or a policy this capability will not waive. |
| `502` | AiUpstreamFailed | The AI provider could not complete the request. The provider's own message is deliberately not forwarded. |
| `503` | AiCapabilityDisabled | This capability is switched off for this deployment. |

## Generate images

`POST /v1/api/ai/media/images` · operation ID `generateAiImages`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Request body** — `application/json`, `GenerateImages` (required)

| Property | Type | Required | Notes |
| --- | --- | --- | --- |
| `aspectRatio` | string | no | min length 1, max length 32 |
| `n` | integer | no | min 1, max 10 |
| `projectId` | string | no | min length 1 |
| `prompt` | string | **yes** | min length 1, max length 4000 |
| `resolution` | string | no | min length 1, max length 32 |
| `useWorkspaceBrand` | boolean | no |  |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `201` | AiGeneratedImages | The stored images. A provider may return fewer than asked; `keys` says how many landed, and `urls` is index-aligned with it. |
| `400` | ValidationError \| ApiError | The JSON body failed schema validation (`ValidationError`), or the request named no active organization (`ApiError`). |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not entitled to this endpoint. The whole `/v1/api/ai` family is agency-only: a client collaborator is refused every operation in it, on every project. |
| `404` | ApiError | The `projectId` names no project in this workspace. A project belonging to another workspace answers identically (`code: "project_not_found"`) — its existence is not confirmed. |
| `422` | AiInputRefused | The request was understood and refused — a blocked URL, a source that is not a parseable document, an artifact key outside this workspace, or a policy this capability will not waive. |
| `502` | AiUpstreamFailed | The AI provider could not complete the request. The provider's own message is deliberately not forwarded. |
| `503` | AiCapabilityDisabled | This capability is switched off for this deployment. |

## Synthesize speech

`POST /v1/api/ai/media/speech` · operation ID `synthesizeAiSpeech`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Request body** — `application/json`, `SynthesizeSpeech` (required)

| Property | Type | Required | Notes |
| --- | --- | --- | --- |
| `format` | `mp3` | `pcm` | no |  |
| `projectId` | string | no | min length 1 |
| `speed` | number | no | min 0.25, max 4 |
| `text` | string | **yes** | min length 1, max length 10000 |
| `voice` | string | **yes** | min length 1, max length 100 |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `201` | AiSpeech | The stored audio. |
| `400` | ValidationError \| ApiError | The JSON body failed schema validation (`ValidationError`), or the request named no active organization (`ApiError`). |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not entitled to this endpoint. The whole `/v1/api/ai` family is agency-only: a client collaborator is refused every operation in it, on every project. |
| `404` | ApiError | The `projectId` names no project in this workspace. A project belonging to another workspace answers identically (`code: "project_not_found"`) — its existence is not confirmed. |
| `422` | AiInputRefused | The request was understood and refused — a blocked URL, a source that is not a parseable document, an artifact key outside this workspace, or a policy this capability will not waive. |
| `502` | AiUpstreamFailed | The AI provider could not complete the request. The provider's own message is deliberately not forwarded. |
| `503` | AiCapabilityDisabled | This capability is switched off for this deployment. |

## Transcribe stored audio

`POST /v1/api/ai/media/transcriptions` · operation ID `transcribeAiAudio`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Request body** — `application/json`, `TranscribeAudio` (required)

| Property | Type | Required | Notes |
| --- | --- | --- | --- |
| `artifactKey` | string | **yes** | min length 1, max length 512 |
| `format` | `wav` | `mp3` | `flac` | `m4a` | `ogg` | `webm` | `aac` | **yes** |  |
| `language` | string | no | min length 2, max length 16 |
| `projectId` | string | no | min length 1 |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | AiTextResult | The transcript and what it consumed. |
| `400` | ValidationError \| ApiError | The JSON body failed schema validation (`ValidationError`), or the request named no active organization (`ApiError`). |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not entitled to this endpoint. The whole `/v1/api/ai` family is agency-only: a client collaborator is refused every operation in it, on every project. |
| `404` | ApiError | The `projectId` names no project in this workspace. A project belonging to another workspace answers identically (`code: "project_not_found"`) — its existence is not confirmed. |
| `422` | AiInputRefused | The request was understood and refused — a blocked URL, a source that is not a parseable document, an artifact key outside this workspace, or a policy this capability will not waive. |
| `502` | AiUpstreamFailed | The AI provider could not complete the request. The provider's own message is deliberately not forwarded. |
| `503` | AiCapabilityDisabled | This capability is switched off for this deployment. |

## Submit a video generation

`POST /v1/api/ai/media/video` · operation ID `generateAiVideo`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Request body** — `application/json`, `GenerateVideo` (required)

| Property | Type | Required | Notes |
| --- | --- | --- | --- |
| `aspectRatio` | string | no | min length 1, max length 32 |
| `duration` | integer | no | max 600 |
| `idempotencyKey` | string | **yes** | min length 1, max length 200 |
| `projectId` | string | no | min length 1 |
| `prompt` | string | **yes** | min length 1, max length 4000 |
| `resolution` | string | no | min length 1, max length 32 |
| `useWorkspaceBrand` | boolean | no |  |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `202` | AiMediaJobAccepted | Accepted. The row exists; the video does not yet. Read `job.status` — a submit the provider refused is recorded on the row as `failed` with its own `error` rather than raised, so the attempt is never lost. Replaying the same `idempotencyKey` returns the first job rather than paying twice. |
| `400` | ValidationError \| ApiError | The JSON body failed schema validation (`ValidationError`), or the request named no active organization (`ApiError`). |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not entitled to this endpoint. The whole `/v1/api/ai` family is agency-only: a client collaborator is refused every operation in it, on every project. |
| `404` | ApiError | The `projectId` names no project in this workspace. A project belonging to another workspace answers identically (`code: "project_not_found"`) — its existence is not confirmed. |
| `422` | AiInputRefused | The request was understood and refused — a blocked URL, a source that is not a parseable document, an artifact key outside this workspace, or a policy this capability will not waive. |
| `503` | AiCapabilityDisabled | This capability is switched off for this deployment. |

## Read one video job

`GET /v1/api/ai/media/video/{id}` · operation ID `getAiVideoJob`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `id` | path | **yes** | string |  |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | AiMediaJobRead | The job, plus `outputUrl` once the finished video has been collected. |
| `400` | ApiError | The request named no active organization. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not entitled to this endpoint. The whole `/v1/api/ai` family is agency-only: a client collaborator is refused every operation in it, on every project. |
| `404` | ApiError | No such media job in this workspace. |

## Record a review verdict on a generated video

`POST /v1/api/ai/media/video/{id}/review` · operation ID `reviewAiVideoJob`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `id` | path | **yes** | string |  |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Request body** — `application/json`, `ReviewMediaJob` (required)

| Property | Type | Required | Notes |
| --- | --- | --- | --- |
| `state` | `approved` | `rejected` | `unreviewed` | **yes** |  |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | AiMediaJobRead | The job with its new review state. |
| `400` | ValidationError \| ApiError | The JSON body failed schema validation (`ValidationError`), or the request named no active organization (`ApiError`). |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError | Authenticated, but not an owner or admin of this workspace — or a client collaborator, for whom the whole family is closed. |
| `404` | ApiError | No such media job in this workspace. |

## Run an OpenAI-compatible chat completion on the workspace's own model budget

`POST /v1/api/ai/w/{workspaceId}/chat/completions` · operation ID `createHlixCodeChatCompletion`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `workspaceId` | path | **yes** | string |  |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Request body** — `application/json`, `ChatCompletions` (required)

| Property | Type | Required | Notes |
| --- | --- | --- | --- |
| `messages` | *not pinned*[] | **yes** |  |
| `model` | string | no | min length 1, max length 200 — An OpenRouter model id, or "default" for the model this workspace has chosen for its coder ("hlix/default" and omitting the field mean the same thing). GET ../models lists every id that may be sent, and names "default" as its own. |
| `stream` | boolean | no |  |
| `stream_options` | object | no |  |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | ChatCompletion | The provider's own completion, forwarded unchanged. A request with `stream: true` answers `text/event-stream` and the provider's SSE frames are passed through byte-for-byte, ending with a usage frame; anything else answers the JSON body. |
| `400` | ValidationError \| ApiError \| OpenAiError | The body failed validation, the request named no workspace, or the requested model is not one the deployment's governance allowlist names — the allowed models are listed in the message. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError \| OpenAiError | The credential is not a member of the workspace named in the path, or belongs to a client collaborator — this family is agency-only, and this endpoint spends the agency's own model budget. |
| `404` | ApiError | The resource does not exist, or the caller is a task-scoped credential and this endpoint is outside its allowlist. |
| `502` | OpenAiError | The workspace has no usable model credential, or the provider could not complete the request. The provider's own message is deliberately not forwarded; the status it answered is named instead. |

## List the models a Hlix Code session may run, and the workspace default

`GET /v1/api/ai/w/{workspaceId}/models` · operation ID `listHlixCodeModels`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `workspaceId` | path | **yes** | string |  |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | HlixCodeModels | The catalog's chat models, narrowed to the deployment's governance allowlist when one is configured, plus a `default` entry naming the model this workspace's coder uses. `default` is an id to SEND, not a model name — a client that stores it keeps following the workspace's own choice. |
| `400` | ApiError | The request named no active organization. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError \| OpenAiError | The credential is not a member of the workspace named in the path, or belongs to a client collaborator — this family is agency-only. |
| `404` | ApiError | The resource does not exist, or the caller is a task-scoped credential and this endpoint is outside its allowlist. |

## Run an OpenAI Responses request on the workspace's own model budget

`POST /v1/api/ai/w/{workspaceId}/responses` · operation ID `createHlixCodeResponse`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `workspaceId` | path | **yes** | string |  |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Request body** — `application/json`, `Responses` (required)

| Property | Type | Required | Notes |
| --- | --- | --- | --- |
| `input` | string | *not pinned*[] | **yes** |  |
| `model` | string | no | min length 1, max length 200 — An OpenRouter model id, or "default" for the model this workspace has chosen for its coder ("hlix/default" and omitting the field mean the same thing). GET ../models lists every id that may be sent, and names "default" as its own. |
| `stream` | boolean | no |  |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | ResponsesResult | The provider's own response, forwarded unchanged. A request with `stream: true` answers `text/event-stream` and the provider's SSE events are passed through byte-for-byte, ending with `response.completed`; anything else answers the JSON body. |
| `400` | ValidationError \| ApiError \| OpenAiError | The body failed validation, the request named no workspace, or the requested model is not one the deployment's governance allowlist names — the allowed models are listed in the message. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError \| OpenAiError | The credential is not a member of the workspace named in the path, or belongs to a client collaborator — this family is agency-only, and this endpoint spends the agency's own model budget. |
| `404` | ApiError | The resource does not exist, or the caller is a task-scoped credential and this endpoint is outside its allowlist. |
| `502` | OpenAiError | The workspace has no usable model credential, or the provider could not complete the request. The provider's own message is deliberately not forwarded; the status it answered is named instead. |

## Run an Anthropic Messages request on the workspace's own model budget

`POST /v1/api/ai/w/{workspaceId}/v1/messages` · operation ID `createHlixCodeMessage`

**Parameters**

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| `workspaceId` | path | **yes** | string |  |
| `X-Organization-Id` | header | no | string | The workspace (organization) to act in. Omitted, the session's active organization is used. |

**Request body** — `application/json`, `AnthropicMessages` (required)

| Property | Type | Required | Notes |
| --- | --- | --- | --- |
| `messages` | *not pinned*[] | **yes** |  |
| `model` | string | no | min length 1, max length 200 — An OpenRouter model id, or "default" for the model this workspace has chosen for its coder ("hlix/default" and omitting the field mean the same thing). GET ../models lists every id that may be sent, and names "default" as its own. |
| `stream` | boolean | no |  |

**Responses**

| Status | Body | Description |
| --- | --- | --- |
| `200` | AnthropicMessage | The provider's own message, forwarded unchanged. A request with `stream: true` answers `text/event-stream` and the provider's SSE events are passed through byte-for-byte; anything else answers the JSON body. |
| `400` | ValidationError \| ApiError \| AnthropicError | The body failed validation, the request named no workspace, or the requested model is not one the deployment's governance allowlist names — the allowed models are listed in the message. |
| `401` | ApiError | No valid session or API key. |
| `403` | ApiError \| AnthropicError | The credential is not a member of the workspace named in the path, or belongs to a client collaborator — this family is agency-only, and this endpoint spends the agency's own model budget. |
| `404` | ApiError | The resource does not exist, or the caller is a task-scoped credential and this endpoint is outside its allowlist. |
| `502` | AnthropicError | The workspace has no usable model credential, or the provider could not complete the request. The provider's own message is deliberately not forwarded; the status it answered is named instead. |

## Reading the response tables

A `Body` cell reading ***not pinned*** means the contract declares a response body but does **not** describe its shape. That is the contract's own honest state, not a gap in this page — the operation returns JSON, and the published document says nothing about its fields.

Consequences worth knowing: a generated client types that body as `unknown`, and no field in it is a compatibility promise. Do not infer a shape from a sample response; treat those bodies as unstable until the contract pins them.

## If a request fails

These apply to every operation on this page.

- `400` — the body failed schema validation, or the request named no active organization. A `ValidationError` body carries the failing fields; an `ApiError` body carries only `error`.
- `401` — no valid session or API key.
- `403` — authenticated, but not a member of the named organization, or a client collaborator without the required access.
- `404` — no such resource **in this workspace**. Absent and not-visible are deliberately the same answer; do not infer cross-tenant existence from it.
- `409` — the expected revision or state is stale, or another operation currently owns the transition.
- `500` — the operation failed server-side. Retry only where an idempotency key makes that safe.

## Next steps

[API reference](/api/reference/)
  [API & OpenAPI](/api/openapi/)
  [TypeScript SDK](/sdk/typescript/)
  [CLI reference](/reference/cli/)