Ürün Uçları

1.8k görüntülenme Markdown

Ürün kataloğunu listeleyen, ürün açan, okuyan, güncelleyen ve silen dokuz uç.

Genel Bakış

Bu uçlar katalogdaki ürünün kendisini yönetir: listeleme, oluşturma, okuma, güncelleme ve silme. Yanlarındaki üç arama ucu oluşturma sırasında hangi değerlerin geçerli olduğunu söyler.

Oluşturma ile güncelleme arasında bilinçli bir iş bölümü var: oluşturma yalnız iskeleti kurar, ürünü satılabilir yapan her şey güncelleme ucundan girer. Panel de aynı sırayı izler.

Referans

Ürünleri Listeleme

get/api/v1/admin/products
Products/GetProducts admin sayfalı

Ürün kataloğunu döndürür. Süzgeç vermezseniz tüm tipler gelir, en yeniden eskiye.

Sorgu parametreleri 7
searchstringÜrün başlığında arar.
typestringTipe göre süzer: hosting, server, software, ssl ya da special.
group_idintÖzel grup kimliği. Kullanmak type alanını special yapmayı gerektirir.
categoryintKategori kimliğine göre süzer.
statusstringactive ya da inactive.
pageintVarsayılan 1.
limitintVarsayılan 25, en çok 100.
Dönen alanlar data[] — 8
idintÜrün kimliği.
titlestringÜrün başlığı, geçerli dilde.
typestringÜrünün davranış tipi.
modulestringBağlı modül. Bağlı değilse none.
statusstringactive ya da inactive.
categoryobjectKategori: {id, title}. Kategorisiz üründe başlık boş gelir.
service_countintBu üründen açılmış hizmet sayısı.
created_atstringOluşturma zamanı.
Meta 4
totalintSüzgece uyan toplam kayıt.
pageintBulunduğunuz sayfa.
limitintSayfa boyutu.
next_pageintSonraki sayfa. 0 son sayfada olduğunuz anlamına gelir.
Hatalar 1
insufficient_scope403Anahtar gerekli kapsamı taşımıyor.
İstek
curl -G 'https://panel.ornek.com/api/v1/admin/products' \
  -H "Authorization: Bearer $API_KEY" \
  -d type=hosting \
  -d limit=50
const url = new URL('https://panel.ornek.com/api/v1/admin/products');
url.searchParams.set('type', 'hosting');
url.searchParams.set('limit', '50');

const res  = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
const body = await res.json();
$url = 'https://panel.ornek.com/api/v1/admin/products?' . http_build_query(['type' => 'hosting', 'limit' => 50]);

$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);
$page = 1;
$all  = [];

do {
    $response = Api::Products()->GetProducts([], [
        'type'  => 'hosting',
        'page'  => $page,
        'limit' => 100,
    ]);

    $all  = array_merge($all, $response['data']);
    $page = $response['meta']['next_page'];
} while ($page > 0);
Yanıt
{
  "data": [
    {
      "id": 15,
      "title": "Starter SSD 1",
      "type": "hosting",
      "module": "cPanel",
      "status": "active",
      "category": { "id": 439, "title": "Economy Web Hosting" },
      "service_count": 12,
      "created_at": "2026-01-01 10:00:00"
    }
  ],
  "meta": { "total": 499, "page": 1, "limit": 25, "next_page": 2 }
}

Ürün Oluşturma

post/api/v1/admin/products
Products/CreateProduct admin 201

İskelet bir ürün açar. Fiyat, limit ve dil içeriği sonradan güncelleme ucuyla girilir.

Gövde 6
typestringzorunluÜrün tipi: hosting, server, software ya da special. ssl tek başına açılamaz; özel grup içinde yaşar.
namestringzorunluÜrün başlığı. Tüm dillere aynı metin yazılır.
group_idintÖzel grup kimliği. Tip special ise zorunlu.
categoryintKategori kimliği.
modulestringBağlanacak modülün adı. Verirseniz otomatik kurulum açılır.
hiddenboolÜrünü vitrinde gizler.
Dönen alanlar data
dataobjectOluşturulan ürün, 201 ile döner. Detay ucuyla aynı şekildedir.
Hatalar 5
invalid_type422Tip izinli değerlerden değil.
name_required422name boş.
group_required422Tip special ama grup verilmedi.
blocked_by_gate422gate:product.create kancası işlemi veto etti.
create_failed422Oluşturma reddedildi. Grup yok ya da adres çakışıyor olabilir.
İstek
curl -X POST 'https://panel.ornek.com/api/v1/admin/products' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"type":"hosting","name":"Starter SSD 1","category":439,"module":"cPanel"}'
const res = await fetch('https://panel.ornek.com/api/v1/admin/products', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    type: 'hosting',
    name: 'Starter SSD 1',
    category: 439,
    module: 'cPanel',
  }),
});

