Staff Departments

7 views Markdown

The six endpoints that set up support departments and assign their staff.

Overview

Departments decide which team a support ticket lands with. A client picks a department when opening one, and the staff assigned there are the people who can take it on.

A department's name and description are kept per language. Creating one wants a name in every live language on the installation, while an update changes the ones you send alone.

The icon comes in two forms: a typeface icon or an uploaded image. A separate endpoint removes the image, and the type falls back to the typeface once it goes.

Reference

Listing the Departments

get/api/v1/admin/admins/departments
Admins/GetDepartments admin

Returns the support departments and who handles them.

Query 3
pageintWhich page.
limitintRecords per page.
searchstringSearches the department name.
Response fields data[] — 7 + meta — 4
idintThe department id.
namestringIts name. In the panel's current language.
descriptionstringWhat it is for.
iconstringIts icon.
icon_typestringWhether the icon comes from a typeface or an image.
icon_urlstringThe image icon's address. Filled for an image icon alone.
appointee_idsint[]The ids of the staff handling it.
totalintHow many there are. It comes back under meta.
pageintThe page you are on.
limitintThe page size.
next_pageintThe next page.
Errors 1
insufficient_scope403The key lacks the required scope.
Request
curl 'https://panel.example.com/api/v1/admin/admins/departments' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch('https://panel.example.com/api/v1/admin/admins/departments', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const { data } = await res.json();

const orphan = data.filter((d) => d.appointee_ids.length === 0);
$ch = curl_init('https://panel.example.com/api/v1/admin/admins/departments');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// A ticket landing in a department with no staff can be assigned to NOBODY; look for empty lists.
$deps   = Api::Admins()->GetDepartments()['data'];
$orphan = array_filter($deps, fn ($d) => ! $d['appointee_ids']);

Creating a Department

post/api/v1/admin/admins/departments
Admins/CreateDepartment admin every language needed

Opens a new support department.

Body 7
namesobjectreqThe department name per language. A name is needed in every live language on the installation.
descriptionsobjectThe description per language.
rankintWhere it sits in the listing.
appointeesint[]The staff handling it. These are the people a ticket can be assigned to.
icon_typestringWhether the icon comes from a typeface or an image. A typeface by default.
iconstringThe typeface icon's class.
icon_imagestringThe icon image to upload.
Response fields 201 — data — 7
dataobjectThe department created. Same shape as the detail endpoint.
Errors 3
name_required422The name is missing in one of the live languages.
create_failed422The department could not be created.
insufficient_scope403The key lacks the required scope.
Request
curl -X POST 'https://panel.example.com/api/v1/admin/admins/departments' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"names":{"tr":"Genel","en":"General"},"appointees":[1,5]}'
const res = await fetch('https://panel.example.com/api/v1/admin/admins/departments', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    names: { en: 'General', tr: 'Genel' },
    descriptions: { en: 'General questions' },
    appointees: [1, 5],
    icon_type: 'font',
    icon: 'fa-solid fa-globe',
  }),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/admins/departments');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'names'      => ['en' => 'General', 'tr' => 'Genel'],
        'appointees' => [1, 5],
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Creating wants a name in EVERY live language; an update touches the ones you send alone.
Api::Admins()->CreateDepartment([
    'names'      => ['en' => 'General', 'tr' => 'Genel'],
    'appointees' => [1, 5],
]);

Reading One Department

get/api/v1/admin/admins/departments/{did}
Admins/GetDepartment admin

Returns one department with all of its languages.

