Originos

Originos Merchant Admin API

Bu rehber, mağaza sahibinin veya mağaza ekibinin React, Vue, Next.js, mobil uygulama ya da başka bir istemciyle kendi yönetim panelini geliştirmesi içindir. Merchant authentication, dashboard, katalog, stok, sipariş, ödeme, kargo, indirim, dijital ürün, EPIN, ayar, tema ve webhook API'lerinin tamamını kapsar.

1. API adresi

Production:

https://originos.netkora.com/api/v1

Local:

http://127.0.0.1:8000/api/v1

Merchant endpointleri /admin prefix'i altındadır.

https://originos.netkora.com/api/v1/admin

2. Authentication

Login

POST /admin/auth/login
Accept: application/json
Content-Type: application/json
X-Store-Key: pk_live_...
{
  "email": "owner@example.com",
  "password": "YOUR_PASSWORD",
  "device_name": "merchant-dashboard"
}

email ve password zorunlu, device_name opsiyonel ve en fazla 100 karakterdir. Kullanıcı aktif olmalı ve X-Store-Key ile çözülen mağazaya bağlı olmalıdır.

Başarılı yanıt:

{
  "data": {
    "token": "1|MERCHANT_BEARER_TOKEN",
    "token_type": "Bearer",
    "user": {
      "id": "USER_UUID",
      "name": "Mağaza Sahibi",
      "email": "owner@example.com"
    }
  }
}

Aynı device_name ile yeniden login olunduğunda önceki aynı adlı token iptal edilir.

Authenticated istekler

Login dışındaki bütün merchant endpointlerinde iki header birlikte gönderilir:

Accept: application/json
Authorization: Bearer 1|MERCHANT_BEARER_TOKEN
X-Store-Key: pk_live_...

JSON mutasyonlarında ayrıca:

Content-Type: application/json

Logout

POST /admin/auth/logout

Yalnız geçerli bearer token iptal edilir.

Güvenlik notları

3. Rol ve izin sistemi

Mağaza üyeliği rolleri:

Rol Varsayılan erişim
owner Tüm merchant işlemleri
admin Tüm merchant işlemleri
manager Dashboard, ürün, sipariş, müşteri CRM, stok, kargo, indirim, EPIN, webhook, ayar ve tema yönetimi
staff Ürün ve sipariş görüntüleme

Üyeliğe özel permission değerleri role ek yetki verebilir. Başlıca permission anahtarları:

dashboard.view
products.view
products.create
products.update
products.delete
orders.view
orders.update
customers.view
customers.update
inventory.view
inventory.update
shipping.view
shipping.update
discounts.view
discounts.update
epins.view
epins.update
epins.import
epins.reveal
webhooks.view
webhooks.update
settings.view
settings.update
themes.view
themes.update
notifications.view
notifications.update
reports.view

Yetki yoksa 403 PERMISSION_DENIED veya policy kaynaklı 403 döner. Frontend menüleri role göre gizleyebilir; gerçek güvenlik kontrolü her zaman backend'dedir.

4. Plan ve mağaza durumları

5. Genel veri kuralları

Para

Bütün parasal değerler integer minor unit olarak gönderilir:

{"amount": 12990, "currency": "TRY"}

Bu değer 129,90 TRY anlamına gelir. Ürün price_amount, discount minimumu ve refund amount değerlerinde decimal kullanılmaz.

Kimlikler

Public kaynak kimlikleri UUID'dir. Route parametrelerinde response içindeki id kullanılır. Ürün detay route'u admin tarafında slug değil UUID kullanır.

Tarihler

Tarih/zaman değerleri ISO 8601 formatındadır. Order filtrelerinde YYYY-MM-DD kullanılabilir.

Sayfalama

Çoğu liste endpointi:

?page=1&per_page=20

per_page maksimum 100 değeridir. Shipping, discount, theme, EPIN pool ve webhook listeleri şu anda sabit 50 kayıtlık pagination kullanır.

Rate limit

Limit aşıldığında 429 Too Many Requests döner.

6. Tüm endpointler

Auth ve dashboard

Metot Endpoint
POST /admin/auth/login
POST /admin/auth/logout
GET /admin/dashboard

Ürünler, seçenekler ve medya

Metot Endpoint
GET /admin/products
POST /admin/products
GET /admin/products/{product}
PATCH /admin/products/{product}
DELETE /admin/products/{product}
PUT /admin/products/{product}/options
POST /admin/products/{product}/media
PUT /admin/products/{product}/media/order
DELETE /admin/products/{product}/media/{media}
GET /admin/products/{product}/digital-files
POST /admin/products/{product}/digital-files
DELETE /admin/products/{product}/digital-files/{digitalFile}

Müşteri CRM

Metot Endpoint
GET /admin/customers
GET /admin/customers/{customer}
PATCH /admin/customers/{customer}
GET /admin/customers/{customer}/orders
POST /admin/customers/{customer}/addresses
PATCH/DELETE /admin/customers/{customer}/addresses/{address}
GET/POST /admin/customers/{customer}/notes
PATCH/DELETE /admin/customers/{customer}/notes/{note}

Kategoriler ve stok

Metot Endpoint
GET /admin/categories
POST /admin/categories
GET /admin/categories/{category}
PUT/PATCH /admin/categories/{category}
DELETE /admin/categories/{category}
POST/DELETE /admin/categories/{category}/image
GET /admin/inventory
GET /admin/inventory/movements
GET /admin/inventory/reservations
POST /admin/inventory/reservations/{reservation}/release
GET /admin/inventory/{variant}
POST /admin/inventory/{variant}/adjustments
PATCH /admin/inventory/{variant}/settings