const body = await res.json();
$ch = curl_init('https://panel.ornek.com/api/v1/admin/products');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'type'     => 'hosting',
        'name'     => 'Starter SSD 1',
        'category' => 439,
        'module'   => 'cPanel',
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Olusturma iskelet birakir; kullanilabilir bir urun icin ardindan guncelleyin.
$created = Api::Products()->CreateProduct([
    'type'     => 'hosting',
    'name'     => 'Starter SSD 1',
    'category' => 439,
    'module'   => 'cPanel',
]);

Api::Products()->UpdateProduct([
    'id'     => $created['data']['id'],
    'limits' => ['disk' => 100, 'bandwidth' => 'unlimited'],
]);

Ürün Detayı

get/api/v1/admin/products/{id}
Products/GetProduct admin modüle göre değişir

Ürünün tüm ayarlarını, ilişkilerini ve her dildeki içeriğini döndürür.

Dönen alanlar data — 26
idintÜrün kimliği.
typestringÜrünün davranış tipi.
group_typestringGrup tipi anahtarı.
group_idintÖzel grup kimliği. Gruplu değilse 0.
categoryobjectKategori: {id, name}.
statusstringactive ya da inactive.
visibilitystringvisible ya da invisible.
modulestringBağlı modülün adı.
module_dataobjectModülün kendi yapılandırması. Alanlar tamamen modüle bağlıdır; sabit bir şema yoktur.
optionsobjectÜrün seçenekleri. Alanlar tipe ve modüle göre değişir.
additional_taxobjectEk vergi: {enabled, items}.
tax_exemptboolVergiden muaf mı.
override_user_currencyboolMüşterinin para birimini yok sayar mı.
upgrade_enabledboolYükseltme açık mı.
affiliate_disabledboolSatış ortaklığı kapalı mı.
affiliate_ratefloatSatış ortaklığı oranı.
stockint | nullKalan stok. null sınırsız demektir.
rankintGörüntülenme sırası.
upgradeable_product_idsint[]Bu üründen geçilebilecek ürünler.
addon_idsint[]Bağlı add-on kimlikleri.
requirement_idsint[]Bağlı gereksinim kimlikleri.
notesstringYönetici notları. Müşteriye gösterilmez.
prorateobjectGün bazlı orantılama: {enabled, days}.
recurring_cycles_limitobjectYenileme sayısı sınırı: {enabled, value}.
auto_terminateobjectOtomatik sonlandırma: {enabled, days}.
langsobjectDil kodundan içerik nesnesine eşleme.
titlestringÜrün başlığı.
descriptionstringKısa açıklama.
contentstringUzun içerik.
routestringAdres parçası.
featuresstringÖzellik listesi.
seo_titlestringArama başlığı.
seo_keywordsstringArama anahtar kelimeleri.
seo_descriptionstringArama açıklaması.
Hatalar 2
not_found404Ürün bulunamadı.
insufficient_scope403Anahtar gerekli kapsamı taşımıyor.
İstek
curl 'https://panel.ornek.com/api/v1/admin/products/15' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch('https://panel.ornek.com/api/v1/admin/products/15', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
$ch = curl_init('https://panel.ornek.com/api/v1/admin/products/15');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Products()->GetProduct(['id' => 15]);

// module_data'nin sekli modulden geliyor — anahtar varligini kontrol edin.
$plan = $response['data']['module_data']['plan'] ?? null;

Ürünü Güncelleme

patch/api/v1/admin/products/{id}
Products/UpdateProduct admin kısmi güvenli

Gönderdiğiniz alanları uygular, geri kalanını olduğu gibi bırakır.

Gövde 22
statusstringactive ya da inactive.
categoryintKategori kimliği.
hiddenboolVitrinde gizler.
notesstringYönetici notları.
rankintGörüntülenme sırası.
stockint | nullStok. Boş bırakmak sınırsız demektir.
subdomainsstringAlt barındırmaya izinli ürünler.
affiliate_disabledboolSatış ortaklığını kapatır.
affiliate_ratefloatSatış ortaklığı oranı.
override_user_currencyboolMüşterinin para birimini yok sayar.
tax_exemptboolVergiden muaf kılar.
additional_taxobjectEk vergi yapılandırması.
allow_qtyboolSiparişte adet seçilmesine izin verir.
prorateobject{enabled, days}.
recurring_cycles_limitobject{enabled, value}.
auto_terminateobject{enabled, days}.
addon_idsint[]Bağlanacak add-on kimlikleri.
requirement_idsint[]Bağlanacak gereksinim kimlikleri.
upgradeable_product_idsint[]Yükseltme hedefi ürünler.
optionsobjectÜrün seçenekleri: popular, auto_approval, auto_install, seo_index, restrict_access, order_limit_per_user, free_domain, domain_requirement, hide_domain, show_domain, hide_hosting, show_hosting, change_domain, renewal_selection_hide, download_link, demo_link, demo_admin_link, demo_admin_link, product_file_access, ctoc_service_transfer, server_group_id, server_id, activation_notification. domain_requirement, hosting, server ve special ürünlerde none, optional ya da required değerini alır ve hide_domain / show_domain bayrağını türetir; yalnız eski bayrağı göndermek de çalışır, bilinmeyen değer yoksayılır.
limitsobjectBarındırma kaynak sınırları: disk, bandwidth, email, database, addons, subdomain, ftp, park, max_email_per_hour. Her biri sayı ya da unlimited. Boş değer, null ya da negatif sayı unlimited olarak kaydedilir; üründen okunan değer olduğu gibi geri gönderilebilir. Sayım sınırlarında 0 hak vermez.
langsobjectDil kodundan içerik nesnesine eşleme. Yalnız gönderdiğiniz diller değişir.
titlestringÜrün başlığı.
descriptionstringKısa açıklama.
contentstringUzun içerik.
routestringAdres parçası.
featuresstringÖzellik listesi.
seo_titlestringArama başlığı.
seo_keywordsstringArama anahtar kelimeleri.
seo_descriptionstringArama açıklaması.
Dönen alanlar data
dataobjectGüncel ürün. Detay ucuyla aynı şekildedir.
Hatalar 3
not_found404Ürün bulunamadı.
insufficient_scope403Anahtar gerekli kapsamı taşımıyor.
invalid_limit422Bir limits değeri sayı, unlimited, boş ya da null değil. details.field hangisi olduğunu söyler.
İstek
curl -X PATCH 'https://panel.ornek.com/api/v1/admin/products/15' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"status":"inactive","limits":{"disk":100,"bandwidth":"unlimited"}}'
const res = await fetch('https://panel.ornek.com/api/v1/admin/products/15', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    status: 'inactive',
    limits: { disk: 100, bandwidth: 'unlimited' },
  }),
});

