---
title: "Chat"
method: POST
path: "/v1/conversations/{conversation_id}/chat"
tags: ["V1 - Conversations"]
---

# Chat

`POST /v1/conversations/{conversation_id}/chat`

## Request

- Base URL: `https://api.app.noxus.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.app.noxus.ai/v1/conversations/{conversation_id}/chat`
- Auth: API key in header `X-API-Key`

## Path parameters

- `conversation_id` string, uuid, required

## Query parameters

- `assistant_id` string, uuid, nullable

## Request body

- AddMessageRequest
  - `content` string, nullable, required
  - `tool` union
    - 'web_research' | 'kb_qa'
    - string
  - `kb_id` string, nullable
  - `files` ConversationFile[], nullable
    - `id` string, uuid, nullable, required
    - `name` string, required
    - `size` integer, nullable, required
    - `type` string, nullable, required
    - `status` 'pending' | 'success' | 'error', required
    - `url` string, nullable, required
    - `b64_content` string, nullable
  - `model_selection` string[], nullable

## Response `200`

Successful Response

- ChatMessage
  - `id` string, uuid, required
  - `parts` union[], required
    - union
      - ModelRequest: A request generated by Pydantic AI and sent to a model, e.g. a message from the Pydantic AI app to the model.
        - `parts` union[], required
          - union
            - SystemPromptPart: A system prompt, generally written by the application developer. This gives the model context and guidance on how to respond.
              - …
            - UserPromptPart: A user prompt, generally written by the end user. Content comes from the `user_prompt` parameter of [`Agent.run`][pydantic_ai.agent.AbstractAgent.run], [`Agent.run_sync`][pydantic_ai.agent.AbstractAgent.run_sync], and [`Agent.run_stream`][pydantic_ai.agent.AbstractAgent.run_stream].
              - …
            - SpeechPart: Spoken audio exchanged during a realtime session, paired with its transcript. This part is a member of both [`ModelRequestPart`][pydantic_ai.messages.ModelRequestPart] and [`ModelResponsePart`][pydantic_ai.messages.ModelResponsePart], distinguished by `speaker`: in `ModelRequest.parts` the speaker is always `'user'`; in `ModelResponse.parts` it is always `'assistant'`. This invariant is enforced at runtime when a message is constructed. Standard (non-realtime) models can't consume this part directly; when history containing it is used in an agent run, [`Model.prepare_messages`][pydantic_ai.models.Model.prepare_messages] converts user-speaker parts to [`UserPromptPart`][pydantic_ai.messages.UserPromptPart]s and assistant-speaker parts to [`TextPart`][pydantic_ai.messages.TextPart]s.
              - …
            - ToolSearchReturnPart: Typed view of a [`ToolReturnPart`][pydantic_ai.messages.ToolReturnPart] for the local `search_tools` function return. Used on the local-fallback path (and as the synthetic-injection target on non-native providers receiving cross-provider history). The native server-side path uses [`NativeToolSearchReturnPart`][pydantic_ai.messages.NativeToolSearchReturnPart] instead. To detect a tool-search part regardless of execution path (native server-side vs. local fallback), check `part.tool_kind == 'tool-search'` — this works across both call/return and both server/local variants. Shadows `content` with a narrower [`ToolSearchReturnContent`][pydantic_ai.messages.ToolSearchReturnContent] `TypedDict`.
              - …
            - LoadCapabilityReturnPart: Typed `ToolReturnPart` for the `load_capability` tool.
              - …
            - ToolReturnPart: A tool return message, this encodes the result of running a tool.
              - …
            - RetryPromptPart: A message back to a model asking it to try again. This can be sent for a number of reasons: * Pydantic validation of tool arguments failed, here content is derived from a Pydantic [`ValidationError`][pydantic_core.ValidationError] * a tool raised a [`ModelRetry`][pydantic_ai.exceptions.ModelRetry] exception * no tool was found for the tool name * the model returned plain text when a structured response was expected * Pydantic validation of a structured response failed, here content is derived from a Pydantic [`ValidationError`][pydantic_core.ValidationError] * an output validator raised a [`ModelRetry`][pydantic_ai.exceptions.ModelRetry] exception
              - …
            - ToolAvailabilityDeltaPart: Records that the set of tools available to the model changed at this point. Additions only. Withdrawing a tool is not supported yet, because no provider can be told about one without also invalidating the prompt cache this part exists to protect: Anthropic rejects a reference to a tool the request doesn't declare, so a withdrawn tool has to leave the `tools` array, and that is itself the invalidation. The name says *availability* rather than *addition* so removals can join once they can be done cache-safely — see https://github.com/pydantic/pydantic-ai/issues/6985.
              - …
        - `timestamp` string, date-time, nullable
        - `instructions` string, nullable
        - `kind` 'request'
        - `run_id` string, nullable
        - `conversation_id` string, nullable
        - `metadata` object, nullable
        - `state` 'complete' | 'interrupted'
      - ModelResponse: A response from a model, e.g. a message from the model to the Pydantic AI app.
        - `parts` union[], required
          - union
            - TextPart: A plain text response from a model.
              - …
            - ToolSearchCallPart: Typed view of a [`ToolCallPart`][pydantic_ai.messages.ToolCallPart] for the local `search_tools` function call. Used on the local-fallback path (and as the synthetic-injection target on non-native providers receiving cross-provider history). The native server-side path uses [`NativeToolSearchCallPart`][pydantic_ai.messages.NativeToolSearchCallPart] instead. To detect a tool-search part regardless of execution path (native server-side vs. local fallback), check `part.tool_kind == 'tool-search'` — this works across both call/return and both server/local variants. Shadows `args` with the canonical typed shape. The `str` variant covers the streaming / partial-args case before parsing completes; once parsed, `args` is a [`ToolSearchArgs`][pydantic_ai.messages.ToolSearchArgs] `TypedDict`.
              - …
            - LoadCapabilityCallPart: Typed `ToolCallPart` for the `load_capability` tool.
              - …
            - ToolCallPart: A tool call from a model.
              - …
            - NativeToolSearchCallPart: Typed view of a [`NativeToolCallPart`][pydantic_ai.messages.NativeToolCallPart] for tool search. Used on the native server-side tool-search path (Anthropic BM25/regex, OpenAI Responses) where the provider executes the search and emits a native result. The local-fallback path uses [`ToolSearchCallPart`][pydantic_ai.messages.ToolSearchCallPart] instead. To detect a tool-search part regardless of execution path (native server-side vs. local fallback), check `part.tool_kind == 'tool-search'` — this works across both call/return and both server/local variants. Shadows `args` with a narrower type. The `str` variant covers the streaming / partial-args case before parsing completes; once parsed, `args` is a [`ToolSearchArgs`][pydantic_ai.messages.ToolSearchArgs] `TypedDict`.
              - …
            - NativeToolCallPart: A tool call to a native tool. For native tools with a stable cross-provider shape (currently `tool_search`), this base class can be promoted to a typed subclass with a narrowed `args` `TypedDict`. See [`NativeToolSearchCallPart`][pydantic_ai.messages.NativeToolSearchCallPart] for the canonical example. Adding a typed subclass for a future native tool (see `pydantic_ai._tool_search` for a worked example): 1. Add a sibling `pydantic_ai/_<name>.py` module that defines the cross-provider `TypedDict`s, the `NativeToolCallPart` / `NativeToolReturnPart` subclasses, and registers their narrowers into `_NATIVE_CALL_NARROWERS` / `_NATIVE_RETURN_NARROWERS` keyed by `tool_kind`. Subclass overrides `tool_kind: Literal['<emitter>']` to match the emitting [`AbstractNativeTool.kind`][pydantic_ai.native_tools.AbstractNativeTool.kind], and shadows `args` / `content` with a narrower type. 2. Late-import the new module from this file (alongside the existing tool-search import) so registration runs whenever `pydantic_ai.messages` is imported. 3. Add the subclass to `ModelResponsePart`'s discriminated union and to `_model_response_part_discriminator` so Pydantic deserialization auto-promotes on `model_validate` / `model_validate_json`. Dispatch is by `tool_kind`, not `tool_name`. This protects users whose tools happen to share a name with one of ours from accidentally getting their parts promoted (and failing shape validation against the typed `args`/`content`). The `provider_details` field carries genuinely non-portable provider extras (e.g. Anthropic's `strategy: 'bm25' | 'regex'` for tool search). Promote a field to a typed slot in `args` / `content` only when at least two of OpenAI, Anthropic, and Google support it (cf. [issue #3885](https://github.com/pydantic/pydantic-ai/issues/3885)). MCP server tools land here with `tool_kind='mcp_server'` (label stays in `tool_name='mcp_server:<label>'`); typed-subclass work for MCP is tracked by [issue #3561](https://github.com/pydantic/pydantic-ai/issues/3561).
              - …
            - NativeToolSearchReturnPart: Typed view of a [`NativeToolReturnPart`][pydantic_ai.messages.NativeToolReturnPart] for tool search. Used on the native server-side tool-search path (Anthropic BM25/regex, OpenAI Responses) where the provider executes the search and emits a native result. The local-fallback path uses [`ToolSearchReturnPart`][pydantic_ai.messages.ToolSearchReturnPart] instead. To detect a tool-search part regardless of execution path (native server-side vs. local fallback), check `part.tool_kind == 'tool-search'` — this works across both call/return and both server/local variants. Shadows `content` with a narrower [`ToolSearchReturnContent`][pydantic_ai.messages.ToolSearchReturnContent] `TypedDict`.
              - …
            - NativeToolReturnPart: A tool return message from a native tool. For native tools with a stable cross-provider shape (currently `tool_search`), a `NativeToolReturnPart` may be promoted to a typed subclass like [`NativeToolSearchReturnPart`][pydantic_ai.messages.NativeToolSearchReturnPart] with a narrowed `content` `TypedDict`. See `NativeToolCallPart` for the pattern.
              - …
            - ThinkingPart: A thinking response from a model.
              - …
            - CompactionPart: A compaction part that summarizes previous conversation history. Compaction parts contain an opaque or readable summary of prior messages, produced by provider-specific compaction mechanisms. They must be round-tripped back to the same provider in subsequent requests. For Anthropic, `content` contains a readable text summary. For OpenAI, `content` is `None` and the encrypted data is stored in `provider_details`.
              - …
            - FilePart: A file response from a model.
              - …
            - SpeechPart: Spoken audio exchanged during a realtime session, paired with its transcript. This part is a member of both [`ModelRequestPart`][pydantic_ai.messages.ModelRequestPart] and [`ModelResponsePart`][pydantic_ai.messages.ModelResponsePart], distinguished by `speaker`: in `ModelRequest.parts` the speaker is always `'user'`; in `ModelResponse.parts` it is always `'assistant'`. This invariant is enforced at runtime when a message is constructed. Standard (non-realtime) models can't consume this part directly; when history containing it is used in an agent run, [`Model.prepare_messages`][pydantic_ai.models.Model.prepare_messages] converts user-speaker parts to [`UserPromptPart`][pydantic_ai.messages.UserPromptPart]s and assistant-speaker parts to [`TextPart`][pydantic_ai.messages.TextPart]s.
              - …
        - `usage` RequestUsage: LLM usage associated with a single request. This is an implementation of `genai_prices.types.AbstractUsage` so it can be used to calculate the price of the request using [genai-prices](https://github.com/pydantic/genai-prices).
          - `input_tokens` integer
          - `cache_write_tokens` integer
          - `cache_read_tokens` integer
          - `output_tokens` integer
          - `input_audio_tokens` integer
          - `cache_audio_read_tokens` integer
          - `output_audio_tokens` integer
          - `audio_seconds` number
          - `details` object
          - `cost` string, nullable
        - `model_name` string, nullable
        - `timestamp` string, date-time
        - `kind` 'response'
        - `provider_name` string, nullable
        - `provider_url` string, nullable
        - `provider_details` object, nullable
        - `provider_response_id` string, nullable
        - `finish_reason` 'stop' | 'length' | 'content_filter' | 'tool_call' | 'error', nullable
        - `run_id` string, nullable
        - `conversation_id` string, nullable
        - `metadata` object, nullable
        - `workspace_ref` WorkspaceRef: Serializable identity of a [workspace](../workspace.md) environment, without credentials. Pass it to a later run as `workspace=` to continue in that environment.
          - `provider` string, required
          - `id` string, required
        - `state` 'complete' | 'incomplete' | 'suspended' | 'interrupted'

## Other responses

- `422`: Validation Error
- `502`: Conversation job failed or returned no assistant content.
- `504`: Conversation job did not finish before the synchronous wait timed out.

---

[API](https://skmtc.dev/noxus/apis/noxus-backend.md) - [All operations](https://skmtc.dev/noxus/apis/noxus-backend/llms.txt) - [OpenAPI document](https://skmtc.dev/noxus/apis/noxus-backend/revisions/0e37810b7ad5?raw)