Kargo ve indirimler

Metot Endpoint
GET /admin/shipping-methods
POST /admin/shipping-methods
GET /admin/shipping-methods/{shipping_method}
PUT/PATCH /admin/shipping-methods/{shipping_method}
DELETE /admin/shipping-methods/{shipping_method}
GET /admin/discounts
POST /admin/discounts
GET /admin/discounts/{discount}
PUT/PATCH /admin/discounts/{discount}
DELETE /admin/discounts/{discount}

Sipariş ve ödeme

Metot Endpoint
GET /admin/orders
GET /admin/orders/{order}
PATCH /admin/orders/{order}/status
PATCH /admin/orders/{order}/fulfillment-status
POST /admin/orders/{order}/cancel
POST /admin/orders/{order}/refund-requests
POST /admin/orders/{order}/payments/manual/complete
POST /admin/orders/{order}/payments/bank-transfer/complete

EPIN

Metot Endpoint
GET /admin/epin-pools
POST /admin/epin-pools
GET /admin/epin-pools/{epinPool}
PUT /admin/epin-pools/{epinPool}
DELETE /admin/epin-pools/{epinPool}
GET /admin/epin-pools/{epinPool}/codes
POST /admin/epin-pools/{epinPool}/codes/import
POST /admin/epin-pools/{epinPool}/imports
GET /admin/epin-imports/{epinImport}
POST /admin/epin-codes/{epinCode}/reveal

Ayarlar ve temalar

Metot Endpoint
GET /admin/settings
PATCH /admin/settings
POST/DELETE /admin/settings/logo
GET /admin/themes
GET /admin/theme
PUT /admin/theme
PUT /admin/theme/settings

Webhooklar

Metot Endpoint
GET /admin/webhook-events
GET /admin/webhooks
POST /admin/webhooks
GET /admin/webhooks/{webhook}
PUT/PATCH /admin/webhooks/{webhook}
DELETE /admin/webhooks/{webhook}
POST /admin/webhooks/{webhook}/rotate-secret
GET /admin/webhook-deliveries
GET /admin/webhook-deliveries/{delivery}
POST /admin/webhook-deliveries/{delivery}/retry
POST /admin/webhook-deliveries/{delivery}/replay

7. Dashboard

GET /admin/dashboard?days=30

days 1–365 arasındadır, varsayılan 30.

{
  "data": {
    "period": {"days": 30, "from": "2026-07-12", "to": "2026-08-10"},
    "orders_count": 120,
    "paid_orders_count": 98,
    "gross_revenue": {"amount": 1589000, "currency": "TRY"},
    "average_order_value": {"amount": 16214, "currency": "TRY"},
    "customers_count": 84,
    "active_products_count": 52,
    "low_stock_count": 4,
    "out_of_stock_count": 2,
    "backordered_count": 1,
    "orders_by_status": {"pending": 10, "processing": 6, "completed": 104},
    "revenue_by_day": [
      {"date": "2026-08-10", "amount": 129900, "orders": 5}
    ],
    "recent_orders": [
      {
        "id": "ORDER_UUID",
        "order_number": "100001",
        "status": "pending",
        "payment_status": "pending",
        "total_amount": 129900,
        "currency": "TRY",
        "placed_at": "2026-08-10T12:00:00+03:00"
      }
    ]
  }
}

Gelir metrikleri yalnız paid siparişleri kapsar. Recent orders en fazla 10 kayıttır.

8. Ürün yönetimi

Ürün listesi

GET /admin/products?search=kulaklık&filter[status]=active&filter[type]=physical&sort=-created_at&page=1&per_page=20

Desteklenen filtreler:

Liste response'u ürünler, temel varyantlar ve kategorileri içerir. Tam seçenek/media/stok verisi için detail çağrılır.

Ürün oluşturma

POST /admin/products

Fiziksel ürün:

{
  "name": "Kablosuz Kulaklık",
  "slug": "kablosuz-kulaklik",
  "type": "physical",
  "status": "active",
  "visibility": "public",
  "description": "Ürün açıklaması",
  "short_description": "Kısa açıklama",
  "brand": "Originos",
  "taxable": true,
  "sku": "KB-001",
  "price_amount": 129900,
  "currency": "TRY",
  "quantity": 20,
  "category_ids": ["CATEGORY_UUID"],
  "physical": {
    "weight": 350,
    "weight_unit": "g",
    "width": 20,
    "height": 10,
    "length": 25,
    "dimension_unit": "cm"
  }
}

Dijital ürün:

{
  "name": "E-kitap",
  "slug": "e-kitap",
  "type": "digital",
  "status": "active",
  "price_amount": 29900,
  "currency": "TRY",
  "digital": {
    "delivery_type": "download",
    "download_limit": 5,
    "download_expiry_hours": 720
  }
}

EPIN ürün oluşturmak için type: epin ve aktif epin_enabled plan özelliği gerekir.

Alan kuralları:

Alan Kural
name Zorunlu, max 255
slug Zorunlu, mağazada unique, alpha-dash
type physical, digital, epin
status draft, active, archived
visibility public, hidden; varsayılan public
price_amount Integer, minimum 0
currency Üç harf; kayıtta uppercase olur
quantity Integer, minimum 0
category_ids Aynı mağazaya ait category UUID listesi
weight_unit g, kg, lb, oz
dimension_unit mm, cm, m, in
delivery_type download, external

