Client Configuration

8 views Markdown

The six endpoints that read and save client groups, badge thresholds and trust score tiers.

Overview

These six endpoints read and write the installation-wide client configuration: groups, badge thresholds and trust score tiers. None of them looks at an individual client.

The trust score is worked out on four axes: service count, revenue, account age and support tickets. Each axis is a list of tiers, and a client scores whatever the tier they fall into is worth.

Reference

Listing the Groups

get/api/v1/admin/clients/groups
Clients/GetClientGroups admin

Returns every client group in the installation.

Response fields data[] — 11
idintId of an existing group. Leave it out or send 0 for a new one.
namestringrequiredThe group name. If it is empty the group is quietly skipped.
descriptionstringA description.
colorstringBadge colour. Defaults to #095174.
iconstringIcon name.
discount_ratenumberThe discount rate applied to the group.
discount_productsstringProduct groups the discount covers. Comma-separated ids.
combine_discountboolLets the discount stack with other discounts.
protectionboolPuts the group under protection.
priorityintPriority order.
separate_invoicesboolIssues separate invoices for the clients in the group.
Errors 1
insufficient_scope403The key lacks the required scope.
Request
curl 'https://panel.example.com/api/v1/admin/clients/groups' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch('https://panel.example.com/api/v1/admin/clients/groups', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/groups');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Clients()->GetClientGroups();

Saving the Groups

put/api/v1/admin/clients/groups
Clients/SaveClientGroups admin the whole list

Saves the group list as it stands. The list you send becomes the truth: a group missing from it is deleted.

Body 1
groupsobject[]requiredThe complete set of groups.
idintId of an existing group. Leave it out or send 0 for a new one.
namestringrequiredThe group name. If it is empty the group is quietly skipped.
descriptionstringA description.
colorstringBadge colour. Defaults to #095174.
iconstringIcon name.
discount_ratenumberThe discount rate applied to the group.
discount_productsstringProduct groups the discount covers. Comma-separated ids.
combine_discountboolLets the discount stack with other discounts.
protectionboolPuts the group under protection.
priorityintPriority order.
separate_invoicesboolIssues separate invoices for the clients in the group.
Response fields data[] — 11
dataobject[]The group list as it now stands. Same shape as the listing endpoint.
Errors 2
groups_invalid422groups is not an array.
insufficient_scope403The key lacks the required scope.
Request
curl -X PUT 'https://panel.example.com/api/v1/admin/clients/groups' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"groups":[{"id":5,"name":"VIP","discount_rate":10,"discount_products":"1,2","priority":1}]}'
// Read the list first, change it, then send all of it back.
const current = await (await fetch('https://panel.example.com/api/v1/admin/clients/groups', {
  headers: { Authorization: `Bearer ${apiKey}` },
})).json();

const groups = current.data.map((g) =>
  g.id === 5 ? { ...g, discount_rate: 15 } : g);

const res = await fetch('https://panel.example.com/api/v1/admin/clients/groups', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ groups }),
});
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/groups');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PUT',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'groups' => [
            [
                'id'            => 5,
                'name'          => 'VIP',
                'discount_rate' => 10,
                'priority'      => 1,
            ],
        ],
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Even to change one group, the WHOLE list goes back.
$groups = Api::Clients()->GetClientGroups()['data'];

foreach ($groups as &$group)
    if ((int) $group['id'] === 5) $group['discount_rate'] = 15;
unset($group);

$response = Api::Clients()->SaveClientGroups(['groups' => $groups]);

Reading the Badge Thresholds

get/api/v1/admin/clients/badge-settings
Clients/GetBadgeSettings admin

Returns the thresholds at which client badges are earned. If none were saved, you get the defaults.

Response fields data — 5
loyal_yearsintYears needed for the loyal client badge.
rev_silverintRevenue threshold for the silver badge.
rev_goldintRevenue threshold for the gold badge.
multi_service_minintFewest services needed for the multi-service badge.
experienced_maxintUpper bound of the experienced badge.
Errors 1
insufficient_scope403The key lacks the required scope.
Request
curl 'https://panel.example.com/api/v1/admin/clients/badge-settings' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch('https://panel.example.com/api/v1/admin/clients/badge-settings', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/badge-settings');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Clients()->GetBadgeSettings();

Saving the Badge Thresholds

put/api/v1/admin/clients/badge-settings
Clients/SaveBadgeSettings admin values get trimmed

Saves all five thresholds at once. One you leave out drops back to its default, so send the whole set. Values are pulled into a safe range rather than refused.

Body 5
loyal_yearsintLoyal client year threshold. Minimum 1.
rev_silverintSilver revenue threshold. Minimum 0.
rev_goldintGold revenue threshold. If you send it at or below silver it becomes rev_silver + 1.
multi_service_minintMulti-service badge minimum. Minimum 1.
experienced_maxintExperienced badge upper bound. Minimum 0.
Response fields data — 5
dataobjectThe thresholds as they now stand. Same shape as the read endpoint.
Errors 1
insufficient_scope403The key lacks the required scope.
Request
curl -X PUT 'https://panel.example.com/api/v1/admin/clients/badge-settings' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"loyal_years":5,"rev_silver":500,"rev_gold":1000,"multi_service_min":5,"experienced_max":15}'
const res = await fetch('https://panel.example.com/api/v1/admin/clients/badge-settings', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    loyal_years: 5,
    rev_silver: 500,
    rev_gold: 1000,
    multi_service_min: 5,
    experienced_max: 15,
  }),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/badge-settings');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PUT',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'loyal_years'       => 5,
        'rev_silver'        => 500,
        'rev_gold'          => 1000,
        'multi_service_min' => 5,
        'experienced_max'   => 15,
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Clients()->SaveBadgeSettings([
    'rev_silver' => 500,
    'rev_gold'   => 400,
]);

