> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flextell.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Ürünler, kategoriler, markalar ve setler

> Ürünleri, ürün kategorilerini, markaları, katalog ürünlerini ve ürün setlerini anlatır.

Bu sayfa, kliniğin ürün envanterini yöneten beş kaynağı anlatır: ürünler, ürün kategorileri, ürün markaları, salt okunur katalog ürünleri ve ürün setleri. Ürünler, stok ve satış tarafındaki kayıtlara kaynaklık eder. Stok bakiyeleri ve hareketleri için [Depolar ve stok](/api/kaynaklar/depolar-ve-stok), satış kalemleri için [Satışlar](/api/kaynaklar/satislar) sayfasına bakın.

Bu sayfadaki tüm endpoint'ler `https://app.flextell.ai/api/v1` altındadır. Her istekte `Authorization: Bearer <access_token>` ve `X-Tenant: <tenant_id>` başlıkları gerekir ([Klinikler ve X-Tenant](/api/klinikler-ve-x-tenant)). Listeler sayfalıdır; `per_page` 1–100 arasındadır, varsayılan 15'tir ([Sayfalama](/api/istekler/sayfalama)).

## Endpoint özeti

| Metot | Endpoint | Açıklama | Scope | İzin |
| - | - | - | - | - |
| GET | `/products` | Ürünleri listeler | `products:read` | `View:Product` |
| POST | `/products` | Ürün oluşturur | `products:write` | `Create:Product` |
| GET | `/products/{id}` | Ürün detayı | `products:read` | `View:Product` |
| PUT | `/products/{id}` | Ürünü günceller | `products:write` | `Update:Product` |
| DELETE | `/products/{id}` | Ürünü siler | `products:write` | `Delete:Product` |
| GET | `/product-categories` | Kategorileri listeler | `product_categories:read` | `View:ProductCategory` |
| POST | `/product-categories` | Kategori oluşturur | `product_categories:write` | `Create:ProductCategory` |
| GET | `/product-categories/{id}` | Kategori detayı | `product_categories:read` | `View:ProductCategory` |
| PUT | `/product-categories/{id}` | Kategoriyi günceller | `product_categories:write` | `Update:ProductCategory` |
| DELETE | `/product-categories/{id}` | Kategoriyi siler | `product_categories:write` | `Delete:ProductCategory` |
| GET | `/product-brands` | Markaları listeler | `product_brands:read` | `View:ProductBrand` |
| POST | `/product-brands` | Marka oluşturur | `product_brands:write` | `Create:ProductBrand` |
| GET | `/product-brands/{id}` | Marka detayı | `product_brands:read` | `View:ProductBrand` |
| PUT | `/product-brands/{id}` | Markayı günceller | `product_brands:write` | `Update:ProductBrand` |
| DELETE | `/product-brands/{id}` | Markayı siler | `product_brands:write` | `Delete:ProductBrand` |
| GET | `/catalog-products` | Katalog ürünlerini listeler | `products:read` | `View:Product` |
| GET | `/catalog-products/{id}` | Katalog ürünü ve hazır ürün taslağı | `products:read` | `View:Product` |
| GET | `/product-sets` | Ürün setlerini listeler | `products:read` | `View:ProductSet` |
| POST | `/product-sets` | Ürün seti oluşturur | `products:write` | `Create:ProductSet` |
| GET | `/product-sets/{id}` | Ürün seti ve kalemleri | `products:read` | `View:ProductSet` |
| GET | `/product-sets/{id}/sale-items` | Seti satış kalemlerine açar | `products:read` | `View:ProductSet` |
| PUT | `/product-sets/{id}` | Ürün setini günceller | `products:write` | `Update:ProductSet` |
| DELETE | `/product-sets/{id}` | Ürün setini siler | `products:write` | `Delete:ProductSet` |

Başarılı yanıtlar `{"success": true, "data": ...}` zarfıyla gelir. Başka bir kliniğe ait kayıtlar `404` döner. İzin eksikse `403 FORBIDDEN` alırsınız ([İzinler ve görünürlük](/api/izinler-ve-gorunurluk)).

## Ürün nesnesi

Ürün, kliniğe aittir. Ürün oluştururken `product_type_id` ve `base_unit_code_id` değerlerini `GET /general/product-types` ve `GET /general/unit-codes` arama listelerinden alın ([Klinik ve genel](/api/kaynaklar/klinik-ve-genel)).

