Sepetler ve Checkout

Sepetler

Sahiplik token semantiği ve tam sepet response gövdesi dahil olmak üzere sepet oluşturma, okuma ve güncelleme.

Markdown olarak görüntüle

Sepet, bir storefront'un checkout öncesinde adım adım oluşturduğu değiştirilebilir ön-sipariş nesnesidir. Her sepet tek bir mağazaya aittir, UUID bir id'ye sahiptir ve her zaman EUR para birimiyle ve 30 günlük geçerlilik süresiyle oluşturulur. Sepete yapılan her yazma işlemi (satır ekleme, e-posta değiştirme, indirim kodu ekleme) geçerlilik süresini 30 gün daha uzatır ve sepetin son etkinlik zaman damgasını günceller. Süresi dolan sepetler fiziksel olarak silinir; süresi dolmuş bir sepet id'si 404 döner.

Tüm sepet endpoint'leri Authorization: Bearer {api_key} header'ını gerektirir. Okuma endpoint'leri commerce:read scope'una, yazma endpoint'leri commerce:write scope'una ihtiyaç duyar ve commerce modülünün mağaza için etkin olması gerekir. Dakikada 120 request'lik tenant rate limit'i geçerlidir.

Sepet yaşam döngüsü ve durumu

DurumAnlamı
activeSepet yazma işlemlerini kabul eder. Bir sepetin oluşturulduğu tek durum budur.
convertedSepet bir siparişe (checkout) veya teklife (teklif isteği) dönüştü. Salt okunur.
mergedSepet bir claim sırasında başka bir sepetle birleştirildi. Salt okunur.

Yazma endpoint'leri sepeti status = active koşuluyla arar; bu nedenle converted veya merged durumundaki bir sepet id'si her yazma işleminde 404 döner. İstisnalar, herhangi bir durumdaki sepeti döndüren GET /v1/api/commerce/carts/{id} ve zaten dönüştürülmüş bir sepet için mevcut siparişi döndüren POST /v1/api/commerce/carts/{id}/checkout'tur (idempotent tekrar).

Sahiplik: X-Customer-Token header'ı

Sepetler anonim başlar. Opsiyonel X-Customer-Token header'ı (customers modülü tarafından verilen) opak bir müşteri oturum token'ı taşır ve sepet route'larını üç şekilde etkiler:

  1. Fiyatlandırma. Mevcut ve geçerli olduğunda fiyatlar o müşterinin fiyatlandırma bağlamında çözümlenir (müşteri grubu fiyatlandırması, B2B fiyat gösterimi). Yokluğunda misafir fiyatlandırması uygulanır.
  2. Sahiplik. Bir sepetin customer_id alanı doluysa ve bu müşteri gerçek (misafir olmayan) bir hesapsa, sepet kapsamındaki her request'in aynı müşteriye çözümlenen bir X-Customer-Token taşıması gerekir. Aksi halde request 403 {"message": "This cart belongs to a customer."} ile başarısız olur. customer_id alanı null olan sepetler açık kalır; e-posta yakalamayla oluşturulmuş bir misafir müşteri kaydına bağlı sepetler de öyle (misafirlerin sunacak token'ı yoktur). Customers modülü kullanılamıyorsa kontrol aynı 403 ile güvenli tarafta (kapalı) başarısız olur.
  3. Bağlama. POST /v1/api/commerce/carts/{id}/claim bu header'ı zorunlu kılar ve checkout sırasında geçerli bir token ortaya çıkan siparişi müşteriye bağlar.

Mevcut olup çözümlenemeyen bir token; checkout, teklif isteği ve sipariş geçmişinde 401 {"message": "Invalid customer token."}, claim'de ise düz bir 401 döner. Diğer sepet route'larında çözümlenemeyen bir token, sepet bir müşteriye bağlı olmadığı sürece (o durumda sahiplik 403'ü uygulanır) sessizce misafir fiyatlandırmasına düşer.

Sepet response gövdesi

Her sepet endpoint'i (ve birkaç sepet satırı ve indirim endpoint'i) aynı zarfı döndürür: {"data": {...cart...}}. Alanlar:

