Skip to content

Catalogue ​

18 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
GET/contact-center/dispositionsList the active call dispositions agents can pick during wrap-up
POST/contact-center/dispositionsCreate a wrap-up disposition, deriving its code from the name when none is given
DELETE/contact-center/dispositions/{id}Delete a wrap-up disposition from the tenant's catalogue
GET/contact-center/ivrsList the tenant's IVR flows with their published and draft version pointers
POST/contact-center/ivrsCreate an IVR flow together with its first empty draft version
GET/contact-center/ivrs/{id}Fetch one IVR with its version history and the graph of the currently live version
POST/contact-center/ivrs/{id}/publishPublish the IVR's draft version so live calls start using it, refusing an invalid flow
POST/contact-center/ivrs/{id}/validateValidation errors are data, not exceptions: the builder renders them inline
POST/contact-center/operators/{operatorId}/skillsAssign a skill to an operator at a given proficiency, updating the assignment if it already exists
POST/contact-center/queues/{queueId}/membersAdd an operator to a queue with a penalty and priority, or update the existing membership
DELETE/contact-center/queues/{queueId}/members/{operatorId}Remove an operator from a queue's membership list
POST/contact-center/queues/{queueId}/members/{operatorId}/pausePause or unpause an operator in one queue, recording the pause reason and timestamp
GET/contact-center/ring-groupsList the tenant's ring groups with their strategy, ring timeout and member counts
POST/contact-center/ring-groupsCreate a ring group with a generated slug and return its id, name and slug
PATCH/contact-center/ring-groups/{id}Update a ring group's name, extension, strategy or ring timings
DELETE/contact-center/ring-groups/{id}Delete a ring group
GET/contact-center/skillsList the tenant's active routing skills with their category and maximum proficiency
POST/contact-center/skillsCreate a routing skill with a generated slug and return its id and slug

Endpoints ​

List the active call dispositions agents can pick during wrap-up ​

GET/contact-center/dispositions
  • No scope is enforced in the handler — any valid key may call it.
  • Inactive dispositions are never returned and there is no query parameter to include them.
bash
curl -X GET "$CALLAGENT_API_URL/contact-center/dispositions" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/dispositions`, {
  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/dispositions');

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

Responses

StatusBody
200data-wrapped array

Example response, generated from the schema:

json
{
  "data": {},
  "meta": {
    "page": 1,
    "limit": 25,
    "total": 1,
    "pages": 1
  }
}

Create a wrap-up disposition, deriving its code from the name when none is given ​

POST/contact-center/dispositions
  • Requires queue.write.
  • Returns 201 with a minimal body of id and code only, not the full disposition.

Request body

FieldTypeRequiredNotes
namestringyesmax 255 chars
codestring | null—max 48 chars
outcomeresolved · unresolved · escalated · callback_scheduled · sale · no_sale …yes
descriptionstring | null—max 255 chars
requires_noteboolean | null—
schedules_callbackboolean | null—
ends_wrap_upboolean | null—
queue_idsstring[] | null—
positioninteger | null—min 0
bash
curl -X POST "$CALLAGENT_API_URL/contact-center/dispositions" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
       "name": "Support Line",
       "outcome": "resolved",
       "requires_note": true,
       "schedules_callback": true,
       "ends_wrap_up": true,
       "position": 1
     }'
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/dispositions`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "name": "Support Line",
    "outcome": "resolved",
    "requires_note": true,
    "schedules_callback": true,
    "ends_wrap_up": true,
    "position": 1
  }),
});

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/dispositions');

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([
    'name' => 'Support Line',
    'outcome' => 'resolved',
    'requires_note' => true,
    'schedules_callback' => true,
    'ends_wrap_up' => true,
    'position' => 1,
]),
]);

$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/dispositions",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    json={
      "name": "Support Line",
      "outcome": "resolved",
      "requires_note": True,
      "schedules_callback": True,
      "ends_wrap_up": True,
      "position": 1
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200JSON object

Errors

StatusWhen it happens
403Session user lacks the queue.write permission
422Validation failed; name and a known outcome are required

Delete a wrap-up disposition from the tenant's catalogue ​

DELETE/contact-center/dispositions/{id}
  • Requires queue.write.
  • This response is not data-wrapped.

Path parameters

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

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

Responses

StatusBody
200Bare JSON object, not data-wrapped

Errors

StatusWhen it happens
403Session user lacks the queue.write permission
404No disposition with this id in the caller's tenant

List the tenant's IVR flows with their published and draft version pointers ​

GET/contact-center/ivrs
  • No scope is enforced in the handler — any valid key may call it.