Ürün ilk oluşturulduğunda Default adlı bir varyant otomatik oluşur. Physical ürün için inventory, digital ürün için digital metadata oluşturulur.

Ürün detayı

GET /admin/products/{product}

Response; categories, variants/inventory, option values, media, physical/digital metadata içerir.

Ürün güncelleme

PATCH /admin/products/{product}

Kısmi güncellemedir:

{
  "name": "Yeni ürün adı",
  "status": "active",
  "price_amount": 139900,
  "compare_at_price_amount": 159900,
  "quantity": 25,
  "category_ids": ["CATEGORY_UUID"]
}

type ve ilk SKU bu endpoint üzerinden değiştirilmez. category_ids: [] tüm kategori bağlantılarını kaldırır. Aktif yapılan ürünün published_at değeri atanır.

Ürün silme

DELETE /admin/products/{product}

Başarılı yanıt 204 No Content.

9. Ürün seçenekleri ve varyantlar

PUT /admin/products/{product}/options

En fazla 3 option, option başına 50 value ve toplam 200 varyant kabul edilir.

{
  "options": [
    {"name": "Renk", "values": ["Siyah", "Beyaz"]},
    {"name": "Beden", "values": ["S", "M"]}
  ],
  "variants": [
    {
      "sku": "TS-SIYAH-S",
      "title": "Siyah / S",
      "price_amount": 49900,
      "currency": "TRY",
      "quantity": 10,
      "values": ["Siyah", "S"]
    },
    {
      "sku": "TS-BEYAZ-M",
      "title": "Beyaz / M",
      "price_amount": 51900,
      "currency": "TRY",
      "quantity": 7,
      "values": ["Beyaz", "M"]
    }
  ]
}

Her varyantın values kombinasyonu tanımlanan option değerleriyle eşleşmelidir. İşlem atomiktir ve product detail döndürür.

10. Ürün medyası

POST /admin/products/{product}/media
Content-Type: multipart/form-data

Form alanları:

Alan Kural
file Zorunlu; jpg, jpeg, png, webp, gif veya mp4; max 10 MB
variant_id Opsiyonel, ürüne ait variant UUID
alt_text Opsiyonel, max 255
sort_order Opsiyonel integer, min 0

Response 201:

{
  "data": {
    "id": "MEDIA_UUID",
    "type": "image",
    "url": "https://cdn.example.com/product.jpg",
    "alt_text": "Ürün görseli"
  }
}

Silme:

DELETE /admin/products/{product}/media/{media}

Galeri sırasını kalıcı olarak değiştirmek için ürünün bütün medya kimlikleri istenen sırada gönderilir. Liste eksik, tekrarlı veya başka ürüne ait bir kimlik içeriyorsa işlem atomik olarak reddedilir.

PUT /admin/products/{product}/media/order
Content-Type: application/json

{
  "media_ids": ["media-uuid-2", "media-uuid-1"]
}

Storage dosyası ve DB kaydı silinir; yanıt 204.

11. Dijital ürün dosyaları

Yalnız digital ürün ve digital_products_enabled plan özelliği için kullanılabilir.

GET /admin/products/{product}/digital-files

Yükleme:

POST /admin/products/{product}/digital-files
Content-Type: multipart/form-data
Alan Kural
file pdf, zip, epub, mp3, mp4 veya txt; max 100 MB
name Zorunlu, max 255
variant_id Opsiyonel, aynı ürüne ait varyant
status active, inactive
sort_order Integer, min 0

Dosya private disk üzerinde saklanır; storage path API'de gösterilmez.

Silme:

DELETE /admin/products/{product}/digital-files/{digitalFile}

Satın alınmış/download grant'i bulunan dosya 422 DIGITAL_FILE_IN_USE nedeniyle silinemez.

12. Kategoriler

Liste

GET /admin/categories?search=elektronik&filter[status]=active&sort=sort_order&page=1&per_page=20

Filtre: filter[status]. Sort: name, sort_order, created_at; - prefix descending.

Oluşturma

POST /admin/categories
{
  "name": "Elektronik",
  "slug": "elektronik",
  "parent_id": null,
  "description": "Kategori açıklaması",
  "status": "active",
  "sort_order": 10,
  "meta_title": "Elektronik Ürünler",
  "meta_description": "Elektronik ürün kataloğu"
}

name, slug ve status zorunludur. status: active veya inactive. parent_id aynı mağazaya ait kategori UUID'sidir.

Detail/update/delete:

GET /admin/categories/{category}
PUT /admin/categories/{category}
PATCH /admin/categories/{category}
DELETE /admin/categories/{category}

Kategori görseli multipart/form-data ile yönetilir. image alanı jpg, jpeg, png, webp veya gif ve en fazla 10 MB olabilir:

POST   /admin/categories/{category}/image
DELETE /admin/categories/{category}/image

Category response image_url döndürür. Yeni upload eski dosyayı güvenli biçimde değiştirir.

Kategori request'i update sırasında da zorunlu alanların tamamını bekler; PATCH kullanılsa bile name, slug ve status gönderilmelidir.

13. Stok

Liste

