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

# Build an Embedded AI Analyst UI

> Ask deep analysis questions from your own app and stream the progress and answer

You can embed [Deep Analysis](/docs/integration/context-layer/deep-analysis) in your own
application with the [GraphQL API](/docs/integration/graphql-api). The Honeydew UI, the Slack
and Teams apps, and the MCP server use the same calls: submit a question, then poll for
messages as the analysis runs. If your application can wait for the full answer,
[`ask_deep_analysis_question_sync`](/docs/integration/graphql-api#ask-deep-analysis-questions)
returns it in one call, without progress.

## Prerequisites

* [GraphQL API](/docs/integration/graphql-api) access for your organization, and an
  [API key](/docs/initial-setup#api-keys) with Viewer role or higher
* One or more [agents](/docs/integration/context-layer/agents) to answer the questions

## Architecture

Call Honeydew from your server, so the API key and secret never reach the browser.
Your server sets the `X-Honeydew-Workspace` and `X-Honeydew-Branch`
[headers](/docs/integration/graphql-api#headers) on every call.

Chats belong to the user of the API key. To keep per-user ownership, give each end user a
Honeydew user and a [per-user API key](/docs/access-control/api-keys#per-user-api-keys), which
support enables for your organization. Each chat then belongs to its end user, who also finds
it in the Honeydew UI. With one shared key, your server records which end user owns each chat,
and checks it before passing a chat ID to Honeydew.

## Call flow

```mermaid theme={null}
sequenceDiagram
    participant UI as Your UI
    participant BE as Your server
    participant HD as Honeydew API

    UI->>BE: First question
    opt Agent routing
        BE->>HD: agents_for_question(question)
        HD-->>BE: agents, most relevant first
        alt No agent
            BE-->>UI: No agent fits the question
            Note over UI,BE: Stop here, create no chat
        else Several agents
            BE-->>UI: Which agent?
            UI->>BE: Chosen agent
        end
    end
    BE->>HD: create_chat(agent)
    HD-->>BE: chat_id, ui_url
    BE->>HD: subscribe_to_chat(chat_id)
    HD-->>BE: subscription_id
    BE->>HD: ask_deep_analysis_question(chat_id, question)
    HD-->>BE: null (analysis started)

    loop Every few seconds, until StopUpdate
        BE->>HD: get_new_messages(subscription_id)
        HD-->>BE: new_messages
        BE-->>UI: Steps, text, data, charts
    end

    UI->>BE: Follow-up question
    BE->>HD: ask_deep_analysis_question(chat_id, follow-up)
    Note over BE,HD: Poll the same subscription again
```

## Steps

<Steps>
  <Step title="Create a chat">
    Call [`create_chat`](/docs/integration/graphql-api#create-chat-for-deep-analysis-questions)
    with the agent name, either a fixed agent or one picked by
    [agent routing](#route-questions-to-an-agent). Store the returned `chat_id`; follow-up
    questions use the same chat.
  </Step>

  <Step title="Subscribe to the chat">
    Call [`subscribe_to_chat`](/docs/integration/graphql-api#subscribe-to-deep-analysis-chat)
    with the `chat_id`. Subscribe before asking, so the queue receives every message of
    the analysis.
  </Step>

  <Step title="Ask the question">
    Call [`ask_deep_analysis_question`](/docs/integration/graphql-api#ask-deep-analysis-question-async).
    It returns `null` as soon as the analysis starts.
  </Step>

  <Step title="Poll for messages">
    Call [`get_new_messages`](/docs/integration/graphql-api#get-new-deep-analysis-messages)
    every 5 seconds and render each message by its content type. Stop polling when a
    `StopUpdate` arrives.
  </Step>

  <Step title="Ask follow-ups">
    Call `ask_deep_analysis_question` again with the same `chat_id`, and poll the same
    subscription again. Show the `suggested_responses` of the `StopUpdate` as one-click
    follow-ups.
  </Step>
</Steps>

## Route questions to an agent

Instead of a fixed agent, your server can let Honeydew pick one for each new conversation with
[agent routing](/docs/integration/context-layer/agents#agent-routing). Before `create_chat`, call
[`agents_for_question`](/docs/integration/graphql-api#find-agents-for-a-question) with the first
question:

* **One agent**: pass its `name` to `create_chat`.
* **Several agents**: they come most relevant first. Let the user pick one, by its
  `display_name`.
* **No agent**: tell the user that no agent fits the question, and create no chat.

To improve routing results, see
[What the Router Considers](/docs/integration/context-layer/agents#what-the-router-considers).

## Render messages

| Content type | What to show |
| - | - |
| `UserContent` | The user's question, from `text` |
| `StepStart` / `StepEnd` | A progress item per `step_id`: its `description`, then its `insight` |
| `StatusUpdate` | A short status line, such as "Thinking…" |
| `MarkdownContent` | Answer or progress text, by `category` |
| `DataContent` | A table. `is_main_content` marks tables that belong to the answer. |
| `GraphContent` | A chart. `vega_lite` is a complete Vega-Lite specification that renders as-is. |
| `StopUpdate` | The end: `DONE`, `FAIL`, `ABORTED`, or `ASK` (the agent needs user input) |

To let users stop a running analysis, call
[`abort_chat`](/docs/integration/graphql-api#abort-deep-analysis-chat).

## Reload and resume

To show a past conversation, call
[`get_chat`](/docs/integration/graphql-api#get-deep-analysis-chat) and render its `history`.
The messages use the same format as `get_new_messages`.

To continue it, or to resume after a subscription expired, call `subscribe_to_chat` with
`from_message_id` set to the last `message_id` you have plus one. The queue then starts
with the messages you missed. A chat with `is_readonly: true` can be shown but not continued:
`subscribe_to_chat` and `ask_deep_analysis_question` return `CHAT_IS_READONLY` for it.

<Note>
  Polling counts toward the API [rate limit](/docs/integration/graphql-api#rate-limiting), which
  applies per API key: every running chat on a shared key polls against the same budget,
  while per-user keys each get their own. Back off when a call fails.
</Note>

## Manage chats

* **List chats**: [`get_all_chats`](/docs/integration/graphql-api#list-deep-analysis-chats)
  returns the chats of the key's user, newest first, with `limit` and `offset` for paging.
  A key with the Admin role also lists the chats of other users. With a shared key, filter the
  list by the chat owners your server records.
* **Fetch a chat**: [`get_chat`](/docs/integration/graphql-api#get-deep-analysis-chat) returns one
  chat by `chat_id`, with its `history`, as described under [Reload and resume](#reload-and-resume).
* **Rename a chat**: [`rename_chat`](/docs/integration/graphql-api#rename-deep-analysis-chat) sets
  its title to `new_title`.
* **Give feedback**:
  [`update_chat_feedback`](/docs/integration/graphql-api#set-deep-analysis-chat-feedback) stores
  the user's feedback on a chat, replacing earlier feedback. Pass `null` to clear it. The
  feedback appears in [AI question history](/docs/integration/graphql-api#list-ai-question-history).
* **Delete a chat**: [`delete_chat`](/docs/integration/graphql-api#delete-deep-analysis-chat)
  deletes a chat of the key's user. It can no longer be listed, fetched or continued.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.