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

# List the messages in a widget thread

> Read the questions and answers in one widget thread, oldest first, for instance to restore the panel after a reload. Needs the widget key and visitor token.

Call this from the visitor's browser, for example to restore a thread after a page reload. It takes the embed's **public widget key** in `X-ARUKZ-Widget-Key`, and the browser's `Origin` must be allowed by both the deployment's `allowed_origins` and the platform-wide widget allowlist. See [Website widget](/channels/widget).

You must also send the thread's `X-ARUKZ-Visitor-Token`. The token is checked before any message is read. A missing token, another thread's token and an unknown conversation all return the same `404`.

Messages come oldest first. Page through them with `cursor`; see [Pagination](/api-reference/pagination). Render an assistant message as a finished answer only when its `status` is `complete`. An answer with `abstained: true` is a successful response in which the assistant said it could not find the answer in its knowledge; see [How answers work](/concepts/how-answers-work).

When a request is refused, the response carries no `Access-Control-Allow-Origin` header, so in a cross-origin browser request `fetch` rejects with a network error instead of exposing the error body.

<ParamField path="conversation_id" type="string" required>
  The conversation's ID (UUID).
</ParamField>

<ParamField header="X-ARUKZ-Widget-Key" type="string" required>
  The deployment's public widget key, `arukz_wk_…`.
</ParamField>

<ParamField header="X-ARUKZ-Visitor-Token" type="string" required>
  The visitor token returned when this thread was started.
</ParamField>

<ParamField header="Origin" type="string" required>
  Set by the browser. It must exactly match an origin allowed for this deployment. When you call
  from outside a browser, set it yourself.
</ParamField>

<ParamField query="limit" type="integer" default="50">
  How many messages to return, from 1 to 100.
</ParamField>

<ParamField query="cursor" type="string">
  The `next_cursor` from the previous page. Omit it for the first page.
</ParamField>

## Response

<ResponseField name="data" type="object[]" required>
  The messages, oldest first.

  <Expandable title="properties">
    <ResponseField name="id" type="string" required>
      The message's ID (UUID).
    </ResponseField>

    <ResponseField name="conversation_id" type="string" required>
      The conversation it belongs to.
    </ResponseField>

    <ResponseField name="role" type="string" required>
      `user` for a visitor's question, `assistant` for an answer.
    </ResponseField>

    <ResponseField name="sequence" type="integer" required>
      Position in the conversation.
    </ResponseField>

    <ResponseField name="status" type="string" required>
      `complete`, `pending` (still being generated), `interrupted` (stopped part way) or `failed`. A
      question is always `complete`.
    </ResponseField>

    <ResponseField name="text" type="string" required>
      The message text.
    </ResponseField>

    <ResponseField name="citations" type="object[]" required>
      Sources the answer is grounded in. Empty for a question and for an abstention.

      <Expandable title="properties">
        <ResponseField name="source_id" type="string">
          Identifier of the cited passage. It stays the same while the document's content is
          unchanged and changes when changed content is re-ingested. It is not a knowledge source ID
          or a document ID.
        </ResponseField>

        <ResponseField name="ordinal" type="integer">
          The citation's number, matching the `[n]` marker in `text`.
        </ResponseField>

        <ResponseField name="title" type="string">
          Document title. May be an empty string.
        </ResponseField>

        <ResponseField name="url" type="string | null">
          Link to the source.
        </ResponseField>

        <ResponseField name="snippet" type="string | null">
          The passage the answer relied on.
        </ResponseField>

        <ResponseField name="anchor" type="string | null">
          Section anchor within the source.
        </ResponseField>

        <ResponseField name="score" type="number | null">
          Retrieval relevance score.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="abstained" type="boolean" required>
      `true` when the assistant declined to answer because its knowledge did not contain the answer.
    </ResponseField>

    <ResponseField name="created_at" type="string" required>
      ISO 8601 in UTC.
    </ResponseField>

    <ResponseField name="model" type="string | null" required>
      The model that produced an answer. `null` for a question.
    </ResponseField>

    <ResponseField name="finish_reason" type="string | null" required>
      Why generation ended. `null` for a question.
    </ResponseField>

    <ResponseField name="idempotency_key" type="string | null" required>
      The idempotency key sent with the question, if any.
    </ResponseField>

    <ResponseField name="metadata" type="object" required>
      Metadata sent with the question.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="next_cursor" type="string | null" required>
  Pass as `cursor` to get the next page, or `null` on the last page.
