# Siparişler

Bir sipariş, checkout ile (veya bir teklifin kabul edilmesiyle) `pending_payment` durumunda oluşturulur. Storefront API tarafında siparişler salt okunurdur: tüm durum değişiklikleri (ödeme, kargo, iadeler) satıcı tarafında, dashboard üzerinden yapılır. Her iki endpoint de `commerce:read` scope'unu ve commerce modülünü gerektirir.

## Sipariş durumu

| Durum | Anlamı | Geçebileceği durumlar |
| --- | --- | --- |
| `pending_payment` | Oluşturuldu, ödeme bekleniyor. | `paid`, `cancelled` |
| `paid` | Ödeme alındı. | `shipped`, `cancelled`, `refunded` |
| `shipped` | Taşıyıcıya teslim edildi; takip alanları ayarlanmış olabilir. | `completed`, `refunded` |
| `completed` | Sipariş karşılandı. | `refunded` |
| `cancelled` | Karşılanmadan önce iptal edildi. Envanter stoğa geri eklenir. | terminal |
| `refunded` | İade edildi. Envanter stoğa geri eklenir. | terminal |

Enum'u açık uçlu kabul edin: bir istemci, bilmediği gelecekteki bir durumu hata vermek yerine nötr şekilde göstermelidir.

## Sipariş response yapısı

Her iki endpoint de siparişleri aynı şekilde serileştirir (tekil siparişler `{"data": {...}}` içine sarılır, geçmiş kayıtları sayfalanmış bir `data` dizisinin öğeleri olarak döner). Tüm para değerleri, `amount` alanı minör birim cinsinden olmak üzere `{"amount": int, "currency": "EUR"}` nesneleridir. Tarihler ISO-8601 dizeleridir.

| Ad | Tür | Zorunlu | Açıklama |
| --- | --- | --- | --- |
| `id` | string (UUID) | her zaman | Sipariş id'si. |
| `number` | integer | her zaman | Mağaza başına bir sayaçtan gelen, kullanıcıya gösterilen sipariş numarası. UUID değil, düz tamsayıdır. |
| `status` | string | her zaman | Yukarıdaki durum tablosuna bakın. |
| `email` | string | her zaman | Checkout sırasında verilen e-posta. |
| `billing_address` | object | her zaman | Gönderildiği haliyle fatura adresi (`name`, `street`, `postal_code`, `city`, `country`). |
| `shipping_address` | object or null | her zaman | Teslimat adresi; fatura adresine gönderim yapıldığında null. |
| `currency` | string | her zaman | `EUR`. |
| `lines` | array | her zaman | Sipariş satırları, aşağıya bakın. |
| `subtotal` | money | her zaman | Vergi hariç ürün toplamı. |
| `tax_total` | money | her zaman | Kargo vergisi dahil toplam vergi. |
| `total` | money | her zaman | Kargo dahil genel toplam. |
| `tax_breakdown` | array | her zaman | Oran bazında döküm, her biri `{"rate": float, "base": int, "tax": int}`. |
| `discount_total` | money | her zaman | Ödeme sırasında uygulanan toplam ürün indirimi; varsa ücretsiz kargo indirimi hariçtir. İndirim uygulanmadığında `amount` `0` olur. |
| `discount_breakdown` | array or null | her zaman | Uygulanan her indirim için bir kayıt, her biri `{"discount_id": uuid, "name": string, "code": string or null, "kind": "order" / "products" / "bogo" / "shipping", "amount": int}`. İndirim uygulanmadığında null. Bir `shipping` kaydının `amount` değeri, alınmayan kargo ücretidir. |
| `shipping_method_name` | string or null | her zaman | Seçilen kargo yönteminin ad snapshot'ı; kargo uygulanmadığında null. |
| `shipping` | money | her zaman | Vergi hariç kargo ücreti. Kargo uygulanmadığında `amount` null olur. |
| `shipping_tax` | money | her zaman | Kargo vergisi. Kargo uygulanmadığında `amount` null olur. |
| `tracking_carrier` | string or null | her zaman | Kargolama sırasında satıcı tarafından ayarlanır. |
| `tracking_number` | string or null | her zaman | Kargolama sırasında satıcı tarafından ayarlanır. |
| `invoice_number` | integer or null | her zaman | Mağaza başına fatura sayacı; satıcı siparişi faturaladığında ayarlanır. |
| `invoiced_at` | string (ISO-8601) or null | her zaman | Siparişin faturalandığı zaman. |
| `customer_id` | string (UUID) or null | her zaman | Siparişin bağlı olduğu kişi; misafir siparişlerinde null. |
| `contact_id` | string (UUID) or null | her zaman | `customer_id` ile aynı değer; bundan sonraki kanonik ad. |
| `placed_at` | string (ISO-8601) or null | her zaman | Siparişin verildiği zaman. |
| `created_at` | string (ISO-8601) or null | her zaman | Satırın oluşturulma zamanı. |
| `invoice_id` | string (UUID) or null | her zaman | Bu siparişten oluşturulan sales faturası, varsa. Fatura yoksa veya mağaza sales modülünü kullanmıyorsa null. |