GET /admin/inventory?search=KB-001&status=low_stock&sort=available_quantity&direction=asc&page=1&per_page=20
{
  "data": [
    {
      "variant": {
        "id": "VARIANT_UUID",
        "sku": "KB-001",
        "title": "Default",
        "product": {"id": "PRODUCT_UUID", "name": "Kulaklık"}
      },
      "quantity": 20,
      "on_hand_quantity": 20,
      "reserved_quantity": 3,
      "available_quantity": 17,
      "stock_status": "in_stock",
      "track_inventory": true,
      "allow_backorder": false,
      "low_stock_threshold": 5,
      "is_low_stock": false
    }
  ],
  "metrics": {
    "total_variants": 42,
    "tracked_count": 40,
    "untracked_count": 2,
    "low_stock_count": 2,
    "out_of_stock_count": 1,
    "backordered_count": 0,
    "on_hand_quantity": 840,
    "reserved_quantity": 23,
    "available_quantity": 817
  }
}

Atomik stok düzeltmesi

POST /admin/inventory/{variant}/adjustments
{
  "operation": "increase",
  "quantity": 25,
  "reason": "Mal kabulü",
  "reference": "IRSALIYE-2026-001"
}

Tracking, backorder ve düşük stok ayarları

PATCH /admin/inventory/{variant}/settings
{
  "track_inventory": true,
  "allow_backorder": false,
  "low_stock_threshold": 5
}

Aktif rezervasyon varken tracking kapatılamaz. Negatif available stok varken backorder kapatılamaz. Ayar değişiklikleri de settings_updated hareketi olarak denetlenebilir deftere yazılır.

Varyant stok zaman çizelgesi

GET /admin/inventory/{variant}

{variant} product variant UUID'sidir. En fazla 100 aktif reservation ve 100 movement döner. Movement alanları quantity/reserved delta, işlem sonrası değer, reason ve tarih içerir.

Hareket defteri

GET /admin/inventory/movements?variant_id={variant}&type=adjustment_increase&date_from=2026-08-01&date_to=2026-08-31&per_page=20

Hareket tipleri: reserved, consumed, released, expired, adjustment_set, adjustment_increase, adjustment_decrease, settings_updated. Yanıt variant/product, order/reservation referansları, quantity/reserved delta, işlem sonrası on-hand/reserved/available, reason, metadata ve zamanı döndürür.

Rezervasyon yönetimi

GET  /admin/inventory/reservations?status=active&variant_id={variant}
POST /admin/inventory/reservations/{reservation}/release

Liste active, consumed, released, expired durumlarını; cart/order referanslarını ve süre aşımı bilgisini gösterir. expired=true scheduler henüz çalışmadan süresi dolmuş aktif kayıtları bulur. Manuel release zorunlu bir reason alır, available stoğu geri açar ve hareket oluşturur.

Ürün PATCH ve option/variant sync içindeki quantity değişiklikleri de aynı atomik adjustment servisini kullanır. Böylece aktif rezervasyonlar atlanamaz ve stok hareket geçmişi sessizce kaybolmaz.

14. Kargo yöntemleri

Liste/CRUD:

GET    /admin/shipping-methods
POST   /admin/shipping-methods
GET    /admin/shipping-methods/{shipping_method}
PUT    /admin/shipping-methods/{shipping_method}
PATCH  /admin/shipping-methods/{shipping_method}
DELETE /admin/shipping-methods/{shipping_method}

Request:

{
  "name": "Standart Kargo",
  "code": "standard",
  "type": "flat_rate",
  "price_amount": 4990,
  "currency": "TRY",
  "is_active": true,
  "settings": {}
}

type: free veya flat_rate. free seçildiğinde price_amount otomatik 0 olur. Code mağaza içinde unique ve lowercase normalize edilir. Update tam request bekler.

15. İndirimler

Liste/CRUD:

GET    /admin/discounts
POST   /admin/discounts
GET    /admin/discounts/{discount}
PUT    /admin/discounts/{discount}
PATCH  /admin/discounts/{discount}
DELETE /admin/discounts/{discount}

Percentage örneği:

{
  "name": "Hoş Geldin İndirimi",
  "code": "welcome10",
  "type": "percentage",
  "value": 10,
  "minimum_order_amount": 50000,
  "usage_limit": 1000,
  "starts_at": "2026-08-10T00:00:00+03:00",
  "ends_at": "2026-12-31T23:59:59+03:00",
  "is_active": true
}

Code uppercase normalize edilir. type: fixed veya percentage. Percentage value 1–100; fixed value minor unit'tir. ends_at, starts_at sonrasında olmalıdır. Update tam request bekler.

16. Sipariş listesi ve detayı

Liste

GET /admin/orders?status=processing&payment_status=paid&fulfillment_status=partial&search=buyer@example.com&date_from=2026-08-01&date_to=2026-08-10&sort=created_at&direction=desc&per_page=20

Status değerleri:

Search order number veya customer email üzerinde çalışır. Sort: created_at, total_amount, order_number.

Detay

GET /admin/orders/{order}

Response şunları içerir:

17. Sipariş state machine

İzin verilen order geçişleri:

pending -> confirmed -> processing -> completed
   |           |             |
   +-----------+-------------+-> cancelled

Status değiştirme:

PATCH /admin/orders/{order}/status
{
  "status": "confirmed",
  "note": "Sipariş kontrol edildi."
}

Fulfillment geçişleri:

unfulfilled -> partial -> fulfilled
unfulfilled ----------> fulfilled

Yalnız confirmed veya processing order fulfill edilebilir.

PATCH /admin/orders/{order}/fulfillment-status
{
  "status": "fulfilled",
  "note": "Kargoya teslim edildi."
}

Cancel:

POST /admin/orders/{order}/cancel
{"reason": "Müşteri talebi"}

Cancel aktif fiziksel stok ve EPIN reservation'larını serbest bırakır.

18. Ödeme yöntemleri, PayTR ve refund