bash
curl -X GET "$CALLAGENT_API_URL/contact-center/ivrs" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/ivrs`, {
  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/ivrs');

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

Responses

StatusBody
200data-wrapped array

Example response, generated from the schema:

json
{
  "data": {},
  "meta": {
    "page": 1,
    "limit": 25,
    "total": 1,
    "pages": 1
  }
}

Create an IVR flow together with its first empty draft version ​

POST/contact-center/ivrs
  • Requires ivr.write.
  • Returns 201. The slug is always generated from the name; a client-supplied slug is ignored.

Request body

FieldTypeRequiredNotes
namestringyesmax 255 chars
descriptionstring | null—max 255 chars
extensionstring | null—max 24 chars
languagestring | null—max 16 chars
bash
curl -X POST "$CALLAGENT_API_URL/contact-center/ivrs" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
       "name": "Support Line"
     }'
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/ivrs`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "name": "Support Line"
  }),
});

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/ivrs');

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([
    'name' => 'Support Line',
]),
]);

$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/ivrs",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    json={
      "name": "Support Line"
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200JSON object

Errors

StatusWhen it happens
403Session user lacks the ivr.write permission
422Validation failed; name is required

Fetch one IVR with its version history and the graph of the currently live version ​

GET/contact-center/ivrs/{id}
  • No scope is enforced in the handler — any valid key may call it.

Path parameters

NameTypeRequiredNotes
idstringyes
bash
curl -X GET "$CALLAGENT_API_URL/contact-center/ivrs/01JQ0000000000000000000000" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/ivrs/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/ivrs/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/ivrs/01JQ0000000000000000000000",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200data-wrapped object

Errors

StatusWhen it happens
404No IVR with this id in the caller's tenant

Example response, generated from the schema:

json
{
  "data": {
    "id": null,
    "name": "Support Line",
    "slug": "string",
    "is_active": true,
    "versions": [
      {}
    ],
    "live_graph": {}
  }
}

Publish the IVR's draft version so live calls start using it, refusing an invalid flow ​

POST/contact-center/ivrs/{id}/publish
  • Requires ivr.write.
  • An IVR that exists but has no draft returns 404 ('IVR draft not found'), not 409.

Path parameters

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

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

Responses

StatusBody
200JSON object

Errors

StatusWhen it happens
403Session user lacks the ivr.write permission
404No IVR with this id, or the IVR has no draft version
422The draft is not valid, or the version is not in draft status

Validation errors are data, not exceptions: the builder renders them inline ​

POST/contact-center/ivrs/{id}/validate
  • No scope is enforced in the handler — any valid key may call it.
  • An invalid draft is still a 200: read the valid flag and errors array rather than the status code.

Path parameters

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

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

Responses

StatusBody
200data-wrapped object

Errors

StatusWhen it happens
404No IVR with this id, or the IVR has no draft version

Example response, generated from the schema:

json
{
  "data": {
    "valid": true,
    "errors": [
      "string"
    ]
  }
}

Assign a skill to an operator at a given proficiency, updating the assignment if it already exists ​

POST/contact-center/operators/{operatorId}/skills
  • Requires operator.write.
  • Upsert semantics: re-posting the same skill_id overwrites proficiency (default 3) and expires_at instead of erroring.

Path parameters

NameTypeRequiredNotes
operatorIdstringyes

Request body

FieldTypeRequiredNotes
skill_idstringyes
proficiencyinteger | null—min 1. max 10
expires_atstring | null—date-time
bash
curl -X POST "$CALLAGENT_API_URL/contact-center/operators/01JQ0000000000000000000000/skills" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
       "skill_id": "01JQ0000000000000000000000",
       "proficiency": 1,
       "expires_at": "2026-01-01T12:00:00+00:00"
     }'
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/operators/01JQ0000000000000000000000/skills`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "skill_id": "01JQ0000000000000000000000",
    "proficiency": 1,
    "expires_at": "2026-01-01T12:00:00+00:00"
  }),
});

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/operators/01JQ0000000000000000000000/skills');

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([
    'skill_id' => '01JQ0000000000000000000000',
    'proficiency' => 1,
    'expires_at' => '2026-01-01T12:00:00+00:00',
]),
]);

$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/operators/01JQ0000000000000000000000/skills",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    json={
      "skill_id": "01JQ0000000000000000000000",
      "proficiency": 1,
      "expires_at": "2026-01-01T12:00:00+00:00"
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200JSON object

Errors

StatusWhen it happens
403Session user lacks the operator.write permission
404No operator with this id in the caller's tenant
422skill_id is missing or does not reference an existing skill

Add an operator to a queue with a penalty and priority, or update the existing membership ​

POST/contact-center/queues/{queueId}/members
  • Requires queue.write.
  • Returns 201 even when it updated an existing membership; joined_at is reset to now on every call.

Path parameters

NameTypeRequiredNotes
queueIdstringyes

Request body

FieldTypeRequiredNotes
operator_idstringyes
penaltyinteger | null—min 0. max 100
priorityinteger | null—min 0. max 1000
membershipstatic · dynamic · null | null—
bash
curl -X POST "$CALLAGENT_API_URL/contact-center/queues/01JQ0000000000000000000000/members" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
       "operator_id": "01JQ0000000000000000000000",
       "penalty": 1,
       "priority": 1,
       "membership": "static"
     }'
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/queues/01JQ0000000000000000000000/members`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "operator_id": "01JQ0000000000000000000000",
    "penalty": 1,
    "priority": 1,
    "membership": "static"
  }),
});

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/queues/01JQ0000000000000000000000/members');

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([
    'operator_id' => '01JQ0000000000000000000000',
    'penalty' => 1,
    'priority' => 1,
    'membership' => 'static',
]),
]);

