> For the complete documentation index, see [llms.txt](https://docs.uptiq.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.uptiq.ai/agent-builder/deploy/agent-integration.md).

# Agent Integration

Once an agent is built, you can wire it into your own product in three ways — embed a prebuilt chat widget, call the REST API, or drive it with the JavaScript SDK. This page walks through all three, along with the credentials and domain rules they share. Find them under **Manage Agent → Agent Integration**.

<figure><img src="/files/VHj9dnrV5FzLdHCid1jL" alt="The Integrate Agent options on the screen: Embed, API, and Headless"><figcaption><p>The three Integrate Agent options — Embed, API, and Headless — sit in the lower row of the screen.</p></figcaption></figure>

{% hint style="info" %}
This agent uses **SDK Version 1.181.0** and **Executor Version 1.3**. Use these versions in your app and API calls for compatibility.
{% endhint %}

## Choosing an integration

Start by matching the integration to where your agent runs and how much of the interface you want to own. The table below maps each option to its runtime; the sections that follow document each one in full.

| If you want to…                                          | Use              | Runtime                       |
| -------------------------------------------------------- | ---------------- | ----------------------------- |
| Drop a chat onto a web page with no UI to build          | **Embed widget** | Browser (prebuilt UI)         |
| Call the agent from a backend, service, or scheduled job | **REST API**     | Server-to-server (no browser) |
| Build your own custom chat UI in the browser             | **JS SDK**       | Browser (your UI)             |

**Shared prerequisites.** All three connect using credentials and domain rules configured on the agent:

| Requirement            | Where                                        | Applies to                                                       |
| ---------------------- | -------------------------------------------- | ---------------------------------------------------------------- |
| **Widget Key**         | Agent Config Panel → **Authentication**      | Embed, JS SDK (and optionally the API)                           |
| **API Key + Secret**   | Agent Config Panel → **Authentication**      | REST API (server-to-server)                                      |
| **Whitelisted domain** | Agent Config Panel → **Whitelisted Domains** | Embed, JS SDK — add the full URL or hostname, no trailing spaces |

To obtain a **Widget Key**: open your agent's **Agent Config Panel → Authentication** tab, then create and copy the key. To **whitelist a domain**: open **Agent Config Panel → Whitelisted Domains**, then add and save your domain.

Set up [Authentication](/agent-builder/deploy/authentication.md) first. Then add your allowed hosts in [Whitelisted Domains](/agent-builder/deploy/whitelisted-domains.md).

{% hint style="warning" %}
Wherever you supply a `user` object, it must represent a **trusted, authenticated identity** from your own auth system — the user currently logged into your application and verified by your auth system. Never populate it from query parameters or untrusted input, which can be manipulated.
{% endhint %}

## Embedding

Embedding is the quickest path — a prebuilt chat UI you drop onto a page, with no interface to build yourself.

The **Embed Agent** widget is a drop-in chat interface backed by `@uptiqai/widgets-sdk`. It comes as **React** components or a framework-agnostic **HTML web component**, and each offers a compact **Chat Widget** (floating popover) or an immersive **Full Screen** layout with sidebar navigation. The widget handles conversation state, history, and messaging for you.

**Install**

```bash
npm install @uptiqai/widgets-sdk@1.181.0
# or
pnpm add @uptiqai/widgets-sdk@1.181.0
```

Import the stylesheet once in your application entry point:

```js
import '@uptiqai/widgets-sdk/dist/style.css';
```

**Chat Widget vs. Full Screen** — both share the same `config`, `user`, `theme`, `instanceId`, and ref API. Full Screen adds a `hideTrigger` / `hide-trigger` option to hide the default launcher and open via your own button. Expand the variant you need:

<details>

<summary>React — Chat Widget (popover)</summary>

```tsx
import { ChatWidget } from '@uptiqai/widgets-sdk';
import type { ChatWidgetRef } from '@uptiqai/widgets-sdk';
import '@uptiqai/widgets-sdk/dist/style.css';
import { useRef } from 'react';

function App() {
  const currentUser = useAuth(); // your auth hook
  return (
    <ChatWidget
      config={{
        serverUrl: 'https://api-builder-dev.uptiq.dev',
        agentId: '<agent-id>',
        widgetKey: '<your-widget-key>',
        agentExecutorVersion: '1.3',
      }}
      user={{
        uid: currentUser.id,
        firstName: currentUser.firstName,
        lastName: currentUser.lastName,
        email: currentUser.email,
      }}
    />
  );
}
```

</details>

<details>

<summary>React — Full Screen</summary>

Use `FullScreenChatWidget` / `FullScreenChatWidgetRef`. Add `hideTrigger` when driving visibility from your own button:

```tsx
import { FullScreenChatWidget } from '@uptiqai/widgets-sdk';
import type { FullScreenChatWidgetRef } from '@uptiqai/widgets-sdk';
import '@uptiqai/widgets-sdk/dist/style.css';
import { useRef } from 'react';

function App() {
  const widgetRef = useRef<FullScreenChatWidgetRef>(null);
  const currentUser = useAuth();
  return (
    <FullScreenChatWidget
      config={{
        serverUrl: 'https://api-builder-dev.uptiq.dev',
        agentId: '<agent-id>',
        widgetKey: '<your-widget-key>',
        agentExecutorVersion: '1.3',
      }}
      user={{
        uid: currentUser.id,
        firstName: currentUser.firstName,
        lastName: currentUser.lastName,
        email: currentUser.email,
      }}
      hideTrigger={true}
      widgetRef={widgetRef}
    />
  );
}
```

</details>

<details>

<summary>HTML — Chat Widget (popover)</summary>

Add the widget script to your page `<head>`, then use the custom element:

```html
<uptiq-chat-widget
  id="chat-widget"
  config='{
    "serverUrl": "https://api-builder-dev.uptiq.dev",
    "agentId": "<agent-id>",
    "widgetKey": "<your-widget-key>",
    "agentExecutorVersion": "1.3"
  }'
  user='{
    "uid": "auth0|<user-id>",
    "firstName": "Jane",
    "lastName": "Smith",
    "email": "jane.smith@company.com"
  }'
></uptiq-chat-widget>
```

</details>

<details>

<summary>HTML — Full Screen</summary>

Use `<uptiq-full-screen-chat-widget>` and add `hide-trigger="true"` to hide the default launcher:

```html
<uptiq-full-screen-chat-widget
  id="chat-widget"
  hide-trigger="true"
  config='{
    "serverUrl": "https://api-builder-dev.uptiq.dev",
    "agentId": "<agent-id>",
    "widgetKey": "<your-widget-key>",
    "agentExecutorVersion": "1.3"
  }'
  user='{
    "uid": "auth0|<user-id>",
    "firstName": "Jane",
    "lastName": "Smith",
    "email": "jane.smith@company.com"
  }'
></uptiq-full-screen-chat-widget>
```

</details>

### Props / attributes reference

React uses **props** (objects); the HTML web component uses **attributes** (JSON-stringified objects, kebab-case names). Otherwise they map 1:1.

| React prop           | HTML attribute         | Required | Type                     | Description                                                                                 |
| -------------------- | ---------------------- | -------- | ------------------------ | ------------------------------------------------------------------------------------------- |
| `config`             | `config`               | Yes      | `WidgetConfig`           | Backend/agent config — see below.                                                           |
| `user`               | `user`                 | Yes      | `WidgetUser`             | Authenticated user — see below.                                                             |
| `instanceId`         | `instance-id`          | No       | string                   | Unique ID when rendering multiple widgets on one page. Default: auto-generated.             |
| `theme`              | `theme`                | No       | `WidgetTheme`            | Palette overrides — see **Theme customization**.                                            |
| `defaultExecutionId` | `default-execution-id` | No       | string                   | Start with a specific conversation/execution loaded (continue a previous chat).             |
| `onExecutionChange`  | —                      | No       | `(executionId?) => void` | Fires when the current conversation changes.                                                |
| `defaultOpen`        | `default-open`         | No       | boolean                  | Open on mount. Default `false`.                                                             |
| `hideTrigger`        | `hide-trigger`         | No       | boolean                  | *(Full Screen)* Hide the default launcher; open via your own button + ref. Default `false`. |
| `onClose`            | —                      | No       | `() => void`             | Fires when the user closes the widget.                                                      |
| `widgetRef`          | —                      | No       | `React.Ref<…Ref>`        | Programmatic `open()` / `close()` control.                                                  |

**`config` (required)** — `WidgetConfig`:

```ts
{
  serverUrl: 'https://api-builder-dev.uptiq.dev', // don't change this
  agentId: '<agent-id>',                          // don't change this
  widgetKey: string,          // from Agent Config -> Authentication
  agentExecutorVersion?: string, // Executor version from agent config (optional)
}
```

**`user` (required)** — `WidgetUser`:

```ts
{
  uid: string;        // Unique identifier for the user in your system
  firstName: string;  // User's first name
  lastName?: string;  // User's last name (optional)
  email: string;      // User's email address
}
```

{% hint style="warning" %}
**Security:** populate `user` from your authenticated session — e.g. `const currentUser = useAuth();` — never from query params, form input, or other untrusted sources.
{% endhint %}

<details>

<summary>widgetRef — programmatic open/close control</summary>

```ts
// React.Ref<ChatWidgetRef> | React.Ref<FullScreenChatWidgetRef>
{
  open: () => void;   // Opens the widget
  close: () => void;  // Closes the widget
}
```

```tsx
const widgetRef = useRef<FullScreenChatWidgetRef>(null);

const handleOpenChat = () => widgetRef.current?.open();
const handleCloseChat = () => widgetRef.current?.close();
```

</details>

### Theme customization

Pass a `theme` (React object / HTML JSON string) to match your design system:

```tsx
theme={{
  palette: {
    primary: '#3b82f6',
    primaryForeground: '#ffffff',
    background: '#ffffff',
    foreground: '#0f172a',
    border: '#e2e8f0',
    success: '#10b981',
    destructive: '#ef4444',
  },
}}
```

<details>

<summary>Full palette reference (WidgetTheme)</summary>

```ts
{
  palette?: {
    // Primary shades
    primary00?; primary100?; primary200?; primary300?; primary400?; primary500?;
    // Secondary shades
    secondary300?; secondary500?; secondary700?;
    // Background shades (00 lightest → 900 darkest)
    background00?; background100?; background200?; background300?; background800?; background900?;
    // Foreground / text
    foreground00?; foreground200?; foreground600?; foreground800?; foreground900?;
    // Borders
    border100?; border200?; border300?; border400?;
    // Semantic
    primary?; primaryForeground?;
    secondary?; secondaryForeground?;
    background?; foreground?;
    border?; input?;
    success?; successForeground?;
    warning?; warningForeground?;
    destructive?; destructiveForeground?;
    sidebar?; sidebarForeground?;
    ring?;
    // all values are string (optional)
  }
}
```

</details>

### Examples

<details>

<summary>Example 1 — Basic implementation</summary>

```tsx
import { FullScreenChatWidget } from '@uptiqai/widgets-sdk';
import '@uptiqai/widgets-sdk/dist/style.css';

function App() {
  const currentUser = useAuth();
  return (
    <div>
      <h1>My Application</h1>
      <FullScreenChatWidget
        config={{ serverUrl: 'https://api-builder-dev.uptiq.dev', agentId: '<agent-id>', widgetKey: '<your-widget-key>', agentExecutorVersion: '1.3' }}
        user={{ uid: currentUser.id, firstName: currentUser.firstName, lastName: currentUser.lastName, email: currentUser.email }}
      />
    </div>
  );
}
```

</details>

<details>

<summary>Example 2 — Custom trigger with ref control</summary>

```tsx
import { FullScreenChatWidget } from '@uptiqai/widgets-sdk';
import type { FullScreenChatWidgetRef } from '@uptiqai/widgets-sdk';
import '@uptiqai/widgets-sdk/dist/style.css';
import { useRef } from 'react';

function App() {
  const widgetRef = useRef<FullScreenChatWidgetRef>(null);
  const currentUser = useAuth();
  return (
    <div>
      <button onClick={() => widgetRef.current?.open()}>💬 Chat with AI Assistant</button>
      <FullScreenChatWidget
        config={{ serverUrl: 'https://api-builder-dev.uptiq.dev', agentId: '<agent-id>', widgetKey: '<your-widget-key>', agentExecutorVersion: '1.3' }}
        user={{ uid: currentUser.id, firstName: currentUser.firstName, lastName: currentUser.lastName, email: currentUser.email }}
        hideTrigger={true}
        widgetRef={widgetRef}
      />
    </div>
  );
}
```

For the **popover** `ChatWidget`, the same pattern applies with both open and close buttons (`widgetRef.current?.open()` / `.close()`).

</details>

<details>

<summary>Example 3 — Theme customization</summary>

```tsx
const customTheme = {
  palette: {
    primary: '#6366f1', primaryForeground: '#ffffff',
    background: '#f8fafc', foreground: '#1e293b', border: '#cbd5e1',
    sidebar: '#ffffff', sidebarForeground: '#475569',
    success: '#22c55e', warning: '#f59e0b', destructive: '#ef4444',
  },
};

<FullScreenChatWidget config={/* … */} user={/* … */} theme={customTheme} />
```

</details>

<details>

<summary>Example 4 — Tracking conversations</summary>

```tsx
import { useState } from 'react';

function App() {
  const currentUser = useAuth();
  const [currentExecutionId, setCurrentExecutionId] = useState<string>();

  const handleExecutionChange = (executionId?: string) => {
    setCurrentExecutionId(executionId);
    if (executionId) localStorage.setItem('lastExecutionId', executionId);
    analytics.track('conversation_changed', { executionId });
  };

  const lastExecutionId = localStorage.getItem('lastExecutionId') || undefined;

  return (
    <FullScreenChatWidget
      config={{ serverUrl: 'https://api-builder-dev.uptiq.dev', agentId: '<agent-id>', widgetKey: '<your-widget-key>', agentExecutorVersion: '1.3' }}
      user={{ uid: currentUser.id, firstName: currentUser.firstName, lastName: currentUser.lastName, email: currentUser.email }}
      defaultExecutionId={lastExecutionId}
      onExecutionChange={handleExecutionChange}
      onClose={() => console.log('Widget closed with execution:', currentExecutionId)}
    />
  );
}
```

</details>

<details>

<summary>Example 5 — Multiple widgets on the same page</summary>

Give each widget a distinct `instanceId` (React) / `instance-id` (HTML):

```tsx
<FullScreenChatWidget instanceId="sales-agent" config={{ /* sales agentId + widgetKey */ }} user={/* … */} />
<FullScreenChatWidget instanceId="support-agent" config={{ /* support agentId + widgetKey */ }} user={/* … */} />
```

</details>

### Features

* Chat interface (floating popover or full-screen) with responsive design
* Conversation sidebar for managing multiple chats
* New chat creation for starting fresh conversations
* Message history persistence across sessions
* Real-time messaging with the AI agent
* Agent avatar display in the trigger button
* Customizable theming to match your brand
* TypeScript support with full type definitions

### Browser support

All modern browsers: Chrome/Edge (latest), Firefox (latest), Safari (latest), and mobile browsers (iOS Safari, Chrome Mobile).

### Troubleshooting

* **Widget not appearing** — ensure you imported the CSS (`import '@uptiqai/widgets-sdk/dist/style.css';`), that both required props (`config` and `user`) are provided, and that your Widget Key is correct and active.
* **"Unauthorized" errors** — confirm your application's domain is whitelisted exactly (full URL with protocol or hostname only, no trailing spaces).

## REST API & JS SDK

When you'd rather drive the agent from your own code than a prebuilt UI, reach for one of these two. The **REST API** runs server-to-server with no browser; the **JS SDK** runs in the browser so you can build a fully custom chat interface. Pick a tab:

{% tabs %}
{% tab title="REST API" %}

### REST API

The **Headless Agent Trigger API** invokes an agent over HTTP — no UI or browser. Use it for backend services, scheduled jobs, or any workflow that starts the agent from your own systems.

* **Base URL:** `https://api-builder-dev.uptiq.dev` · **Format:** JSON

#### Authentication

Every request must include exactly one of the following header sets.

<details>

<summary>Option 1 — API Key + Secret (server-to-server)</summary>

Best for backend and service-to-service integrations.

```http
x-api-key: YOUR_AGENT_API_KEY
x-api-key-secret: YOUR_AGENT_API_KEY_SECRET
Content-Type: application/json
```

Create and copy both from **Agent Config Panel → Authentication**.

</details>

<details>

<summary>Option 2 — Widget Key</summary>

Best for first-party platform integrations.

```http
x-widget-key: YOUR_AGENT_WIDGET_KEY
Content-Type: application/json
```

Create and copy it from **Agent Config Panel → Authentication**.

</details>

#### Trigger an agent

```
POST /agent-executor/1.3/agents/:agentId/trigger
```

Starts a new agent execution or resumes a paused one.

**Path parameters**

| Name      | Type   | Required | Description                                |
| --------- | ------ | -------- | ------------------------------------------ |
| `agentId` | string | Yes      | The unique identifier of the agent to run. |

**Request body** — provide either `message` or `resumeData`; all other fields are optional.

| Field            | Type   | Description                                                                       |
| ---------------- | ------ | --------------------------------------------------------------------------------- |
| `message`        | string | The instruction sent to the agent. Required for new executions.                   |
| `payload`        | object | Structured data sent alongside `message` for programmatic inputs.                 |
| `documents`      | array  | File attachments. See **Document handling**.                                      |
| `executionId`    | string | Specific execution ID. Auto-generated if omitted.                                 |
| `executionMode`  | string | `async` (default) or `sync`. Use `sync` only when you need an immediate response. |
| `responseFormat` | string | `Markdown` (default) or `Json`.                                                   |
| `webhooks`       | array  | Webhook URLs to receive execution updates. See **Webhooks**.                      |

```bash
curl -X POST "https://api-builder-dev.uptiq.dev/agent-executor/1.3/agents/:agentId/trigger" \
  -H "x-api-key: YOUR_AGENT_API_KEY" \
  -H "x-api-key-secret: YOUR_AGENT_API_KEY_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"message": "Summarize the latest sales report"}'
```

Success response: `{ "executionId": "exec_123" }`

#### Document handling

Attaching documents is a two-step process: upload the file, then reference it in the trigger request.

<details>

<summary>Step 1 — Get a signed upload URL</summary>

```
POST /agent-executor/1.3/agents/:agentId/uploads/signed-urls
```

```bash
curl -X POST "https://api-builder-dev.uptiq.dev/agent-executor/1.3/agents/:agentId/uploads/signed-urls" \
  -H "x-widget-key: YOUR_AGENT_WIDGET_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "count": 1 }'
```

| Field         | Type   | Required | Description                                     |
| ------------- | ------ | -------- | ----------------------------------------------- |
| `count`       | number | No       | Number of signed URLs to generate. Default `1`. |
| `executionId` | string | No       | Execution ID to associate the upload with.      |

Response:

```json
{
  "message": "Signed URL generated successfully.",
  "data": [
    { "id": "document-id", "url": "https://storage.googleapis.com/.../uploads/...", "agentId": "agent-id" }
  ]
}
```

`PUT` your file to the returned `url`, then use the `id` when triggering the agent.

{% hint style="warning" %}
The previous endpoint `POST /agent-executor/1.3/agents/:agentId/documents/presigned-url` is **deprecated** and will be removed — migrate to `uploads/signed-urls`.
{% endhint %}

</details>

<details>

<summary>Step 2 — Attach the document to the trigger request</summary>

```bash
curl -X POST "https://api-builder-dev.uptiq.dev/agent-executor/1.3/agents/:agentId/trigger" \
  -H "x-api-key: YOUR_AGENT_API_KEY" \
  -H "x-api-key-secret: YOUR_AGENT_API_KEY_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Analyze financial risk",
    "documents": [
      { "id": "<document-id>", "fileName": "balance-sheet.pdf", "mimeType": "application/pdf" }
    ]
  }'
```

| Field       | Type   | Description                                                  |
| ----------- | ------ | ------------------------------------------------------------ |
| `id`        | string | Document ID returned from the upload endpoint.               |
| `signedUrl` | string | Alternative to `id` — the signed URL of the uploaded file.   |
| `fileName`  | string | Original filename. Recommended for better agent context.     |
| `mimeType`  | string | MIME type of the file. Recommended for better agent context. |

</details>

#### Webhooks

{% hint style="info" %}
Webhooks are available on **Agent Executor Version 1.2 and onwards**.
{% endhint %}

Register webhooks in the trigger request to receive real-time updates when an execution completes or needs input:

```json
{
  "webhooks": [
    { "url": "https://your-service.com/webhook", "metadata": "optional-context-id" }
  ]
}
```

Your endpoint receives:

```json
{
  "executionId": "exec_123",
  "success": true,
  "result": { "message": "Agent response..." },
  "error": null,
  "metadata": "optional-context-id"
}
```

<details>

<summary>Verify the webhook signature</summary>

Each webhook includes an `X-Webhook-Signature` header — a hex-encoded RSA-SHA256 signature of the raw JSON body. Verify it against the platform's public key (available on the agent's API Integration screen):

