> ## Documentation Index
> Fetch the complete documentation index at: https://blackbox.dasha.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Submit one user turn to an existing chat session.

> Drives the agent through one LLM round-trip and returns only the new assistant turn(s)
(tool turns first, final reply last). The full transcript stays on the server. Supply
`idempotency_key` to make the submit safely retryable — a repeated request with the
same key (even after the original response finalised the session) replays the previous
assistant turn without re-running the LLM.

## Idempotency

Network retries (especially over SMS) can re-submit the same logical turn twice. Always send an
`idempotency_key` (any client-chosen unique value, e.g. UUID or `sessionId+turnNumber`) so the
server can dedupe. The retry returns the prior assistant response — including when the original
turn finalised the session.


## OpenAPI

````yaml https://blackbox.dasha.ai/swagger/v1/swagger.json post /api/v1/chats/{id}/messages
openapi: 3.0.4
info:
  title: Dasha BlackBox Agent API
  description: API for managing AI agents and calls
  contact:
    name: DashaAI Team
    email: support@dasha.ai
  version: v1
servers:
  - url: https://blackbox.dasha.ai
    description: Dasha BlackBox Agent API
security:
  - ApiKey: []
  - OAuth: []
tags:
  - name: ActivityLogs
  - name: Agents
  - name: AgentTestCases
  - name: CallResults
  - name: Calls
  - name: Chats
  - name: Copilot
  - name: CustomerData
  - name: Mcp
  - name: Media
  - name: Misc
  - name: PronunciationDictionaries
  - name: Providers
  - name: SipAliases
  - name: SipCredentials
  - name: SipPhoneNumbers
  - name: TextChat
  - name: TwilioProvider
  - name: Voice
  - name: WebhookTest
  - name: WebIntegrations
  - name: WebSocket
    description: WebSocket endpoints for real-time communication
