# Exchange Session

`POST /api/sdk/session`

The [browser widget](/api-docs/sdk/widget) calls this from the page with the token your backend returned from [Mint SDK Token](/api-docs/sdk/token). Do not send your API Bearer token here.

You do not need to call this endpoint or handle the response. The widget uses the result automatically to connect and place calls.

Your page must be served over HTTPS on a hostname you have added under **Profile → Call SDK** (see the [embed guide](/api-docs/sdk)). For `http://localhost`, turn on test mode there instead.

## Request Parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| token | string | Yes | The token from your backend. 16–128 characters. |

## Request Example

The examples below are for debugging. Production traffic is the widget in the browser.

```bash
curl -X POST https://api.awajdigital.com/api/sdk/session \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -H "Origin: https://shop.example.com" \
  -d '{
    "token": "avt_…"
  }'
```

```javascript
// The widget does this. You do not need this code.
const response = await fetch('https://api.awajdigital.com/api/sdk/session', {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
  },
  credentials: 'omit',
  body: JSON.stringify({
    token: avtTokenFromYourBackend
  })
});

const session = await response.json();
console.log(session);
```

```javascript
// Node.js with axios — for testing only.
const axios = require('axios');

async function exchangeSdkSession(token) {
  try {
    const response = await axios.post('https://api.awajdigital.com/api/sdk/session', {
      token
    }, {
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
        'Origin': 'https://shop.example.com'
      }
    });

    console.log(response.data);
  } catch (error) {
    console.error('Error:', error.response?.data || error.message);
  }
}

exchangeSdkSession('avt_…');
```

```python
# Python with requests — for testing only.
import requests

def exchange_sdk_session(token):
    url = 'https://api.awajdigital.com/api/sdk/session'
    headers = {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
        'Origin': 'https://shop.example.com'
    }
    data = {
        'token': token
    }

    try:
        response = requests.post(url, json=data, headers=headers)
        print(response.json())
    except requests.exceptions.RequestException as e:
        print(f'Error: {e}')

exchange_sdk_session('avt_…')
```

```php
<?php
// PHP with cURL — for testing only.
$url = 'https://api.awajdigital.com/api/sdk/session';

$data = [
    'token' => 'avt_…'
];

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Accept: application/json',
    'Content-Type: application/json',
    'Origin: https://shop.example.com'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response, true);
print_r($result);
?>
```

## Success Response Example

The widget uses this payload automatically. You can ignore these fields unless you are building your own client.

```json
{
  "wss_url": "wss://pbxfs1wss.awajdigital.com",
  "domain": "agent.example.awajdigital.com",
  "extension": "1001",
  "sip_username": "1001",
  "sip_password": "a1b2c3d4e5f6…",
  "expires_in": 43200,
  "expires_at": "2026-09-07T00:00:00.000+06:00",
  "ice_servers": [
    {
      "urls": ["stun:stun.l.google.com:19302"]
    }
  ]
}
```

| Field | Type | Description |
| --- | --- | --- |
| wss_url | string | WebSocket URL the phone registers against. |
| domain | string | Domain for this agent. |
| extension | string | Extension number. |
| sip_username | string | Username for this session. |
| sip_password | string | Password for this session. Do not persist in your app. |
| expires_in | integer | Advisory lifetime in seconds. Ends sooner if you connect again or revoke. |
| expires_at | string | ISO 8601 advisory expiry. |
| ice_servers | array | Connection servers (`urls`, optional `username` / `credential`). |

## Error Responses

| Status | Code | Description |
| --- | --- | --- |
| 401 | `token_invalid` | Token missing, already used, expired, or unknown |
| 403 | `agent_inactive` | Agent was deactivated or unapproved after the token was created |
| 403 | `origin_not_allowed` | This page is not on HTTPS, or its hostname is not on your Call SDK allowed-domain list (and test mode is off) |
| 422 | — | Validation failed (`token` missing or wrong length) |
| 429 | — | Too many requests |

```json
{
  "error": "invalid or expired token",
  "code": "token_invalid"
}
```