### `lines[]`

| Ad | Tür | Zorunlu | Açıklama |
| --- | --- | --- | --- |
| `id` | string (UUID) | her zaman | Sipariş satırı id'si. |
| `product_id` | string (UUID) | her zaman | Ürün. |
| `variant_id` | string (UUID) or null | her zaman | Varsa varyant. |
| `variant_label` | string or null | her zaman | Okunabilir varyant etiketi snapshot'ı, örneğin `"Green / M"`. |
| `name` | string | her zaman | Ürün adı snapshot'ı. |
| `sku` | string or null | her zaman | SKU snapshot'ı. |
| `quantity` | number | her zaman | Sipariş edilen adet: `piece` ürün için tam sayı, diğer tüm birimler için en fazla üç ondalık basamak (örneğin `0.75`). |
| `unit` | string | her zaman | Sipariş anında ürünün birimi: `piece`, `kg`, `g`, `l`, `m`, `m2`, `m3` veya `hour`. |
| `unit_price` | money | her zaman | Birim fiyat. |
| `line_subtotal` | money | her zaman | Vergi hariç satır toplamı. |
| `tax_rate` | number | her zaman | Satıra uygulanan vergi oranı yüzdesi. |
| `tax` | money | her zaman | Satırın vergisi. |
| `line_total` | money | her zaman | Vergi dahil satır toplamı. |
| `attributes` | object or null | her zaman | Sipariş verildiğinde kaydedilen satır anlık görüntüsü, aşağıya bakın. |

### `lines[].attributes`

| Ad | Tür | Zorunlu | Açıklama |
| --- | --- | --- | --- |
| `returnable` | boolean | koşullu | Satırın iade edilip edilemeyeceği. `made_to_measure` ürün için her zaman `false`; aksi halde sipariş anında ürünün `returnable` değeri. Ürünü olmayan bir satır (özel bir teklif satırı veya teklif kabul edilmeden önce silinmiş bir ürün) `true` olur ve `lead_time_days` `null` olur. |
| `lead_time_days` | integer or null | koşullu | Sipariş anında ürünün gün cinsinden teslim süresi; yoksa `null`. |
| `configuration` | object | koşullu | Yalnızca made-to-measure satırlar: sepet satırındaki gibi yapılandırma anlık görüntüsü (boyutlar, seçimler, döküm, bileşenler, matris). `components[].qty` kesin bir ondalık string'dir. |

`returnable` ve `lead_time_days`, 2026-10-11 tarihinden itibaren checkout, satıcının manuel siparişi veya kabul edilen bir teklif üzerinden verilen siparişlerin her satırına kaydedilir. Daha önceki siparişlerde `attributes` null olabilir veya bu anahtarları içermeyebilir: eksik bir değeri bilinmiyor olarak değerlendirin.

## GET /v1/api/commerce/orders/{id}

Tek bir siparişi, satırlarıyla birlikte id ile getirir. Bu endpoint'te müşteri sahipliği denetimi yoktur: yetkilendirme yalnızca sunucu tarafında saklanan bir sır olan tenant API anahtarıyla yapılır. Endpoint storefront sunucusu içindir; örneğin checkout'tan hemen sonra sipariş onay sayfasını render etmek için. Sunucunuz önce kendi sahiplik denetimini yapmadıkça, istemciden gelen bir sipariş id'siyle bu endpoint'i asla tarayıcılara proxy'lemeyin.