Originos mağaza ayarları bank_transfer ve paytr yöntemlerini destekler. PayTR için merchant_id, merchant_key, merchant_salt, test/taksit ayarları ile başarı ve hata dönüş URL'leri PATCH /admin/settings üzerinden kaydedilir. Key ve salt şifreli saklanır; okuma yanıtlarında değerleri yerine yalnız merchant_key_configured ve merchant_salt_configured bayrakları döner.

Checkout sonrasında PayTR iframe tokeni şu endpoint ile oluşturulur:

POST /storefront/payments/paytr/token
Content-Type: application/json

{"order_id":"order-uuid","guest_access_token":"64-karakter-token"}

PayTR panelindeki Bildirim URL değeri https://originos.netkora.com/api/v1/payment/paytr/callback olmalıdır. Sipariş yalnız bu sunucudan sunucuya callback'in HMAC doğrulaması başarılı olduğunda ödenmiş sayılır. Başarı dönüş URL'si ödeme onayı amacıyla kullanılmaz.

Banka havalesini tamamla

POST /admin/orders/{order}/payments/bank-transfer/complete
{
  "transaction_id": "BANK-TRANSFER-2026-001",
  "note": "Havale kontrol edildi."
}

bank_transfer yeni siparişlerde varsayılan provider'dır. transaction_id opsiyoneldir; gönderilmezse sistem üretir. Aynı transaction ID ile retry idempotent'tir. Eski entegrasyonlar için /payments/manual/complete alias'ı korunur. Başarılı ödeme fulfillment işlerini ve ilgili webhook eventlerini tetikler.

Refund isteği

POST /admin/orders/{order}/refund-requests
{
  "amount": 5000,
  "reason": "Eksik ürün"
}

amount opsiyoneldir; gönderilmezse kalan refundable tutarın tamamı kullanılır. Yalnız paid veya partially refunded order için açılır. EPIN içeren siparişlerde manual_review_required: true olur.

{
  "data": {
    "id": "REFUND_UUID",
    "amount": {"amount": 5000, "currency": "TRY"},
    "status": "pending",
    "reason": "Eksik ürün",
    "manual_review_required": false,
    "created_at": "2026-08-10T12:00:00+03:00"
  }
}

19. EPIN yönetimi

EPIN kodları şifreli saklanır. Normal liste yanıtları tam kodu hiçbir zaman göstermez.

Pool CRUD

GET    /admin/epin-pools
POST   /admin/epin-pools
GET    /admin/epin-pools/{epinPool}
PUT    /admin/epin-pools/{epinPool}
DELETE /admin/epin-pools/{epinPool}
{
  "product_id": "EPIN_PRODUCT_UUID",
  "variant_id": null,
  "name": "Standart Kod Havuzu",
  "status": "active"
}

Product epin tipinde olmalıdır. Variant verilirse aynı ürüne ait olmalıdır. Kod içeren pool silinemez.

Pool response'u total, available, reserved ve sold sayaçlarını içerir.

Kod listesi

GET /admin/epin-pools/{epinPool}/codes?status=available&page=1&per_page=50

Kod maskeli döner:

{
  "id": "EPIN_CODE_UUID",
  "code": "********ABCD",
  "status": "available",
  "order_id": null,
  "reserved_at": null,
  "reservation_expires_at": null,
  "sold_at": null,
  "delivered_at": null
}

JSON import

POST /admin/epin-pools/{epinPool}/codes/import
{
  "codes": ["CODE-001", "CODE-002", "CODE-003"]
}

CSV import

POST /admin/epin-pools/{epinPool}/imports
Content-Type: multipart/form-data

Form alanı file; csv/txt ve maksimum 10 MB. İlk kolon okunur. İlk satır code, epin veya epin_code ise header kabul edilir.

Büyük import queue'ya alınabilir. Import takibi:

GET /admin/epin-imports/{epinImport}

Response; status, total/processed/imported/duplicate/failed sayaçları ve kod içermeyen hata raporu döndürür.

Tam kod reveal

POST /admin/epin-codes/{epinCode}/reveal
{"reason": "Müşteri destek talebi #1234"}

Yalnız satılmış ve order'a bağlı kod açılabilir. epins.reveal izni gerekir. Reason 3–500 karakterdir. Yanıt Cache-Control: no-store, private taşır ve audit log oluşur. Tam kod loglanmamalı ve UI'da gereğinden uzun tutulmamalıdır.

20. Mağaza ayarları

GET /admin/settings
PATCH /admin/settings

PATCH kısmi güncellemedir:

{
  "commerce": {
    "show_prices_with_tax": true,
    "show_out_of_stock": false
  },
  "contact": {
    "support_email": "support@example.com",
    "support_phone": "+905551112233"
  },
  "seo": {
    "title": "Mağaza başlığı",
    "description": "En fazla 160 karakter açıklama"
  },
  "announcement": {
    "enabled": true,
    "message": "Aynı gün kargo"
  },
  "payments": {
    "default_method": "bank_transfer",
    "bank_transfer": {
      "enabled": true,
      "bank_name": "Originos Bank",
      "account_holder": "Store Ltd.",
      "iban": "TR33 0006 1005 1978 6457 8413 26",
      "branch": null,
      "instructions": "Sipariş numaranızı açıklamaya yazınız."
    }
  }
}

Sınırlar: SEO title 70, description 160, announcement message 280, phone 30 karakter. Bilinmeyen nested key'ler validation ile reddedilir. Güncelleme storefront config cache'ini temizler.