```js
const crypto = require('crypto');

function verifyWebhook(rawBody, signatureHex, publicKey) {
  const signature = Buffer.from(signatureHex, 'hex');
  return crypto.verify('RSA-SHA256', Buffer.from(rawBody), publicKey, signature);
}
```

</details>

#### Common examples

<details>

<summary>Send structured data with a message</summary>

```bash
curl -X POST "https://api-builder-dev.uptiq.dev/agent-executor/1.3/agents/:agentId/trigger" \
  -H "x-api-key: YOUR_AGENT_API_KEY" \
  -H "x-api-key-secret: YOUR_AGENT_API_KEY_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "message": "Generate quarterly report", "payload": { "quarter": "Q4", "year": 2024 } }'
```

</details>

<details>

<summary>Resume a paused execution</summary>

```bash
curl -X POST "https://api-builder-dev.uptiq.dev/agent-executor/1.3/agents/:agentId/trigger" \
  -H "x-api-key: YOUR_AGENT_API_KEY" \
  -H "x-api-key-secret: YOUR_AGENT_API_KEY_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "executionId": "exec_123", "resumeData": { "lastStep": "analysis" } }'
```

</details>

<details>

<summary>Pin a specific reasoning model (advanced)</summary>

By default the platform picks the reasoning model. To override:

```json
{ "message": "Analyze this contract", "agentStrategy": { "reasoningModelId": "your-model-id" } }
```

</details>

#### Error responses

| Status | Meaning         | Example                                                          |
| ------ | --------------- | ---------------------------------------------------------------- |
| `400`  | Invalid request | `{ "error": "Message or resume data is required" }`              |
| `401`  | Bad credentials | `{ "error": "Invalid or missing agent API key" }`                |
| `403`  | Forbidden       | `{ "message": "You're not authorized to perform this action." }` |
| `500`  | Server error    | `{ "message": "Something went wrong. Please try again later." }` |

{% hint style="info" %}
Executions default to **async** — use `sync` only when you must block on the result. The trigger endpoint is **not idempotent**: each call starts a new execution unless you pass an existing `executionId`.
{% endhint %}
{% endtab %}

{% tab title="JS SDK" %}

### JS SDK

The **Headless Agent JS SDK** lets you build a custom chat interface while it handles the socket connection, real-time agent events, and file uploads automatically. Runs in the browser (React, Vue, or vanilla JS). Entry point: `createHeadlessAgentInstance(params)`, which returns an instance with `emit()`, `on()`, and `cleanup()` methods.

**Install & import**

```bash
npm install @uptiqai/widgets-sdk@1.181.0
```