| Alan | Tür | Açıklama |
| - | - | - |
| `id` | integer | Ürün kimliği. |
| `name` | string | Ürün adı. Oluşturmada zorunlu, en çok 255 karakter. |
| `full_name` | string | Marka ve ürün adından oluşan görünen ad. Salt okunur. |
| `barcode` | string, null | Barkod. Silinmemiş ürünler arasında klinik içinde benzersizdir. |
| `description` | string, null | Açıklama. |
| `invoice_name` | string, null | Faturada kullanılacak ad. |
| `product_category_id` | integer, null | Kategori. Kliniğe ait olmalıdır. |
| `product_brand_id` | integer, null | Marka. Kliniğe ait olmalıdır. |
| `product_type_id` | integer | Ürün tipi. Oluşturmada zorunlu. |
| `base_unit_code_id` | integer | Temel birim (örn. mL, ADET). Oluşturmada zorunlu. |
| `stock_tracking_mode` | string | Stok takip modu. Oluşturmada zorunlu. Aşağıdaki tabloya bakın. |
| `inner_unit_count` | integer | Bir kutudaki iç birim (veya direkt adet) sayısı. Oluşturmada zorunlu, en az 0. |
| `base_unit_per_inner` | decimal, null | Bir iç birimdeki temel birim sayısı. Her modda isteğe bağlıdır. |
| `critical_stock_level` | decimal, null | Kritik stok eşiği, takip biriminde. |
| `price` | number | Fiyat. Oluşturmada zorunlu, en az 0. Bir kutunun (paket biriminin) fiyatıdır. |
| `tax_rate` | number | KDV oranı: `0`, `1`, `10` veya `20`. Oluşturmada zorunlu. |
| `is_active` | boolean | Aktif mi. Oluşturmada zorunlu. |
| `catalog_product_id` | integer, null | Ürünün oluşturulduğu katalog kaydı. |
| `brand`, `category`, `product_type`, `unit_code` | object | İlişkili kayıtların özeti: `brand{id,name}`, `category{id,name}`, `product_type{id,name,category}`, `unit_code{id,name,code}`. |
| `import_source` | object, null | Kayıt içe aktarmayla geldiyse kaynağı. |
| `created_at`, `updated_at`, `deleted_at` | string | Zaman damgaları. |

Ürün nesnesi stok bakiyesi içermez. Bakiye için [Depolar ve stok](/api/kaynaklar/depolar-ve-stok) sayfasındaki stok endpoint'lerini kullanın.

### Stok takip modları

| `stock_tracking_mode` | Anlamı |
| - | - |
| `base_unit` | Stok temel birimde (örn. mL) tutulur. Bir kutu, `inner_unit_count × base_unit_per_inner` temel birimdir. |
| `inner_unit` | Stok iç birimde (flakon, parça) tutulur. Bir kutu, `inner_unit_count` iç birimdir. |
| `direct_unit` | Stok doğrudan adet olarak tutulur. Bir kutu, `inner_unit_count` adettir. |

### Ürün listeleme

`GET /products` için süzgeçler:

| Parametre | Açıklama |
| - | - |
| `search` | Ad, marka adı, barkod, fatura adı ve açıklamada öneki eşleştirir. |
| `product_brand_id`, `product_category_id`, `product_type_id`, `base_unit_code_id` | İlişkiye göre süzer. |
| `catalog_product_id` | Belirli bir katalog kaydından oluşturulan ürünler. |
| `is_active` | Aktiflik durumu. |
| `tax_rate` | `0`, `1`, `10` veya `20`. |
| `created_at_from`, `created_at_to` | Klinik saat dilimine göre oluşturulma aralığı. `created_at_to` o günün tamamını kapsar. |
| `sort_by` | `full_name`, `name`, `price`, `is_active`, `created_at`, `updated_at`. Varsayılan `created_at`, `sort_order` varsayılanı `desc`. |

Sıralama kuralları (Türkçe harf sıralaması, `sort_order` verilmediğinde yön) için [Filtreleme ve sıralama](/api/istekler/filtreleme-ve-siralama) sayfasına bakın.

### Ürün oluşturma

`POST /products` gövdesinde yukarıdaki alanlara ek olarak `initial_stock_quantity` gönderebilirsiniz (0 ile 9999999999.9999 arası, en çok 4 ondalık).

```bash theme={null}
curl -X POST https://app.flextell.ai/api/v1/products \
  -H "Authorization: Bearer <access_token>" \
  -H "X-Tenant: <tenant_id>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Hyaluronik asit serum",
    "product_type_id": 123,
    "base_unit_code_id": 12,
    "stock_tracking_mode": "inner_unit",
    "inner_unit_count": 5,
    "price": 1500,
    "tax_rate": 20,
    "is_active": true,
    "initial_stock_quantity": 10
  }'
```

* `initial_stock_quantity` 0'dan büyükse `Create:Product` izninin yanında `Create:StockMovement` izni de gerekir. Ürün oluşurken kliniğin varsayılan deposuna bir başlangıç stoku hareketi yazılır. Varsayılan depo yoksa `Ana Depo` adıyla oluşturulur.
* Güncellemede (`PUT`) alanların hepsi isteğe bağlıdır. Boşaltılabilir alanlara `null` göndererek değeri silebilirsiniz. `initial_stock_quantity` ve `catalog_product_id` güncellemede kabul edilmez.
* Aynı barkodu ikinci kez kaydederseniz `422` döner: `This barcode is already registered for the current tenant.`

