openapi: 3.1.0
info:
  title: Sırmava Kuyumcu E-Ticaret API
  version: 1.0.0
  summary: Kuyumcu e-ticaret sitesi, mobil uygulama ve mağaza paneli için ortak REST sözleşmesi
  description: |
    Sırmava web sitesi, React Native mobil uygulaması ve mağaza yönetim paneli aynı `ApiClient` sözleşmesini kullanır.
    Demo sürümünde `MockAdapter` bu uçları tarayıcı içinde taklit eder; kurulumda `HttpAdapter` gerçek sunucuya bağlanır.
    Bütün tutarlar KURUŞ cinsinden tamsayıdır (1 ₺ = 100); ağırlıklar gram (2 ondalık), saflık milyem (binde).
    Ürünün kayıtlı fiyatı yoktur: fiyat her istekte canlı has altın / gümüş fiyatından `urunFiyat` ile hesaplanır
    (altın = gram × milyem × has satış + işçilik + taş; KDV mevzuata göre işçilik ve taş üzerinden; gümüşte tüm bedel üzerinden; yatırımlık altında KDV uygulanmaz).
    Sepete eklenen ürünün fiyatı sunucuda KİLİTLENİR (varsayılan 10 dk); ödeme kilit süresi içinde kilitli tutarla alınır.
    Ödeme sağlayıcılarının gizli anahtarları yalnız sunucudadır; istemci kart verisi görmez (PayTR iFrame / iyzico Checkout Form).
    Demo fiyatları örnek simülasyondur; kurulumda lisanslı fiyat sağlayıcı bağlanır. Bu belge Briefikir tarafından hazırlanmış bir demo sözleşmesidir.
  contact:
    name: Briefikir
    url: https://www.briefikir.com.tr/yazilim/e-ticaret-yazilimi/
servers:
  - url: https://api.ornek-kuyumcu.com
    description: Üretim (kurulumda mağazanın alan adı)
  - url: https://api-test.ornek-kuyumcu.com
    description: Test ortamı
security:
  - bearer: []
tags:
  - name: Oturum
    description: Telefonla tek kullanımlık kod girişi, bayi girişi, jeton yenileme
  - name: Fiyat
    description: Canlı has altın / gümüş, kalem tablosu (çeyrek, 22 ayar…), geçmiş, dalgalanma durumu
  - name: Katalog
    description: Kategoriler, koleksiyonlar, ürünler, varyant fiyatı ve şeffaf fiyat dökümü
  - name: Sepet
    description: Sepet satırları, fiyat kilidi, kişiselleştirme (gravür), kupon
  - name: Siparişler
    description: Sipariş verme, Siparişlerim, iade ve ölçü değişimi talebi
  - name: Müşteri
    description: Favoriler, fiyat alarmları, birikim planı, ölçüler, KVKK
  - name: Ödeme
    description: PayTR / iyzico ödeme başlatma, 3D Secure dönüşü, bildirim (callback), iade
  - name: Panel · Satış
    description: Sipariş yönetimi, atölye iş emirleri, kargo, bayi (rol yetkili)
  - name: Panel · Fiyat
    description: Makas, fiyat kuralları, kilit süresi, satış duraklatma (rol yetkili)
