# JS API and events

> Open the chat, ask a question for the visitor, say who they are, and learn when a conversation goes to people.

Your page can control `<tolkly-chat>` with methods on the element and listen to three events. A
plain install needs none of this.

## Getting the element

The methods appear once the script defines the element. Wait for that:

```js
await customElements.whenDefined('tolkly-chat')
const chat = document.querySelector('tolkly-chat')
chat.open()
```

## Methods

| Method | What it does |
|---|---|
| `open({ focus })` | Opens the chat. Loads its window first if needed. By default, focus moves into the chat; `focus: false` leaves it where it is. |
| `close()` | Minimizes the chat. Does nothing on an `inline` chat. |
| `ask(text)` | Opens the chat if it is closed and sends `text` as the visitor's message. Returns a promise. Does nothing if `text` is empty or an answer is still coming. The server accepts up to 1000 characters. |
| `identify(token)` | Tells the chat who the visitor is, with a token your server signed. Call it after the visitor signs in on your site ([identity](https://tolkly.io/docs/en/identity.md#pass-the-token)). |
| `identify({ id, name, email, phone, fields })` | Tells the chat who the visitor is, without a signature. Operators see the visitor marked «not verified». Such a visitor never gets a history shared across devices. Only `id` is required. |
| `reset()` | Call it on sign-out. Forgets the visitor and the conversation stored in this browser, and the chat starts over. Also stop rendering `data-identity`. |

## Suggested questions
`suggestions` is a property, not an attribute. It holds questions the chat offers before the first
message. Set on a page, they replace the questions from «Widget» on that page, for example a
question about one exchange direction on its own page.

```js
chat.suggestions = ['How long does a withdrawal take?', 'Which documents do you need?']
chat.suggestions = null // the questions from «Widget» again
```

The chat keeps up to 6 and drops empty ones. They show only until the visitor's first message.
Questions set by a page are not counted in the report; the ones from «Widget» are
([Frequent questions](https://tolkly.io/docs/en/widget.md#suggestions)).

## Events

All three events bubble and cross the shadow root (`composed`). So you can listen on `document`:

```js
document.addEventListener('tolkly:handoff', (event) => {
  const { reason, tokens } = event.detail
  console.log('handed to people:', reason, tokens)
})

document.addEventListener('tolkly:resolved', (event) => {
  console.log('the visitor says this answer helped:', event.detail.answerId)
})
```

### `tolkly:handoff`
The conversation goes to people. The event fires in this tab when:

- the bot hands the conversation over while answering a message;
- a message goes straight to people: in operators-only mode, after the AI limit is spent (the
  company's month or the project's daily guard), or when the visitor sends a file on its own;
- the visitor presses the button that calls a person.

It does not fire when:

- the bot refuses to answer;
- the bot only offers a person;
- the visitor follows the `handoff` link;
- an operator joins;
- a conversation is restored on page load.

`detail.tokens` lists order numbers and transaction hashes found in the question:
`{ kind: 'order' | 'tx', value: string }[]`. `detail.reason` is one of:

| `reason` | Why |
|---|---|
| `requested` | The visitor asked for a person. |
| `personal_case` | The question is about the visitor's own order, payment or account. Only staff can check it. |
| `topic` | The message is about one of the topics the project sends to a person. |
| `operators_only` | The project runs without the AI: every message goes to people. |
| `cap_reached` | The AI limit is spent: the company's month of AI conversations ([Plan, payment and limit](https://tolkly.io/docs/en/billing.md#cap)) or the project's daily guard ([How Tolkly answers](https://tolkly.io/docs/en/overview.md#daily-cap)). People answer instead of the bot. |
| `attachment` | The visitor sent a file, which the bot does not read. |
| `scenario` | The project's order system did not answer for the bot (an error, a timeout, an unknown status), so people take it. |

### `tolkly:resolved`
The visitor pressed «It helped» under a bot answer. `detail.answerId` is the answer's id, or
`null` if the chat does not know it. The event fires once per answer. It does not fire for the
rating the visitor gives after an operator closes a conversation.

### `tolkly:unread`
The replies the visitor has not read changed. `detail.unread` is their count, `detail.ask` is
`true` when the chat asks for a contact the visitor has not seen yet. It fires only on a change.
With `launcher="none"` this is how your page shows the mark the button would have shown:

```js
document.addEventListener('tolkly:unread', (event) => {
  const { unread, ask } = event.detail
  helpButton.classList.toggle('has-news', unread > 0 || ask)
})
```

## Language
The chat uses the language of its `lang` attribute. Without it, the chat uses `<html lang>`.

The chat watches both. If your site switches language without a reload, or sets
`chat.lang = 'ru'`, the chat redraws itself in the new language and loads the conversation from
the server again.

The chat has texts in 15 languages: `en`, `ru`, `hy`, `kk`, `uz`, `az`, `ka`, `ky`, `tg`, `uk`,
`tr`, `de`, `es`, `fr` and `pt`. Any other language gets the project's primary language
([How the chat looks](https://tolkly.io/docs/en/widget.md#language)), or English when none is set, but operators' names
still follow the page's language.