AdTürZorunluAçıklama
idstring (UUID)her zamanSepet id'si. İstemci tarafında saklayın; ziyaretçinin tek erişim anahtarıdır.
currencystringher zamanHer zaman EUR.
statusstringher zamanactive, converted veya merged.
emailstring veya nullher zamanPATCH /carts/{id} ile yakalanan e-posta, yoksa null.
metadataobject veya nullher zamanPATCH /carts/{id} ile ayarlanan serbest biçimli skaler map, yoksa null.
discount_codestring veya nullher zamanEklenen kod, olduğu gibi saklanır, yoksa null.
discount_code_errorstring veya nullher zamanKod uygulanabildiğinde (veya kod ayarlanmadığında) null. Aksi halde şunlardan biri: invalid, expired, min_order, not_eligible, usage_limit.
discountsarrayher zamanUygulanan indirimler, her biri {id, name, code, kind, amount}. kind şunlardan biridir: order, products, shipping, bogo; otomatik indirimlerde code null'dur; amount minör birim cinsinden bir tamsayıdır.
policyobjecther zamanMağazanın sepet politikası, aşağıya bakın.
requires_quotebooleanher zamanSepet şu anda bir teklif tetikleyicisine takılıyorsa ve checkout QUOTE_REQUIRED ile reddedecekse true. Mağazada sales modülü devre dışıysa veya teklif talepleri kapalıysa her zaman false.
quote_reasonsarray of stringsher zamanAktif tetikleyici nedenleri: cart_threshold, configurator_choice, customer_group, product_purchasability. requires_quote false olduğunda boştur.
linesarrayher zamanSepet satırları, aşağıya bakın.
totalsobjecther zamanSepet toplamları, aşağıya bakın.

policy

Tenant ayarlarından canlı olarak değerlendirilen, mağazanın sepet politikası. Storefront'lar arayüzü buna göre oluşturmalıdır (örneğin misafirler için fiyatları gizlemek, checkout öncesinde giriş zorunlu kılmak).

AdTürZorunluAçıklama
identity_modestringher zamanguest_allowed, login_required veya guest_only.
audiencestringher zamanboth, b2b_only veya b2c_only.
min_order_value_amountinteger veya nullher zamanCheckout için gereken minör birim cinsinden minimum sepet toplamı, minimum yoksa null.
max_linesintegerher zamanMaksimum ayrı satır sayısı. Varsayılan 100.
max_quantity_per_lineintegerher zamanSatır başına maksimum adet. Varsayılan 100.
pricingobjecther zamanGeçerli fiyatlandırma bağlamı için fiyat gösterim bloğu.
pricing.guest_price_visibilitystringher zamanvisible veya hidden.
pricing.vat_displaystringher zamaninc veya ex. B2B müşteriler için otomatik olarak ex değerine çözümlenir.
pricing.show_original_pricebooleanher zamanİndirimli fiyatın yanında indirim öncesi fiyatın gösterilip gösterilmeyeceği.
pricing.show_tier_tablebooleanher zamanAdet bazlı kademeli fiyat tablolarının gösterilip gösterilmeyeceği.

lines[]

AdTürZorunluAçıklama
idstring (UUID)her zamanSatır id'si.
product_idstring (UUID)her zamanÜrün.
variant_idstring (UUID) veya nullher zamanÜrünün varyantları olduğunda varyant.
namestringher zamanSatır eklendiği anda alınan ürün adı anlık görüntüsü.
skustring veya nullher zamanSKU anlık görüntüsü.
quantitynumberher zamanAdet, sıfırdan büyük. piece olarak satılan bir ürün için tam sayı; diğer tüm birimler için en fazla üç ondalık basamak (örneğin 0,75 kg için 0.75).
unit_price_amountintegerher zamanMinör birim (kuruş/cent) cinsinden birim fiyat.
unit_priceobjecther zamanAynı birim fiyatın para nesnesi hali: {"amount": int, "currency": "EUR"}.
line_totalobjecther zamanİndirim dağıtımı sonrası satır toplamı para nesnesi. Birim fiyat çarpı adet olarak hesaplanır ve yarım yukarı yuvarlanarak tam küçük birime getirilir.
attributesobject veya nullher zamanDüz satırlar için null. Made-to-measure ürünlerde tam configuration anlık görüntüsünü tutar (boyutlar, seçimler, döküm, bileşenler, matris). Her components[] öğesi {product_id, qty} şeklindedir; qty, yapılandırılmış birim başına kesin bir ondalık string'dir (örneğin "2.16").

totals

Tüm para değerleri, amount alanı minör birim cinsinden olmak üzere {"amount": int, "currency": "EUR"} nesneleridir. Fiyatların vergi içerip içermediği bir mağaza ayarıdır (prices_include_tax, varsayılan true).