$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/queues/01JQ0000000000000000000000/members",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    json={
      "operator_id": "01JQ0000000000000000000000",
      "penalty": 1,
      "priority": 1,
      "membership": "static"
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200JSON object

Errors

StatusWhen it happens
403Session user lacks the queue.write permission
404No queue with this id in the caller's tenant
422operator_id is missing or does not reference an existing operator

Remove an operator from a queue's membership list ​

DELETE/contact-center/queues/{queueId}/members/{operatorId}
  • Requires queue.write.
  • This response is not data-wrapped.

Path parameters

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

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

Responses

StatusBody
200Bare JSON object, not data-wrapped

Errors

StatusWhen it happens
403Session user lacks the queue.write permission
404That operator is not a member of that queue

Pause or unpause an operator in one queue, recording the pause reason and timestamp ​

POST/contact-center/queues/{queueId}/members/{operatorId}/pause
  • No scope is enforced in the handler — any valid key may call it.
  • Enforces no permission at all, unlike the sibling member add/remove routes. Body fields paused (default true) and reason are unvalidated.

Path parameters

NameTypeRequiredNotes
queueIdstringyes
operatorIdstringyes

Request body

FieldTypeRequiredNotes
pausedboolean—default true
bash
curl -X POST "$CALLAGENT_API_URL/contact-center/queues/01JQ0000000000000000000000/members/01JQ0000000000000000000000/pause" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
       "paused": true
     }'
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/queues/01JQ0000000000000000000000/members/01JQ0000000000000000000000/pause`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "paused": true
  }),
});

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/queues/01JQ0000000000000000000000/members/01JQ0000000000000000000000/pause');

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([
    'paused' => true,
]),
]);

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

Responses

StatusBody
200data-wrapped object

Errors

StatusWhen it happens
404That operator is not a member of that queue

Example response, generated from the schema:

json
{
  "data": {
    "id": null,
    "is_paused": true
  }
}

List the tenant's ring groups with their strategy, ring timeout and member counts ​

GET/contact-center/ring-groups
  • No scope is enforced in the handler — any valid key may call it.
bash
curl -X GET "$CALLAGENT_API_URL/contact-center/ring-groups" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/ring-groups`, {
  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/ring-groups');

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

Responses

StatusBody
200data-wrapped array

Example response, generated from the schema:

json
{
  "data": {},
  "meta": {
    "page": 1,
    "limit": 25,
    "total": 1,
    "pages": 1
  }
}

Create a ring group with a generated slug and return its id, name and slug ​

POST/contact-center/ring-groups
  • Requires extension.write.
  • Guarded by extension.write, not a ring-group-specific permission. Returns 201 with a minimal body.

Request body

FieldTypeRequiredNotes
namestringyesmax 255 chars
extensionstring | null—max 24 chars
strategysimultaneous · sequential · round_robin · random · null | null—
ring_timeout_secondsinteger | null—min 5. max 300
member_ring_secondsinteger | null—min 5. max 120
confirm_answerboolean | null—
skip_busy_membersboolean | null—
bash
curl -X POST "$CALLAGENT_API_URL/contact-center/ring-groups" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
       "name": "Support Line",
       "strategy": "simultaneous",
       "ring_timeout_seconds": 30,
       "member_ring_seconds": 30,
       "confirm_answer": true,
       "skip_busy_members": true
     }'
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/ring-groups`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "name": "Support Line",
    "strategy": "simultaneous",
    "ring_timeout_seconds": 30,
    "member_ring_seconds": 30,
    "confirm_answer": true,
    "skip_busy_members": true
  }),
});

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/ring-groups');

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([
    'name' => 'Support Line',
    'strategy' => 'simultaneous',
    'ring_timeout_seconds' => 30,
    'member_ring_seconds' => 30,
    'confirm_answer' => true,
    'skip_busy_members' => true,
]),
]);

$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/ring-groups",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    json={
      "name": "Support Line",
      "strategy": "simultaneous",
      "ring_timeout_seconds": 30,
      "member_ring_seconds": 30,
      "confirm_answer": True,
      "skip_busy_members": True
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200JSON object

Errors

StatusWhen it happens
403Session user lacks the extension.write permission
422Validation failed; name is required

Update a ring group's name, extension, strategy or ring timings ​

PATCH/contact-center/ring-groups/{id}
  • Requires extension.write.
  • The response is only id and name; confirm_answer and skip_busy_members are accepted on create but not on update.

Path parameters

NameTypeRequiredNotes
idstringyes

Request body

FieldTypeRequiredNotes
namestring—max 255 chars
extensionstring | null—max 24 chars
strategysimultaneous · sequential · round_robin · random · null | null—
ring_timeout_secondsinteger | null—min 5. max 300
member_ring_secondsinteger | null—min 5. max 120
is_activeboolean | null—
bash
curl -X PATCH "$CALLAGENT_API_URL/contact-center/ring-groups/01JQ0000000000000000000000" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
       "name": "Support Line",
       "strategy": "simultaneous",
       "ring_timeout_seconds": 30,
       "member_ring_seconds": 30,
       "is_active": true
     }'
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/ring-groups/01JQ0000000000000000000000`, {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "name": "Support Line",
    "strategy": "simultaneous",
    "ring_timeout_seconds": 30,
    "member_ring_seconds": 30,
    "is_active": true
  }),
});

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/ring-groups/01JQ0000000000000000000000');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'PATCH',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
    'name' => 'Support Line',
    'strategy' => 'simultaneous',
    'ring_timeout_seconds' => 30,
    'member_ring_seconds' => 30,
    'is_active' => true,
]),
]);