```ts
import { createHeadlessAgentInstance } from '@uptiqai/widgets-sdk';
// TypeScript projects also import the types:
import type { HeadlessAgentInstance, AgentInterruptEvent } from '@uptiqai/widgets-sdk';
```

Authentication uses the **Widget Key**; your application's domain must be whitelisted (see **Shared prerequisites** above).

#### Create an instance

```ts
const instance = createHeadlessAgentInstance({
  config: { serverUrl: 'https://api-builder-dev.uptiq.dev', agentId: '<agent-id>', widgetKey: '<your-widget-key>', agentExecutorVersion: '1.3' },
  user: { uid: 'user-123', firstName: 'Jane', lastName: 'User', email: 'jane@example.com' },
  instanceId: 'my-chat-instance',
});
```

| Parameter    | Type           | Required | Description                                                           |
| ------------ | -------------- | -------- | --------------------------------------------------------------------- |
| `config`     | `WidgetConfig` | Yes      | `serverUrl`, `agentId`, `widgetKey`, optional `agentExecutorVersion`. |
| `user`       | `WidgetUser`   | Yes      | `uid`, `firstName`, `email` (required); `lastName` (optional).        |
| `instanceId` | string         | Yes      | Unique identifier used for socket scoping.                            |

#### Instance API

| Method    | Signature                                           | Description                                                   |
| --------- | --------------------------------------------------- | ------------------------------------------------------------- |
| `emit`    | `(event: 'query', payload: QueryPayload) => void`   | Send a query to the agent, optionally with file attachments.  |
| `on`      | `(event: 'agent-interrupt', handler) => () => void` | Subscribe to agent events. Returns an unsubscribe function.   |
| `cleanup` | `() => void`                                        | Remove listeners and disconnect the socket (call on unmount). |

