# Browser Widget

Load the script from:

```
https://dashboard.awajdigital.com/sdk/amarvoice-call.js
```

That makes `AmarVoiceCall` available on the page. The phone popup sits in the bottom-right corner and uses its own styles, so your page CSS will not restyle it. It still opens from `open()`, `call()`, or an incoming call if you never pass a button.

HTTPS is required. Add production hostnames under **Profile → Call SDK**. For `http://localhost`, turn on localhost test mode on that page (1 or 3 days).

## Init

```javascript
const phone = new AmarVoiceCall({
  tokenUrl: '/api/amarvoice-token',
  callbacks: {
    onRegistrationState: (state) => {},
    onIncomingCall: ({ remoteParty, remoteName }) => {},
    onCallAnswered: () => {},
    onCallEnded: () => {},
    onError: (message) => {},
    onMuteChanged: (muted) => {},
  },
});

phone.mount('[data-call]');
```

`mount` puts the phone popup on the page and starts connecting in the background. How a call starts is below.

| Option | Type | Required | Description |
| --- | --- | --- | --- |
| tokenUrl | string | Yes* | Your login-protected route that proxies [Mint SDK Token](/api-docs/sdk/token). |
| sessionUrl | string | No | Override for `POST /api/sdk/session`. Taken from the token response when omitted. |
| token | string | No | Already-created token. Use `tokenUrl` instead unless you create it yourself. |
| callbacks | object | No | Optional hooks; the widget still updates itself without them. |

\* Pass `tokenUrl`, or pass both `token` and `sessionUrl`.

The SDK POSTs `tokenUrl` when the user connects (not on page load). After `disconnect()`, create a new `AmarVoiceCall` so it can request a token again.

## Two ways to start a call

Both use the same `AmarVoiceCall` object. `mount` always adds the popup. The difference is who handles the click.

### Let the SDK listen to your buttons

Pass a selector for the elements that should open the phone.

```html
<button type="button" data-call="01712345678">Call customer</button>
<button type="button" id="open-phone">Open phone</button>
```

```javascript
phone.mount('[data-call], #open-phone');
```

Against that HTML:

- Click **Call customer** — the element has `data-call="01712345678"`, so the popup opens and a call starts to that number.
- Click **Open phone** — no `data-call`, so the keypad opens empty and the agent types the number.

Any element you pass to `mount` opens the phone. `data-call="01…"` is the special part: that value is the destination, and the call starts. Without it, the agent uses the keypad.

You can pass a selector, a DOM element, or a list of elements. A second `mount` replaces the first.

```javascript
phone.mount('#open-phone');
phone.mount(document.getElementById('open-phone'));
phone.mount(document.querySelectorAll('[data-call]'));
```

### Call from your own JavaScript

Use this when the number is already in your JavaScript — a selected row, a search result, or a handler you already have. Do not put `data-call` on those elements. Call `mount()` with no selector so the popup is on the page, then `phone.call(number)` from your code.

**From a function**

```javascript
const phone = new AmarVoiceCall({
  tokenUrl: '/api/amarvoice-token',
});

phone.mount();

function callCustomer(number) {
  phone.call(number);
}

callCustomer('01712345678');
```

`mount()` adds the popup without wiring buttons. `phone.call` opens it and starts the call to that number — same result as clicking a `data-call` button.

**From your own click handler**

```html
<tr data-phone="01712345678">
  <td>Ayesha</td>
  <td><button type="button" class="call-btn">Call</button></td>
</tr>
```

```javascript
phone.mount();

document.querySelectorAll('[data-phone]').forEach((row) => {
  row.querySelector('.call-btn').addEventListener('click', () => {
    phone.call(row.getAttribute('data-phone'));
  });
});
```

The number lives on the row (or in your app state), not in `data-call`. Your handler decides which number to dial.

**Open the keypad without starting a call**

```javascript
phone.mount();
phone.open();
```

Use this for a toolbar button or shortcut that should only show the dialer. The agent types the number.

**Mix both**

```javascript
phone.mount('[data-call]');

function callFromSearch(number) {
  phone.call(number);
}
```

The SDK still listens to `data-call` buttons. Other parts of your page call `phone.call` with a number they already have. Incoming calls open the popup in all of these.

## Methods

| Method | Description |
| --- | --- |
| `mount(target?)` | Attach the popup to buttons (or to the page with no trigger). Returns `this`. |
| `unmount()` | Remove the popup and unbind those buttons. |
| `open()` / `close()` / `isOpen()` | Show or hide the panel. |
| `connect()` | Start the session. `mount()` already calls this. |
| `call(number)` | Place an outbound call. Also available as `placeCall(number)`. Opens the popup. Does nothing on an empty string; errors if a call is already in progress. |
| `answer()` / `reject()` | Answer or decline an incoming call. |
| `hangup()` | End the current call (outbound or inbound). |
| `mute()` / `unmute()` / `setMuted(boolean)` | Mute the local microphone on an **established** call. Does not put the other party on hold. |
| `isMuted()` / `isOnCall()` | Current mute / call flags. |
| `setAudioElement(el)` | Where remote audio plays. If omitted, `connect()` creates a hidden `<audio>` element. |
| `disconnect()` | Sign out of the phone and return the popup to idle. Create a new `AmarVoiceCall` to connect again. |

## Callbacks

| Callback | When |
| --- | --- |
| `onRegistrationState(state)` | `state` is `registering`, `registered`, `failed`, or `disconnected`. |
| `onIncomingCall({ remoteParty, remoteName })` | An incoming call. The popup opens itself. |
| `onCallAnswered()` | Call established (outbound or inbound). |
| `onCallEnded()` | Call terminated (local hangup, remote hangup, or failure after ringing). |
| `onError(message)` | Connect failure, mute with no call, overlapping `call()`, or a call error. |
| `onMuteChanged(muted)` | Mute applied or cleared, including on hangup. |

## In the popup

- **Idle** — number field, 12-key pad, Call.
- **Ringing out** — destination + Hang up.
- **Ringing in** — remote party, Answer, Decline.
- **Active** — duration, Mute / Unmute, Hang up.
- **Ended** — returns to idle after a short pause.

The widget requests the microphone when a call starts. The user must allow it.

## Cleanup

```javascript
phone.unmount();
await phone.disconnect();
```

Call these when your user leaves the page or logs out, and revoke the agent session from your backend with [Revoke Session](/api-docs/sdk/revoke).