// The response carries what was stored: rev_gold comes back as 501 here.
$saved = $response['data']['rev_gold'];

Reading the Trust Score Tiers

get/api/v1/admin/clients/trust-score-settings
Clients/GetTrustScoreSettings admin

Returns the tiers on all four trust score axes. If none were saved, you get the defaults.

Response fields data — 4
servicesobject[]The service count axis.
maxint | nullrequiredThe upper bound of the tier. null is the last, unbounded tier.
pointsintrequiredThe points the tier is worth.
revenueobject[]The revenue axis.
maxint | nullrequiredThe upper bound of the tier. null is the last, unbounded tier.
pointsintrequiredThe points the tier is worth.
ageobject[]The account age axis.
maxint | nullrequiredThe upper bound of the tier. null is the last, unbounded tier.
pointsintrequiredThe points the tier is worth.
ticketsobject[]The support ticket axis.
maxint | nullrequiredThe upper bound of the tier. null is the last, unbounded tier.
pointsintrequiredThe points the tier is worth.
Errors 1
insufficient_scope403The key lacks the required scope.
Request
curl 'https://panel.example.com/api/v1/admin/clients/trust-score-settings' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch('https://panel.example.com/api/v1/admin/clients/trust-score-settings', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/trust-score-settings');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Clients()->GetTrustScoreSettings();
Response
{
  "data": {
    "services": [
      { "max": 5, "points": 20 },
      { "max": null, "points": 30 }
    ],
    "revenue": [{ "max": 1000, "points": 25 }],
    "age":     [{ "max": 12, "points": 10 }],
    "tickets": [{ "max": null, "points": 5 }]
  }
}

Saving the Trust Score Tiers

put/api/v1/admin/clients/trust-score-settings
Clients/SaveTrustScoreSettings admin all four axes at once

Saves all four axes at once. An axis you leave out is saved empty and loses its tiers, so send every axis you want to keep.

Body 4
servicesobject[]Service count tiers.
maxint | nullrequiredThe upper bound of the tier. null is the last, unbounded tier.
pointsintrequiredThe points the tier is worth.
revenueobject[]Revenue tiers.
maxint | nullrequiredThe upper bound of the tier. null is the last, unbounded tier.
pointsintrequiredThe points the tier is worth.
ageobject[]Account age tiers.
maxint | nullrequiredThe upper bound of the tier. null is the last, unbounded tier.
pointsintrequiredThe points the tier is worth.
ticketsobject[]Support ticket tiers.
maxint | nullrequiredThe upper bound of the tier. null is the last, unbounded tier.
pointsintrequiredThe points the tier is worth.
Response fields data — 4
dataobjectThe tiers as they now stand. Same shape as the read endpoint.
Errors 1
insufficient_scope403The key lacks the required scope.
Request
curl -X PUT 'https://panel.example.com/api/v1/admin/clients/trust-score-settings' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"services":[{"max":5,"points":20},{"max":null,"points":30}]}'
const res = await fetch('https://panel.example.com/api/v1/admin/clients/trust-score-settings', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    services: [
      { max: 5, points: 20 },
      { max: null, points: 30 },
    ],
  }),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/trust-score-settings');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PUT',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'services' => [
            ['max' => 5,    'points' => 20],
            ['max' => null, 'points' => 30],
        ],
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// The last tier needs 'max' => null, or a client above the bound scores nothing.
$response = Api::Clients()->SaveTrustScoreSettings([
    'services' => [
        ['max' => 5,    'points' => 20],
        ['max' => null, 'points' => 30],
    ],
]);

Pitfalls

Saving groups replaces the whole list

The save endpoint does not merge. A group missing from the list you send is deleted, and the clients in it are left without one. To change a single group, read the list first, edit it, and send all of it back.

The gold threshold is pushed above silver

Sending the gold revenue threshold at or below silver does not raise an error; the value quietly becomes rev_silver + 1. Read the response to see what was stored.

The last tier has to be unbounded

Leave max as null on an axis's last tier. Otherwise a client above the highest bound falls into no tier and scores nothing on that axis.

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.