<details>

<summary>Sending messages — emit('query', payload)</summary>

| Property      | Type     | Required | Description                                                  |
| ------------- | -------- | -------- | ------------------------------------------------------------ |
| `content`     | string   | Yes      | The user's message text (use `' '` when sending only files). |
| `executionId` | string   | No       | Existing execution ID to continue a conversation.            |
| `files`       | `File[]` | No       | Browser `File` objects to upload and attach.                 |

The SDK obtains presigned upload URLs, uploads each file to cloud storage, and attaches the metadata to the message automatically — just pass the `File` objects.

```ts
// New conversation
instance.emit('query', { content: 'Hello, can you help me?' });

// With attachments
instance.emit('query', { content: 'Analyze these documents', files: [file1, file2] });

// Continue an existing conversation
instance.emit('query', { content: 'Tell me more', executionId: 'existing-execution-uuid' });

// Files only (no text)
instance.emit('query', { content: ' ', files: [selectedFile] });
```

</details>

<details>

<summary>Receiving events — on('agent-interrupt', handler)</summary>

The handler receives an `AgentInterruptEvent`; branch on its `type`:

| Event `type`    | Description                  | Key fields           |
| --------------- | ---------------------------- | -------------------- |
| `agent_message` | Agent text response          | `content`, `subtype` |
| `status_update` | Progress indicator           | `status`             |
| `done`          | Execution completed          | `content` (optional) |
| `error`         | Error occurred               | `error`              |
| `tool_call`     | Agent is calling a tool      | tool details         |
| `tool_result`   | Tool call completed          | tool result          |
| `plan_update`   | Agent created/updated a plan | plan details         |