AdTürZorunluAçıklama
subtotalmoneyher zamanVergi hariç ürün toplamı.
tax_totalmoneyher zamanToplam vergi.
totalmoneyher zamanGenel toplam.
discount_totalmoneyher zamanUygulanan toplam ürün indirimi.
tax_breakdownarrayher zamanOran bazında döküm; her biri {"rate": float, "base": int, "tax": int}, base ve tax minör birim cinsindendir.

POST /v1/api/commerce/carts

Yeni ve boş bir sepet oluşturur. commerce:write gerektirir. Request body yoktur ve müşteri token'ı gerekmez: sepetler anonim başlar. Sepet EUR para birimiyle, active durumuyla ve 30 günlük bir expires_at ile oluşturulur. Dönen id değerini istemci tarafında saklayın (cookie veya local storage); sepete erişimin tek anahtarı budur.

Parametreler

Yok.

Request
curl -X POST https://api.borkol.com/v1/api/commerce/carts \
  -H "Authorization: Bearer {api_key}"
Request (JS)
const res = await fetch("https://api.borkol.com/v1/api/commerce/carts", {
  method: "POST",
  headers: { Authorization: `Bearer ${apiKey}` },
});
const { data: cart } = await res.json();
// persist cart.id
Response
{
  "data": {
    "id": "9d3f2a10-6b7c-4e6d-9f21-8a54c1d2e3f4",
    "currency": "EUR",
    "status": "active",
    "email": null,
    "metadata": null,
    "discount_code": null,
    "discount_code_error": null,
    "discounts": [],
    "policy": {
      "identity_mode": "guest_allowed",
      "audience": "both",
      "min_order_value_amount": null,
      "max_lines": 100,
      "max_quantity_per_line": 100,
      "pricing": {
        "guest_price_visibility": "visible",
        "vat_display": "inc",
        "show_original_price": false,
        "show_tier_table": true
      }
    },
    "requires_quote": false,
    "quote_reasons": [],
    "lines": [],
    "totals": {
      "subtotal": { "amount": 0, "currency": "EUR" },
      "tax_total": { "amount": 0, "currency": "EUR" },
      "total": { "amount": 0, "currency": "EUR" },
      "discount_total": { "amount": 0, "currency": "EUR" },
      "tax_breakdown": []
    }
  }
}

Response durumu 201'dir.

Hatalar

DurumGövdeNe zaman
401{"message": "Unauthenticated."}Eksik veya geçersiz API anahtarı.
403{"message": "Invalid ability provided."}Anahtarda commerce:write yok.
403{"error": "Module not enabled: commerce"}Commerce modülü mağaza için devre dışı.
403{"message": "Tenant suspended.", "code": "tenant_suspended"}Mağaza askıya alınmış.
429{"message": "Too Many Attempts."}Rate limit aşıldı.

GET /v1/api/commerce/carts/{id}

Bir sepeti satırları, canlı değerlendirilen indirimleri, toplamları, mağazanın sepet politikası bloğu ve güncel teklif tetikleyici durumuyla birlikte getirir. commerce:read gerektirir. Yazma endpoint'lerinin aksine, bu endpoint herhangi bir durumdaki (active, converted, merged) sepet için çalışır. İndirimler ve discount_code_error her okumada yeniden değerlendirilir; bu nedenle sepeti render etmek için doğruluk kaynağı bu endpoint'tir. Sepet sahipliği uygulanır (yukarıya bakın).

Parametreler

Path

AdTürZorunluAçıklama
idstring (UUID)evetSepet id'si.

Header'lar

AdTürZorunluAçıklama
X-Customer-TokenstringhayırSepet misafir olmayan bir müşteriye bağlıysa zorunludur. Ayrıca gösterilen fiyatlar için müşteri grubu fiyatlandırmasını seçer.
Request
curl https://api.borkol.com/v1/api/commerce/carts/9d3f2a10-6b7c-4e6d-9f21-8a54c1d2e3f4 \
  -H "Authorization: Bearer {api_key}"
