Ürünler
storefront:read — herkese açık, token isteğe bağlı. İndirimli fiyat (discountPrice) için storefront:pricing gerekir. Token almak için Kimlik Doğrulama, hata gövdelerinin biçimi için Genel Bakış.Listeleme
curl -s 'https://<domain>/api/v3/storefront/2026-01/products?page[number]=1&page[size]=20' \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer <TOKEN>'
Yanıt zarfı — kayıtlar data dizisinde, sayfa bilgisi meta.page içinde, gezinme bağlantıları links altında döner:
{
"meta": {
"page": {
"currentPage": 1,
"from": 1,
"to": 20,
"perPage": 20,
"lastPage": 8,
"total": 156
}
},
"jsonapi": { "version": "1.0" },
"links": {
"first": "https://<domain>/api/v3/storefront/2026-01/products?page[number]=1&page[size]=20",
"next": "https://<domain>/api/v3/storefront/2026-01/products?page[number]=2&page[size]=20",
"last": "https://<domain>/api/v3/storefront/2026-01/products?page[number]=8&page[size]=20"
},
"data": [ /* ürün kayıtları */ ]
}
page[size] verilmezse sayfa boyutu 20'dir. Sonsuz kaydırmada bir sonraki sayfayı links.next üzerinden iste; bu alan son sayfada yer almaz — bitişi böyle tespit et (currentPage === lastPage karşılaştırması da aynı sonucu verir). Toplam kayıt sayısı meta.page.total, o anki dilim from–to aralığıdır.
Örnek bir ürün kaydı (data dizisinin bir elemanı) — tam alan seti:
{
"type": "products",
"id": "42",
"attributes": {
"name": "Kırmızı Koltuk",
"slug": "kirmizi-koltuk",
"seoTitle": "Kırmızı Koltuk | Mağaza",
"seoDescription": "…",
"brand": "Nike",
"brandId": 80,
"categoryId": 335,
"ratingAverage": 4.4,
"commentCount": 3,
"price": { "amount": "200.00", "currencyCode": "TRY", "decimalPlaces": 2 },
"vatIncluded": true,
"vatRate": 20,
"isNew": true,
"discountPrice": { "amount": "149.90", "currencyCode": "TRY", "decimalPlaces": 2 },
"isFeatured": true,
"isBestseller": false,
"isOpportunity": true,
"opportunityEndsAt": 1784286835,
"availableForSale": true,
"stock": 12,
"hasVariants": false,
"image": "https://<domain>/Data/EcommerceCatalog/…/urun-adi.jpg"
}
}
Alanlar
| Alan | Tip | Kural |
|---|---|---|
name | string | Ürün adı. Her zaman döner |
slug | string | SEO bağlantı parçası. Her zaman döner |
seoTitle | string | Sayfa başlığı; tanımlı değilse boş gelebilir |
seoDescription | string | Meta açıklama; tanımlı değilse boş gelebilir |
brand | string | Marka adı. Markasız üründe boş gelir — marka bağlantısı için brandId kullan |
brandId | integer | null | Markasız üründe null (0 değil) |
categoryId | integer | Ürünün ana kategorisi (tüm kategorileri değil) |
ratingAverage | number | 0–5, tek ondalık. Yorumu yoksa 0 |
commentCount | integer | Yalnızca onaylı yorum sayısı |
price | Money | Liste fiyatı. Her zaman döner |
discountPrice | Money | Yalnız storefront:pricing yetkisi ve aktif indirim varken döner; yoksa alan yanıtta yer almaz |
isFeatured | boolean | Vitrin/öne çıkan işareti |
isBestseller | boolean | Çok satan işareti |
isOpportunity | boolean | Fırsat penceresi şu anda aktif mi (karar sunucuda) |
opportunityEndsAt | integer | Epoch saniye. Yalnız isOpportunity: true iken döner; yoksa alan yanıtta yer almaz (null değil) |
availableForSale | boolean | Sepete eklenebilir mi. Her zaman döner |
stock | integer | Ham stok adedi. Yalnız storefront:read scope'lu token'da döner; yoksa alan yanıtta yer almaz |
hasVariants | boolean | true ise fiyat alanları varsayılan varyantı gösterir; seçenekler için ?include=variants |
image | string | Ana görselin tam URL'si. Görsel yoksa boş string (null değil) |
symbols | array | Üründe aktif olan simgeler (rozet/etiket). Aktif simge yoksa boş dizi |
attributes | array | Ürünün özellik (filtre) değerleri. Detay isteğinde her zaman döner; listede yalnız fields[products]=attributes ile istenirse döner |
orderNoteEnabled | boolean | Ürüne sipariş notu yazılabilir mi. Yalnız detay isteğinde döner |
Koşullu alanlarda (discountPrice, opportunityEndsAt, stock) null kontrolü değil varlık kontrolü yap — alan yanıtta hiç yer almaz.
symbols semantiği
Mağazanın tanımladığı ürün simgeleri (ör. "Ücretsiz Kargo", "Yeni Sezon"). Liste ve detay yüzeyinde aynı şekilde döner.
"symbols": [
{ "id": 1, "label": "Ücretsiz Kargo", "icon": "https://<domain>/free-shipping.svg" },
{ "id": 4, "label": "Yeni Sezon", "icon": "" }
]
| Alan | Tip | Kural |
|---|---|---|
id | integer | Simge numarası (1–20). Mağaza ayarlarındaki simge sırasıdır |
label | string | Simgenin metni. Tanımsızsa boş string |
icon | string | Simge görselinin adresi. Tanımsızsa boş string |
- Yalnız üründe aktif olan simgeler döner; pasif olanlar listeye girmez.
- Mağazanın hiç tanımlamadığı (etiketi de görseli de boş) bir simge, üründe aktif olsa bile dönmez — gösterilecek içeriği yoktur.
- Kullanılabilir simge sayısı mağazanın lisansına bağlıdır;
iddeğerleri bu yüzden aralıklı olabilir (ör.1,4,7). - Sıra, simge numarasına göre artan biçimdedir.
attributes semantiği
Ürünün özellik değerleri — ürün detayındaki "Tüm özellikler" bölümünü besler. Tekil ürün isteğinde her zaman döner.
Liste yanıtında alan varsayılan olarak yer almaz; her kayıt için ayrıca okunduğundan listeyi ağırlaştırmasın diye açıkça istenmesi gerekir:
curl "https://<domain>/api/v3/storefront/2026-01/products?fields[products]=name,attributes" \
-H "Accept: application/vnd.api+json" \
-H "Authorization: Bearer <access_token>"
fields[products] listesine attributes yazıldığında alan liste kayıtlarında da döner; yazılmazsa hiç görünmez.
"attributes": [
{ "id": 12, "label": "Renk", "values": [
{ "id": 340, "label": "Kırmızı" },
{ "id": 341, "label": "Mavi" }
] },
{ "id": 18, "label": "Ağırlık", "values": [
{ "id": null, "label": "2.5" }
] }
]
| Alan | Tip | Kural |
|---|---|---|
id | integer | Özellik grubunun id'si. filter[attr] ile filtrelerken kullanılan grup id'si ile aynıdır |
label | string | Özellik grubunun adı (ör. Renk, Beden) |
values | array | Ürünün o gruptaki değerleri |
values[].id | integer | null | Seçenek id'si. Sayısal özelliklerde null |
values[].label | string | Gösterilecek değer |
- Çoklu seçimli gruplarda birden çok değer dönebilir; tekli seçimde tek değer döner.
- Sayısal gruplarda (ör. ağırlık, hacim)
values[].idnull'dur velabelsayının kendisidir. - Mağazanın pasife aldığı özellik grupları dönmez.
- Değeri artık geçerli bir seçeneğe karşılık gelmeyen grup dönmez; gösterilecek içeriği yoktur.
- Gruplar mağaza ayarındaki sıraya göre döner.
- Yalnızca yayında olan ürünler döner. Gizli ürünler listede yer almaz; tekil istekte de
404verir. availableForSale(boolean) herkese açıktır;stock(integer) ise ham stok adedidir ve yalnızcastorefront:readscope'lu token'da döner — bkz. stock semantiği.brandId(integer | null) markanın Markalar kaynağındaki id'sidir. Markası olmayan üründenulldöner (0değil). Marka sayfası akışı: üründekibrandIdileGET /brands/{brandId}marka detayını,GET /products?filter[brandId]={brandId}markanın ürün listesini verir.ratingAverage(number) onaylı yorumlardan hesaplanan puan ortalamasıdır; 0-5 ölçeğinde, 1 ondalık hassasiyetle döner (tam değerler ondalıksız serileşir:4). Hiç yorumu olmayan üründe0döner; yıldız bileşeninin boş durumunucommentCount === 0üzerinden çizin.commentCount(integer) yalnızca onaylı yorumları sayar ve?include=commentsile dönen kayıt kümesiyle aynı sayıdadır — bkz. Yorumlar.imageher zaman tam URL'dir. Görsel yoksa boş string gelir (nulldeğil).priceürünün gösterilecek fiyatıdır. Ürünün KDV gösterim ayarı açıksa KDV dahil döner; bu durumdavatIncludedtrueolur vevatRateuygulanan oranı verir. Ayar kapalıysa fiyat KDV hariçtir vevatIncludedfalsedöner. Fiyatın üzerine istemci tarafında ayrıca KDV eklenmez.vatIncluded(boolean)pricevediscountPricedeğerlerine KDV'nin dahil olup olmadığını söyler.vatRate(number) ürünün KDV oranıdır (örn.20) ve ayar kapalıyken de dolu gelir.isNew(boolean) ürünün "Yeni" olarak işaretlenip işaretlenmediğidir; rozet gösterimi bu alandan çizilir.discountPriceyalnızcastorefront:pricingscope'lu token'da ve aktif bir indirim varken yer alır — bkz. Money.isOpportunity(boolean) ürünün şu anda aktif bir fırsat penceresinde olup olmadığını söyler. Karar sunucudadır: fırsat işareti ve başlangıç/bitiş tarihleri sunucu saatiyle değerlendirilir — istemci tarafında tarih karşılaştırması yapmayın.opportunityEndsAt(integer, epoch saniye) fırsatın bitiş zamanıdır ve yalnızcaisOpportunity: trueiken döner; diğer durumlarda alan yanıtta hiç yer almaz (nulldeğil — varlık kontrolü yapın). Geri sayım bileşenini bu değerden çizin; süre dolduğunda sonraki yanıtta hemisOpportunityfalseolur hem de alan kaybolur.
Tek ürün
curl -s 'https://<domain>/api/v3/storefront/2026-01/products/42' \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer <TOKEN>'
Yanıt yapısı listeleme ile aynıdır; data tekil bir obje olarak döner. Gizli veya var olmayan ürün → 404.
Filtreler
| Filtre | Örnek | Davranış |
|---|---|---|
filter[id][] | filter[id][]=42&filter[id][]=43 | Belirli id'lerle sınırla |
filter[categoryId] | filter[categoryId]=335 veya filter[categoryId]=335,340 | Kategori id'si (attributes.categoryId ile aynı değer uzayı) — alt kategoriler dahil, virgülle birden fazla kategori |
filter[brand] | filter[brand]=Nike | Marka adı (string) |
filter[brandId] | filter[brandId]=80 veya filter[brandId]=80,81 | Marka id'si — virgülle birden fazla marka |
filter[priceMin] / [priceMax] | filter[priceMin]=40&filter[priceMax]=60 | Ham liste fiyatı aralığı |
filter[availableForSale] | filter[availableForSale]=true | Satılabilirlik |
filter[hasDiscount] | filter[hasDiscount]=true | İndirimdekiler (boolean). Filtrenin kendisi yetki gerektirmez; discountPrice alanı storefront:pricing ister. Yani storefront:pricing yetkili token'da true listesindeki her üründe discountPrice döner, false listesinde hiçbirinde dönmez; bu yetki olmadan discountPrice hiçbir üründe dönmez ama filtre yine indirimli ürünleri süzer. Süzme, mağazanın ürünü indirimli olarak gösterme işaretine bakar — vitrinde indirimli görünen küme ile bu filtrenin döndürdüğü küme aynıdır |
filter[isOpportunity] | filter[isOpportunity]=true | Fırsat ürünleri (boolean). attributes.isOpportunity ile aynı değer uzayı: true yalnızca aktif fırsat penceresindeki ürünleri döner. Fırsat ekranı = filter[isOpportunity]=true + istenen sort |
filter[modelId] | filter[modelId]=12 veya filter[modelId]=12,13 | Model id'si — virgülle birden fazla model |
filter[variantType1Id] | filter[variantType1Id]=24,26 | Birinci varyant ekseni (genelde renk); seçenek id'leri virgülle |
filter[variantType2Id] | filter[variantType2Id]=31 | İkinci varyant ekseni (genelde beden); seçenek id'leri virgülle |
filter[isNew] | filter[isNew]=true | Yeni ürünler (boolean). attributes.isNew ile aynı değer uzayı |
filter[attr] | filter[attr][1][]=101 | Ürün özelliği seçimi — grup id'si ve seçenek id'leri |
filter[q] | filter[q]=koltuk | Ürün adında kısmi arama (case-insensitive) |
Filtreler birleştirilebilir; birden fazla filtre AND mantığıyla çalışır:
products?filter[categoryId]=335&filter[availableForSale]=true&filter[priceMax]=500&sort=-newest
filter[priceMin] / filter[priceMax]ham liste fiyatı üzerinden çalışır — üye grubuna özel fiyatlar bu aralık hesabına girmez. UI'da "liste fiyatına göre filtrele" olarak konumla.filter[categoryId] kategori ağacında aşağı iner: verilen kategoriye veya onun herhangi bir alt kategorisine bağlı tüm ürünler döner. filter[categoryId]=335, hem doğrudan 335'teki hem de 335'in alt dallarındaki ürünleri getirir — alt kategori id'lerini ayrıca toplamanıza gerek yoktur. Virgülle birden fazla kategori verilebilir (filter[categoryId]=335,340 → iki ağacın birleşimi). Sayısal olmayan değerler yok sayılır; ürünün attributes.categoryId alanı yine yalnızca ana kategorisini gösterir.filter[brand] marka adıyla eşleşir (attributes.brand ile aynı string, yazım farkına duyarlı), filter[brandId] ise marka id'siyle — Markalar kaynağının döndüğü id değerini doğrudan kullanabilir, virgülle birden fazla marka geçebilirsin. Sağlam eşleşme için filter[brandId] tercih edilir.filter[isOpportunity] ile filter[hasDiscount]bağımsız kümelerdir: fırsat ürünü indirimli olmak zorunda değildir, indirimli ürün fırsat olmak zorunda değildir. İkisi birlikte gönderilirse kesişim döner.Sıralama
sort= parametresi. Alan adının başına - koymak azalan sırayı verir. sort verilmezse kayıtlar id sırasıyla döner; sayfalar arasında tutarlı bir sıra istiyorsan açık bir sort gönder.
| Sort | Anlamı |
|---|---|
name / -name | Ürün adı (alfabetik) |
price / -price | Ürünün gösterilen fiyatı — üye grubuna özel fiyat veya indirim uygulanmışsa sıralama da onun üzerinden yapılır |
-newest | En yeni eklenen |
-bestseller | Çok satılan sırası |
-rate | Puan — sıralanan değer yanıtta attributes.ratingAverage alanında döner |
-viewCount | En çok görüntülenen |
-recommendationCount | En çok tavsiye edilen |
-commentCount | En çok yorumlanan |
-favoriteCount | En çok favoriye eklenen |
random | Rastgele sıra |
position | Mağazanın elle verdiği sıra |
sort=price ile filter[priceMin] / filter[priceMax]aynı fiyatı kullanmaz: sıralama gösterilen (indirimli veya gruba özel) fiyata, aralık filtresi ham liste fiyatına bakar. Fiyat aralığı seçip fiyata göre sıralayan bir ekranda bu fark görünür olabilir.sort=name dizilişi veritabanının karşılaştırma kurallarına göredir; Türkçe'ye özel alfabetik sıra garanti edilmez (ç c-bloğunda dizilir, ı/i ayrışmaz). Kesin Türkçe sıra gerekiyorsa istemci kendi tarafında sıralamalıdır.sort=discountPricedesteklenmez — fiyat alanları obje taşıdığı için doğrudan sıralanamaz. Eski koddan kaldıysa temizle.Include'lar
İlişkili kayıtlar ?include= ile aynı yanıtta (included[] dizisinde) istenir; hem listelemede hem tek üründe çalışır, virgülle birden fazla ilişki verilebilir:
products/42?include=images,variants
products?filter[categoryId]=335&include=images
| İlişki | Ne döner | Notlar |
|---|---|---|
images | Ürün galerisi (product-images): url, mediumUrl, smallUrl, sortOrder | Ürün kartındaki görsel kaydırma için listelemede de kullanılabilir; sortOrder galeri sırasıdır |
variants | Varyantlar (variants): productId, sku, barcode, options, inStock, price | discountPrice burada da storefront:pricing yetkisine bağlıdır |
comments | Onaylı yorumlar (product-comments) — bkz. Yorumlar | Tamamı döner, ayrıca sayfalanmaz |
relatedProducts | İlişkili/alternatif ürünler (yine products tipinde) | Ayrı bir adet alanı yoktur; sayı gerekiyorsa dönen listenin uzunluğunu sayın |
Varyantlar included[] içinde şu biçimde döner — options bir {name, value} dizisidir, varyant seçiciyi bu diziden kur:
{
"type": "variants",
"id": "803",
"attributes": {
"productId": 773,
"sku": "",
"barcode": "",
"options": [
{ "name": "Renk", "value": "Mavi" },
{ "name": "Beden", "value": "M" }
],
"inStock": true
}
}
Varyantta satılabilirlik alanı inStock'tur; üründeki availableForSale ile aynı soruyu yanıtlar, adlandırma farkı kaynak tipinden gelir. sku ve barcode tanımlı değilse boş string döner.
include=relatedProducts.images gibi zincirleme yol desteklenmez.availableForSale semantiği
availableForSale: true şu koşulda döner:
Mağaza backorder'a (eksi stoğa satış) açık veya güncel stok > 0
Yani bu alan "sepete eklenebilir mi?" sinyalidir; "depoda kaç adet var?" değil. Buton ve rozet mantığını doğrudan bu boolean'a bağla. availableForSale herkese açıktır — storefront:read scope'u olmayan anonim istekte de döner.
Ham stok adedi (stock) ayrı bir alandır ve yetkiye bağlıdır — bkz. stock semantiği.
stock semantiği
stock ürünün ham stok adedidir (kaç adet kaldı) ve yetkiye bağlıdır: yalnızca storefront:read scope'lu bir token ile yapılan isteklerde döner. Token gönderilmeyen (anonim) veya bu scope'u taşımayan isteklerde alan yanıtta hiç yer almaz (null değil — varlık kontrolü yapın).
{ "stock": 12, "availableForSale": true }
stockveavailableForSalefarklı sorulara yanıt verir:availableForSale"sepete eklenebilir mi?" (herkese açık boolean, backorder ayarını da hesaba katar),stockise "depoda kaç adet var?" (yetkili ham sayı). Vitrin butonunuavailableForSale'e, "son N ürün" gibi adet gösterimlerinistock'a bağlayın.- Anonim vitrinde
stockalanı gelmeyeceği için, bu değere bağlı bileşenleri yalnızca scope'lu token ile çalışan istemciler çizmelidir.