const body = await res.json();
$ch = curl_init('https://panel.ornek.com/api/v1/admin/products/15');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PATCH',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'status' => 'inactive',
        'limits' => ['disk' => 100, 'bandwidth' => 'unlimited'],
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Yalniz Ingilizce metni degistirmek diger dillere dokunmaz.
$response = Api::Products()->UpdateProduct([
    'id'    => 15,
    'langs' => [
        'en' => ['title' => 'Starter SSD 1', 'features' => 'NVMe storage'],
    ],
]);

Toplu Durum Değiştirme

post/api/v1/admin/products/bulk
Products/BulkProducts admin yalnız durum

Birden çok ürünün durumunu tek çağrıda değiştirir. Silme bu uçtan yapılamaz.

Gövde 2
idsint[]zorunluÜrün kimlikleri. En az bir tane.
actionstringzorunluactive ya da inactive.
Dönen alanlar data — 2
updatedint[]Durumu değişen kimlikler.
actionstringUygulanan durum.
Hatalar 2
ids_required422ids boş.
invalid_action422İşlem iki değerden biri değil.
İstek
curl -X POST 'https://panel.ornek.com/api/v1/admin/products/bulk' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"ids":[15,16],"action":"inactive"}'
const res = await fetch('https://panel.ornek.com/api/v1/admin/products/bulk', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ ids: [15, 16], action: 'inactive' }),
});

const body = await res.json();
$ch = curl_init('https://panel.ornek.com/api/v1/admin/products/bulk');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'ids'    => [15, 16],
        'action' => 'inactive',
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Products()->BulkProducts([
    'ids'    => [15, 16],
    'action' => 'inactive',
]);

Ürünü Silme

delete/api/v1/admin/products/{id}
Products/DeleteProduct admin geri alınamaz

Ürünü siler. Dil kayıtları ve fiyatları birlikte gider.

Dönen alanlar data — 2
deletedboolSilme başarılı mı.
idintSilinen ürünün kimliği.
Hatalar 2
not_found404Ürün bulunamadı.
blocked_by_gate422gate:product.delete kancası işlemi veto etti.
İstek
curl -X DELETE 'https://panel.ornek.com/api/v1/admin/products/2030' \
  -H "Authorization: Bearer $API_KEY"