paths:
  /v1/oturum/kod:
    post:
      tags: [Oturum]
      summary: Telefona tek kullanımlık giriş kodu gönder
      security: []
      requestBody:
        content:
          application/json:
            schema: { type: object, required: [telefon], properties: { telefon: { type: string, example: '0123 456 12 34' } } }
      responses:
        '204': { description: 'Kod gönderildi (SMS)' }
        '429': { $ref: '#/components/responses/HizSiniri' }
  /v1/oturum/dogrula:
    post:
      tags: [Oturum]
      summary: Kodu doğrula, erişim ve yenileme jetonu al
      security: []
      requestBody:
        content:
          application/json:
            schema: { type: object, required: [telefon, kod], properties: { telefon: { type: string }, kod: { type: string, example: '482613' } } }
      responses:
        '200':
          description: Jetonlar (erişim 15 dk, yenileme 30 gün)
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Jeton' }
        '401': { $ref: '#/components/responses/Yetkisiz' }
  /v1/oturum/bayi:
    post:
      tags: [Oturum]
      summary: Toptan bayi girişi — sonraki fiyat yanıtları toptan (işçilik milyemi) hesaplanır
      security: []
      requestBody:
        content:
          application/json:
            schema: { type: object, required: [kod, parola], properties: { kod: { type: string, example: 'BAYI-4826' }, parola: { type: string } } }
      responses:
        '200':
          description: Bayi jetonu
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Jeton' }
        '403': { description: 'Bayi hesabı onay bekliyor ya da pasif' }
  /v1/oturum/yenile:
    post:
      tags: [Oturum]
      summary: Yenileme jetonuyla yeni erişim jetonu
      security: []
      requestBody:
        content:
          application/json:
            schema: { type: object, properties: { yenile: { type: string } } }
      responses:
        '200':
          description: Yeni jetonlar
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Jeton' }
  /v1/fiyat/canli:
    get:
      tags: [Fiyat]
      summary: Anlık piyasa (has altın ve has gümüş alış/satış, döviz, 24 saat değişim)
      description: Sunucu-gönderimli olay akışı da vardır (`/v1/fiyat/akis`, text/event-stream, 5 sn).
      security: []
      responses:
        '200':
          description: Piyasa anı
          content:
            application/json:
              schema: { $ref: '#/components/schemas/PiyasaAn' }
  /v1/fiyat/kalemler:
    get:
      tags: [Fiyat]
      summary: Kalem tablosu (gram altın, 22/18/14 ayar, çeyrek, yarım, tam, Ata, gremse, gümüş) — makaslı alış/satış
      security: []
      responses:
        '200':
          description: Kalemler
          content:
            application/json:
              schema: { type: array, items: { $ref: '#/components/schemas/KalemFiyat' } }
  /v1/fiyat/gecmis:
    get:
      tags: [Fiyat]
      summary: Günlük kapanış geçmişi (grafik)
      security: []
      parameters:
        - { name: gun, in: query, schema: { type: integer, enum: [30, 90, 365], default: 90 } }
      responses:
        '200':
          description: Kapanışlar
          content:
            application/json:
              schema: { type: array, items: { type: object, properties: { gun: { type: string, format: date }, has: { type: integer }, gumus: { type: integer }, usd: { type: integer } } } }
  /v1/fiyat/durum:
    get:
      tags: [Fiyat]
      summary: Satış durumu — ani dalgalanmada altın satışı duraklatıldıysa neden ve zaman
      security: []
      responses:
        '200':
          description: Durum
          content:
            application/json:
              schema: { type: object, properties: { satisDurdu: { type: boolean }, neden: { type: string }, t: { type: string, format: date-time }, kilitDk: { type: integer, example: 10 } } }
  /v1/kategoriler:
    get:
      tags: [Katalog]
      summary: Kategori ağacı (altın, gümüş 925, pırlanta, kişiye özel, yatırımlık, hediye)
      security: []
      responses:
        '200':
          description: Kategoriler
          content:
            application/json:
              schema: { type: array, items: { $ref: '#/components/schemas/Kategori' } }
  /v1/urunler:
    get:
      tags: [Katalog]
      summary: Ürün listesi — süzgeç ve canlı "başlayan" fiyat
      security: []
      parameters:
        - { name: kategori, in: query, schema: { type: string, example: 'altin' } }
        - { name: alt, in: query, schema: { type: string, example: 'yuzuk' } }
        - { name: ayar, in: query, schema: { type: array, items: { type: string, enum: ['8', '14', '18', '22', '24', '925', '950'] } } }
        - { name: renk, in: query, schema: { type: string, enum: [sari, beyaz, rose, rodaj, oksit, dogal, altin-kaplama] } }
        - { name: gramMin, in: query, schema: { type: number } }
        - { name: gramMax, in: query, schema: { type: number } }
        - { name: fiyatMin, in: query, description: 'Kuruş (canlı fiyata göre)', schema: { type: integer } }
        - { name: fiyatMax, in: query, schema: { type: integer } }
        - { name: koleksiyon, in: query, schema: { type: string } }
        - { name: kisisel, in: query, schema: { type: boolean } }
        - { name: imlec, in: query, schema: { type: string } }
      responses:
        '200':
          description: Ürünler
          content:
            application/json:
              schema: { type: object, properties: { urunler: { type: array, items: { $ref: '#/components/schemas/Urun' } }, sonraki: { type: string } } }
  /v1/urunler/{id}:
    get:
      tags: [Katalog]
      summary: Ürün detayı (metin, taş bilgisi, kişiselleştirme ayarı, mağaza stoğu)
      security: []
      parameters:
        - { name: id, in: path, required: true, schema: { type: string, example: 'sirma-burgu-yuzuk' } }
      responses:
        '200':
          description: Ürün
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Urun' }
        '404': { $ref: '#/components/responses/Bulunamadi' }
  /v1/urunler/{id}/fiyat:
    get:
      tags: [Katalog]
      summary: Varyant fiyatı ve şeffaf döküm (gram, milyem, has karşılığı, işçilik, taş, KDV)
      security: []
      parameters:
        - { name: id, in: path, required: true, schema: { type: string } }
        - { name: ayar, in: query, required: true, schema: { type: string, example: '14' } }
        - { name: renk, in: query, required: true, schema: { type: string, example: 'sari' } }
        - { name: olcu, in: query, description: 'Yüzük TR ölçüsü / bileklik cm / zincir cm', schema: { type: number, example: 14 } }
        - { name: kisisel, in: query, schema: { type: boolean } }
      responses:
        '200':
          description: Fiyat dökümü (bayi jetonuyla toptan)
          content:
            application/json:
              schema: { $ref: '#/components/schemas/FiyatDokum' }
  /v1/arama:
    get:
      tags: [Katalog]
      summary: Türkçe karakter duyarsız, yazım toleranslı arama ("pirlanta" → pırlanta)
      security: []
      parameters:
        - { name: q, in: query, required: true, schema: { type: string } }
      responses:
        '200':
          description: Sonuçlar ve öneri
          content:
            application/json:
              schema: { type: object, properties: { sonuc: { type: array, items: { $ref: '#/components/schemas/Urun' } }, oneri: { type: string, example: 'pırlanta' } } }
  /v1/sepet:
    get:
      tags: [Sepet]
      summary: Sepet ve hesap (kilitli birimler, kalan kilit süreleri, kargo, sigorta, KDV)
      responses:
        '200':
          description: Sepet hesabı
          content:
            application/json:
              schema: { $ref: '#/components/schemas/SepetHesap' }
    patch:
      tags: [Sepet]
      summary: Sepet ayarları (teslimat kargo/mağaza, adres, hediye paketi ve notu, sigorta, fatura)
      requestBody:
        content:
          application/json:
            schema: { type: object, properties: { teslimat: { type: string, enum: [kargo, magaza] }, adres: { type: string }, magaza: { type: string }, hediyePaketi: { type: boolean }, hediyeNotu: { type: string, maxLength: 240 }, sigorta: { type: boolean }, fatura: { type: object } } }
      responses:
        '200': { description: 'Güncel sepet' }
  /v1/sepet/satirlar:
    post:
      tags: [Sepet]
      summary: Sepete ekle — sunucu o anın fiyatını hesaplar ve KİLİTLER
      description: Altın satışı ani dalgalanma nedeniyle duraklatılmışsa altın ürünlerde 409 döner. Kişiye özel üründe yazı zorunludur.
      requestBody:
        content:
          application/json:
            schema: { $ref: '#/components/schemas/SepetEkle' }
      responses:
        '201':
          description: Eklenen satır ve kilit
          content:
            application/json:
              schema: { type: object, properties: { satir: { type: string }, kilit: { $ref: '#/components/schemas/FiyatKilidi' } } }
        '409': { description: 'Altın satışı geçici olarak duraklatıldı' }
        '422': { $ref: '#/components/responses/Gecersiz' }
  /v1/sepet/satirlar/{id}:
    patch:
      tags: [Sepet]
      summary: Adet değiştir (0 → sil)
      parameters:
        - { name: id, in: path, required: true, schema: { type: string } }
      requestBody:
        content:
          application/json:
            schema: { type: object, properties: { adet: { type: integer, minimum: 0, maximum: 10 } } }
      responses:
        '200': { description: 'Güncel sepet' }
  /v1/sepet/kilit-yenile:
    post:
      tags: [Sepet]
      summary: Süresi dolan kilitleri güncel fiyatla yenile (müşteri onayıyla)
      requestBody:
        content:
          application/json:
            schema: { type: object, properties: { hepsi: { type: boolean, default: false } } }
      responses:
        '200':
          description: Yeni kilitler ve fiyat farkı
          content:
            application/json:
              schema: { type: object, properties: { fark: { type: integer, description: 'Kuruş (yeni − eski)' }, kilitler: { type: array, items: { $ref: '#/components/schemas/FiyatKilidi' } } } }
  /v1/sepet/kupon:
    post:
      tags: [Sepet]
      summary: Kupon uygula / kaldır
      requestBody:
        content:
          application/json:
            schema: { type: object, properties: { kod: { type: [string, 'null'], example: 'ISIL10' } } }
      responses:
        '200': { description: 'Güncel sepet' }
        '422': { $ref: '#/components/responses/Gecersiz' }
  /v1/siparisler:
    get:
      tags: [Siparişler]
      summary: Siparişlerim
      responses:
        '200':
          description: Siparişler
          content:
            application/json:
              schema: { type: array, items: { $ref: '#/components/schemas/Siparis' } }
    post:
      tags: [Siparişler]
      summary: Sipariş oluştur (ödeme başarıyla kesinleştikten sonra sunucu çağırır ya da havale için doğrudan)
      description: Kilit süresi dolmuş satır varsa 409. Kişiye özel ürün varsa kisiselOnay=true zorunlu (cayma hakkı istisnası). Yüksek tutarda ek doğrulama gerekir.
      requestBody:
        content:
          application/json:
            schema: { type: object, required: [yontem], properties: { yontem: { type: string, enum: [kart, kayitli-kart, havale] }, odemeReferans: { type: string }, kisiselOnay: { type: boolean }, ekDogrulama: { type: string, description: 'Ek doğrulama kodu (yüksek tutar)' } } }
      responses:
        '201':
          description: Sipariş
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Siparis' }
        '409': { description: 'Fiyat kilidi süresi doldu — /v1/sepet/kilit-yenile' }
  /v1/siparisler/{id}:
    get:
      tags: [Siparişler]
      summary: Sipariş detayı (durum zaman çizgisi, atölye, sigortalı kargo takibi, kilit kaydı)
      parameters:
        - { $ref: '#/components/parameters/SiparisId' }
      responses:
        '200':
          description: Sipariş
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Siparis' }
        '404': { $ref: '#/components/responses/Bulunamadi' }
  /v1/siparisler/{id}/iade-talebi:
    post:
      tags: [Siparişler]
      summary: İade, değişim ya da ölçü değişimi talebi (ölçü değişimi yeni atölye iş emri açar)
      parameters:
        - { $ref: '#/components/parameters/SiparisId' }
      requestBody:
        content:
          application/json:
            schema: { type: object, required: [tur, satirlar, neden], properties: { tur: { type: string, enum: [iade, olcu-degisim, degisim, tamir] }, satirlar: { type: array, items: { type: integer } }, neden: { type: string }, yeniOlcu: { type: number } } }
      responses:
        '201': { description: 'Talep oluşturuldu' }
        '422': { description: 'Kişiye özel ürünlerde cayma hakkı istisnası (mevzuata göre)' }
  /v1/ben/alarmlar:
    get:
      tags: [Müşteri]
      summary: Fiyat alarmlarım
      responses:
        '200':
          description: Alarmlar
          content:
            application/json:
              schema: { type: array, items: { $ref: '#/components/schemas/FiyatAlarmi' } }
    post:
      tags: [Müşteri]
      summary: Fiyat alarmı kur (ürün, has altın, gümüş ya da çeyrek hedef fiyata inince/çıkınca bildirim)
      requestBody:
        content:
          application/json:
            schema: { $ref: '#/components/schemas/FiyatAlarmi' }
      responses:
        '201': { description: 'Alarm kuruldu' }
  /v1/ben/favoriler/{urun}:
    put:
      tags: [Müşteri]
      summary: Favoriye ekle
      parameters:
        - { name: urun, in: path, required: true, schema: { type: string } }
      responses:
        '204': { description: 'Eklendi' }
    delete:
      tags: [Müşteri]
      summary: Favoriden çıkar
      parameters:
        - { name: urun, in: path, required: true, schema: { type: string } }
      responses:
        '204': { description: 'Çıkarıldı' }
  /v1/ben/birikim:
    put:
      tags: [Müşteri]
      summary: Altın birikim planı (örnek akış — yatırım ürünü değildir)
      requestBody:
        content:
          application/json:
            schema: { type: object, properties: { aylik: { type: integer, description: 'Kuruş' }, gun: { type: integer, minimum: 1, maximum: 28 }, durum: { type: string, enum: [aktif, durduruldu] } } }
      responses:
        '200': { description: 'Plan' }
  /v1/ben/veri-disa-aktarim:
    get:
      tags: [Müşteri]
      summary: KVKK — kişisel verilerin JSON dökümü
      responses:
        '200': { description: 'JSON' }
  /v1/odeme/baslat:
    post:
      tags: [Ödeme]
      summary: Ödemeyi başlat — etkin sağlayıcı (hata verirse yedek) için iFrame / Checkout Form
      description: |
        Sunucu sepeti kilitli fiyatlarla yeniden hesaplar (istemci tutarına güvenilmez), kilit süresini denetler ve sağlayıcıya tam tutarla satış (auth) isteği gönderir.
        PayTR — `get-token` (HMAC-SHA256, merchant_key + merchant_salt yalnız sunucuda) → `url` iFrame'de açılır.
        iyzico — Checkout Form initialize (IYZWSv2 imzası) → `icerik` (sağlayıcının betiği) ya da `paymentPageUrl`.
        Kuyumcuda ön provizyon kullanılmaz: kesin tutar ödeme anında bellidir.
      requestBody:
        content:
          application/json:
            schema: { type: object, properties: { taksit: { type: integer, minimum: 1, maximum: 12 }, kayitliKart: { type: string } } }
      responses:
        '200':
          description: Ödeme oturumu
          content:
            application/json:
              schema: { $ref: '#/components/schemas/OdemeBaslat' }
        '409': { description: 'Fiyat kilidi süresi doldu ya da altın satışı duraklatıldı' }
  /v1/odeme/donus/{saglayici}:
    post:
      tags: [Ödeme]
      summary: 3D Secure dönüşü (tarayıcı) — yalnız sonucu gösterir; kesinleşme sunucu sorgusu/bildirimiyle
      security: []
      parameters:
        - { name: saglayici, in: path, required: true, schema: { type: string, enum: [paytr, iyzico] } }
      responses:
        '303': { description: 'Sipariş sayfasına yönlendir' }
  /v1/odeme/bildirim/paytr/{magazaAnahtari}:
    post:
      tags: [Ödeme]
      summary: PayTR bildirimi (callback) — hash doğrulanır, idempotent işlenir, düz metin "OK" döner
      description: Bildirim adresi PayTR mağaza panelinde TEK tanımlıdır (istekle gönderilmez); bu yüzden mağazaya özel anahtar yol parametresinde taşınır. Test kipindeki ödeme sipariş/tahsilat YAZMAZ.
      security: []
      parameters:
        - { name: magazaAnahtari, in: path, required: true, schema: { type: string } }
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema: { type: object, properties: { merchant_oid: { type: string }, status: { type: string, enum: [success, failed] }, total_amount: { type: string }, hash: { type: string }, test_mode: { type: string } } }
      responses:
        '200': { description: 'OK' }
        '400': { description: 'İmza geçersiz' }
  /v1/odeme/bildirim/iyzico:
    post:
      tags: [Ödeme]
      summary: iyzico callback — token ile Checkout Form detay sorgusu (sunucudan) yapılır, sonuç ona göre yazılır
      security: []
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema: { type: object, properties: { token: { type: string } } }
      responses:
        '303': { description: 'Sonuç sayfası' }
  /v1/odeme/taksit:
    get:
      tags: [Ödeme]
      summary: BIN'e göre taksit seçenekleri (sağlayıcı sorgusu)
      parameters:
        - { name: bin, in: query, required: true, schema: { type: string, pattern: '^[0-9]{6,8}$' } }
        - { name: tutar, in: query, required: true, schema: { type: integer } }
      responses:
        '200':
          description: Taksitler
          content:
            application/json:
              schema: { type: array, items: { type: object, properties: { taksit: { type: integer }, toplam: { type: integer }, aylik: { type: integer } } } }
  /v1/panel/siparisler/{id}/iade:
    post:
      tags: [Ödeme, Panel · Satış]
      summary: Tam/kısmi iade — iade toplamı net tahsilatı aşamaz; anahtar ile idempotent
      parameters:
        - { $ref: '#/components/parameters/SiparisId' }
      requestBody:
        content:
          application/json:
            schema: { type: object, required: [tutar, gerekce], properties: { tutar: { type: integer }, gerekce: { type: string }, anahtar: { type: string, description: 'Idempotency-Key' } } }
      responses:
        '200': { description: 'İade işlendi (kismi-iade | iade)' }
        '422': { description: 'İade tutarı iade edilebilir kalanı aşıyor' }
  /v1/panel/siparisler:
    get:
      tags: [Panel · Satış]
      summary: Sipariş listesi (durum, kanal, mağaza süzgeci)
      parameters:
        - { name: durum, in: query, schema: { type: string } }
        - { name: kanal, in: query, schema: { type: string } }
      responses:
        '200': { description: 'Siparişler' }
  /v1/panel/siparisler/{id}/durum:
    post:
      tags: [Panel · Satış]
      summary: Durum geçişi (alındı → atölye → kalite → kargoya hazır → sigortalı kargo → teslim)
      parameters:
        - { $ref: '#/components/parameters/SiparisId' }
      requestBody:
        content:
          application/json:
            schema: { type: object, required: [durum], properties: { durum: { type: string } } }
      responses:
        '200': { description: 'Yeni durum' }
        '409': { description: 'Geçersiz geçiş' }
  /v1/panel/siparisler/{id}/kargo:
    post:
      tags: [Panel · Satış]
      summary: Sigortalı kargo etiketi (değer beyanlı)
      parameters:
        - { $ref: '#/components/parameters/SiparisId' }
      responses:
        '201': { description: 'Takip numarası ve etiket PDF adresi' }
  /v1/panel/is-emirleri:
    get:
      tags: [Panel · Satış]
      summary: Atölye kuyruğu (gravür, isim kolye, ölçü değişimi, üretim)
      responses:
        '200':
          description: İş emirleri
          content:
            application/json:
              schema: { type: array, items: { $ref: '#/components/schemas/IsEmri' } }
  /v1/panel/is-emirleri/{id}:
    patch:
      tags: [Panel · Satış]
      summary: İş emri ilerlet / usta ata / kalite kontrol fotoğrafı / müşteri onayı iste
      parameters:
        - { name: id, in: path, required: true, schema: { type: string } }
      requestBody:
        content:
          application/json:
            schema: { type: object, properties: { durum: { type: string, enum: [kuyruk, uretimde, kalite, musteri-onay, tamam, iptal] }, usta: { type: string }, kkFoto: { type: string, description: 'Yükleme anahtarı (/v1/medya/yukleme)' }, kkNot: { type: string } } }
      responses:
        '200': { description: 'İş emri' }
  /v1/panel/fiyat/ayar:
    get:
      tags: [Panel · Fiyat]
      summary: Fiyat ayarları (kaynak, makaslar, ürün makası, kilit süresi, dalgalanma eşiği, kurallar)
      responses:
        '200':
          description: Ayarlar
          content:
            application/json:
              schema: { $ref: '#/components/schemas/FiyatAyar' }
    patch:
      tags: [Panel · Fiyat]
      summary: Fiyat ayarlarını güncelle — siteye anında yansır
      requestBody:
        content:
          application/json:
            schema: { $ref: '#/components/schemas/FiyatAyar' }
      responses:
        '200': { description: 'Güncel ayar' }
  /v1/panel/fiyat/duraklat:
    post:
      tags: [Panel · Fiyat]
      summary: Altın satışını duraklat / sürdür (ani dalgalanma)
      requestBody:
        content:
          application/json:
            schema: { type: object, properties: { durdur: { type: boolean }, neden: { type: string } } }
      responses:
        '200': { description: 'Satış durumu' }
  /v1/panel/bayiler:
    get:
      tags: [Panel · Satış]
      summary: Bayi hesapları (toptan gümüş, işçilik milyemi, minimum gram, vade, limit)
      responses:
        '200':
          description: Bayiler
          content:
            application/json:
              schema: { type: array, items: { $ref: '#/components/schemas/Bayi' } }
  /v1/medya/yukleme:
    post:
      tags: [Panel · Satış]
      summary: Medya yükleme bileti (presigned URL) — kalite kontrol fotoğrafı, 360 kare dizisi, AR dekupe
      requestBody:
        content:
          application/json:
            schema: { type: object, required: [ad, tur, boyut], properties: { ad: { type: string }, tur: { type: string, example: 'image/jpeg' }, boyut: { type: integer, maximum: 15728640 } } }
      responses:
        '200': { description: 'Bilet: url, yöntem PUT, başlıklar, anahtar' }
