Hızlı Okumalar

1.7k görüntülenme Markdown

Müşteri arayan, sayıları veren, özet kartını dolduran, müşterinin etkinliğini ve ona gönderilen mesajları listeleyen, hiçbir şeyi değiştirmeyen altı uç.

Genel Bakış

Bu altı uç bir müşteri hakkında hızlı bilgi verir ve hiçbir şeyi değiştirmez. Panelde arama kutusu, pano sayıları ve özet kartı bunları kullanır; iki liste ucu da müşteri sayfasındaki Etkinlik ve Mesajlar sekmeleriyle aynı kayıtları döndürür.

İkisi kurulum geneline bakar (arama ve istatistikler), dördü tek bir müşteriye (özet, öne çıkan not, etkinlik ve gönderilen mesajlar). Adres içinde müşteri kimliği olup olmaması hangisinde olduğunuzu söyler.

Referans

get/api/v1/admin/clients/search
Clients/SearchClients admin otomatik tamamlama

Ada, firmaya ya da e-postaya göre müşteri arar. Otomatik tamamlama kutuları için yazılmıştır.

Sorgu parametreleri 1
qstringArama terimi. search adı da kabul edilir.
Dönen alanlar data[] — 4
idintMüşteri kimliği.
full_namestringAd ve soyad.
company_namestringFirma adı.
textstringHazır görüntü etiketi: ad ve firma birleştirilmiş.
Hatalar 1
insufficient_scope403Anahtar gerekli kapsamı taşımıyor.
İstek
curl -G 'https://panel.ornek.com/api/v1/admin/clients/search' \
  -H "Authorization: Bearer $API_KEY" \
  -d q=acme
const url = new URL('https://panel.ornek.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.ornek.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']);

Müşteri İstatistikleri

get/api/v1/admin/clients/stats
Clients/GetClientsStats admin tüm müşteriler

Kurulumdaki tüm müşteriler için sayıları döndürür. Tek bir müşteriye bakmaz.

Sorgu parametreleri 1
periodstringDönem: all_time, today, week, month ya da year. Varsayılan all_time.
Dönen alanlar data — 9
activeintAktif müşteri sayısı.
blockedintEngelli müşteri sayısı.
newintDönemde eklenen müşteri sayısı.
blacklistedintKara listedeki müşteri sayısı.
active_servicesintAktif hizmet sayısı.
unpaid_invoicesintÖdenmemiş fatura sayısı.
credit_balancefloatToplam kredi bakiyesi. Ham sayı; para birimi sembolünü siz eklersiniz.
growth_ratefloatBüyüme oranı, yüzde olarak.
totalintDönemdeki toplam müşteri sayısı.
Hatalar 1
insufficient_scope403Anahtar gerekli kapsamı taşımıyor.
İstek
curl -G 'https://panel.ornek.com/api/v1/admin/clients/stats' \
  -H "Authorization: Bearer $API_KEY" \
  -d period=month
const url = new URL('https://panel.ornek.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.ornek.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']);
Yanıt
{
  "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
  }
}

Müşteri Özeti

get/api/v1/admin/clients/{id}/summary
Clients/GetClientSummary admin rozet ve güven puanı

Tek bir müşteri için özet kart verisi döndürür: gelir, hizmet ve talep sayıları, rozetler, güven puanı.