21. Tema yönetimi

Tema kataloğu

GET /admin/themes

Aktif ve public temaları 50 kayıtlık pagination ile döndürür. Her theme response'u Originos Theme Contract 1.5.0 manifestini ve 84 setting definition'ı içerir. Bunlara ana sayfa section order, çoklu hero slider, ürün galerisi, giriş/kayıt sunumu, favoriler, son görüntülenenler, indirim ve mobil satın alma araçları, featured products, categories, promo, announcement presentation ve custom CSS dahildir.

Tema görselleri POST /api/v1/admin/theme/assets/images adresine multipart/form-data içindeki image alanıyla yüklenir. İsteğe bağlı purpose alanı hero, promo veya editorial olabilir; gönderilmezse hero kabul edilir. JPG, PNG, WEBP ve GIF desteklenir, üst sınır 10 MB'dir. Dosya mağazaya özel stores/{store_uuid}/themes/{purpose} dizininde saklanır ve yanıttaki data.url değeri ilgili tema görseli alanına yazılır.

Mağaza logosu POST /api/v1/admin/settings/logo adresine multipart/form-data içindeki logo alanıyla yüklenir. JPG, PNG, WEBP ve GIF desteklenir; üst sınır 5 MB'dir. Logo mağazaya özel stores/{store_uuid}/branding dizininde saklanır ve storefront config içindeki logo_url alanında yayınlanır. DELETE /api/v1/admin/settings/logo mevcut logoyu kaldırır.

Aktif tema

GET /admin/theme
{
  "data": {
    "theme": {
      "id": "THEME_UUID",
      "name": "Originos Starter",
      "slug": "originos-starter",
      "version": "1.0.0",
      "manifest": {"schema_version": "1.1.0", "assets": {}, "settings": []}
    },
    "settings": {
      "primary_color": "#111827",
      "font_family": "system",
      "header_style": "minimal"
    }
  }
}

Tema ata

PUT /admin/theme
{"theme_id": "THEME_UUID"}

Tema geçişinde ortak sözleşmeyle uyumlu mağaza ayarları korunur, eksik/geçersiz değerler yeni tema defaults değerleriyle tamamlanır. Ek kurulum isteği gerekmez.

Tema ayarları

PUT /admin/theme/settings

Kısmi ayar güncellemesidir:

{
  "settings": {
    "primary_color": "#2563eb",
    "hero_title": "Mağazamıza hoş geldiniz",
    "catalog_columns": 4,
    "show_search": true
  }
}

Renk #RRGGBB, URL/image HTTP(S), select ve numeric değerler manifest kurallarına uygun olmalıdır. Bilinmeyen key 422 THEME_SETTING_UNKNOWN döndürür.

Tam 84 ayar, grouped homepage config, müşteri hesabı ve etkileşim araçları sunumu ile custom CSS entegrasyonu için Storefront & Theme API rehberine bakın: https://originos.netkora.com/docs/storefront-theme-api.

22. Webhook yönetimi

Event kataloğu

GET /admin/webhook-events

Desteklenen eventler:

order.created
order.paid
order.cancelled
order.completed
payment.succeeded
payment.failed
stock.updated
epin.delivered
digital.delivered
product.created
product.updated
customer.created
customer.updated

Webhook CRUD

GET    /admin/webhooks
POST   /admin/webhooks
GET    /admin/webhooks/{webhook}
PUT    /admin/webhooks/{webhook}
PATCH  /admin/webhooks/{webhook}
DELETE /admin/webhooks/{webhook}

Create:

{
  "name": "ERP entegrasyonu",
  "url": "https://erp.example.com/webhooks/originos",
  "events": ["order.created", "order.paid"],
  "is_active": true
}

URL public HTTP(S) olmalı; localhost, private/reserved IP ve 80/443 dışı portlar reddedilir. Update kısmi olabilir.

Create response'undaki signing_secret yalnız bir kez gösterilir:

{
  "data": {
    "id": "WEBHOOK_UUID",
    "name": "ERP entegrasyonu",
    "url": "https://erp.example.com/webhooks/originos",
    "events": ["order.created", "order.paid"],
    "is_active": true,
    "secret_last_four": "aB3x",
    "signing_secret": "ONE_TIME_SECRET"
  }
}

Secret rotation:

POST /admin/webhooks/{webhook}/rotate-secret

Yeni secret yine yalnız bu response'ta düz metin döner. Consumer güncellenmeden eski secret kaybedilmemelidir.

İmza doğrulama

Originos şu header'ları gönderir:

X-Originos-Event
X-Originos-Delivery
X-Originos-Timestamp
X-Originos-Signature

İmza:

$expected = 'v1='.hash_hmac('sha256', $timestamp.'.'.$rawBody, $secret);
$valid = hash_equals($expected, $signature);

Consumer ham request body ile imzayı doğrulamalı ve delivery UUID'yi idempotency key olarak saklamalıdır.

Delivery izleme

GET /admin/webhook-deliveries?status=failed&event=order.created&page=1&per_page=20
GET /admin/webhook-deliveries/{delivery}

Delivery response; payload, status, attempt count, response status/body, error code/message, retry zamanları ve replay bağlantısını içerir.

Retry aynı delivery UUID'yi sıfırlar ve yeniden kuyruğa alır:

POST /admin/webhook-deliveries/{delivery}/retry

Replay yeni delivery/event UUID üretir ve original delivery'yi replay_of_id ile bağlar:

POST /admin/webhook-deliveries/{delivery}/replay

23. Mağaza müşterileri ve CRM

