# TypeScript ve Python SDK

> **Ne yaparsınız:** API’yi sunucu uygulamanızdan TypeScript veya Python istemcisiyle çağırır; tekrar, sayfalama ve webhook imza doğrulamasını hazır kullanırsınız.
> **Hangi uçlar:** Bütün uçlar; örneklerde [Bağlantıyı doğrula](https://developer.siparis.app/uc/baglantiyi-dogrula), [Siparişleri listele](https://developer.siparis.app/uc/siparisleri-listele), [Sipariş oluştur](https://developer.siparis.app/uc/siparis-olustur), [Siparişi düzelt](https://developer.siparis.app/uc/siparisi-duzelt), [Dışa aktarma dosyasını indir](https://developer.siparis.app/uc/disa-aktarma-dosyasini-indir), [Kargo etiketini indir](https://developer.siparis.app/uc/kargo-etiketini-indir)
> **Gereken izin:** Çağırdığınız ucun kapsamı; örneklerde `orders:read` ve `orders:write`.

SDK'ler bu depodaki `sdk/typescript/` ve `sdk/python/` dizinlerinde hazırdır; npm/PyPI'ye
henüz yayımlanmadı. Kaynak ve model tipleri OpenAPI sözleşmesinden üretilir.
**Anahtarı tarayıcıya koymayın.** TypeScript paketi Node.js 18+ içindir; Python paketi
Python 3.10+ ister ve senkron/asenkron istemci sunar.

## Repodan kurulum ve ilk istek

Depoyu bilgisayarınıza aldıktan sonra yolunu kullanın:

```sh
npm install /path/to/depo/sdk/typescript
python -m pip install /path/to/depo/sdk/python
```

TypeScript (ESM, paket adı `@siparis/api`):

```ts
import { Siparis } from "@siparis/api";

const client = new Siparis(process.env.SIPARIS_API_KEY!, { sandbox: true });
console.log((await client.me.get()).data);
for await (const order of client.orders.list({ limit: 50, sort: "-created_at" })) {
  console.log(order.id, order.total);
}
```

Python (paket adı `siparis`):

```python
import os
from siparis import Siparis

with Siparis(os.environ["SIPARIS_API_KEY"], sandbox=True) as client:
    print(client.me.get().data)
    for order in client.orders.list({"limit": 50, "sort": "-created_at"}):
        print(order["id"], order["total"])
```

`sandbox` seçimi `https://api.sandbox.siparis.app/v1`, varsayılan canlı seçim
`https://api.siparis.app/v1` adresini kullanır. `spk_test_…` yalnız denemede,
`spk_live_…` canlıda geçerlidir; önek adresi kendiliğinden değiştirmez. OAuth `sat_…`
erişim belirteci de kullanılabilir; belirteci yenilemek uygulamanın sorumluluğundadır.
Adres önceliği: TypeScript `baseUrl` / Python `base_url`, sonra `SIPARIS_API_URL`,
sonra ortam seçimi. Adrese `/v1` dahil olmalıdır.

## Sipariş açma ve ETag

Kendi ürün kodunuzu kullanın. Bu örnek elden teslimi ve alınmış nakit ödemeyi kaydeder.
Sipariş açmak `orders:write`; okumak ayrıca `orders:read` kapsamını (erişim iznini) ister. Müşteri/adres
eklemek `personal_data:write` gerektirir. Birden çok markada `store` alanıyla satış markanızın `sto_…`
kimliğini verin. SDK, bağlantının marka ve kapsam sınırlarını değiştirmez. Alanlar
[Sipariş oluştur](https://developer.siparis.app/uc/siparis-olustur) sayfasındadır; ayrıntılı akış [Sipariş eklemek](https://developer.siparis.app/siparis-eklemek) rehberinde.

```ts
const created = await client.orders.create({
  items: [{ sku: "KUPA-MAVI", quantity: "2" }],
  delivery_method: "hand", payment_method: "cash", paid: true,
}, { idempotencyKey: "kendi-siparis-numaram-2026-001" });
await client.orders.update(created.data.id, { delivery_day: "2026-10-17" }, {
  etag: created.etag ?? undefined,
});
```

```python
with Siparis(os.environ["SIPARIS_API_KEY"], sandbox=True) as client:
    created = client.orders.create({
        "items": [{"sku": "KUPA-MAVI", "quantity": "2"}],
        "delivery_method": "hand", "payment_method": "cash", "paid": True,
    }, idempotency_key="kendi-siparis-numaram-2026-001")
    client.orders.update(created.data["id"], {"delivery_day": "2026-10-17"},
                         etag=created.etag)
```

`etag` kaydın sürüm etiketidir (`ETag`) ve `If-Match` başlığına aynen yazılır; kayıt siz okuduktan sonra
değişmişse 412 hatası gelir ve yazma yapılmaz.
Para ve miktarlar ondalık metin olarak korunur; hesabı ondalık sayı araçlarıyla yapın.

## Tekrar, sayfalama ve hata

`Idempotency-Key` tekrar anahtarıdır: aynı isteği güvenle yeniden göndermek için kullanılan benzersiz metin.
Yazmalarda verilmezse UUID otomatik üretilir. Ağ hatası, zaman aşımı,
5xx veya 429 yanıtında aynı gövde ve anahtarla tekrar edilir. Varsayılan sınır ilk istek
dahil **3 deneme**dir; TypeScript `maxAttempts`, Python `max_attempts` ile değişir.
429 dışındaki 4xx yanıtlar tekrar edilmez. Üstel bekleme 0,5 saniyeden başlar; tabanı
30 saniyede sınırlanır, %0–25 rastgele süre eklenir. `Retry-After` ve kalan puanı sıfır
olan `RateLimit` başlığının istediği süre kısaltılmaz. Yeni yöntem çağrısında yeni UUID
üretilir; uygulama yeniden başladığında aynı işi tekrarlayacaksanız kendi anahtarınızı
kalıcı iş kaydınızda saklayın. Değiştirilmiş gövde için yeni anahtar kullanın.

Liste yöntemleri tembeldir: öğeler tüketilirken `next_cursor` (sonraki sayfanın yer imi) ile ilerler, `has_more=false`
olunca durur. `.page()` tek sayfayı, `.pages()` yanıt sayfalarını verir. Olaylarda boş/son
sayfanın imlecini de işlemler tamamlandıktan sonra saklayın; gezgin sürekli yoklama yapmaz.
Python `AsyncSiparis` ile `async with`, `await client.me.get()` ve
`async for order in client.orders.list(...)` kullanılır.

Tek kayıt ve yazma yanıtları `data`, `status`, `headers`, `etag`, `request_id` alanlarını
taşır. HTTP hatalarında `ApiError` içindeki `code`, `detail`, `errors`, `request_id` ve
`status` okunur; tam hata gövdesi `problem` alanındadır. Bağlantı hataları Node'un yerleşik
ağ hatası veya Python'da `httpx.TransportError` olarak kalır.

## Webhook doğrulama

HTTP çatınızdan **ham gövdeyi** ve `webhook-id`, `webhook-timestamp`, `webhook-signature`
başlıklarını alın. JSON'u doğrulamadan önce yeniden yazmayın:

```ts
import { verifyWebhook, WebhookVerificationError } from "@siparis/api";

function receive(rawBody: Uint8Array, headers: Record<string, string>) {
  try {
    verifyWebhook(rawBody, headers, process.env.SIPARIS_WEBHOOK_SECRET!);
  } catch (error) {
    if (error instanceof WebhookVerificationError) return null; // HTTP 400 verin.
    throw error;
  }
  return JSON.parse(new TextDecoder().decode(rawBody));
}
```

```python
import json
from siparis import verify_webhook, WebhookVerificationError

def receive(raw_body: bytes, headers: dict[str, str]):
    try:
        verify_webhook(raw_body, headers, os.environ["SIPARIS_WEBHOOK_SECRET"])
    except WebhookVerificationError:
        return None  # HTTP 400 verin.
    return json.loads(raw_body)
```

`whsec_…` webhook sırrı API anahtarından farklıdır. Standard Webhooks HMAC-SHA256 imzası
sabit zamanlı karşılaştırılır; geçmiş ve gelecek için tolerans **300 saniye**dir.
Sır döndürmede imzalardan biri yeterlidir. Tekrar teslimleri `webhook-id` ile kendi kalıcı
kaydınızda tekilleştirin. Ayrıntılar: [Webhook](https://developer.siparis.app/webhook).

## Dosya ve etiket

TypeScript `await client.files.download("fil_…")` yanıtında `data` bir `Uint8Array`;
Python `client.files.download("fil_…").data` bir `bytes` nesnesidir. Dosya 307 ile
yönlendirilirse aynı kökene dönüş dahil API anahtarı, ETag ve çerez taşınmaz; en çok
5 yönlendirme izlenir. Diğer uçlarda yönlendirme izlenmez. İndirme bellekte tutulur;
büyük dosyalarda bellek ihtiyacını hesaba katın.

Etiket TypeScript `await client.shipments.label("shp_…", { page: 1 })`, Python
`client.shipments.label("shp_…", {"page": 1})` ile SVG metni olarak alınır.
`X-Label-Pages` başlığından toplam etiket sayısını okuyabilirsiniz.

Depodaki paket README'leri ayrıntılı örnekleri, `sdk/REFERENCE.md` bütün üretilen yöntemleri
listeler. Sözleşme değişince `python3 sdk/generate.py` ile yenileyin;
`python3 sdk/generate.py --check` eski veya eksik üretilmiş dosyada başarısız olur.