webhooks:
  siparisDurumu:
    post:
      tags: [Siparişler]
      summary: Sipariş durumu değişti (ERP, kargo ve bildirim servislerine giden olay)
      requestBody:
        content:
          application/json:
            schema: { type: object, properties: { olay: { type: string, example: 'siparis.durum' }, siparis: { type: string, example: 'SR-24817' }, durum: { type: string, example: 'kargoda' }, t: { type: string, format: date-time } } }
      responses:
        '200': { description: 'Alındı' }
  fiyatAlarmi:
    post:
      tags: [Müşteri]
      summary: Fiyat alarmı tetiklendi (push / SMS / e-posta servisine)
      requestBody:
        content:
          application/json:
            schema: { type: object, properties: { olay: { type: string, example: 'alarm.tetiklendi' }, musteri: { type: string }, hedef: { type: integer }, guncel: { type: integer } } }
      responses:
        '200': { description: 'Alındı' }
  satisDuraklatildi:
    post:
      tags: [Panel · Fiyat]
      summary: Ani dalgalanmada altın satışı duraklatıldı / sürdürüldü (pazaryeri fiyat gönderimini de durdurur)
      requestBody:
        content:
          application/json:
            schema: { type: object, properties: { olay: { type: string, example: 'fiyat.duraklatildi' }, durdu: { type: boolean }, degisimYuzde: { type: number }, t: { type: string, format: date-time } } }
      responses:
        '200': { description: 'Alındı' }
  isEmri:
    post:
      tags: [Panel · Satış]
      summary: Atölye iş emri durumu (kalite kontrol fotoğrafı yüklendi, müşteri onayı bekleniyor)
      requestBody:
        content:
          application/json:
            schema: { type: object, properties: { olay: { type: string, example: 'isemri.kalite' }, isEmri: { type: string, example: 'AT-3108' }, durum: { type: string } } }
      responses:
        '200': { description: 'Alındı' }