Liste, arama ve segment filtreleri

GET /admin/customers?search=ada&status=active&has_orders=true&sort=total_spent_amount&direction=desc&per_page=20

Filtreler:

Liste response'u müşteri bazında toplam sipariş, paid sipariş, yaşam boyu harcama, ortalama sepet, son sipariş ve not sayısını döndürür. Üst metrics alanında toplam, aktif, pasif, siparişli ve son 30 günde yeni müşteri sayıları bulunur.

Detay ve sipariş geçmişi

GET /admin/customers/{customer}
GET /admin/customers/{customer}/orders?payment_status=paid&per_page=20

Detay response'u profil, CRM metrikleri, varsayılan önce sıralanmış adresler ve pinned notlar önce olacak şekilde iç notları içerir. Sipariş endpoint'i normal admin order şemasını ve filtrelerini kullanır.

Profil ve durum yönetimi

PATCH /admin/customers/{customer}
{
  "first_name": "Ada",
  "last_name": "Lovelace",
  "email": "ada@example.com",
  "phone": "+905551112233",
  "status": "inactive"
}

Alanların tamamı opsiyoneldir. E-posta mağaza içinde unique olmalıdır. Müşteri inactive yapıldığında bütün storefront customer token'ları iptal edilir ve yeniden login engellenir. Güncelleme customer.updated webhook event'i yayınlar.

Adres yönetimi

POST   /admin/customers/{customer}/addresses
PATCH  /admin/customers/{customer}/addresses/{address}
DELETE /admin/customers/{customer}/addresses/{address}

Adres gövdesi storefront customer address şemasıyla aynıdır. is_default: true gönderildiğinde aynı tipteki önceki varsayılan adres kaldırılır.

İç CRM notları

GET    /admin/customers/{customer}/notes
POST   /admin/customers/{customer}/notes
PATCH  /admin/customers/{customer}/notes/{note}
DELETE /admin/customers/{customer}/notes/{note}
{
  "body": "VIP müşteri; siparişleri öncelikli hazırlanmalı.",
  "is_pinned": true
}

Notlar yalnız merchant API'de görünür; storefront customer response'larına dahil edilmez. Her not yazar UUID/adı ve oluşturma/güncelleme zamanını taşır. Tüm endpointler store scope, customers.view veya customers.update izni ve yazma işlemlerinde aktif abonelik kontrolüyle korunur.

24. Gelişmiş katalog, CRM, bildirim ve rapor API'leri

Bu bölüm panelin 5–8 numaralı geliştirme adımlarında eklenen uçları kapsar.

Gelişmiş ürün yönetimi

Metot Endpoint Açıklama
GET/POST /admin/brands Marka listesi/oluşturma
PATCH/DELETE /admin/brands/{brand} Marka güncelleme/silme
GET/POST /admin/collections Koleksiyon listesi/oluşturma
PATCH/DELETE /admin/collections/{collection} Koleksiyon güncelleme/silme
GET/POST /admin/product-tags Ürün etiketi listesi/oluşturma
PATCH/DELETE /admin/product-tags/{tag} Ürün etiketi güncelleme/silme
PATCH /admin/products/bulk En fazla 500 üründe durum, görünürlük ve sınıflandırma güncelleme
GET /admin/products/export/csv Ürünleri CSV indir
POST /admin/products/import/csv En fazla 5 MB/5000 satır CSV içe aktar
PUT /admin/products/{product}/media/{media}/primary Ana ürün görselini seç

Ürün create/update gövdesi artık brand_id, collection_ids, tag_ids, barcode, cost_amount ve compare_at_price_amount alanlarını kabul eder. CSV zorunlu sütunları sku,name,price_amount,currency; önerilen tam başlık ise sku,name,slug,type,status,visibility,price_amount,compare_at_price_amount,cost_amount,currency,barcode,quantity biçimindedir. Miktar değişiklikleri doğrudan yazılmaz, stok hareketi oluşturur.

Toplu güncelleme örneği:

{
  "product_ids": ["PRODUCT_UUID_1", "PRODUCT_UUID_2"],
  "status": "active",
  "visibility": "public",
  "brand_id": "BRAND_UUID",
  "collection_ids": ["COLLECTION_UUID"],
  "tag_ids": ["TAG_UUID"]
}

Gelişmiş CRM

Metot Endpoint Açıklama
POST /admin/customers Panelden müşteri oluştur
GET /admin/customers/export/csv Müşteri CSV dışa aktarımı
POST /admin/customers/import/csv Müşteri CSV içe aktarımı
GET /admin/customers/{customer}/data-export Tek müşterinin profil, adres, sipariş, not ve etiket verisi
GET/POST /admin/crm-tags CRM etiketi listesi/oluşturma
PATCH/DELETE /admin/crm-tags/{crmTag} CRM etiketi güncelleme/silme
PUT /admin/customers/{customer}/tags Müşteri etiketlerini eşitle

Müşteri listesi tag_id, marketing_email_consent ve marketing_sms_consent filtrelerini destekler. Durum active, inactive veya blocked olabilir. blocked ve inactive yapıldığında aktif müşteri tokenları iptal edilir. Profilde marketing_email_consent, marketing_sms_consent, blocked_reason alanları yönetilebilir.

Bildirim merkezi

Metot Endpoint Açıklama
GET /admin/notification-templates Varsayılan ve özelleştirilmiş şablonlar
PUT /admin/notification-templates/{event} E-posta şablonunu güncelle
GET /admin/notification-logs Kuyruk/gönderim/hata geçmişi
POST /admin/notifications/test Test bildirimi kuyruğa al