Dönen alanlar data — 13
user_idintMüşteri kimliği.
full_namestringAd ve soyad.
company_namestringFirma adı.
created_atstringÜyelik tarihi. Ham değer; biçimlendirme sizde.
total_revenuefloatBugüne kadar ödediği toplam tutar.
revenue_currencyintTutarın para birimi kimliği. Liste: reference/currencies.
paid_invoicesintÖdenmiş fatura sayısı.
active_servicesintAktif hizmet sayısı.
inactive_servicesintPasif hizmet sayısı.
total_ticketsintToplam destek talebi sayısı.
recent_ticketsintSon dönemdeki destek talebi sayısı.
badgesobjectHangi rozetlerin kazanıldığı.
loyalboolÜyelik yaşı eşiği aşıldı.
revenueboolGelir eşiği aşıldı.
multi_serviceboolBirden çok aktif hizmeti var.
experiencedboolGeçmiş etkileşim eşiği aşıldı.
trust_scoreobjectGüven puanı ve bileşenleri.
totalintToplam puan. 0 ile 100 arasında.
labelstringpoor, fair, good ya da excellent.
servicesintHizmet ekseninden gelen puan.
revenueintGelir ekseninden gelen puan.
ageintHesap yaşı ekseninden gelen puan.
ticketsintDestek talebi ekseninden gelen puan.
Hatalar 2
not_found404Müşteri bulunamadı.
insufficient_scope403Anahtar gerekli kapsamı taşımıyor.
İstek
curl 'https://panel.ornek.com/api/v1/admin/clients/42/summary' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch('https://panel.ornek.com/api/v1/admin/clients/42/summary', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
$ch = curl_init('https://panel.ornek.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]);

// Puanin nereden geldigini bilesenlerden okuyabilirsiniz.
$score = $response['data']['trust_score'];
$fromServices = $score['services'];
Yanıt
{
  "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
    }
  }
}

Öne Çıkan Notu Getirme

get/api/v1/admin/clients/{id}/latest-note
Clients/GetClientLatestNote admin sabitlenmiş önce

Müşterinin tek bir notunu döndürür: varsa sabitlenmiş olanı, yoksa en yenisini.