paths:
  /api/v1/chats/{id}/messages:
    post:
      tags:
        - Chats
      summary: Submit one user turn to an existing chat session.
      description: >-
        Drives the agent through one LLM round-trip and returns only the new
        assistant turn(s)

        (tool turns first, final reply last). The full transcript stays on the
        server. Supply

        `idempotency_key` to make the submit safely retryable — a repeated
        request with the

        same key (even after the original response finalised the session)
        replays the previous

        assistant turn without re-running the LLM.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SubmitChatTurnRequest'
              description: >-
                Request body for `POST /api/v1/chats/{id}/messages` — submits a
                single user turn to

                the named session. The response contains only the assistant
                turn(s) produced this round,

                not the full transcript (the transcript lives on the server and
                is retrievable via

                `GET /api/v1/chats/{id}`).
          text/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SubmitChatTurnRequest'
              description: >-
                Request body for `POST /api/v1/chats/{id}/messages` — submits a
                single user turn to

                the named session. The response contains only the assistant
                turn(s) produced this round,

                not the full transcript (the transcript lives on the server and
                is retrievable via

                `GET /api/v1/chats/{id}`).
          application/*+json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SubmitChatTurnRequest'
              description: >-
                Request body for `POST /api/v1/chats/{id}/messages` — submits a
                single user turn to

                the named session. The response contains only the assistant
                turn(s) produced this round,

                not the full transcript (the transcript lives on the server and
                is retrievable via

                `GET /api/v1/chats/{id}`).
      responses:
        '200':
          description: >-
            Submit succeeded. Inspect `is_final` to decide whether to keep
            submitting.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubmitChatTurnResponse'
        '400':
          description: >-
            Request failed validation (empty content, oversize idempotency key,
            …).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
        '404':
          description: No session with this id exists for the caller's organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
        '409':
          description: The session has already finalised. Open a new one to keep talking.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
components:
  schemas:
    SubmitChatTurnRequest:
      type: object
      properties:
        content:
          type: string
          description: User-supplied message content for this turn.
          nullable: true
        idempotency_key:
          type: string
          description: >-
            Optional idempotency key. When supplied, a retried submit with the
            same key returns

            the previous assistant response without re-running the LLM. Bound to
            the session, not

            global. Capped at 128 characters.
          nullable: true
        additional_data:
          type: object
          additionalProperties: {}
          description: >-
            Turn-level `additional_data` overrides merged on top of the
            session's persisted

            bag. Reserved keys
            (DashaAI.BlackBox.AgentAPI.TextChat.ChatReservedKeys) are dropped
            before merge.
          nullable: true
      additionalProperties: false
      description: >-
        Request body for `POST /api/v1/chats/{id}/messages` — submits a single
        user turn to

        the named session. The response contains only the assistant turn(s)
        produced this round,

        not the full transcript (the transcript lives on the server and is
        retrievable via

        `GET /api/v1/chats/{id}`).
    SubmitChatTurnResponse:
      type: object
      properties:
        messages:
          type: array
          items:
            $ref: '#/components/schemas/ChatMessageDto'
          description: >-
            New messages produced this turn. Ordered: assistant tool-turns first
            (each bundling

            its tool calls with their executed responses), final plain-text
            assistant reply last.
          nullable: true
        is_final:
          type: boolean
          description: >-
            True when the agent signalled end-of-conversation this turn (e.g.
            invoked the

            `finishTheConversation` built-in tool) and the session has been
            finalised. After

            this point, further submits return 409 Conflict.
        status:
          type: string
          description: >-
            Post-turn session status: `active` while accepting new turns,
            `final` after

            finalisation (matches the `state` filter on the list endpoint).
          nullable: true
      additionalProperties: false
      description: >-
        Response to `POST /api/v1/chats/{id}/messages`. Returns only the new
        assistant turn(s)

        produced this round (per the plan's "returns only the new assistant
        turn(s)" requirement),

        plus the post-turn session status so clients don't need a follow-up GET
        to learn whether

        the agent finished the conversation.
    ProblemDetails:
      type: object
      properties:
        type:
          type: string
          nullable: true
        title:
          type: string
          nullable: true
        status:
          type: integer
          format: int32
          nullable: true
        detail:
          type: string
          nullable: true
        instance:
          type: string
          nullable: true
      additionalProperties: {}
    ChatMessageDto:
      type: object
      properties:
        role:
          type: string
          description: One of "user", "assistant", "system".
          nullable: true
        content:
          type: string
          description: >-
            Plain-text message content. Null when the assistant message only
            contains tool calls.
          nullable: true
        tool_calls:
          type: array
          items:
            $ref: '#/components/schemas/ChatToolCallDto'
          description: >-
            Tool calls produced by the assistant this turn, bundled with their
            responses.
          nullable: true
        time:
          type: string
          description: >-
            Real wall-clock time of the message. The server stamps the messages
            it produces and

            echoes back any client-supplied value; it is used verbatim for the
            call transcript /

            post-call analysis instead of a synthesized clock. One timestamp per
            chat message is

            enough — chat messages are point-in-time events, unlike voice
            utterances. Optional.
          format: date-time
          nullable: true
      additionalProperties: false
      description: >-
        Wire-format text-chat message. Supports user / assistant / system roles.

        Tool invocations are bundled — a single assistant message carries the
        tool call(s)

        alongside their executed response(s) via
        DashaAI.BlackBox.AgentAPI.TextChat.Dtos.ChatMessageDto.ToolCalls.
    ChatToolCallDto:
      type: object
      properties:
        id:
          type: string
          description: >-
            Tool call identifier propagated through the OpenAI round-trip.
            Required.
          nullable: true
        name:
          type: string
          description: >-
            Tool name as registered with the agent (built-in, agent-defined
            function, or MCP).
          nullable: true
        arguments:
          description: >-
            Tool arguments emitted by the LLM, as a JSON object. May be omitted
            for tools with no parameters.
        response:
          description: >-
            Tool response. Set after the server executes the tool. Null while
            the request is still in flight

            (only happens internally — wire-format messages from the client
            always include the response).
          nullable: true
      additionalProperties: false
      description: >-
        Combined tool call: the LLM-generated request and the executed response
        in a single object.

        Wire-format choice — internally the orchestrator translates to OpenAI's
        split assistant/tool format.
  securitySchemes:
    ApiKey:
      type: http
      description: API Key Authentication (Bearer {key})
      scheme: Bearer
    OAuth:
      type: oauth2
      flows:
        implicit:
          authorizationUrl: https://auth.dasha.ai/connect/authorize
          scopes:
            platform_api: Platform API

````