Response fields data — 7
idintThe department id.
rankintWhere it sits in the listing.
iconstringIts icon.
icon_typestringWhether the icon comes from a typeface or an image.
icon_urlstringThe image icon's address.
appointee_idsint[]The ids of the staff handling it.
translationsobjectThe name and description per language. Every language comes together.
Errors 2
not_found404No such department.
insufficient_scope403The key lacks the required scope.
Request
curl 'https://panel.example.com/api/v1/admin/admins/departments/4' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch(`https://panel.example.com/api/v1/admin/admins/departments/${did}`, {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/admins/departments/' . $did);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// The list gives ONE language and the detail gives them all; translation work starts here.
$d = Api::Admins()->GetDepartment(['did' => $did])['data'];
$en = $d['translations']['en']['name'] ?? '';

Updating a Department

patch/api/v1/admin/admins/departments/{did}
Admins/UpdateDepartment admin

Changes the department fields and languages you send.

Body 7
namesobjectThe department name per language. Only the languages you send change.
descriptionsobjectThe description per language.
rankintWhere it sits in the listing.
appointeesint[]The staff handling it. These are the people a ticket can be assigned to.
icon_typestringWhether the icon comes from a typeface or an image. A typeface by default.
iconstringThe typeface icon's class.
icon_imagestringThe icon image to upload.
Response fields data — 7
dataobjectThe department as it now stands. Same shape as the detail endpoint.
Errors 3
not_found404No such department.
name_required422A name is empty in one of the languages you sent.
insufficient_scope403The key lacks the required scope.
Request
curl -X PATCH 'https://panel.example.com/api/v1/admin/admins/departments/4' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"names":{"tr":"Genel Destek"},"appointees":[1,5,8]}'
const res = await fetch(`https://panel.example.com/api/v1/admin/admins/departments/${did}`, {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    names: { en: 'General Support' },
    appointees: [1, 5, 8],
  }),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/admins/departments/' . $did);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PATCH',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'names'      => ['en' => 'General Support'],
        'appointees' => [1, 5, 8],
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// The staff list REPLACES what was there: read the current one before adding to it.
$d = Api::Admins()->GetDepartment(['did' => $did])['data'];
$d['appointee_ids'][] = $newStaffId;

Api::Admins()->UpdateDepartment([
    'did' => $did, 'appointees' => $d['appointee_ids'],
]);

Removing a Department

delete/api/v1/admin/admins/departments/{did}
Admins/DeleteDepartment admin

Removes a department.

Response fields data — 2
deletedboolWhether the delete ran.
idintThe id of the department removed.
Errors 3
not_found404No such department.
blocked_by_gate422A hook refused the delete.
insufficient_scope403The key lacks the required scope.
Request
curl -X DELETE 'https://panel.example.com/api/v1/admin/admins/departments/4' \
  -H "Authorization: Bearer $API_KEY"
const res = await fetch(`https://panel.example.com/api/v1/admin/admins/departments/${did}`, {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/admins/departments/' . $did);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Move the tickets sitting there to another department BEFORE removing this one.
Api::Tickets()->UpdateTicket(['id' => $ticketId, 'department_id' => $otherDid]);
Api::Admins()->DeleteDepartment(['did' => $did]);

Removing the Icon

delete/api/v1/admin/admins/departments/{did}/icon
Admins/DeleteDepartmentIcon admin

Removes a department's image icon.

Response fields data — 7
dataobjectThe department as it now stands. The icon type falls back to the typeface.
Errors 2
not_found404No such department.
insufficient_scope403The key lacks the required scope.
Request
curl -X DELETE 'https://panel.example.com/api/v1/admin/admins/departments/4/icon' \
  -H "Authorization: Bearer $API_KEY"
const res = await fetch(`https://panel.example.com/api/v1/admin/admins/departments/${did}/icon`, {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/admins/departments/' . $did . '/icon');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// The removal drops the file and turns the type back to a typeface; the icon can stay empty.
Api::Admins()->DeleteDepartmentIcon(['did' => $did]);
Api::Admins()->UpdateDepartment(['did' => $did, 'icon' => 'fa-solid fa-globe']);

Pitfalls

A department with no staff orphans its tickets

When no staff are assigned to a department, a ticket landing there can be assigned to nobody and the picker on the ticket comes back empty. The department still shows and clients still choose it, so the gap surfaces only once a ticket arrives. Sweep the listing for empty staff lists.

The staff list replaces what was there

The staff list you send on an update replaces what was assigned. Sending only the person you meant to add takes the others out of the department and changes what tickets they see. Read the detail first and merge the list.

Creating wants every language, updating does not

Creating a department wants a name in every live language on the installation, and the call is refused when one is missing. An update touches only the languages you send and keeps the rest. Reading the two behaviours as one surfaces as an unexpected error at creation.

Move the tickets before removing

Removing a department takes the footing away from the tickets bound to it. The tickets do not vanish, yet they point at a department that no longer exists and grow harder to find in the listings. Move them to another department first.

Removing the icon puts nothing in its place

The endpoint that removes an image icon drops the file and turns the type back to a typeface, while putting nothing in its place. With the typeface field empty the department shows with no icon at all. Writing a typeface icon after the removal is usually the step you want.

Was this helpful?

Thanks for your feedback!

Still Need Help?

Our support team is here around the clock for anything you can't find above.