### Parametreler

**Path**

| Ad | Tür | Zorunlu | Açıklama |
| --- | --- | --- | --- |
| `id` | string (UUID) | evet | Sipariş id'si. |

```bash title="Request"
curl https://api.borkol.com/v1/api/commerce/orders/7f8a9b0c-1d2e-4f3a-b4c5-d6e7f8a9b0c1 \
  -H "Authorization: Bearer {api_key}"
```

```json title="Response"
{
  "data": {
    "id": "7f8a9b0c-1d2e-4f3a-b4c5-d6e7f8a9b0c1",
    "number": 1042,
    "status": "paid",
    "email": "jane@example.com",
    "billing_address": {
      "name": "Jane Doe",
      "street": "Keizersgracht 1",
      "postal_code": "1015 CC",
      "city": "Amsterdam",
      "country": "NL"
    },
    "shipping_address": null,
    "currency": "EUR",
    "lines": [
      {
        "id": "8a9b0c1d-2e3f-4a4b-c5d6-e7f8a9b0c1d2",
        "product_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
        "variant_id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
        "variant_label": "Green / M",
        "name": "Garden Chair",
        "sku": "CHAIR-GRN-M",
        "quantity": 2,
        "unit": "piece",
        "unit_price": { "amount": 2250, "currency": "EUR" },
        "line_subtotal": { "amount": 3347, "currency": "EUR" },
        "tax_rate": 21,
        "tax": { "amount": 703, "currency": "EUR" },
        "line_total": { "amount": 4050, "currency": "EUR" },
        "attributes": { "returnable": true, "lead_time_days": null }
      }
    ],
    "subtotal": { "amount": 3347, "currency": "EUR" },
    "tax_total": { "amount": 789, "currency": "EUR" },
    "total": { "amount": 4545, "currency": "EUR" },
    "tax_breakdown": [{ "rate": 21, "base": 3756, "tax": 789 }],
    "discount_total": { "amount": 0, "currency": "EUR" },
    "discount_breakdown": null,
    "shipping_method_name": "Standard",
    "shipping": { "amount": 409, "currency": "EUR" },
    "shipping_tax": { "amount": 86, "currency": "EUR" },
    "tracking_carrier": "PostNL",
    "tracking_number": "3STEST123456",
    "invoice_number": null,
    "invoiced_at": null,
    "customer_id": null,
    "contact_id": null,
    "placed_at": "2026-08-14T10:15:30+00:00",
    "created_at": "2026-08-14T10:15:30+00:00",
    "invoice_id": null
  }
}
```

### Hatalar

| Durum | Gövde | Ne zaman |
| --- | --- | --- |
| 404 | `{"message": "..."}` | Bilinmeyen veya soft-delete edilmiş sipariş id'si, ya da başka bir mağazanın siparişi. |
| 403 | scope, modül veya askıya alma gövdesi | Anahtar `commerce:read` scope'undan yoksun, modül devre dışı veya mağaza askıya alınmış. |
| 429 | `{"message": "Too Many Attempts."}` | Rate limit aşıldı. |

## GET /v1/api/commerce/my/orders

`X-Customer-Token` ile tanımlanan müşterinin, `placed_at` alanına göre azalan sırada (en yeni önce) sıralanmış, sayfalanmış sipariş geçmişi. Token zorunludur: bu, bir storefront'un "siparişlerim" sayfasının arkasındaki endpoint'tir. Standart Laravel sayfalama zarfını kullanır.

### Parametreler

**Query**

| Ad | Tür | Zorunlu | Açıklama |
| --- | --- | --- | --- |
| `per_page` | integer | hayır | Sayfa boyutu, varsayılan 25, 1..100 aralığına sabitlenir. |
| `page` | integer | hayır | Sayfa numarası, varsayılan 1. |

**Headers**

| Ad | Tür | Zorunlu | Açıklama |
| --- | --- | --- | --- |
| `X-Customer-Token` | string | evet | Müşteri oturum token'ı. Eksikse veya çözümlenemezse: 401. |

