Supervisor
7 endpoints. Every path below is relative to the API base URL and already includes the /api/v1 prefix — see conventions for authentication, pagination, errors and idempotency.
| Endpoint | ||
|---|---|---|
| POST | /contact-center/supervisor/calls/{callId}/barge | Join a live call as an audible third party, gated and audited by the supervisor service |
| POST | /contact-center/supervisor/calls/{callId}/end | Hang up a live call on the supervisor's behalf, writing an audit record either way |
| POST | /contact-center/supervisor/calls/{callId}/listen | Attach a supervisor to a live call silently, via the gateway media leg or a FreeSWITCH eavesdrop |
| POST | /contact-center/supervisor/calls/{callId}/whisper | Attach a supervisor to a live call so only the operator hears them, gated and audited |
| POST | /contact-center/supervisor/operators/{operatorId}/force-logout | Force an operator offline and close their session, recording the supervisor action in the audit log |
| POST | /contact-center/supervisor/operators/{operatorId}/force-state | Force an operator into any state, bypassing the normal transition rules and auditing the override |
| POST | /contact-center/supervisor/queue-calls/{queueCallId}/move | Move a waiting or connected caller into another queue, refusing queues outside the supervisor's team |
Endpoints
Join a live call as an audible third party, gated and audited by the supervisor service
POST/contact-center/supervisor/calls/{callId}/barge
- Requires
operator.barge. - channel_uuid is optional: omitting it takes the browser/gateway path. Permission is checked against the session user, so API-key callers always get 403.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
callId | string | yes |
bash
curl -X POST "$CALLAGENT_API_URL/contact-center/supervisor/calls/01JQ0000000000000000000000/barge" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/supervisor/calls/01JQ0000000000000000000000/barge`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();php
<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/contact-center/supervisor/calls/01JQ0000000000000000000000/barge');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];python
import os, requests
response = requests.post(
f"{os.environ['CALLAGENT_API_URL']}/contact-center/supervisor/calls/01JQ0000000000000000000000/barge",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped object |
Errors
| Status | When it happens |
|---|---|
403 | The caller lacks the operator.barge permission |
404 | No call with this id in the caller's tenant |
422 | channel_uuid is not a string of at most 64 characters |
Example response, generated from the schema:
json
{
"data": "string"
}Hang up a live call on the supervisor's behalf, writing an audit record either way
POST/contact-center/supervisor/calls/{callId}/end
- Requires
call.end. - Permission is checked against the session user, so an API-key request with no user always gets 403.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
callId | string | yes |
bash
curl -X POST "$CALLAGENT_API_URL/contact-center/supervisor/calls/01JQ0000000000000000000000/end" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/supervisor/calls/01JQ0000000000000000000000/end`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();php
<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/contact-center/supervisor/calls/01JQ0000000000000000000000/end');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];python
import os, requests
response = requests.post(
f"{os.environ['CALLAGENT_API_URL']}/contact-center/supervisor/calls/01JQ0000000000000000000000/end",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped object |
Errors
| Status | When it happens |
|---|---|
403 | The caller lacks the call.end permission |
404 | No call with this id in the caller's tenant |
Example response, generated from the schema:
json
{
"data": "string"
}Attach a supervisor to a live call silently, via the gateway media leg or a FreeSWITCH eavesdrop
POST/contact-center/supervisor/calls/{callId}/listen
- Requires
operator.monitor. - channel_uuid is optional; without it the ESL path returns ok=false, error=no_supervisor_channel rather than an HTTP error.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
callId | string | yes |
bash
curl -X POST "$CALLAGENT_API_URL/contact-center/supervisor/calls/01JQ0000000000000000000000/listen" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/supervisor/calls/01JQ0000000000000000000000/listen`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();php
<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/contact-center/supervisor/calls/01JQ0000000000000000000000/listen');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];python
import os, requests
response = requests.post(
f"{os.environ['CALLAGENT_API_URL']}/contact-center/supervisor/calls/01JQ0000000000000000000000/listen",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped object |
Errors
| Status | When it happens |
|---|---|
403 | The caller lacks the operator.monitor permission |
404 | No call with this id in the caller's tenant |
422 | channel_uuid is not a string of at most 64 characters |
Example response, generated from the schema:
json
{
"data": "string"
}Attach a supervisor to a live call so only the operator hears them, gated and audited
POST/contact-center/supervisor/calls/{callId}/whisper
- Requires
operator.whisper.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
callId | string | yes |
bash
curl -X POST "$CALLAGENT_API_URL/contact-center/supervisor/calls/01JQ0000000000000000000000/whisper" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/supervisor/calls/01JQ0000000000000000000000/whisper`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();php
<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/contact-center/supervisor/calls/01JQ0000000000000000000000/whisper');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];python
import os, requests
response = requests.post(
f"{os.environ['CALLAGENT_API_URL']}/contact-center/supervisor/calls/01JQ0000000000000000000000/whisper",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped object |
Errors
| Status | When it happens |
|---|---|
403 | The caller lacks the operator.whisper permission |
404 | No call with this id in the caller's tenant |
422 | channel_uuid is not a string of at most 64 characters |
Example response, generated from the schema:
json
{
"data": "string"
}Force an operator offline and close their session, recording the supervisor action in the audit log
POST/contact-center/supervisor/operators/{operatorId}/force-logout
- Requires
operator.force_state. - The optional reason body field is audited but never validated. Permission is checked against the session user, so API-key callers get 403.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
operatorId | string | yes |
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
reason | string | — |
bash
curl -X POST "$CALLAGENT_API_URL/contact-center/supervisor/operators/01JQ0000000000000000000000/force-logout" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/supervisor/operators/01JQ0000000000000000000000/force-logout`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();php
<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/contact-center/supervisor/operators/01JQ0000000000000000000000/force-logout');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];python
import os, requests
response = requests.post(
f"{os.environ['CALLAGENT_API_URL']}/contact-center/supervisor/operators/01JQ0000000000000000000000/force-logout",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped object |
Errors
| Status | When it happens |
|---|---|
403 | The caller lacks the operator.force_state permission |
404 | No operator with this id in the caller's tenant |
Example response, generated from the schema:
json
{
"data": "string"
}Force an operator into any state, bypassing the normal transition rules and auditing the override
POST/contact-center/supervisor/operators/{operatorId}/force-state
- Requires
operator.force_state. - Unlike POST /operators/{id}/state this accepts engine-owned states too, because it transitions with force enabled.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
operatorId | string | yes |
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
state | offline · available · busy · ringing · on_call · wrap_up … | yes | |
reason | string | null | — | max 64 chars |
bash
curl -X POST "$CALLAGENT_API_URL/contact-center/supervisor/operators/01JQ0000000000000000000000/force-state" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"state": "offline"
}'js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/supervisor/operators/01JQ0000000000000000000000/force-state`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"state": "offline"
}),
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();php
<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/contact-center/supervisor/operators/01JQ0000000000000000000000/force-state');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'state' => 'offline',
]),
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];python
import os, requests
response = requests.post(
f"{os.environ['CALLAGENT_API_URL']}/contact-center/supervisor/operators/01JQ0000000000000000000000/force-state",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
json={
"state": "offline"
},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped object |
Errors
| Status | When it happens |
|---|---|
403 | The caller lacks the operator.force_state permission |
404 | No operator with this id in the caller's tenant |
422 | state is missing or not a known operator state |
Example response, generated from the schema:
json
{
"data": "string"
}Move a waiting or connected caller into another queue, refusing queues outside the supervisor's team
POST/contact-center/supervisor/queue-calls/{queueCallId}/move
- Requires
queue.write. - queue.write alone is not enough: the target queue is also checked against the caller's 'route' ability, and a refusal is audited.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
queueCallId | string | yes |
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
queue_id | string | yes |
bash
curl -X POST "$CALLAGENT_API_URL/contact-center/supervisor/queue-calls/01JQ0000000000000000000000/move" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"queue_id": "01JQ0000000000000000000000"
}'js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/supervisor/queue-calls/01JQ0000000000000000000000/move`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"queue_id": "01JQ0000000000000000000000"
}),
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();php
<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/contact-center/supervisor/queue-calls/01JQ0000000000000000000000/move');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'queue_id' => '01JQ0000000000000000000000',
]),
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];python
import os, requests
response = requests.post(
f"{os.environ['CALLAGENT_API_URL']}/contact-center/supervisor/queue-calls/01JQ0000000000000000000000/move",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
json={
"queue_id": "01JQ0000000000000000000000"
},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped object |
Errors
| Status | When it happens |
|---|---|
403 | The caller lacks queue.write, or the target queue belongs to another team |
404 | The queue call or the target queue does not exist in this tenant |
422 | queue_id is missing or does not reference an existing queue |
Example response, generated from the schema:
json
{
"data": "string"
}