</ResponseField>

<ResponseField name="has_more" type="boolean" required>
  Whether another page exists.
</ResponseField>

<RequestExample>
  ```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  // Runs on your website.
  const MITHUNAI_API = `${MITHUNAI_URL}/arukz/api/v1`
  const WIDGET_KEY = 'arukz_wk_8d0f5a2e-3c41-4b7a-9e6d-1f2a3b4c5d6e'
  const conversationId = sessionStorage.getItem('mithunai.conversation')

  const response = await fetch(
    `${MITHUNAI_API}/widget/conversations/${conversationId}/messages?limit=50`,
    {
      headers: {
        'X-ARUKZ-Widget-Key': WIDGET_KEY,
        'X-ARUKZ-Visitor-Token': sessionStorage.getItem('mithunai.visitorToken'),
      },
    },
  )
  const { data } = await response.json()
  for (const message of data) console.log(message.role, message.text)
  ```

  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl --request GET "$MITHUNAI_URL/arukz/api/v1/widget/conversations/0e6a9b52-7d3f-4c18-a2e5-9b8c7d6e5f4a/messages?limit=50" \
    --header "X-ARUKZ-Widget-Key: arukz_wk_8d0f5a2e-3c41-4b7a-9e6d-1f2a3b4c5d6e" \
    --header "X-ARUKZ-Visitor-Token: $VISITOR_TOKEN" \
    --header "Origin: https://docs.example.com"
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={"theme":{"light":"github-light","dark":"github-dark"}}
  {
    "data": [
      {
        "id": "4a1b2c3d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
        "conversation_id": "0e6a9b52-7d3f-4c18-a2e5-9b8c7d6e5f4a",
        "role": "user",
        "sequence": 1,
        "status": "complete",
        "text": "How do I raise my rate limit?",
        "citations": [],
        "abstained": false,
        "created_at": "2026-09-24T10:02:21.004118+00:00",
        "model": null,
        "finish_reason": null,
        "idempotency_key": "q-7f3c1e",
        "metadata": {}
      },
      {
        "id": "9f8e7d6c-5b4a-4c3d-9e2f-1a0b9c8d7e6f",
        "conversation_id": "0e6a9b52-7d3f-4c18-a2e5-9b8c7d6e5f4a",
        "role": "assistant",
        "sequence": 2,
        "status": "complete",
        "text": "Rate limits are set per plan. To request a higher limit, open a support ticket from the billing page and include your expected peak requests per minute [1].",
        "citations": [
          {
            "source_id": "6e1d3c5b-9a7f-4b2e-8d0c-3f5a7b9d1e2f",
            "ordinal": 1,
            "title": "Rate limits",
            "url": "https://docs.example.com/guides/rate-limits",
            "snippet": "To request a higher limit, open a support ticket from the billing page.",
            "anchor": "requesting-a-higher-limit",
            "score": 0.82
          }
        ],
        "abstained": false,
        "created_at": "2026-09-24T10:02:21.004118+00:00",
        "model": "anthropic/claude-sonnet-5",
        "finish_reason": "stop",
        "idempotency_key": null,
        "metadata": {}
      }
    ],
    "next_cursor": null,
    "has_more": false
  }
  ```

  ```json 400 theme={"theme":{"light":"github-light","dark":"github-dark"}}
  { "code": "validation_error", "message": "'limit' must be between 1 and 100." }
  ```

  ```json 401 theme={"theme":{"light":"github-light","dark":"github-dark"}}
  { "code": "authentication_error", "message": "Authentication is required." }
  ```

  ```json 403 theme={"theme":{"light":"github-light","dark":"github-dark"}}
  { "code": "authorization_error", "message": "This widget may not be embedded from that origin." }
  ```

  ```json 404 theme={"theme":{"light":"github-light","dark":"github-dark"}}
  { "code": "not_found", "message": "The requested resource was not found." }
  ```
</ResponseExample>
