Quick Reads

8 vues Markdown

The four read-only endpoints that search clients, give the counts and fill the summary card.

Overview

These four endpoints tell you something quickly about a client and change nothing. The panel's search box, dashboard counters and summary card all read from them.

Two look across the installation (search and statistics) and two at a single client (summary and the standout note). Whether the path carries a client id tells you which one you are on.

Reference

get/api/v1/admin/clients/search
Clients/SearchClients admin autocomplete

Searches clients by name, company or e-mail. It was written for autocomplete boxes.

Query parameters 1
qstringThe search term. The name search is accepted too.
Response fields data[] — 4
idintClient id.
full_namestringFirst and last name.
company_namestringCompany name.
textstringA ready-made display label with the name and company joined.
Errors 1
insufficient_scope403The key lacks the required scope.
Request
curl -G 'https://panel.example.com/api/v1/admin/clients/search' \
  -H "Authorization: Bearer $API_KEY" \
  -d q=acme
const url = new URL('https://panel.example.com/api/v1/admin/clients/search');
url.searchParams.set('q', 'acme');

const res  = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
const body = await res.json();
$url = 'https://panel.example.com/api/v1/admin/clients/search?' . http_build_query(['q' => 'acme']);

$ch = curl_init($url);
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()->SearchClients([], ['q' => 'acme']);

Client Statistics

get/api/v1/admin/clients/stats
Clients/GetClientsStats admin all clients

Returns the counts across every client in the installation. It looks at no single client.

Query parameters 1
periodstringThe period: all_time, today, week, month or year. Defaults to all_time.
Response fields data — 9
activeintHow many clients are active.
blockedintHow many clients are blocked.
newintHow many clients arrived in the period.
blacklistedintHow many clients are blacklisted.
active_servicesintHow many services are live.
unpaid_invoicesintHow many invoices are unpaid.
credit_balancefloatThe total credit balance. A raw number; the currency symbol is yours to add.
growth_ratefloatThe growth rate as a percentage.
totalintThe total client count in the period.
Errors 1
insufficient_scope403The key lacks the required scope.
Request
curl -G 'https://panel.example.com/api/v1/admin/clients/stats' \
  -H "Authorization: Bearer $API_KEY" \
  -d period=month
const url = new URL('https://panel.example.com/api/v1/admin/clients/stats');
url.searchParams.set('period', 'month');

const res  = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
const body = await res.json();
$url = 'https://panel.example.com/api/v1/admin/clients/stats?' . http_build_query(['period' => 'month']);

$ch = curl_init($url);
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()->GetClientsStats([], ['period' => 'month']);
Response
{
  "data": {
    "active": 120,
    "blocked": 3,
    "new": 18,
    "blacklisted": 2,
    "active_services": 340,
    "unpaid_invoices": 41,
    "credit_balance": 14620.12,
    "growth_rate": 4.5,
    "total": 145
  }
}

Client Summary

get/api/v1/admin/clients/{id}/summary
Clients/GetClientSummary admin badges and trust score

Returns summary card data for one client: revenue, service and ticket counts, badges, trust score.

Response fields data — 13
user_idintClient id.
full_namestringFirst and last name.
company_namestringCompany name.
created_atstringWhen they joined. A raw value; formatting is yours.
total_revenuefloatWhat they have paid in total so far.
revenue_currencyintCurrency id of the amount. List: reference/currencies.
paid_invoicesintHow many invoices were paid.
active_servicesintHow many services are live.
inactive_servicesintHow many services are not live.
total_ticketsintHow many tickets in total.
recent_ticketsintHow many tickets recently.
badgesobjectWhich badges were earned.
loyalboolThe membership age threshold was passed.
revenueboolThe revenue threshold was passed.
multi_serviceboolThey hold more than one live service.
experiencedboolThe past interaction threshold was passed.
trust_scoreobjectThe trust score and its parts.
totalintThe total score. Between 0 and 100.
labelstringpoor, fair, good ya da excellent.
servicesintPoints from the service axis.
revenueintPoints from the revenue axis.
ageintPoints from the account age axis.
ticketsintPoints from the support ticket axis.
Errors 2
not_found404No such client.
insufficient_scope403The key lacks the required scope.
Request
curl 'https://panel.example.com/api/v1/admin/clients/42/summary' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch('https://panel.example.com/api/v1/admin/clients/42/summary', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/42/summary');
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()->GetClientSummary(['id' => 42]);

// The parts tell you where the score came from.
$score = $response['data']['trust_score'];
$fromServices = $score['services'];
Response
{
  "data": {
    "user_id": 9,
    "full_name": "Test Client",
    "company_name": "",
    "created_at": "2021-03-18 00:00:00",
    "total_revenue": 36,
    "revenue_currency": 4,
    "paid_invoices": 1,
    "active_services": 16,
    "inactive_services": 16,
    "total_tickets": 0,
    "recent_tickets": 0,
    "badges": {
      "loyal": true,
      "revenue": false,
      "multi_service": true,
      "experienced": true
    },
    "trust_score": {
      "total": 50,
      "label": "fair",
      "services": 30,
      "revenue": 5,
      "age": 15,
      "tickets": 0
    }
  }
}

Reading the Standout Note

get/api/v1/admin/clients/{id}/latest-note
Clients/GetClientLatestNote admin pinned first

Returns one of the client's notes: the pinned one if there is one, otherwise the newest.

Response fields data — 6
idintNote id.
contentstringThe note content.
pinnedboolWhether the note is pinned.
added_byintId of the admin who added it.
added_by_namestringName of the admin who added it.
created_atstringWhen the note was added.
Errors 2
not_found404No such client.
insufficient_scope403The key lacks the required scope.
Request
curl 'https://panel.example.com/api/v1/admin/clients/42/latest-note' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch('https://panel.example.com/api/v1/admin/clients/42/latest-note', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();

// With no notes at all, data comes back null - not a 404.
if (body.data === null) return;
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/42/latest-note');
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()->GetClientLatestNote(['id' => 42]);

// On a client with no notes, 'data' is null.
$note = $response['data'] ?? null;

Pitfalls

Amounts arrive raw, not formatted

The credit balance and revenue fields are numbers without a symbol, and the date is raw too. You read the currency from its own field and do the formatting yourself. That is deliberate: the server does not know the reader's locale.

A client with no notes returns null

On a client with no notes the standout-note endpoint returns data: null, not a 404. Code that reaches straight into the fields breaks here, so check for empty first.

The trust score depends on your settings

The score in the summary is not a fixed scale; it is worked out from the tiers in your configuration. Change the tiers and the same client scores differently, so do not compare the score across installations.

Cet article vous a-t-il été utile ?

Merci pour votre retour !

Besoin d'aide supplémentaire ?

Notre équipe d'assistance est disponible 24h/24 pour tout ce que vous ne trouvez pas ci-dessus.