components:
  securitySchemes:
    bearer: { type: http, scheme: bearer, bearerFormat: JWT }
    paytrImza: { type: apiKey, in: header, name: X-Paytr-Hash, description: 'Bildirim gövdesindeki hash: base64(HMAC-SHA256(merchant_oid + merchant_salt + status + total_amount, merchant_key))' }
  parameters:
    SiparisId: { name: id, in: path, required: true, schema: { type: string, example: 'SR-24817' } }
  responses:
    Yetkisiz: { description: 'Oturum gerekli ya da jeton süresi doldu' }
    Bulunamadi: { description: 'Kayıt bulunamadı' }
    Gecersiz: { description: 'Doğrulama hatası (alan: ileti)' }
    HizSiniri: { description: 'Çok fazla istek' }
  schemas:
    Jeton:
      type: object
      properties:
        erisim: { type: string }
        yenile: { type: string }
        bitis: { type: integer, description: 'Unix ms' }
    PiyasaAn:
      type: object
      properties:
        t: { type: integer, description: 'ms' }
        hasAlis: { type: integer, example: 614200 }
        hasSatis: { type: integer, example: 618240 }
        gumusAlis: { type: integer, example: 7720 }
        gumusSatis: { type: integer, example: 7840 }
        usd: { type: integer, example: 4562 }
        eur: { type: integer, example: 5291 }
        degisim: { type: number, description: 'Has, 24 saat (%)' }
        gumusDegisim: { type: number }
    KalemFiyat:
      type: object
      properties:
        id: { type: string, example: 'ceyrek' }
        ad: { type: string, example: 'Çeyrek altın' }
        alis: { type: integer }
        satis: { type: integer }
        degisim: { type: number }
        birim: { type: string, example: '₺/adet' }
    Kategori:
      type: object
      properties:
        id: { type: string, example: 'altin' }
        ad: { type: string, example: 'Altın Takı' }
        altlar: { type: array, items: { type: object, properties: { id: { type: string }, ad: { type: string } } } }
    Urun:
      type: object
      properties:
        id: { type: string, example: 'sirma-burgu-yuzuk' }
        ad: { type: string, example: 'Sırma Burgu Yüzük' }
        kategori: { type: string }
        alt: { type: string }
        metal: { type: string, enum: [altin, gumus] }
        ayarlar: { type: array, items: { type: string } }
        renkler: { type: array, items: { type: string } }
        gram: { type: number, example: 2.4 }
        iscilik: { type: object, properties: { tip: { type: string, enum: [gram, yuzde, sabit] }, deger: { type: number } } }
        tas: { type: object, properties: { tur: { type: string }, karat: { type: number }, renk: { type: string }, berraklik: { type: string }, kesim: { type: string }, sertifika: { type: boolean } } }
        olcu: { type: string, enum: [yuzuk, bileklik, zincir, bilezik] }
        kisisel: { type: object, properties: { tur: { type: string }, maxKarakter: { type: integer }, fontlar: { type: array, items: { type: string } }, ekUcret: { type: integer }, ekGun: { type: integer } } }
        stokta: { type: boolean }
        uretimGun: { type: integer }
        baslayanFiyat: { type: integer, description: 'Varsayılan varyantın canlı fiyatı (kuruş)' }
    FiyatDokum:
      type: object
      properties:
        gram: { type: number }
        milyem: { type: integer, example: 585 }
        has: { type: number }
        madenBirim: { type: integer }
        maden: { type: integer }
        iscilik: { type: integer }
        iscilikIndirim: { type: integer }
        tas: { type: integer }
        kisisel: { type: integer }
        matrah: { type: integer, description: 'KDV matrahı (altında işçilik + taş; gümüşte tüm bedel)' }
        kdvOran: { type: number }
        kdv: { type: integer }
        toplam: { type: integer }
        istisna: { type: string }
    FiyatKilidi:
      type: object
      properties:
        t: { type: string, format: date-time }
        bitis: { type: string, format: date-time }
        birim: { type: integer, description: 'Kilitli birim fiyat (kuruş)' }
        hasSatis: { type: integer }
        gumusSatis: { type: integer }
    SepetEkle:
      type: object
      required: [urun, ayar, renk]
      properties:
        urun: { type: string }
        ayar: { type: string }
        renk: { type: string }
        olcu: { type: number }
        adet: { type: integer, default: 1 }
        kisisel: { type: object, properties: { metin: { type: string, maxLength: 24 }, font: { type: string } } }
    SepetHesap:
      type: object
      properties:
        satirlar: { type: array, items: { type: object, properties: { id: { type: string }, urun: { type: string }, birim: { type: integer }, tutar: { type: integer }, kilitli: { type: boolean }, kilitBitti: { type: boolean }, guncelBirim: { type: integer } } } }
        araToplam: { type: integer }
        kuponIndirimi: { type: integer }
        kargo: { type: integer }
        sigorta: { type: integer, description: 'Değer beyanlı sigortalı kargo' }
        hediyePaketi: { type: integer }
        toplam: { type: integer }
        kdv: { type: integer }
        kilitBitis: { type: string, format: date-time }
        yuksekTutar: { type: boolean, description: 'Ek doğrulama gerekir' }
    Siparis:
      type: object
      properties:
        id: { type: string }
        no: { type: string, example: 'SR-24817' }
        durum: { type: string, enum: [odeme-bekliyor, alindi, atolyede, kalite, hazir, kargoda, magazada, teslim, iptal, iade] }
        teslimat: { type: string, enum: [kargo, magaza] }
        tutar: { type: object, properties: { araToplam: { type: integer }, kargo: { type: integer }, sigorta: { type: integer }, toplam: { type: integer }, kdv: { type: integer } } }
        odeme: { type: object, properties: { yontem: { type: string }, saglayici: { type: string }, durum: { type: string }, tahsil: { type: integer }, iade: { type: integer }, taksit: { type: integer } } }
        kilitKaydi: { $ref: '#/components/schemas/FiyatKilidi' }
        kargo: { type: object, properties: { firma: { type: string }, takip: { type: string }, deger: { type: integer }, sigortali: { type: boolean } } }
        zaman: { type: array, items: { type: object, properties: { t: { type: string }, durum: { type: string }, metin: { type: string } } } }
    IsEmri:
      type: object
      properties:
        id: { type: string }
        no: { type: string, example: 'AT-3108' }
        tur: { type: string, enum: [gravur, isim-kolye, harf, olcu-degisim, uretim, tamir, tas-montaj] }
        metin: { type: string, example: 'Çağlar' }
        font: { type: string }
        durum: { type: string, enum: [kuyruk, uretimde, kalite, musteri-onay, tamam, iptal] }
        termin: { type: string, format: date }
        usta: { type: string }
    FiyatAlarmi:
      type: object
      properties:
        tur: { type: string, enum: [urun, has, gumus, ceyrek] }
        urun: { type: string }
        hedef: { type: integer }
        yon: { type: string, enum: [alti, ustu] }
        kanal: { type: array, items: { type: string, enum: [eposta, sms, push] } }
    OdemeBaslat:
      type: object
      properties:
        saglayici: { type: string, enum: [paytr, iyzico] }
        tur: { type: string, enum: [iframe, form] }
        url: { type: string }
        icerik: { type: string }
        referans: { type: string }
        tutar: { type: integer }
        kilitBitis: { type: string, format: date-time }
    FiyatAyar:
      type: object
      properties:
        kaynak: { type: string, enum: [demo, manuel, api] }
        makas: { type: object, additionalProperties: { type: object, properties: { alisYuzde: { type: number }, satisYuzde: { type: number } } } }
        urunMakas: { type: object, properties: { altin: { type: number }, gumus: { type: number } } }
        kilitDk: { type: integer, example: 10 }
        dalgalanma: { type: object, properties: { esikYuzde: { type: number }, pencereDk: { type: integer }, otomatik: { type: boolean } } }
        yuvarlama: { type: integer }
    Bayi:
      type: object
      properties:
        id: { type: string }
        firma: { type: string }
        gumusMilyem: { type: integer, example: 120 }
        altinMilyem: { type: integer, example: 30 }
        minSiparisGr: { type: integer }
        vade: { type: integer }
        durum: { type: string, enum: [aktif, basvuru, pasif] }
