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

# Build a custom frontend

> Use the REST endpoints and WebSocket streaming to power your own search UI.

<Warning>
  Generate one `sessionId` per browser session and one `requestId` per user
  action. Reuse both values across the coordinated calls for that action.
</Warning>

## Environments

| Environment | REST base URL            | WebSocket URL                    |
| ----------- | ------------------------ | -------------------------------- |
| Production  | `https://api.webless.ai` | `wss://api.webless.ai/api/v1/ws` |

Use `ws://` only for local development.

## Request flow

```mermaid theme={null}
sequenceDiagram
  participant U as User
  participant App as Your frontend
  participant Search as POST /api/v1/queries
  participant WS as WebSocket /api/v1/ws
  participant CTA as POST /api/v1/cta-selection
  participant Suggestions as POST /api/v1/suggestions

  U->>App: Ask a question
  App->>App: Reuse sessionId\nCreate requestId
  par Fetch content tiles
    App->>Search: POST /api/v1/queries
  and Stream summary
    App->>WS: get_summary_with_cache
  and Fetch CTA
    App->>CTA: POST /api/v1/cta-selection
  and Fetch follow-up prompts
    App->>Suggestions: POST /api/v1/suggestions
  end
```

## API routes

| Use             | Route                            |
| --------------- | -------------------------------- |
| Query tiles     | `POST /api/v1/queries`           |
| Stream summary  | `wss://api.webless.ai/api/v1/ws` |
| Select CTA      | `POST /api/v1/cta-selection`     |
| Get suggestions | `POST /api/v1/suggestions`       |

## Orchestrate the full experience

<Steps>
  <Step title="Create identifiers" icon="key-round">
    Create a `sessionId` once per user session. Create a new `requestId` for each
    query or action.
  </Step>

  <Step title="Fetch tiles with /api/v1/queries" icon="grid-2x2">
    Call `POST /api/v1/queries` to fetch the top content tiles for the query.
    Keep the same `sessionId` and `requestId` you will use everywhere else.
  </Step>

  <Step title="Stream the summary over WebSocket" icon="radio">
    Open `/api/v1/ws` and send the `get_summary_with_cache` action. Append
    `summary_part` chunks as they arrive, then finalize the UI when you receive
    `summary_complete`.
  </Step>

  <Step title="Fetch a CTA and suggestions in parallel" icon="workflow">
    Call `POST /api/v1/cta-selection` and `POST /api/v1/suggestions` with the
    same IDs so the platform can correlate the entire experience.
  </Step>
</Steps>

## WebSocket request

```json theme={null}
{
  "action": "get_summary_with_cache",
  "params": {
    "query": "What does Webless do?",
    "company": "YOUR_COMPANY",
    "requestId": "YOUR_REQUEST_ID",
    "sessionId": "YOUR_SESSION_ID",
    "version": "published",
    "markdown": true,
    "number_of_tiles": 6,
    "summary_word_limit": 120
  }
}
```

## WebSocket events

| Event              | Meaning                          |
| ------------------ | -------------------------------- |
| `summary_part`     | A streamed chunk of summary text |
| `summary_tiles`    | Tile IDs emitted near completion |
| `summary_complete` | The stream finished successfully |
| `error`            | The request failed               |

## JavaScript example

```javascript theme={null}
const sessionId = getOrCreateSessionId();
const requestId = crypto.randomUUID();

const ws = new WebSocket("wss://api.webless.ai/api/v1/ws");

ws.onopen = () => {
  ws.send(
    JSON.stringify({
      action: "get_summary_with_cache",
      params: {
        query: "What does Webless do?",
        company: "YOUR_COMPANY",
        requestId,
        sessionId,
        version: "published",
        number_of_tiles: 6,
        markdown: true,
        summary_word_limit: 120
      }
    })
  );
};

ws.onmessage = (event) => {
  const message = JSON.parse(event.data);

  if (message.event === "summary_part") {
    appendSummary(message.data.summary_part);
  } else if (message.event === "summary_tiles") {
    renderTileIds(message.data.summary_tiles);
  } else if (message.event === "summary_complete") {
    finalizeExperience();
  } else if (message.event === "error") {
    console.error(message.data?.message);
  }
};
```

<Tip>
  Use the pages in [API reference](/api-reference/latest/introduction) for
  request and response schemas. Use this guide for orchestration and WebSocket
  behavior.
</Tip>