const res = await fetch('https://panel.ornek.com/api/v1/admin/products/2030', {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
$ch = curl_init('https://panel.ornek.com/api/v1/admin/products/2030');
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);
$response = Api::Products()->DeleteProduct(['id' => 2030]);

Ürün Tiplerini Listeleme

get/api/v1/admin/products/types
Products/GetProductTypes admin arama ucu

Bu kurulumda kullanılabilen ürün tiplerini döndürür. Oluştururken geçerli değerler buradan gelir.

Dönen alanlar data[] — 4
keystringTip anahtarı. Oluşturma gövdesine bu değer yazılır.
titlestringGörüntülenecek etiket.
descriptionstringTipin açıklaması.
iconstringİkon sınıfı.
Hatalar 1
insufficient_scope403Anahtar gerekli kapsamı taşımıyor.
İstek
curl 'https://panel.ornek.com/api/v1/admin/products/types' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch('https://panel.ornek.com/api/v1/admin/products/types', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
$ch = curl_init('https://panel.ornek.com/api/v1/admin/products/types');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

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

Grupları Listeleme

get/api/v1/admin/products/groups
Products/GetProductGroups admin arama ucu

Sabit ve özel katalog gruplarını döndürür. Her satır oluşturma için hazır bir tip ve grup çifti verir.

Dönen alanlar data[] — 4
keystringGrup anahtarı. Özel gruplarda kimlik son ekiyle gelir.
titlestringGörüntülenecek etiket.
typestringBu gruba karşılık gelen ürün tipi.
group_idintÖzel grup kimliği. Sabit gruplarda 0.
Hatalar 1
insufficient_scope403Anahtar gerekli kapsamı taşımıyor.
İstek
curl 'https://panel.ornek.com/api/v1/admin/products/groups' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch('https://panel.ornek.com/api/v1/admin/products/groups', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
$ch = curl_init('https://panel.ornek.com/api/v1/admin/products/groups');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Grup satiri olusturma govdesinin iki alanini birden verir.
$group = Api::Products()->GetProductGroups()['data'][0];

Api::Products()->CreateProduct([
    'type'     => $group['type'],
    'group_id' => $group['group_id'],
    'name'     => 'New product',
]);

Kategorileri Listeleme

get/api/v1/admin/products/categories
Products/GetProductCategories admin arama ucu

Kategori listesini düz olarak döndürür. Ağacı üst kimliklerden siz kurarsınız.

Sorgu parametreleri 2
typestringGrup tipi. Varsayılan hosting.
group_idintÖzel grup kimliği. Sıfırdan büyük vermek tipi special yapar.
Dönen alanlar data[] — 4
idintKategori kimliği.
parent_idintÜst kategorinin kimliği. 0 üst seviye demektir.
titlestringKategori başlığı.
routestringAdres parçası.
Hatalar 1
insufficient_scope403Anahtar gerekli kapsamı taşımıyor.
İstek
curl -G 'https://panel.ornek.com/api/v1/admin/products/categories' \
  -H "Authorization: Bearer $API_KEY" \
  -d type=hosting
const url = new URL('https://panel.ornek.com/api/v1/admin/products/categories');
url.searchParams.set('type', 'hosting');

const res  = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
const body = await res.json();
$url = 'https://panel.ornek.com/api/v1/admin/products/categories?' . http_build_query(['type' => 'hosting']);

$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);
$rows = Api::Products()->GetProductCategories([], ['type' => 'hosting'])['data'];

$byParent = [];
foreach ($rows as $row) $byParent[$row['parent_id']][] = $row;

Tuzaklar

Oluşturma satılabilir bir ürün vermez

Yeni ürün iskelet hâlde doğar: varsayılan para biriminde sıfır tutarlı aylık bir fiyat konur ve başlık tüm dillere kopyalanır. Limitler, gerçek fiyat ve içerik girilene kadar ürün satışa hazır değildir. Oluşturmayı bir güncelleme çağrısı takip etmelidir.

Güncelleme bazı bölümleri dışarıda bırakır

Dönemsel fiyatlandırma, metrik fiyatlandırma, modül yapılandırması ve lisans parametreleri bu uçtan düzenlenmez. Bunlar mevcut değerleriyle yeniden yazılır, yani gövdenizde olmamaları onları silmez. Kendi uçlarında yönetilirler.

İki alanın şeması modüle bağlıdır

Detayda dönen module_data ve options alanlarının içeriği bağlı modüle ve ürün tipine göre değişir; sabit bir şemaları yoktur. Bunlara doğrudan erişen kod modül değişince kırılır, anahtar varlığını kontrol edin.

Toplu uç silmez

Toplu işlem yalnız durum değiştirir. Ürün silmek tek tek yapılır ve her silme gate:product.delete kancasından geçer; bir eklenti veto edebilir.

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.