Skip to content

Transfers ​

5 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/calls/{callId}/transferTransfer a live call blind, to a queue, to a phone or SIP destination, or start a warm consultation
GET/contact-center/transfers/{transferId}Read the state of an in-flight warm transfer, which is what a supervisor panel polls
POST/contact-center/transfers/{transferId}/briefStep 2 of a warm transfer: brief the specialist before connecting
POST/contact-center/transfers/{transferId}/cancelAbandon a warm transfer, hang up the specialist leg and take the caller off hold
POST/contact-center/transfers/{transferId}/completeStep 3 of a warm transfer: bridge the caller to the specialist and drop the transferring operator

Endpoints ​

Transfer a live call blind, to a queue, to a phone or SIP destination, or start a warm consultation ​

POST/contact-center/calls/{callId}/transfer
  • No scope is enforced in the handler — any valid key may call it.
  • A failed transfer still returns 200 with data.ok=false and an error code (no_live_channel, unknown_queue). No API-key scope is enforced

Path parameters

NameTypeRequiredNotes
callIdstringyes

Request body

FieldTypeRequiredNotes
modeblind · warm · assistant_warm · dynamic · sip · phone …yes
destination_typeassistant · squad · queue · ivr · ring_group · extension … | null—
destination_idstring | null—max 32 chars
destinationstring | null—max 255 chars
operator_idstring | null—
queue_call_idstring | null—
bash
curl -X POST "$CALLAGENT_API_URL/contact-center/calls/01JQ0000000000000000000000/transfer" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
       "mode": "blind",
       "destination_type": "assistant",
       "destination_id": "01JQ0000000000000000000000",
       "operator_id": "01JQ0000000000000000000000",
       "queue_call_id": "01JQ0000000000000000000000"
     }'
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/calls/01JQ0000000000000000000000/transfer`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "mode": "blind",
    "destination_type": "assistant",
    "destination_id": "01JQ0000000000000000000000",
    "operator_id": "01JQ0000000000000000000000",
    "queue_call_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/calls/01JQ0000000000000000000000/transfer');

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([
    'mode' => 'blind',
    'destination_type' => 'assistant',
    'destination_id' => '01JQ0000000000000000000000',
    'operator_id' => '01JQ0000000000000000000000',
    'queue_call_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/calls/01JQ0000000000000000000000/transfer",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    json={
      "mode": "blind",
      "destination_type": "assistant",
      "destination_id": "01JQ0000000000000000000000",
      "operator_id": "01JQ0000000000000000000000",
      "queue_call_id": "01JQ0000000000000000000000"
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200JSON object

Errors

StatusWhen it happens
404No call with that id in this organization
422Validation failed, or a warm transfer is missing its operator_id or destination

Example response, generated from the schema:

json
{
  "data": {
    "ok": "string",
    "mode": "string",
    "error": "string",
    "queued": true,
    "bridged": "string",
    "queue_call_id": null
  }
}

Read the state of an in-flight warm transfer, which is what a supervisor panel polls ​

GET/contact-center/transfers/{transferId}
  • No scope is enforced in the handler — any valid key may call it.
  • Backed by a cache entry keyed only on the transfer id, with no organization in the key, and no API-key scope is enforced

Path parameters

NameTypeRequiredNotes
transferIdstringyes
bash
curl -X GET "$CALLAGENT_API_URL/contact-center/transfers/01JQ0000000000000000000000" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/transfers/01JQ0000000000000000000000`, {
  method: 'GET',
  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/transfers/01JQ0000000000000000000000');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    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.get(
    f"{os.environ['CALLAGENT_API_URL']}/contact-center/transfers/01JQ0000000000000000000000",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200data-wrapped array

Errors

StatusWhen it happens
404No pending transfer with that id, or it has expired from the cache

Example response, generated from the schema:

json
{
  "data": {}
}

Step 2 of a warm transfer: brief the specialist before connecting ​

POST/contact-center/transfers/{transferId}/brief
  • No scope is enforced in the handler — any valid key may call it.
  • An unknown or expired transfer id returns 200 with data.ok=false and error=unknown_transfer, never a 404. No scope is enforced

Path parameters

NameTypeRequiredNotes
transferIdstringyes

Request body

FieldTypeRequiredNotes
queue_call_idstring—
bash
curl -X POST "$CALLAGENT_API_URL/contact-center/transfers/01JQ0000000000000000000000/brief" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
       "queue_call_id": "01JQ0000000000000000000000"
     }'
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/transfers/01JQ0000000000000000000000/brief`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "queue_call_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/transfers/01JQ0000000000000000000000/brief');

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_call_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/transfers/01JQ0000000000000000000000/brief",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    json={
      "queue_call_id": "01JQ0000000000000000000000"
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200data-wrapped object

Example response, generated from the schema:

json
{
  "data": {
    "ok": "string",
    "error": "string",
    "briefing": {
      "version": 1,
      "assembled_at": "2026-01-01T12:00:00+00:00",
      "reason": "string",
      "reason_label": "Customer asked for a person",
      "caller": {},
      "assistant": {},
      "call": {},
      "summary": "string",
      "intent": "string",
      "topics": "string",
      "sentiment": {},
      "transcript": [],
      "transcript_truncated": true,
      "tool_results": [],
      "customer": {},
      "caller_history": {},
      "recommended_action": "string",
      "variables": {}
    },
    "spoken": "string"
  }
}

Abandon a warm transfer, hang up the specialist leg and take the caller off hold ​

POST/contact-center/transfers/{transferId}/cancel
  • No scope is enforced in the handler — any valid key may call it.
  • An unknown or expired transfer id returns 200 with data.ok=false and error=unknown_transfer, never a 404. No scope is enforced

Path parameters

NameTypeRequiredNotes
transferIdstringyes
bash
curl -X POST "$CALLAGENT_API_URL/contact-center/transfers/01JQ0000000000000000000000/cancel" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/transfers/01JQ0000000000000000000000/cancel`, {
  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/transfers/01JQ0000000000000000000000/cancel');

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/transfers/01JQ0000000000000000000000/cancel",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200data-wrapped object

Example response, generated from the schema:

json
{
  "data": {
    "ok": true,
    "error": null
  }
}

Step 3 of a warm transfer: bridge the caller to the specialist and drop the transferring operator ​

POST/contact-center/transfers/{transferId}/complete
  • No scope is enforced in the handler — any valid key may call it.
  • An unknown or expired transfer id returns 200 with data.ok=false and error=unknown_transfer, never a 404. No scope is enforced

Path parameters

NameTypeRequiredNotes
transferIdstringyes
bash
curl -X POST "$CALLAGENT_API_URL/contact-center/transfers/01JQ0000000000000000000000/complete" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/transfers/01JQ0000000000000000000000/complete`, {
  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/transfers/01JQ0000000000000000000000/complete');

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/transfers/01JQ0000000000000000000000/complete",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200data-wrapped object

Example response, generated from the schema:

json
{
  "data": {
    "ok": "string",
    "error": "string"
  }
}

Documented against the code. Anything not yet implemented is labelled, never described as working.