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

# API reference

> Every method on the tai global and on an agent instance, with parameters and return types.

The embed script defines `window.tai`. Its static methods create and destroy agent instances. Everything else is a method on an instance.

## Global methods

### tai.getInstance(assistantId)

Returns the instance for an assistant ID, creating an empty one if none exists. Creating an instance does not render anything. Rendering happens when the embed script finds the matching `<div>` or when you call `initializeChatbot()`.

```javascript theme={null}
const chatbot = tai.getInstance("YOUR_ASSISTANT_ID");
```

<ParamField path="assistantId" type="string" required>
  The value of `data-chatbot-id`.
</ParamField>

### tai.getReadyInstance(assistantId)

Returns a Promise for the instance that resolves once the agent is ready. Rejects with `No instance found for assistant ID ...` if the instance was never created, which means the embed script has not processed that div yet.

```javascript theme={null}
const chatbot = await tai.getReadyInstance("YOUR_ASSISTANT_ID");
```

### tai.destroyInstance(assistantId)

Tears the agent down: removes the iframe and button, drops all listeners, clears the upload cache, and forgets the instance. Pending `sendMessage()` calls resolve with `code: "destroyed"` and pending uploads reject. Call it when a single-page app unmounts the view.

### tai.initializeAll()

Scans the document for `div[data-chatbot-id]`, initializes each one, and resolves once all are ready. The embed script calls this once on load and then dispatches `teamAIChatbotReady` on `window`. Do not call it again on a page that already has initialized agents; it appends a second iframe to each of them. For a div added later, use `initializeChatbot()` on that instance instead.

## Page events

### teamAIChatbotReady

Dispatched on `window` once every agent found by the embed script is ready. `event.detail.chatbots` is a `Map<string, TeamAIChatbot>` keyed by assistant ID.

```javascript theme={null}
window.addEventListener("teamAIChatbotReady", (event) => {
  const chatbot = event.detail.chatbots.get("YOUR_ASSISTANT_ID");
});
```

## Readiness

### ready()

Resolves when the iframe has loaded and announced itself. Never rejects. After `destroyInstance()` it resolves to nothing and no longer represents a live agent.

### conversationReady()

Resolves when the iframe has applied the current chat's history. Rejects with an `Error` carrying `code: "timeout"` after 30 seconds without history, or `code: "destroyed"`. Waits for `ready()` and any pending `identify()` first.

## Messages

### sendMessage(message)

Submits a message as the visitor. Resolves with a `ChatbotSendResult` when the iframe accepts or rejects it. Never rejects. See [Messages and status](/sdks/embed-sdk/messages-and-status) for the result codes and busy handling.

<ParamField path="message" type="string" required>
  Non-empty text. Whitespace-only text is rejected with `invalid_message`.
</ParamField>

```typescript theme={null}
type ChatbotSendResult =
  | { success: true }
  | { success: false; code: "busy" | "not_ready" | "timeout" | "destroyed" | "invalid_message"; message: string };
```

### getConversation()

Resolves with the messages currently shown in the chat. Rejects after 5 seconds without a reply. Call after `conversationReady()` to include restored history.

```typescript theme={null}
interface ConversationData {
  assistantId: string;
  messages: Array<{
    id: string;
    role: "user" | "assistant";
    content: string;
    parts: unknown[];
    timestamp: number;
  }>;
}
```

### resetConversation()

Deletes the current chat, stops any answer still streaming, and starts a new chat showing the agent's opener. Resolves with nothing. Rejects after 5 seconds without a reply, or with the iframe's error message.

## Events

The instance extends Node's `EventEmitter`. `on(event, callback)`, `once(event, callback)`, and `off(event, callback)` accept these names:

| Event               | Callback argument                                                              |
| ------------------- | ------------------------------------------------------------------------------ |
| `thinking`          | none                                                                           |
| `answering`         | none                                                                           |
| `answerComplete`    | none                                                                           |
| `agentHandoff`      | `{ targetAgentId, targetAgentName, task, reason, context }`, all strings       |
| `returnToMainAgent` | `{ completedTask, taskResults, taskSummary, additionalContext? }`, all strings |

Named helpers exist for each: `onThinking(cb)`, `onAnswering(cb)`, `onAnswerComplete(cb)`, `onAgentHandoff(cb)`, `onSpecialistReturn(cb)`. Each is `this.on(...)` with the matching event name and returns nothing.

## Context

### updateContext(newContext)

Merges `newContext` into the stored context and sends the merged object to the iframe. Keys are available in the agent's instructions as `{{key}}`. The context is sent with every request, so updates apply to the next message.

<ParamField path="newContext" type="object" required>
  Any JSON-serializable object. Existing keys are overwritten, other keys are kept.
</ParamField>

### getContext()

Returns a shallow copy of the stored context.

## Client-side tools

See [Client-side tools](/sdks/embed-sdk/client-tools) for the schema format and execution rules.

### registerTool(tool)

Stores the tool and, if the iframe is already loaded, sends the updated tool list to it. Throws `Error("Invalid tool definition...")` if `name`, `description`, or `execute` is missing.

```typescript theme={null}
interface ClientTool {
  name: string;
  displayName?: string;
  description: string;
  parameters: Record<string, any>; // JSON Schema for the tool input
  execute: (params: Record<string, any>) => Promise<any> | any;
}
```

### unregisterTool(toolName)

Removes the tool and sends the updated list to the iframe. Returns `true` if a tool with that name existed.

### getRegisteredTools()

Returns an array of the registered `ClientTool` objects.

## File uploads

See [File uploads](/sdks/embed-sdk/file-uploads) for requirements and limits.

### uploadBlob(blob)

Uploads a `Blob` or `File` through the iframe and attaches it to the chat. Resolves with the upload record. Rejects if the file is over 10 MB, the upload takes longer than 60 seconds, the embed has no `data-chatbot-embed-key`, or the iframe is not initialized.

```typescript theme={null}
interface UploadResponse {
  url: string;        // https://storage.googleapis.com/<bucket>/<objectName>
  objectName?: string;
  fileId?: string;    // same as objectName
  type?: string;      // "file"
  fileName?: string;
}
```

### clearUploadCache()

Forgets every cached upload for this assistant, in memory and in `localStorage`. The next `uploadBlob()` of the same content uploads again.

### clearExpiredUploads()

Drops cached uploads older than 30 days. The SDK does this on load as well.

## Identity

### identify(config)

Verifies the user with TeamAI and, on success, attaches the identity to every later message. Returns nothing. Failures are logged, not thrown. See [Identity verification](/sdks/embed-sdk/identity-verification).

```typescript theme={null}
interface IdentityConfig {
  user_id: string;
  user_hash: string; // HMAC-SHA256 hex of user_id, computed on your server
  user_metadata?: Record<string, any>; // up to 1000 characters serialized
}
```

## Initialization

### initializeChatbot(element)

Reads the `data-*` attributes from `element`, creates the popover button if the mode is `popover`, creates the iframe inside `element`, and starts listening for messages from it. The embed script calls this for every div it finds. Call it yourself only for a div added after the script ran.
