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

# Chat

> Create sessions, send messages, and manage chat history.

All chat endpoints are under the `/api/chat` prefix. Streaming responses use newline-delimited JSON (NDJSON) over `text/event-stream`.

***

## Create a chat session

```
POST /api/chat/create-chat-session
```

Creates a new chat session and returns its ID. You must create a session before sending messages to it, or pass `chat_session_info` inline in `send-chat-message` to create a session implicitly.

### Request body

<ParamField body="persona_id" type="integer" default="0">
  ID of the agent (persona) to use for this session. Defaults to `0` (the default Hadiq.io assistant).
</ParamField>

<ParamField body="description" type="string">
  Optional human-readable name for the session.
</ParamField>

<ParamField body="project_id" type="integer">
  Optional project ID to associate the session with.
</ParamField>

### Response

<ResponseField name="chat_session_id" type="string (UUID)">
  Unique identifier for the new session.
</ResponseField>

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://cloud.hadiq.io/api/chat/create-chat-session \
    -H "Authorization: Bearer hadiqk-..." \
    -H "Content-Type: application/json" \
    -d '{"persona_id": 0, "description": "Onboarding questions"}'
  ```

  ```python Python theme={null}
  import requests

  resp = requests.post(
      "https://cloud.hadiq.io/api/chat/create-chat-session",
      headers={"Authorization": "Bearer hadiqk-..."},
      json={"persona_id": 0, "description": "Onboarding questions"},
  )
  session_id = resp.json()["chat_session_id"]
  ```
</CodeGroup>

***

## Send a chat message

```
POST /api/chat/send-chat-message
```

Sends a message in a chat session. When `stream` is `true` (the default), the response is a streaming `text/event-stream` of NDJSON packets. When `stream` is `false`, the full response is returned as a single JSON object.

### Request body

<ParamField body="message" type="string" required>
  The user message to send.
</ParamField>

<ParamField body="chat_session_id" type="string (UUID)">
  ID of an existing session. Provide either `chat_session_id` or `chat_session_info`, not both.
</ParamField>

<ParamField body="chat_session_info" type="object">
  Create a session implicitly alongside the message. Provide either this or `chat_session_id`, not both.

  <Expandable title="chat_session_info fields">
    <ParamField body="persona_id" type="integer" default="0">
      Agent (persona) ID for the new session.
    </ParamField>

    <ParamField body="description" type="string">
      Human-readable name for the new session.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="stream" type="boolean" default="true">
  When `true`, returns a streaming `text/event-stream`. When `false`, returns a complete `ChatFullResponse` JSON object.
</ParamField>

<ParamField body="parent_message_id" type="integer" default="-1">
  Placement of the new message in the conversation tree. `-1` appends after the latest message. `null` regenerates from the root.
</ParamField>

<ParamField body="llm_override" type="object">
  Override the LLM model for this message.

  <Expandable title="llm_override fields">
    <ParamField body="model_name" type="string">
      Model identifier (e.g. `gpt-4o`).
    </ParamField>

    <ParamField body="model_provider" type="string">
      Provider name (e.g. `openai`).
    </ParamField>

    <ParamField body="temperature" type="number">
      Sampling temperature (0–2).
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="include_citations" type="boolean" default="true">
  When `false`, citation markers and `CitationInfo` packets are suppressed.
</ParamField>

<ParamField body="internal_search_filters" type="object">
  Optional filters to restrict which documents are searched.
</ParamField>

<ParamField body="file_descriptors" type="array">
  Uploaded files to attach to the message.
</ParamField>

<ParamField body="additional_context" type="string">
  Extra context injected into the LLM call but not stored in chat history.
</ParamField>

<ParamField body="deep_research" type="boolean" default="false">
  Enable deep research mode for more thorough retrieval.
</ParamField>

### Streaming response

Each event is a NDJSON line representing one packet in the response stream. Packet types include answer tokens, citations, search results, and tool call info.

### Non-streaming response (`stream: false`)

<ResponseField name="answer" type="string">
  The complete assistant answer.
</ResponseField>

<ResponseField name="chat_message_id" type="integer">
  ID of the created assistant message.
</ResponseField>

<ResponseField name="context_docs" type="object">
  Search results used to generate the answer.
</ResponseField>

<ResponseField name="citations" type="object">
  Map of citation number to document ID.
</ResponseField>

<CodeGroup>
  ```bash curl (streaming) theme={null}
  curl -X POST https://cloud.hadiq.io/api/chat/send-chat-message \
    -H "Authorization: Bearer hadiqk-..." \
    -H "Content-Type: application/json" \
    -d '{
      "chat_session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "message": "What is our PTO policy?",
      "stream": true
    }'
  ```

  ```bash curl (non-streaming) theme={null}
  curl -X POST https://cloud.hadiq.io/api/chat/send-chat-message \
    -H "Authorization: Bearer hadiqk-..." \
    -H "Content-Type: application/json" \
    -d '{
      "chat_session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "message": "What is our PTO policy?",
      "stream": false
    }'
  ```

  ```python Python (streaming) theme={null}
  import requests
  import json

  resp = requests.post(
      "https://cloud.hadiq.io/api/chat/send-chat-message",
      headers={"Authorization": "Bearer hadiqk-..."},
      json={
          "chat_session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
          "message": "What is our PTO policy?",
          "stream": True,
      },
      stream=True,
  )
  for line in resp.iter_lines():
      if line:
          print(json.loads(line))
  ```

  ```python Python (non-streaming) theme={null}
  import requests

  resp = requests.post(
      "https://cloud.hadiq.io/api/chat/send-chat-message",
      headers={"Authorization": "Bearer hadiqk-..."},
      json={
          "chat_session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
          "message": "What is our PTO policy?",
          "stream": False,
      },
  )
  data = resp.json()
  print(data["answer"])
  ```
</CodeGroup>

<Note>
  The correct path is `/api/chat/send-chat-message` (note: `send-chat-message`, not `send-message`).
</Note>

***

## Get a chat session

```
GET /api/chat/get-chat-session/{session_id}
```

Returns the full history of a session including all messages.

### Path parameters

<ParamField path="session_id" type="string (UUID)" required>
  The session to retrieve.
</ParamField>

### Query parameters

<ParamField query="is_shared" type="boolean" default="false">
  Set to `true` to retrieve a publicly shared session without authentication.
</ParamField>

<ParamField query="include_deleted" type="boolean" default="false">
  Include sessions that have been soft-deleted.
</ParamField>

### Response

<ResponseField name="chat_session_id" type="string (UUID)">
  Session identifier.
</ResponseField>

<ResponseField name="description" type="string">
  Session name or description.
</ResponseField>

<ResponseField name="persona_id" type="integer">
  Agent associated with this session.
</ResponseField>

<ResponseField name="persona_name" type="string">
  Display name of the agent.
</ResponseField>

<ResponseField name="messages" type="array">
  Ordered list of messages in the session.

  <Expandable title="message fields">
    <ResponseField name="message_id" type="integer">
      Unique message identifier.
    </ResponseField>

    <ResponseField name="message" type="string">
      Text content of the message.
    </ResponseField>

    <ResponseField name="message_type" type="string">
      Either `user` or `assistant`.
    </ResponseField>

    <ResponseField name="time_sent" type="string (ISO 8601)">
      When the message was sent.
    </ResponseField>

    <ResponseField name="citations" type="object">
      Map of citation number to document ID, if applicable.
    </ResponseField>

    <ResponseField name="context_docs" type="array">
      Search documents used for this message, if applicable.
    </ResponseField>

    <ResponseField name="files" type="array">
      Files attached to the message.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="time_created" type="string (ISO 8601)">
  When the session was created.
</ResponseField>

<ResponseField name="shared_status" type="string">
  Sharing state: `private` or `public`.
</ResponseField>

<CodeGroup>
  ```bash curl theme={null}
  curl https://cloud.hadiq.io/api/chat/get-chat-session/3fa85f64-5717-4562-b3fc-2c963f66afa6 \
    -H "Authorization: Bearer hadiqk-..."
  ```

  ```python Python theme={null}
  import requests

  session_id = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  resp = requests.get(
      f"https://cloud.hadiq.io/api/chat/get-chat-session/{session_id}",
      headers={"Authorization": "Bearer hadiqk-..."},
  )
  session = resp.json()
  for msg in session["messages"]:
      print(msg["message_type"], ":", msg["message"])
  ```
</CodeGroup>

***

## List chat sessions

```
GET /api/chat/get-user-chat-sessions
```

Returns a paginated list of the authenticated user's chat sessions.

### Query parameters

<ParamField query="page_size" type="integer" default="50">
  Number of sessions per page. Minimum `1`, maximum `100`.
</ParamField>

<ParamField query="before" type="string (ISO 8601)">
  Cursor for pagination. Pass the `time_created` of the last session from the previous page to fetch older sessions.
</ParamField>

<ParamField query="project_id" type="integer">
  Filter by a specific project.
</ParamField>

<ParamField query="only_non_project_chats" type="boolean" default="true">
  When `true`, excludes sessions that belong to a project.
</ParamField>

<ParamField query="include_failed_chats" type="boolean" default="false">
  Include sessions that ended in an error state.
</ParamField>

### Response

<ResponseField name="sessions" type="array">
  List of session summaries.

  <Expandable title="session fields">
    <ResponseField name="id" type="string (UUID)">
      Session identifier.
    </ResponseField>

    <ResponseField name="name" type="string">
      Session name or description.
    </ResponseField>

    <ResponseField name="persona_id" type="integer">
      Agent used in the session.
    </ResponseField>

    <ResponseField name="time_created" type="string (ISO 8601)">
      Creation timestamp.
    </ResponseField>

    <ResponseField name="time_updated" type="string (ISO 8601)">
      Last update timestamp.
    </ResponseField>

    <ResponseField name="shared_status" type="string">
      Sharing state: `private` or `public`.
    </ResponseField>

    <ResponseField name="current_alternate_model" type="string">
      Override LLM model in use for this session, if any.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="has_more" type="boolean">
  Whether more sessions are available. Use the `time_created` of the last session as `before` for the next page.
</ResponseField>

<CodeGroup>
  ```bash curl theme={null}
  curl "https://cloud.hadiq.io/api/chat/get-user-chat-sessions?page_size=20" \
    -H "Authorization: Bearer hadiqk-..."
  ```

  ```python Python theme={null}
  import requests

  resp = requests.get(
      "https://cloud.hadiq.io/api/chat/get-user-chat-sessions",
      headers={"Authorization": "Bearer hadiqk-..."},
      params={"page_size": 20},
  )
  data = resp.json()
  for session in data["sessions"]:
      print(session["id"], session["name"])

  if data["has_more"]:
      oldest = data["sessions"][-1]["time_created"]
      # fetch next page with before=oldest
  ```
</CodeGroup>

***

## Delete a chat session

```
DELETE /api/chat/delete-chat-session/{session_id}
```

Deletes a chat session. By default, performs a soft delete (recoverable). Pass `hard_delete=true` to permanently remove the session.

### Path parameters

<ParamField path="session_id" type="string (UUID)" required>
  The session to delete.
</ParamField>

### Query parameters

<ParamField query="hard_delete" type="boolean">
  When `true`, permanently deletes the session and all its messages. When omitted, the default behavior is controlled by your instance's deletion policy.
</ParamField>

Returns `204 No Content` on success.

<CodeGroup>
  ```bash curl theme={null}
  curl -X DELETE \
    "https://cloud.hadiq.io/api/chat/delete-chat-session/3fa85f64-5717-4562-b3fc-2c963f66afa6" \
    -H "Authorization: Bearer hadiqk-..."
  ```

  ```python Python theme={null}
  import requests

  session_id = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  requests.delete(
      f"https://cloud.hadiq.io/api/chat/delete-chat-session/{session_id}",
      headers={"Authorization": "Bearer hadiqk-..."},
  )
  ```
</CodeGroup>

***

## Stop a running chat session

```
POST /api/chat/stop-chat-session/{chat_session_id}
```

Signals the server to stop generating a response for a streaming session (equivalent to clicking "Stop" in the UI).

### Path parameters

<ParamField path="chat_session_id" type="string (UUID)" required>
  The session whose generation to stop.
</ParamField>

Returns `{"message": "Chat session stopped"}`.

***

## Error codes

| Status | Cause                                                                         |
| ------ | ----------------------------------------------------------------------------- |
| `400`  | Invalid input, e.g. providing both `chat_session_id` and `chat_session_info`. |
| `403`  | Session belongs to another user, or session is not publicly shared.           |
| `404`  | Session not found or has been deleted.                                        |
| `422`  | Malformed `before` timestamp.                                                 |
| `429`  | Token or API rate limit exceeded.                                             |