Eventler: customer.created, order.created, payment.succeeded, payment.failed, order.fulfilled, inventory.low_stock. Şablonlar {{customer_name}}, {{order_number}}, {{order_total}}, {{currency}}, {{product_name}}, {{variant_name}} ve {{available_quantity}} değişkenlerini kullanabilir. Gönderim queue worker üzerinden yapılır; production'da php artisan queue:work --queue=notifications,default çalışmalıdır.

Raporlama

Metot Endpoint
GET /admin/reports/overview
GET /admin/reports/products
GET /admin/reports/customers
GET /admin/reports/discounts
GET /admin/reports/inventory
GET /admin/reports/export/csv

Tarih bazlı raporlar date_from, date_to (en fazla 366 gün) ve sıralı raporlar limit parametresini alır. CSV için type=overview|products|customers|discounts|inventory kullanılır. Para değerleri diğer API'lerde olduğu gibi minor unit integer döner.

25. Hata formatları

Domain hatası:

{
  "message": "This action is forbidden.",
  "code": "PERMISSION_DENIED"
}

Validation hatası:

{
  "message": "The given data was invalid.",
  "errors": {
    "price_amount": ["The price amount field is required."]
  }
}

Önemli hata kodları:

HTTP Kod Anlamı
401 INVALID_CREDENTIALS Login bilgileri hatalı
401 API_KEY_INVALID / API_KEY_REVOKED / API_KEY_EXPIRED Store key geçersiz
403 STORE_MEMBERSHIP_REQUIRED Kullanıcı mağazaya bağlı değil veya token merchant değil
403 PERMISSION_DENIED Gerekli mağaza izni yok
403 STORE_SUSPENDED Mağaza operasyonel değil
403 SUBSCRIPTION_EXPIRED Yazma hakkı yok
403 FEATURE_NOT_AVAILABLE Plan özelliği kapalı
409 PLAN_LIMIT_REACHED Ürün limiti doldu
422 INVALID_ORDER_TRANSITION Sipariş status geçişi yasak
422 ORDER_PAYMENT_REQUIRED Complete için ödeme gerekli
422 ORDER_FULFILLMENT_REQUIRED Complete için fulfillment gerekli
422 PAID_ORDER_REQUIRES_REFUND Paid order cancel yerine refund ister
422 INVALID_FULFILLMENT_TRANSITION Fulfillment geçişi yasak
422 ORDER_NOT_REFUNDABLE Order refund koşulunu sağlamıyor
422 INVALID_REFUND_AMOUNT Refund tutarı kalan tutarı aşıyor
422 INVENTORY_BELOW_RESERVED Stok aktif rezervasyon toplamının altına indirilemez
422 INVENTORY_HAS_ACTIVE_RESERVATIONS Aktif rezervasyon varken tracking kapatılamaz
422 INVENTORY_BACKORDER_EXISTS Negatif available stok temizlenmeden backorder kapatılamaz
422 INVENTORY_QUANTITY_OUT_OF_RANGE İşlem sonucu desteklenen integer aralığı dışında
404 MANUAL_PAYMENT_NOT_FOUND Manual payment yok
409 PAYMENT_ALREADY_COMPLETED Başka transaction ile ödeme tamamlanmış
422 DIGITAL_PRODUCT_REQUIRED Dosya hedefi digital ürün değil
422 DIGITAL_VARIANT_INVALID Variant ürüne ait değil
422 DIGITAL_FILE_IN_USE Satılmış dosya silinemez
422 EPIN_PRODUCT_INVALID / EPIN_VARIANT_INVALID Pool hedefi geçersiz
422 EPIN_POOL_NOT_EMPTY Kodlu pool silinemez
422 EPIN_NOT_SOLD Kod reveal edilemez
403 THEME_NOT_INCLUDED Paid tema planda yok
422 THEME_NOT_AVAILABLE Tema aktif/public değil
422 THEME_NOT_ASSIGNED Aktif tema yok
422 THEME_SETTING_UNKNOWN Ayar ortak contract'ta yok
422 webhook URL validation Webhook hedefi güvenli değil
429 rate limit İstek limiti aşıldı

Her response'ta X-Request-ID bulunur. Hata loglarında status, code ve request ID birlikte saklanmalıdır.

25. Önerilen yönetim paneli akışı

  1. Store key seçtir ve /admin/auth/login ile bearer token al.
  2. Token ile /admin/dashboard yükle.
  3. Menüleri role/permission ve plan feature'larına göre göster.
  4. Product list/detail üzerinden katalog ekranlarını oluştur.
  5. Physical üründe inventory; digital üründe digital file; EPIN üründe pool yönetimini göster.
  6. Order list/detail ekranında state machine'e göre yalnız geçerli aksiyonları etkinleştir.
  7. Paid order için cancel yerine refund ekranı göster.
  8. Tema/ayar değişikliklerinden sonra storefront config'in otomatik invalid edildiğini kabul et.
  9. Webhook secret'ı create/rotate yanıtında kullanıcıya bir kez göster ve yeniden okunamayacağını belirt.
  10. EPIN reveal'i ek onay, zorunlu reason ve no-cache UI ile koru.

26. Frontend güvenlik kontrol listesi

27. API artifact'leri

Postman collection merchant login, katalog, inventory, shipping, discount, checkout/order, payment, EPIN, digital file, webhook, settings, theme ve dashboard örneklerini çalıştırılabilir sırada içerir.