```bash title="Request"
curl "https://api.borkol.com/v1/api/commerce/my/orders?per_page=25&page=1" \
  -H "Authorization: Bearer {api_key}" \
  -H "X-Customer-Token: {customer_token}"
```

```javascript title="Request (JS)"
const res = await fetch(
  "https://api.borkol.com/v1/api/commerce/my/orders?per_page=25",
  {
    headers: {
      Authorization: `Bearer ${apiKey}`,
      "X-Customer-Token": customerToken,
    },
  }
);
const { data: orders, meta } = await res.json();
```

```json title="Response"
{
  "data": [
    {
      "id": "7f8a9b0c-1d2e-4f3a-b4c5-d6e7f8a9b0c1",
      "number": 1042,
      "status": "shipped",
      "email": "jane@example.com",
      "billing_address": {
        "name": "Jane Doe",
        "street": "Keizersgracht 1",
        "postal_code": "1015 CC",
        "city": "Amsterdam",
        "country": "NL"
      },
      "shipping_address": null,
      "currency": "EUR",
      "lines": [
        {
          "id": "8a9b0c1d-2e3f-4a4b-c5d6-e7f8a9b0c1d2",
          "product_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
          "variant_id": null,
          "variant_label": null,
          "name": "Garden Chair",
          "sku": "CHAIR-GRN",
          "quantity": 2,
          "unit": "piece",
          "unit_price": { "amount": 2250, "currency": "EUR" },
          "line_subtotal": { "amount": 3719, "currency": "EUR" },
          "tax_rate": 21,
          "tax": { "amount": 781, "currency": "EUR" },
          "line_total": { "amount": 4500, "currency": "EUR" },
          "attributes": { "returnable": true, "lead_time_days": 3 }
        }
      ],
      "subtotal": { "amount": 3719, "currency": "EUR" },
      "tax_total": { "amount": 867, "currency": "EUR" },
      "total": { "amount": 4995, "currency": "EUR" },
      "tax_breakdown": [{ "rate": 21, "base": 4128, "tax": 867 }],
      "discount_total": { "amount": 0, "currency": "EUR" },
      "discount_breakdown": null,
      "shipping_method_name": "Standard",
      "shipping": { "amount": 409, "currency": "EUR" },
      "shipping_tax": { "amount": 86, "currency": "EUR" },
      "tracking_carrier": "PostNL",
      "tracking_number": "3STEST123456",
      "invoice_number": null,
      "invoiced_at": null,
      "customer_id": "0a1b2c3d-4e5f-4a6b-7c8d-9e0f1a2b3c4d",
      "contact_id": "0a1b2c3d-4e5f-4a6b-7c8d-9e0f1a2b3c4d",
      "placed_at": "2026-08-10T14:02:11+00:00",
      "created_at": "2026-08-10T14:02:11+00:00",
      "invoice_id": null
    }
  ],
  "links": {
    "first": "https://api.borkol.com/v1/api/commerce/my/orders?page=1",
    "last": "https://api.borkol.com/v1/api/commerce/my/orders?page=1",
    "prev": null,
    "next": null
  },
  "meta": {
    "current_page": 1,
    "from": 1,
    "last_page": 1,
    "links": [
      { "url": null, "label": "&laquo; Previous", "active": false },
      { "url": "https://api.borkol.com/v1/api/commerce/my/orders?page=1", "label": "1", "active": true },
      { "url": null, "label": "Next &raquo;", "active": false }
    ],
    "path": "https://api.borkol.com/v1/api/commerce/my/orders",
    "per_page": 25,
    "to": 1,
    "total": 1
  }
}
```

### Hatalar

| Durum | Gövde | Ne zaman |
| --- | --- | --- |
| 401 | `{"message": "Invalid customer token."}` | `X-Customer-Token` eksik veya çözümlenemiyor. |
| 403 | scope, modül veya askıya alma gövdesi | Anahtar `commerce:read` scope'undan yoksun, modül devre dışı veya mağaza askıya alınmış. |
| 429 | `{"message": "Too Many Attempts."}` | Rate limit aşıldı. |
