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

# Chat Widget API

> The backend contract the StateSet Response chat widget calls — one required endpoint, a handful of optional ones, and the admin API of the widget's self-hosted server.

This tab is different from the others. There is no StateSet host behind it: the
[chat widget](/stateset-response/response-chat-widget) runs in your customer's browser and calls
**your** backend. These pages are the contract that backend has to meet. Implement `POST /api/chat`
and the widget works; implement the rest as you need threads, catalog cards, cart actions, and
analytics.

|                  |                                                                                                     |
| ---------------- | --------------------------------------------------------------------------------------------------- |
| Base URL         | Whatever you set as `messageEndpoint` — `https://api.example.com` stands in on every page           |
| Required         | `POST /api/chat`                                                                                    |
| Optional         | Threads, products, cart, settings, telemetry, review, analytics                                     |
| Reference server | The repository's `server-openai.js` implements every route here against OpenAI, Anthropic or Gemini |
| Admin API        | `/api/admin/*` on the widget admin server, behind an `rw_admin_` bearer key                         |

<Note>
  Nothing here is served by `response.stateset.com`. The widget can *also* be wired to a ResponseCX
  agent through the [ResponseCX API](/api-reference/responsecx/overview); that is a different surface
  with its own tab.
</Note>

## Two surfaces

<CardGroup cols={2}>
  <Card title="Send a message" icon="message" href="/api-reference/chat-widget/chat/api-chat-create">
    The one endpoint the widget needs. Non-streaming JSON, or SSE when `stream: true`.
  </Card>

  <Card title="Threads" icon="messages" href="/api-reference/chat-widget/threads/api-threads-create">
    Create, read, update, delete, and post into a persistent thread.
  </Card>

  <Card title="Analytics events" icon="chart-line" href="/api-reference/chat-widget/analytics/analytics-create">
    Every user, assistant, commerce and lifecycle action, with a funnel stage on outcomes.
  </Card>

  <Card title="Admin API" icon="key" href="/api-reference/chat-widget/admin/api-admin-sites-create">
    Sites, draft and published config, install snippets, versions and rollback.
  </Card>
</CardGroup>

## Authentication

| Surface                                       | Header                                                                 | Where it comes from                                                                                                              |
| --------------------------------------------- | ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| Chat, threads, catalog, cart, analytics       | `x-widget-token: <orgId>.<agentId>.<timestamp>.<signature>`            | Optional. Signed with `STATESET_WIDGET_AUTH_SECRET` and exposed to the page as `widgetAuthToken`; verify it server-side when set |
| `GET /chat-widget/settings`                   | `Authorization: ApiKey <key>` (or `Bearer`), `x-api-key` also accepted | The key you give the widget as `settingsApiKey`                                                                                  |
| `/api/admin/*`                                | `Authorization: Bearer rw_admin_<hex>`                                 | Minted by `POST /api/admin/keys` — the first one with the server's bootstrap secret                                              |
| `GET /api/health`, `GET /api/widget/settings` | none                                                                   | Public                                                                                                                           |

## Streaming

When the request carries `stream: true`, answer with `Content-Type: text/event-stream` and one
JSON object per `data:` line. The widget concatenates every `text_delta` into the reply and renders
the other events as it receives them; end with `data: [DONE]`.

| `type`                          | Payload                                          | The widget shows                         |
| ------------------------------- | ------------------------------------------------ | ---------------------------------------- |
| `text_delta`                    | `delta.text` or `text`                           | The reply, token by token                |
| `tool_call`                     | `id`, `name`, `arguments`                        | A tool-call status line                  |
| `tool_result`                   | `id`, `name`, `result`                           | Its result                               |
| `citation`                      | `title`, `url`, `snippet`                        | A source chip                            |
| `thinking`                      | `text`                                           | A collapsible reasoning block            |
| `product_cards` / `order_cards` | `content`                                        | Product or order cards inside the reply  |
| `outcome` / `agentic_outcome`   | `name`, `resourceType`, `resourceId`, `quantity` | Nothing — recorded as a business outcome |

```text theme={null}
data: {"type":"text_delta","delta":{"text":"Your order "}}
data: {"type":"tool_call","id":"c1","name":"get_order","arguments":{"id":"1001"}}
data: {"type":"tool_result","id":"c1","name":"get_order","result":{"status":"shipped"}}
data: {"type":"text_delta","delta":{"text":"shipped yesterday."}}
data: {"type":"outcome","name":"order.status_checked","resourceType":"order","resourceId":"1001"}
data: [DONE]
```

## Errors

Any non-2xx response is `{ "error": "<message>", "type": "<optional code>" }`. The widget shows
`error` inline in the conversation and calls the `onError` prop with the same object. Leave
`GET /api/threads/{id}` out of your rate limiter — the widget polls it to refresh a thread.

## Not in this reference

The repository also ships integration flows built for individual customers — order lookup against
a specific store, review-platform attachments, subscription changes, promotional offers. They are
implementation details of one backend rather than the contract, and are not documented here.

## Related

* [Chat widget](/stateset-response/response-chat-widget) — install, props, theming, backend options
* [Chat widget quickstart](/stateset-response/response-chat-widget-quickstart)
* [ResponseCX API](/api-reference/responsecx/overview) — when the widget should talk to a ResponseCX agent