$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.patch(
    f"{os.environ['CALLAGENT_API_URL']}/contact-center/ring-groups/01JQ0000000000000000000000",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    json={
      "name": "Support Line",
      "strategy": "simultaneous",
      "ring_timeout_seconds": 30,
      "member_ring_seconds": 30,
      "is_active": True
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200JSON object

Errors

StatusWhen it happens
403Session user lacks the extension.write permission
404No ring group with this id in the caller's tenant
422Validation failed on the ring group payload

Delete a ring group ​

DELETE/contact-center/ring-groups/{id}
  • Requires extension.write.
  • This response is not data-wrapped.

Path parameters

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

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

Responses

StatusBody
200Bare JSON object, not data-wrapped

Errors

StatusWhen it happens
403Session user lacks the extension.write permission
404No ring group with this id in the caller's tenant

List the tenant's active routing skills with their category and maximum proficiency ​

GET/contact-center/skills
  • No scope is enforced in the handler — any valid key may call it.
bash
curl -X GET "$CALLAGENT_API_URL/contact-center/skills" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/skills`, {
  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/skills');

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

Responses

StatusBody
200data-wrapped array

Example response, generated from the schema:

json
{
  "data": {},
  "meta": {
    "page": 1,
    "limit": 25,
    "total": 1,
    "pages": 1
  }
}

Create a routing skill with a generated slug and return its id and slug ​

POST/contact-center/skills
  • Requires operator.write.
  • Guarded by operator.write. category is limited to general, language, product, tier or certification.

Request body

FieldTypeRequiredNotes
namestringyesmax 255 chars
categorygeneral · language · product · tier · certification · null | null—
language_tagstring | null—max 16 chars
max_proficiencyinteger | null—min 1. max 10
descriptionstring | null—max 255 chars
bash
curl -X POST "$CALLAGENT_API_URL/contact-center/skills" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
       "name": "Support Line",
       "category": "general",
       "max_proficiency": 1
     }'
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/contact-center/skills`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "name": "Support Line",
    "category": "general",
    "max_proficiency": 1
  }),
});

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/skills');

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([
    'name' => 'Support Line',
    'category' => 'general',
    'max_proficiency' => 1,
]),
]);

$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/skills",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    json={
      "name": "Support Line",
      "category": "general",
      "max_proficiency": 1
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Responses

StatusBody
200JSON object

Errors

StatusWhen it happens
403Session user lacks the operator.write permission
422Validation failed; name is required and category must be a known value

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