`agent_message` events carry a `subtype`: `intermediate` (streaming), `final` (complete), `question` (needs user response), `final_stream`, `output_files`, `ask_permission`.

{% hint style="warning" %}
**Don't filter only by `subtype === 'final'`** or you'll miss agent questions and streamed replies — handle `final`, `question`, and `final_stream` at minimum.
{% endhint %}

```ts
const unsubscribe = instance.on('agent-interrupt', event => {
  switch (event.type) {
    case 'agent_message':
      if (['final', 'question', 'final_stream'].includes(event.subtype) && event.content) {
        displayMessage({ role: 'agent', content: event.content });
      }
      break;
    case 'error':
      displayMessage({ role: 'system', content: event.error ?? 'An error occurred' });
      break;
    case 'status_update':
    case 'done':
    case 'tool_call':
    case 'tool_result':
    case 'plan_update':
      // optional UI handling
      break;
    default:
      console.log('Unknown event type:', event.type);
  }
});
```

</details>

<details>

<summary>Cleanup</summary>

Always call `cleanup()` (and the unsubscribe function) when you're done — e.g. on component unmount:

```ts
unsubscribe();
instance.cleanup();
```

</details>

#### React integration example

```tsx
import { createHeadlessAgentInstance } from '@uptiqai/widgets-sdk';
import type { HeadlessAgentInstance, AgentInterruptEvent } from '@uptiqai/widgets-sdk';
import { useEffect, useRef, useState } from 'react';

const config = { serverUrl: 'https://api-builder-dev.uptiq.dev', agentId: '<agent-id>', widgetKey: '<your-widget-key>', agentExecutorVersion: '1.3' };
const user = { uid: 'user-123', firstName: 'Jane', lastName: 'User', email: 'jane@example.com' };

export const ChatComponent = () => {
  const [messages, setMessages] = useState<Array<{ role: 'user' | 'agent'; content: string }>>([]);
  const instanceRef = useRef<HeadlessAgentInstance | null>(null);

  useEffect(() => {
    const instance = createHeadlessAgentInstance({ config, user, instanceId: 'my-chat-instance' });
    instanceRef.current = instance;

    const unsubscribe = instance.on('agent-interrupt', (event: AgentInterruptEvent) => {
      if (event.type === 'agent_message'
          && ['final', 'question', 'final_stream'].includes(event.subtype ?? '')
          && event.content) {
        setMessages(prev => [...prev, { role: 'agent', content: event.content! }]);
      }
    });

    return () => { unsubscribe(); instance.cleanup(); };
  }, []);

  const sendMessage = (text: string, files?: File[]) => {
    setMessages(prev => [...prev, { role: 'user', content: text }]);
    instanceRef.current?.emit('query', { content: text, files });
  };

  return <div>{messages.map((m, i) => <div key={i}>{m.role}: {m.content}</div>)}</div>;
};
```