Response
{
  "data": {
    "id": "9d3f2a10-6b7c-4e6d-9f21-8a54c1d2e3f4",
    "currency": "EUR",
    "status": "active",
    "email": "jane@example.com",
    "metadata": { "source": "web" },
    "discount_code": "WELCOME10",
    "discount_code_error": null,
    "discounts": [
      {
        "id": "71c9e0aa-2f4b-4d31-9a77-0b1c2d3e4f5a",
        "name": "Welcome 10%",
        "code": "WELCOME10",
        "kind": "order",
        "amount": 450
      }
    ],
    "policy": {
      "identity_mode": "guest_allowed",
      "audience": "both",
      "min_order_value_amount": null,
      "max_lines": 100,
      "max_quantity_per_line": 100,
      "pricing": {
        "guest_price_visibility": "visible",
        "vat_display": "inc",
        "show_original_price": false,
        "show_tier_table": true
      }
    },
    "requires_quote": false,
    "quote_reasons": [],
    "lines": [
      {
        "id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
        "product_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
        "variant_id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
        "name": "Garden Chair",
        "sku": "CHAIR-GRN-M",
        "quantity": 2,
        "unit_price_amount": 2250,
        "unit_price": { "amount": 2250, "currency": "EUR" },
        "line_total": { "amount": 4050, "currency": "EUR" },
        "attributes": null
      }
    ],
    "totals": {
      "subtotal": { "amount": 3347, "currency": "EUR" },
      "tax_total": { "amount": 703, "currency": "EUR" },
      "total": { "amount": 4050, "currency": "EUR" },
      "discount_total": { "amount": 450, "currency": "EUR" },
      "tax_breakdown": [{ "rate": 21, "base": 3347, "tax": 703 }]
    }
  }
}

Hatalar

DurumGövdeNe zaman
404{"message": "..."}Bilinmeyen id, süresi dolmuş (temizlenmiş) sepet veya başka bir mağazaya ait sepet.
403{"message": "This cart belongs to a customer."}Sepet bir müşteriye bağlı ve token eksik veya farklı bir müşteriye çözümleniyor.
403scope, modül veya askıya alma gövdesiBkz. POST /carts.
429{"message": "Too Many Attempts."}Rate limit aşıldı.

PATCH /v1/api/commerce/carts/{id}

Sepetin e-postasını ve/veya metadata'sını günceller. commerce:write gerektirir; sepet active olmalıdır; sahiplik uygulanır. email ayarlandığında değer küçük harfe çevrilir ve customers modülü aktifse bir misafir müşteri kaydı bulunur veya oluşturulur ve sepet ona bağlanır (ya da geçerli bir X-Customer-Token sahipliği kanıtlıyorsa token'ın hesabına bağlanır). Bu bağlama, terk edilmiş sepet kurtarmanın temelidir; misafire bağlı bir sepet token olmadan erişilebilir kalır.

Parametreler

Path

AdTürZorunluAçıklama
idstring (UUID)evetSepet id'si.

Body

AdTürZorunluAçıklama
emailstringhayırGeçerli e-posta adresi, en fazla 255 karakter. Küçük harfe çevrilerek saklanır.
metadataobject veya nullhayırSerbest biçimli map, en fazla 16 anahtar. Her değer bir skaler (string, number, boolean) veya null olmalıdır. Temizlemek için null gönderin.

Her iki alan da sometimes kurallıdır: bir alanı atlamak onu değiştirmeden bırakır.

Header'lar

AdTürZorunluAçıklama
X-Customer-TokenstringhayırSepet misafir olmayan bir müşteriye bağlıysa zorunludur.
Request
curl -X PATCH https://api.borkol.com/v1/api/commerce/carts/9d3f2a10-6b7c-4e6d-9f21-8a54c1d2e3f4 \
  -H "Authorization: Bearer {api_key}" \
  -H "Content-Type: application/json" \
  -d '{"email": "jane@example.com", "metadata": {"utm_source": "newsletter"}}'
Response
{
  "data": {
    "id": "9d3f2a10-6b7c-4e6d-9f21-8a54c1d2e3f4",
    "email": "jane@example.com",
    "metadata": { "utm_source": "newsletter" },
    "...": "same cart shape as GET /v1/api/commerce/carts/{id}"
  }
}

Response, GET /v1/api/commerce/carts/{id} ile şekil olarak birebir aynı tam sepet zarfıdır ve durum kodu 200'dür.

Hatalar

DurumGövdeNe zaman
422{"message": "...", "errors": {"email": ["The email field must be a valid email address."]}}Doğrulama hatası (geçersiz e-posta, çok fazla metadata anahtarı, skaler olmayan metadata değeri).
404{"message": "..."}Sepet bilinmiyor, süresi dolmuş veya active değil.
403{"message": "This cart belongs to a customer."}Sahiplik kontrolü başarısız.
403scope, modül veya askıya alma gövdesiBkz. POST /carts.
429{"message": "Too Many Attempts."}Rate limit aşıldı.