Dönen alanlar data — 9
idintNot kimliği.
contentstringNotun içeriği.
pinnedboolNot sabitlenmiş mi.
added_byintNotu ekleyen yöneticinin kimliği.
added_by_namestringNotu ekleyen yöneticinin adı; 3.x'ten düz metin olarak gelen notta boştur (added_by 0).
created_atstringNotun eklendiği zaman.
pinned_byint|nullNotu sabitleyen yöneticinin id'si. Not sabit değilse ya da bu alandan önce sabitlendiyse null.
pinned_by_namestring|nullNotu sabitleyenin adı — sabit not bandı yazarı değil bunu gösterir.
pinned_atstring|nullSabitlendiği zaman. Sabit kalan not düzenlenince damga korunur; sabitleme kaldırılınca üçü de silinir.
Hatalar 2
not_found404Müşteri bulunamadı.
insufficient_scope403Anahtar gerekli kapsamı taşımıyor.
İstek
curl 'https://panel.ornek.com/api/v1/admin/clients/42/latest-note' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch('https://panel.ornek.com/api/v1/admin/clients/42/latest-note', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();

// Hic not yoksa data null gelir — 404 degil.
if (body.data === null) return;
$ch = curl_init('https://panel.ornek.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]);

// Notu olmayan musteride 'data' null olur.
$note = $response['data'] ?? null;

Müşterinin Etkinlik Kaydını Listeleme

get/api/v1/admin/clients/{id}/activity
Clients/GetClientActivity admin sayfalı

Bir müşterinin etkinlik kayıtlarını en yeniden eskiye listeler: müşterinin yaptıkları ile personelin ya da sistemin hesap üzerinde yaptıkları. Müşteri sayfasındaki Etkinlik sekmesinin kayıtlarıdır, aynı arama ve tarih süzgeçleriyle.

Sorgu parametreleri 5
pageintSayfa numarası. Varsayılan 1.
limitintSayfa boyutu, 1 ile 100 arası. Varsayılan 25; daha büyük değer 100'e indirilir.
searchstringKayıt kategorisinde, açıklamada (saklandığı hâliyle ve isteğin dilinde), veride, işlemi yapanın adında ya da IP adresinde arar.
datestringY-m-d biçiminde kayıt tarihi; aralık, iki tarih boşluklu kısa çizgiyle birleştirilerek yazılır: 2026-10-01 - 2026-10-12.
date_opstringdate değerinin nasıl karşılaştırılacağı: eq, neq, gte, gt, lte ya da lt. Varsayılan eq: o gün ya da o aralık içinde.
Dönen alanlar data[] — 10
idintKayıt kimliği.
actor_idintİşlemi yapan hesap; sistem için 0.
actor_typestringclient (müşteri ya da alt kullanıcılarından biri), staff, system ya da işlemi yapan hesap artık yoksa deleted.
actor_namestringİşlemi yapan hesabın adı; sistem ya da silinmiş hesap için boş.
reasonstringKayıt kategorisi; örneğin in, alteration, login, added ya da delete.
actionstringKaydın işlem anahtarı.
descriptionstringİsteğin dilinde okunabilir açıklama.
dataobject|nullKayıtla saklanan ayrıntılar. Parola ve token gibi hassas anahtarların değeri maskeli gelir.
ipstringİşlemin geldiği IP adresi.
created_atstringKayıt tarihi, ham (Y-m-d H:i:s).
Sayfalama meta
metaobjectSayılar gönderdiğiniz süzgeçlere göredir.
totalintToplam kayıt sayısı.
pageintGeçerli sayfa.
limitintSayfa boyutu.
next_pageintSonraki sayfa; yoksa 0.
Hatalar 4
not_found404Müşteri bulunamadı. Personel hesabının kimliği de aynı yanıtı alır.
invalid_date422date ne Y-m-d ne de Y-m-d - Y-m-d aralığı.
invalid_date_op422date_op altı işleçten biri değil.
insufficient_scope403Anahtar gerekli kapsamı taşımıyor.
İstek
curl -G 'https://panel.ornek.com/api/v1/admin/clients/42/activity' \
  --data-urlencode 'search=login' \
  --data-urlencode 'date=2026-10-01 - 2026-10-12' \
  -H "Authorization: Bearer $API_KEY"
const query = new URLSearchParams({ search: 'login', limit: '50' });
const res   = await fetch(`https://panel.ornek.com/api/v1/admin/clients/42/activity?${query}`, {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();

// Son sayfada meta.next_page 0 gelir.
const more = body.meta.next_page !== 0;
$query = http_build_query(['date' => '2026-10-01', 'date_op' => 'gte', 'limit' => 50]);
$ch    = curl_init('https://panel.ornek.com/api/v1/admin/clients/42/activity?' . $query);
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()->GetClientActivity(['id' => 42], ['search' => 'login', 'limit' => 50]);

foreach ($response['data'] ?? [] as $row)
    echo $row['created_at'], ' ', $row['description'], PHP_EOL;
Yanıt
{
  "data": [
    {
      "id": 183379,
      "actor_id": 1,
      "actor_type": "staff",
      "actor_name": "Admin",
      "reason": "login",
      "action": "admin-login-as-client",
      "description": "Müşteri olarak giriş yapıldı: Ahmet Yılmaz (#116)",
      "data": { "user_id": 116, "user_name": "Ahmet Yılmaz" },
      "ip": "203.0.113.10",
      "created_at": "2026-10-12 05:41:07"
    }
  ],
  "meta": { "total": 716, "page": 1, "limit": 25, "next_page": 2 }
}

Müşteriye Gönderilen Mesajları Listeleme

get/api/v1/admin/clients/{id}/messages
Clients/GetClientMessages admin e-posta ve SMS

Bir müşteriye gönderilen e-posta ve SMS'leri en yeniden eskiye, müşteri sayfasındaki Mesajlar sekmesiyle aynı arama ve tarih süzgeçleriyle listeler. Listede mesaj gövdesi yoktur.

Sorgu parametreleri 5
pageintSayfa numarası. Varsayılan 1.
limitintSayfa boyutu, 1 ile 100 arası. Varsayılan 25; daha büyük değer 100'e indirilir.
searchstringE-posta konusunda ya da SMS başlığında veya alıcıda arar.
datestringY-m-d biçiminde gönderim tarihi; aralık, iki tarih boşluklu kısa çizgiyle birleştirilerek yazılır: 2026-10-01 - 2026-10-12.
date_opstringdate değerinin nasıl karşılaştırılacağı: eq, neq, gte, gt, lte ya da lt. Varsayılan eq: o gün ya da o aralık içinde.
Dönen alanlar data[] — 7
idintLog kaydı kimliği. Yalnız type ile birlikte benzersizdir.
typestringemail ya da sms.
subjectstringE-posta konusu ya da SMS başlığı.
recipientstringAlıcı adresleri (e-posta) ya da numaraları (SMS), saklandığı hâliyle.
reasonstringBildirim neden anahtarı; örneğin two-factor-verification, subuser-invitation ya da message-from-admin. Gönderim neden saklamadıysa boş.
ipstringGönderimle kaydedilen IP adresi.
created_atstringGönderim tarihi, ham (Y-m-d H:i:s).
Sayfalama meta
metaobjectSayılar gönderdiğiniz süzgeçlere göredir.
totalintToplam mesaj sayısı.
pageintGeçerli sayfa.
limitintSayfa boyutu.
next_pageintSonraki sayfa; yoksa 0.
Hatalar 4
not_found404Müşteri bulunamadı. Personel hesabının kimliği de aynı yanıtı alır.
invalid_date422date ne Y-m-d ne de Y-m-d - Y-m-d aralığı.
invalid_date_op422date_op altı işleçten biri değil.
insufficient_scope403Anahtar gerekli kapsamı taşımıyor.
İstek
curl -G 'https://panel.ornek.com/api/v1/admin/clients/42/messages' \
  --data-urlencode 'date=2026-10-01' \
  --data-urlencode 'date_op=gte' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch('https://panel.ornek.com/api/v1/admin/clients/42/messages?search=fatura', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();

// Listede govde yok: bir mesaji sonra okumak icin type + id saklanir.
const refs = body.data.map(m => ({ type: m.type, id: m.id }));
$query = http_build_query(['search' => 'fatura', 'page' => 2]);
$ch    = curl_init('https://panel.ornek.com/api/v1/admin/clients/42/messages?' . $query);
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()->GetClientMessages(['id' => 42], ['date' => '2026-10-01 - 2026-10-12']);

// Govde onizleme ucundan okunur; listedeki type + id verilir.
$first   = $response['data'][0] ?? null;
$preview = $first ? Api::Clients()->GetMessagePreview([], ['type' => $first['type'], 'id' => $first['id']]) : null;
Yanıt
{
  "data": [
    {
      "id": 17313,
      "type": "email",
      "subject": "Destek talebi oluşturuldu",
      "recipient": "[email protected]",
      "reason": "",
      "ip": "203.0.113.10",
      "created_at": "2026-10-11 18:02:44"
    },
    {
      "id": 905,
      "type": "sms",
      "subject": "Hizmetiniz hazır",
      "recipient": "+905550000000",
      "reason": "message-from-admin",
      "ip": "203.0.113.10",
      "created_at": "2026-10-10 09:00:12"
    }
  ],
  "meta": { "total": 522, "page": 1, "limit": 25, "next_page": 2 }
}

Tuzaklar

Tutarlar ham gelir, biçimlendirilmez

Kredi bakiyesi ve gelir alanları sembolsüz sayılardır; tarih de ham biçimdedir. Para birimini ayrı alandan okuyup biçimlendirmeyi kendiniz yaparsınız. Bu bilinçlidir: sunucu okuyucunun yerelini bilmez.

Notu olmayan müşteride null gelir

Öne çıkan not ucu, notu olmayan bir müşteride 404 değil data: null döndürür. Alanlara doğrudan erişen kod burada patlar; önce boş olup olmadığına bakın.

Güven puanı ayarlara bağlıdır

Özetteki puan sabit bir ölçek değildir; yapılandırmadaki kademelerden hesaplanır. Kademeleri değiştirdiğinizde aynı müşterinin puanı değişir, dolayısıyla puanı kurulumlar arasında karşılaştırmayın.

Mesaj listesinde gövde yoktur

Gönderilen mesajlar ucu yalnız konuyu, alıcıyı ve tarihi döndürür. Bir mesajı okumak için type ve id değerlerini mesaj önizleme ucuna verin; e-postalar ve SMS'ler ayrı numaralandığı için tek başına id yetmez. Önizleme, güvenlik ve gizli mesajların gövdesini vermez.

Faydalı oldu mu?

Geri bildiriminiz için teşekkürler!

Hâlâ Yardıma mı İhtiyacınız Var?

Yukarıda bulamadığınız her şey için destek ekibimiz her zaman yanınızda.