<details>

<summary>TypeScript types</summary>

```ts
import type {
  HeadlessAgentInstance,
  QueryPayload,
  AgentInterruptEvent,
  CreateHeadlessAgentInstanceParams,
} from '@uptiqai/widgets-sdk';

type HeadlessAgentInstance = {
  emit: (event: 'query', payload: QueryPayload) => void;
  on: (event: 'agent-interrupt', handler: (event: AgentInterruptEvent) => void) => () => void;
  cleanup: () => void;
};

type QueryPayload = { content: string; executionId?: string; files?: File[] };
```

</details>

#### Best practices

* **Single instance** — create one instance per chat context and reuse it for the whole conversation.
* **Subscribe before sending** — attach your `on('agent-interrupt', …)` handler before the first `emit` so no responses are missed.
* **Handle multiple subtypes** — capture `final`, `question`, and `final_stream`, not just `final`.
* **Always clean up** — call `cleanup()` on unmount to prevent memory leaks.
* **Persist `executionId`** — store and pass it to continue a conversation across page reloads.
* **Let the SDK handle uploads** — pass `File` objects; presigned-URL upload is automatic.

{% hint style="info" %}
The SDK manages socket connections and reconnection automatically, and shares the socket across instances that use the same `user` and `config`. For server-side or backend-only execution with no browser, use the **REST API** tab instead.
{% endhint %}
{% endtab %}
{% endtabs %}

## How this relates to the agent's other settings

Whichever integration you choose, a few other settings shape how it behaves:

* [Authentication](/agent-builder/deploy/authentication.md) — the keys generated there are the credentials your embed widget, JS SDK, or API integration uses.
* [Whitelisted Domains](/agent-builder/deploy/whitelisted-domains.md) — for the embed widget and JS SDK, the agent only runs on domains in this list.
* [Secrets & Variables](/agent-builder/build/secrets-and-variables.md) — the credentials and values the agent uses at runtime; the widget, SDK, and API all invoke the agent against these same configured secrets.

Tighten these before you publish embeds or share API credentials — once a widget is live on a page, every visitor reaches the agent through whatever auth and domain rules you have set.

{% hint style="info" %}
To export the agent's full configuration as a portable package instead of running it live, see [Export Agent](/agent-builder/deploy/export-agent.md).
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.uptiq.ai/agent-builder/deploy/agent-integration.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