## Kategoriler ve markalar

Kategoriler ve markalar kliniğe aittir. Ürünlere `product_category_id` ve `product_brand_id` ile bağlanır.

### Kategori nesnesi

| Alan | Tür | Açıklama |
| - | - | - |
| `id` | integer | Kategori kimliği. |
| `name` | string | Ad. Zorunlu, en çok 255 karakter. |
| `parent_id` | integer, null | Üst kategori. Kliniğe ait olmalıdır. |
| `description` | string, null | Açıklama. |
| `is_active` | boolean | Aktif mi. Oluşturmada zorunlu. |
| `parent` | object, null | Üst kategorinin özeti: `{id, name}`. |
| `created_at`, `updated_at`, `deleted_at` | string | Zaman damgaları. |

Liste süzgeçleri: `search` (ad ve açıklama), `parent_id`, `is_active`. Sıralama anahtarları: `name`, `is_active`, `created_at`, `updated_at` (varsayılan `created_at`, `desc`). Bir kategoriyi kendi üst kategorisi yaparsanız `422` döner: `A category cannot be its own parent.`

### Marka nesnesi

| Alan | Tür | Açıklama |
| - | - | - |
| `id` | integer | Marka kimliği. |
| `name` | string | Ad. Zorunlu, en çok 255 karakter. Benzersiz olması gerekmez. |
| `is_active` | boolean | Aktif mi. Oluşturmada zorunlu; güncellemede `null` kabul edilmez. |
| `products_count` | integer | Markadaki ürün sayısı (silinmiş ürünler hariç). Yalnızca listede gelir. |
| `created_at`, `updated_at`, `deleted_at` | string | Zaman damgaları. |

Liste süzgeçleri: `search` (ad), `is_active`. Sıralama anahtarları: `name`, `is_active`, `products_count`, `created_at`, `updated_at`. Marka adını değiştirdiğinizde bu markadaki ürünlerin aramada bulunma bilgisi de güncellenir.

## Katalog ürünleri

Katalog, tüm kliniklerin ortak kullandığı salt okunur bir ürün listesidir. API'den katalog kaydı eklenemez, değiştirilemez ve silinemez. Katalog erişimi `products:read` scope'u ve `View:Product` izniyle yapılır; ayrı bir katalog izni gerekmez.

| Alan | Açıklama |
| - | - |
| `id`, `name`, `description` | Katalog kaydı. |
| `brand_name` | Serbest metin marka adı. Marka kaydına bağlı değildir. |
| `stock_tracking_mode`, `product_type_id`, `base_unit_code_id`, `inner_unit_count`, `base_unit_per_inner`, `critical_stock_level` | Ürüne aktarılabilecek stok bilgileri. |
| `is_active` | Aktif mi. |
| `product_type`, `unit_code` | İlişkili kayıtların özeti. |
| `product_prefill` | Yalnızca detay yanıtında gelir. Ürün oluşturma gövdesi olarak kullanabileceğiniz taslak. |

`GET /catalog-products` süzgeçleri: `search` (ad, marka adı, açıklama), `product_type_id`, `is_active`, `created_at_from`, `created_at_to`. `is_active` göndermezseniz yalnızca aktif kayıtlar gelir. Sıralama anahtarları: `name`, `brand_name`, `created_at`, `updated_at` (varsayılan `name`, `asc`). Pasif bir katalog kaydının detayı `404` döner.

### Katalogdan ürün oluşturma

<Steps>
  <Step title="Katalog kaydını bulun">
    `GET /catalog-products?search=serum` ile arayın ve istediğiniz kaydın `id` değerini alın.
  </Step>

  <Step title="Taslağı alın">
    `GET /catalog-products/{id}` yanıtındaki `product_prefill` nesnesini okuyun. `product_brand_id` yalnızca aynı adlı bir marka klinikte zaten varsa gelir; detay endpoint'i marka oluşturmaz.
  </Step>

  <Step title="Ürünü oluşturun">
    `POST /products` gövdesine taslağı koyun, `price`, `tax_rate` ve `is_active` alanlarını ekleyin. Taslak fiyat, KDV oranı ve barkod taşımaz.
  </Step>
</Steps>

<Note>
  `POST /products` gövdesinde `catalog_product_id` gönderir ve `product_brand_id` göndermezseniz marka katalog kaydının `brand_name` değerinden çözülür: aynı adlı bir marka varsa o kullanılır, yoksa yeni ve aktif bir marka oluşturulur. Açıkça gönderdiğiniz `product_brand_id` her zaman önceliklidir. Katalogdan yalnızca bağlantı ve marka alınır; diğer alanları siz göndermelisiniz. Pasif veya silinmiş bir katalog kaydı `422` döner.
