# Embed a Call Widget

This guide shows how to add AwajDigital calling to your own website.

Your agents stay logged in on your site. When they click Call, a phone popup opens so they can dial, answer, mute, and hang up. You keep your AwajDigital API token on your server. The browser only talks to your site; your API token never goes to the page.

You need:

1. An API token from the dashboard (**Profile → API Tokens**)
2. Call center enabled on your account
3. At least one agent — store that agent's numeric **id** on your user ([List Agents](/api-docs/call-center/agents) returns those ids)
4. Every production hostname added under **Profile → Call SDK**. Pages must be **HTTPS**. `shop.example.com` matches that host only; `*.shop.example.com` matches its subdomains (not the apex). Up to 25 domains. An empty list rejects every origin.

Give each of your users one agent. One agent can be used in only one browser at a time.

For local `http://localhost` development, turn on **localhost test mode** on the same Call SDK page (1 or 3 days). While it is on, any origin can connect, including http://localhost. It turns itself off when the window expires. localhost is not a valid allowlist entry.

## 1. Add a token route on your server

When the phone needs to connect, it POSTs to **your** site (cookies / login still apply). Your route calls us with the API token, then returns the JSON unchanged.

`POST https://api.awajdigital.com/api/sdk/token`

Send `{ "agent_id": 42 }` with `Authorization: Bearer your_api_token`.

You get `{ "token": "avt_…", "session_url": "https://api.awajdigital.com/api/sdk/session", … }`.

```php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Route;

Route::post('/amarvoice-token', function (Request $request) {
    $response = Http::withToken(config('services.awajdigital.token'))
        ->acceptJson()
        ->post('https://api.awajdigital.com/api/sdk/token', [
            'agent_id' => $request->user()->awaj_agent_id,
        ]);

    return response()->json($response->json(), $response->status());
})->middleware('auth');
```

Put this in `routes/api.php` so the browser calls `/api/amarvoice-token`. (`auth` can be `auth:sanctum` if that is what you use.)

In `.env`:

```
AWAJDIGITAL_API_TOKEN=your_api_token_here
```

In `config/services.php`:

```php
'awajdigital' => [
    'token' => env('AWAJDIGITAL_API_TOKEN'),
],
```

`awaj_agent_id` is your column. Map each logged-in user to one AwajDigital agent id.

```javascript
app.post('/api/amarvoice-token', requireAuth, async (req, res) => {
  const response = await fetch('https://api.awajdigital.com/api/sdk/token', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.AWAJDIGITAL_API_TOKEN}`,
      Accept: 'application/json',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ agent_id: req.user.awajAgentId }),
  });
  res.status(response.status).json(await response.json());
});
```

```php
$ch = curl_init('https://api.awajdigital.com/api/sdk/token');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('AWAJDIGITAL_API_TOKEN'),
        'Accept: application/json',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'agent_id' => $currentUser->awaj_agent_id,
    ]),
]);
$body = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

http_response_code($code);
header('Content-Type: application/json');
echo $body;
```

```python
import os
import requests
from flask import jsonify

@app.post('/api/amarvoice-token')
@login_required
def amarvoice_token():
    response = requests.post(
        'https://api.awajdigital.com/api/sdk/token',
        headers={
            'Authorization': f"Bearer {os.environ['AWAJDIGITAL_API_TOKEN']}",
            'Accept': 'application/json',
        },
        json={'agent_id': current_user.awaj_agent_id},
        timeout=10,
    )
    return jsonify(response.json()), response.status_code
```

If this fails: `401` bad API token, `403` call center off or agent not active, `404` that `agent_id` is not yours.

## 2. Put the widget on the page

There are two ways to start a call from your page. Most sites use the first. Both are covered in [Browser Widget](/api-docs/sdk/widget).

**Let the SDK listen to your buttons.**

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

<script src="https://dashboard.awajdigital.com/sdk/amarvoice-call.js"></script>
<script>
  const phone = new AmarVoiceCall({
    tokenUrl: '/api/amarvoice-token',
  });

  phone.mount('[data-call], #open-phone');
</script>
```

Against that HTML:

- `[data-call]` is the "Call customer" button. `data-call` is special: its value is the number. Clicking it opens the phone and starts a call to `01712345678`.
- `#open-phone` is the "Open phone" button. Any other element you pass to `mount` only opens the keypad, so the agent can type a number.
- Incoming calls open the popup too.
- The browser will ask for the microphone. That is required.

**Call from your own JavaScript** when the number is in your code, not on the button.

```html
<button type="button" id="call-selected">Call selected customer</button>

<script src="https://dashboard.awajdigital.com/sdk/amarvoice-call.js"></script>
<script>
  const phone = new AmarVoiceCall({
    tokenUrl: '/api/amarvoice-token',
  });

  phone.mount();

  // selectedCustomer.phone is your data — not a data-call attribute
  document.getElementById('call-selected').addEventListener('click', () => {
    phone.call(selectedCustomer.phone);
  });
</script>
```

`mount()` with no selector still puts the popup on the page, but does not wire any buttons. Your click handler reads the number from your own data; `phone.call` opens the popup and starts that call. Use the same `phone.call(number)` from a table row, a search result, or any other function. See [Browser Widget](/api-docs/sdk/widget) for opening the keypad only, mixing both styles, and other patterns.

## 3. Stop the session when they log out

`DELETE https://api.awajdigital.com/api/sdk/session` with `{ "agent_id": 42 }` and your API token.

```php
Http::withToken(config('services.awajdigital.token'))
    ->acceptJson()
    ->delete('https://api.awajdigital.com/api/sdk/session', [
        'agent_id' => $request->user()->awaj_agent_id,
    ]);
```

Call this in your logout action.

```javascript
await fetch('https://api.awajdigital.com/api/sdk/session', {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${process.env.AWAJDIGITAL_API_TOKEN}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ agent_id: req.user.awajAgentId }),
});
```

```php
$ch = curl_init('https://api.awajdigital.com/api/sdk/session');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('AWAJDIGITAL_API_TOKEN'),
        'Accept: application/json',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'agent_id' => $currentUser->awaj_agent_id,
    ]),
]);
curl_exec($ch);
curl_close($ch);
```

```python
requests.delete(
    'https://api.awajdigital.com/api/sdk/session',
    headers={
        'Authorization': f"Bearer {os.environ['AWAJDIGITAL_API_TOKEN']}",
        'Accept': 'application/json',
    },
    json={'agent_id': current_user.awaj_agent_id},
    timeout=10,
)
```

A call that is already connected is not cut off. The next page load starts from step 2 again.