</Note>

## Ürün setleri

Ürün seti, ürün ve tedavilerden oluşan yeniden kullanılabilir bir pakettir. Set, satış oluştururken tek çağrıyla satış kalemlerine açılır. Setlerin kendi para birimi yoktur; yanıttaki `currency_code` kliniğin para birimidir.

| Alan | Tür | Açıklama |
| - | - | - |
| `id` | integer | Set kimliği. |
| `name` | string | Ad. Zorunlu, en çok 255 karakter. |
| `description` | string, null | Açıklama, en çok 65535 karakter. |
| `is_active` | boolean | Varsayılan `true`. |
| `items_count`, `treatments_count`, `products_count` | integer | Kalem sayıları. Listede ve detayda gelir. |
| `items_total_price` | number | Tüm kalemlerin KDV dahil toplamı, 2 ondalık. |
| `currency_code` | string | Kliniğin para birimi. |
| `items` | array | Kalemler. Liste yanıtında gelmez, detayda gelir. |

Her kalem (`items[]`) şu alanlara sahiptir:

| Alan | Zorunlu | Açıklama |
| - | - | - |
| `itemable_type` | evet | `Product` veya `Treatment`. |
| `itemable_id` | evet | Kliniğe ait ürün veya tedavi kimliği. |
| `quantity` | evet | En az 0.0001. |
| `unit_price` | evet | Birim fiyat, KDV hariç. En az 0. |
| `tax_rate` | evet | `0`, `1`, `10` veya `20`. |
| `description` | hayır | En çok 255 karakter. |
| `order` | hayır | Sıra. |

`GET /product-sets` süzgeçleri: `search` (ad ve açıklama), `is_active`, `created_at_from`, `created_at_to`. Sıralama anahtarları: `created_at` (varsayılan, `desc`), `updated_at`, `name`.

<Warning>
  `PUT /product-sets/{id}` isteğinde `items` gönderirseniz mevcut kalemlerin hepsi bu listeyle değiştirilir. Kalemleri değiştirmeyecekseniz `items` alanını hiç göndermeyin.
</Warning>

### Seti satış kalemlerine açma

`GET /product-sets/{id}/sale-items`, setin kalemlerini `POST /sales` gövdesindeki `items[]` biçiminde döndürür. Yanıtta `product_set_id`, `name`, `items[]` ve `total_price` bulunur. Her kalemde `staff_id` ve `warehouse_id` `null` gelir; `staff_id` satış oluştururken zorunlu olduğu için sizin doldurmanız gerekir. Miktar en az 1'e yükseltilir, indirimler 0'dır. Satış oluşturma ayrıntıları için [Satışlar](/api/kaynaklar/satislar) sayfasına bakın.

## Kurallar

* **KDV oranları.** `tax_rate` yalnızca `0`, `1`, `10`, `20` olabilir. `8` ve `18` reddedilir.
* **Silme.** Ürün, kategori ve marka silme geri alınabilir bir silmedir ve bağımlılık denetimi yapmaz: stoğu veya satış kalemi olan ürün, ürünleri olan marka ya da alt kategorisi olan kategori silinebilir. Silinen kayıtlar Geri Dönüşüm Kutusu'ndan geri yüklenemez. Silinen ürünün barkodu yeniden kullanılabilir. Genel kurallar için [Silme yaşam döngüsü](/api/istekler/silme-yasam-dongusu) sayfasına bakın.
* **Set silme.** `DELETE /product-sets/{id}` kalıcıdır; setin kalemleri de silinir.
* **Başka kliniğin kaydı.** Başka bir kliniğe ait marka veya kategori kimliği göndermek `422` döner.
* **Arama.** Ürün aramasında sonuçlar önce eşleşme ilgisine göre sıralanır. Açık bir `sort_by` verirseniz sıralamayı o belirler.

### Hata kodları

| Kod | HTTP | Ne zaman |
| - | - | - |
| `RESOURCE_NOT_FOUND` | 404 | Kayıt yok, başka kliniğe ait veya (katalogda) pasif. |
| `VALIDATION_FAILED` | 422 | Alan doğrulaması başarısız: zorunlu alan eksik, geçersiz KDV oranı, yinelenen barkod, kendi üst kategorisi olma. |
| `FORBIDDEN` | 403 | İzin eksik. Başlangıç stoklu ürün oluşturmada `Create:StockMovement` yoksa da bu hata döner. |

Tüm hata biçimleri için [Hata kodları](/api/istekler/hata-kodlari) sayfasına bakın. Bu kaynakları panelde nasıl yöneteceğiniz için [Ürünler](/panel/finans/urunler) sayfasına bakın.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.