# Heyşirket Senkron API v1

Heyşirket Senkron API; e-ticaret sitenizin, pazaryeri yazılımınızın, ERP ya da ön muhasebe sisteminizin
**cari, ürün (renk/beden varyantları ve görselleriyle), stok, satış faturası, gider/gelen e-fatura, kasa-banka
hareketi ve e-ticaret siparişlerini** Heyşirket'teki firmanıza otomatik aktarmasını; Heyşirket'te yapılan
değişiklikleri (stok, fiyat, yeni varyant, tahsilat, sipariş işlemi…) de geri okumasını sağlar.

- Taban adres: `https://portal.heysirket.com/api/v1`
- Makine tarafından okunur tanım: [`/api/v1/openapi.json`](https://portal.heysirket.com/api/v1/openapi.json) · sınırlar ve sabitler: [`/api/v1/meta`](https://portal.heysirket.com/api/v1/meta)
- Bu sayfanın ham hali (yapay zekâ araçları için): [`/gelistiriciler/senkron-api.md`](https://heysirket.com/gelistiriciler/senkron-api.md)

---

## Yapay zekâ ile entegrasyon (hazır prompt)

Aşağıdaki metni olduğu gibi kopyalayıp kullandığınız yapay zekâ kodlama asistanına (Claude, ChatGPT,
Cursor vb.) verin. Köşeli parantezli yerleri kendi bilgilerinizle doldurun. **API anahtarını prompta
yazmayın**; asistandan anahtarı ortam değişkeninden (`HEYSIRKET_API_KEY`) okumasını isteyin.

```text
Sen kıdemli bir entegrasyon mühendisisin. Görevin: [SİSTEM ADI — ör. WooCommerce mağazam / kendi
e-ticaret yazılımım / ERP'm] ile Heyşirket arasında kesintisiz, çift yönlü ve güvenli bir senkron kurmak.

Kaynaklar (önce tamamını oku, varsayım yapma):
- Rehber: https://heysirket.com/gelistiriciler/senkron-api.md
- OpenAPI: https://portal.heysirket.com/api/v1/openapi.json
- Sınırlar/sabitler: https://portal.heysirket.com/api/v1/meta

Bağlam:
- Heyşirket firmamın API anahtarı HEYSIRKET_API_KEY ortam değişkeninde. Anahtarı asla loglama, koda,
  depoya veya hata mesajına yazma.
- Kaynak sistemim: [dil/çatı, veritabanı, barındırma — ör. PHP 8 + WordPress/WooCommerce, MySQL, cPanel cron].
- Sistemimdeki kalıcı kod (source): [ör. magazam] — küçük harf, rakam, tire.
- Satış kanallarım: [ör. kendi sitem (woocommerce), trendyol, hepsiburada].
- E-fatura sağlayıcım: [ör. Trendyol E-Faturam / yok].

Yapacakların (sırayla, her adımı test ederek):
1. Veri eşlemesi çıkar: sistemimdeki her varlığı (müşteri, tedarikçi, ürün + varyant + görsel, stok, sipariş,
   fatura, iade/iptal, gider, gelen e-fatura, ödeme/tahsilat) rehberdeki alanlara eşle. Kalıcı ve
   değişmeyen kimlikleri externalId yap. Tutarları ana para biriminde ondalık, KDV'yi yüzde gönder.
   Varyantlı ürünlerde yalnız satılabilir varyantları products[] olarak, ana ürünü family ile gönder;
   attributes'a renk/beden gibi özellikleri insan okunur adlarla yaz. Görselleri https adresleriyle gönder.
2. Değişiklik takibi kur: her varlık için "son değişiklik zamanı/sürümü" imleci ve gönderilen kaydın
   parmak izini sakla; yalnız değişenleri gönder. Hiçbir şey değişmediyse istek atma.
3. Gönderimi kur: POST /sync ile sayfalı gönder (istek başına ≤400 kayıt, fatura+gider+sipariş ≤150,
   gövde ≤2 MB). Sıra: business → customers → products(+family) → stock → orders → invoices → expenses
   → transactions → deleted (tedarikçiler suppliers[] ile, customers'tan önce ya da aynı sayfada).
   Önce aynı veriyi ?dryRun=1 ile gönderip errors boşalana kadar eşlemeyi düzelt.
4. Hata yönetimi: 200 yanıtındaki errors[] kayıt bazlıdır; ilgili kaydı düzeltip tekrar gönder
   (aynı sayfayı tekrar göndermek güvenlidir, idempotenttir). 429'da Retry-After kadar bekle
   (DAILY_QUOTA: ertesi UTC gününe kadar, kalan kayıtları sıraya koy). 5xx ve ağ hatasında üstel geri
   çekilme uygula; 401/402/423'te dur ve yöneticiyi uyar.
5. Geri akışı kur: her turda ÖNCE GET /changes?after=<son seq> ile Heyşirket'teki değişiklikleri oku ve
   kendi sistemine uygula (stok için quantity'yi FARK olarak uygula, IN +, OUT −, ADJUSTMENT işaretli),
   sonra kendi değişikliklerini gönder. Uygulanan son seq'i kalıcı sakla. Heyşirket'te yeni açılan
   ürün/varyant/ailede kendi kaydını oluştur ve bir sonraki gönderimde heysirketId ile eşle.
6. Zamanlama: değişiklik akışı ve gönderim için 15 dakikada bir çalışan tek, kilitli bir görev kur.
   İlk tam aktarımı elle başlatılabilir ve kaldığı yerden devam edebilir yap; günlük kotayı aşarsa ertesi
   gün devam etsin.
7. Gözlemlenebilirlik: son çalışma zamanı, gönderilen/hatalı kayıt sayıları ve son hataları sisteminin
   yönetim ekranında göster. GET /sync/runs ile Heyşirket tarafındaki sonucu karşılaştır.
8. Test: eşleme fonksiyonları için birim testleri yaz (tutar yuvarlama, satır toplamlarının fatura
   toplamına eşitliği, varyant/aile eşlemesi, silinen kayıtlar, akış olaylarının uygulanması). Önce
   ?dryRun=1, sonra küçük bir gerçek sayfa ile uçtan uca doğrula; GET /ping ile anahtarı kontrol et.

Kurallar: Para hesaplarında kuruşa dikkat et; aynı parayı iki kez sayma (bir tahsilat ya fatura ödemesi
ya da kasa hareketi olarak gelsin). Faturaları silme, iptali status: "CANCELLED" ile bildir. Kişisel
verileri yalnız rehberdeki alanlarla gönder. Bitince yaptığın eşlemeyi ve çalıştırma talimatını kısa bir
README olarak yaz.
```

---

## Hızlı başlangıç

1. **Anahtar oluşturun.** Heyşirket → **Ayarlar → API ve senkron → Anahtar oluştur**. Anahtar
   (`hsk_live_…`) yalnız bir kez gösterilir; güvenli bir yerde saklayın. Her sistem için ayrı anahtar açın.
2. **Bağlantıyı test edin.**
   ```bash
   curl -s https://portal.heysirket.com/api/v1/ping -H "Authorization: Bearer $HEYSIRKET_API_KEY"
   ```
3. **Önce doğrulayın, sonra yazın.** Aynı gövdeyi `?dryRun=1` ile gönderin; `errors` boşsa parametreyi kaldırın.
   ```bash
   curl -s -X POST "https://portal.heysirket.com/api/v1/sync?dryRun=1" \
     -H "Authorization: Bearer $HEYSIRKET_API_KEY" -H "Content-Type: application/json" \
     -d '{"source":"magazam","customers":[{"externalId":"c-1","title":"Ayşe Yılmaz"}]}'
   ```
4. **Sonucu görün.** Heyşirket'te **Ayarlar → API ve senkron** ekranında her aktarımın sayıları ve kayıt bazlı hataları görünür.

## Kimlik doğrulama ve sınırlar

```
Authorization: Bearer hsk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json
```

| Uç | Anahtar | Açıklama |
| --- | --- | --- |
| `GET /api/v1/meta` | gerekmez | sınırlar, sabit değerler, sürüm |
| `GET /api/v1/openapi.json` | gerekmez | OpenAPI 3.1 tanımı |
| `GET /api/v1/ping` | gerekir | anahtarın bağlı olduğu firma |
| `POST /api/v1/sync` | gerekir | toplu, idempotent aktarım (`?dryRun=1` yalnız doğrular) |
| `GET /api/v1/changes?after=0&limit=200` | gerekir | Heyşirket'teki değişikliklerin akışı |
| `GET /api/v1/sync/runs?limit=20` | gerekir | son aktarımlar |

| Sınır | Değer |
| --- | --- |
| Bir istekteki kayıt | en fazla **400** (fatura + gider + sipariş toplamı en fazla **150**) |
| Gövde boyutu | en fazla **2 MB** |
| Aktarım isteği | anahtar başına dakikada **30** (`429 RATE_LIMITED`, `Retry-After: 60`) |
| Günlük kayıt kotası | firma başına UTC gününde **5.000** kayıt (`429 DAILY_QUOTA`; büyük ilk aktarım ertesi günlere yayılır) |
| Değişiklik akışı saklama | **30 gün** (en az günde bir okuyun) |

## Genel kurallar

- **İdempotent upsert:** Aynı `source` + `externalId` ile gelen kayıt güncellenir, çoğaltılmaz. Ağ hatasında aynı sayfayı tekrar göndermek güvenlidir.
- **Birimler:** tutarlar ana para biriminde ondalık (`149.90`), KDV oranı yüzde (`20`), miktar ondalık (`1.5`), tarihler `YYYY-MM-DD` ya da ISO-8601.
- **`source`:** sisteminizin kalıcı kodu (`^[a-z0-9][a-z0-9_-]{1,39}$`). Aynı firmaya birden çok sistem farklı `source` ile veri gönderebilir.
- **Tam nesne:** her kaydı tam gönderin; gönderilmeyen alan boş kabul edilir. İstisna: `business` nesnesinde yalnız dolu alanlar yazılır.
- **Sıra:** aynı istek içinde siparişler faturalardan önce işlenir; aileler varyantlardan önce oluşur.
- **Yalnız değişenleri gönderin:** hiçbir şey değişmediyse istek atmayın; kota ve hız sınırı tüm firmaların ortak altyapısını korur.

## Gövde

```jsonc
{
  "source": "magazam",
  "business": { "title": "…", "taxId": "…", "taxOffice": "…", "address": "…", "district": "…", "city": "…", "phone": "…", "email": "…",
                "bankAccounts": [ { "bankName": "Ziraat Bankası", "branchName": "Merkez", "accountName": "…", "iban": "TR…", "currency": "TRY", "isDefault": true } ] },
  "customers": [ /* Cari */ ],
  "suppliers": [ /* Tedarikçi */ ],
  "products": [ /* Ürün / varyant */ ],
  "stock": [ /* Stok seviyesi */ ],
  "orders": [ /* E-ticaret siparişi */ ],
  "invoices": [ /* Satış faturası */ ],
  "expenses": [ /* Gider / gelen fatura */ ],
  "transactions": [ /* Kasa-banka hareketi */ ],
  "deleted": { "customers": [], "suppliers": [], "products": [], "expenses": [], "transactions": [] }
}
```

### Firma (`business`)
Yalnız dolu alanlar yazılır. `bankAccounts[]` (en fazla 10): IBAN ile eşlenir; hesap hem faturalarda gösterilen banka
hesaplarına hem de **Nakit ve bankalar** takibine eklenir. `isDefault: true` olan hesap faturalarda ilk sırada gösterilir.

### Cari (`customers[]`)
| Alan | Tür | Not |
| --- | --- | --- |
| `externalId` | metin | zorunlu |
| `title` | metin | zorunlu; şahıs için ad soyad |
| `taxId` | metin | VKN (10) veya TCKN (11) |
| `taxOffice`, `address`, `district`, `city`, `country`, `postalCode`, `phone`, `email` | metin | |
| `contactType` | `customer` \| `supplier` \| `both` | varsayılan `customer` |
| `heysirketId` | metin | Heyşirket'te açılmış cariyi (akıştaki `customer.created`) bu `externalId` ile eşler |
| `metadata` | nesne | serbest |

### Tedarikçi (`suppliers[]`)
| Alan | Tür | Not |
| --- | --- | --- |
| `externalId`, `title` | metin | zorunlu |
| `taxId` | metin | VKN/TCKN — eşleştirmede önceliklidir |
| `contactName`, `email`, `phone`, `address`, `website` | metin | |
| `isActive` | doğru/yanlış | `false` pasife alır |
| `heysirketId` | metin | Heyşirket'te açılmış tedarikçiyi (akıştaki `supplier.created`) eşler |
| `metadata` | nesne | serbest |

Heyşirket'te aynı vergi numaralı ya da aynı unvanlı (büyük/küçük harf, Türkçe karakter duyarsız) bir tedarikçi zaten
varsa yenisi açılmaz, mevcut kart eşlenir. `customers[]` içinde `contactType: "supplier"` ya da `"both"` olan kayıtlar
da tedarikçi kartı olarak yazılır. **Her gider** (`expenses[]`) tedarikçisine `supplierExternalId` → `supplierTaxId` →
`supplierName` sırasıyla bağlanır; bulunamazsa tedarikçi kartı otomatik açılır. Böylece tedarikçi ekstreleri ve borç
bakiyeleri Heyşirket'te kendiliğinden oluşur.

### Ürün ve varyant (`products[]`)
| Alan | Tür | Not |
| --- | --- | --- |
| `externalId`, `name` | metin | zorunlu |
| `sku`, `barcode` | metin | firma içinde benzersiz |
| `description`, `brand`, `category`, `unit` | metin | `unit` varsayılan `Adet` |
| `vatRate` | sayı | yüzde, varsayılan `20` |
| `price` | sayı | KDV dahil satış fiyatı |
| `currency` | metin | varsayılan `TRY` |
| `isActive`, `tracksInventory` | doğru/yanlış | `isActive: false` satışa kapatır |
| `imageUrl`, `images[]` | metin | https görseller (ilki ana görsel, en fazla 10) |
| `family` | nesne | varyantlı ürünün ana ürünü: `externalId`, `name` (zorunlu), `description`, `brand`, `category`, `imageUrl`, `images[]`, `isActive`, `heysirketId` |
| `attributes` | nesne | varyant özellikleri: `{ "Renk": "Pembe", "Beden": "3-6 Ay" }` |
| `heysirketId` | metin | Heyşirket'te açılmış ürünü/varyantı eşler; kopya oluşmaz |
| `metadata` | nesne | serbest |

Varyantlı ürünlerde **yalnız satılabilir varyantlar** `products[]` olarak gönderilir; ana ürün `family` ile
tanımlanır. Heyşirket'te aile tek satırda görünür, varyantlar tek pencerede düzenlenir.

### Stok seviyesi (`stock[]`)
`{ "productExternalId": "123", "quantity": 7, "warehouse": { "code": "ANA", "name": "Ana depo" } }` —
**mutlak** miktar gönderilir; Heyşirket farkı sayım düzeltmesi olarak stok defterine yazar. `warehouse`
gönderilmezse varsayılan depo (yoksa `ANA`) kullanılır.

### Satış faturası (`invoices[]`)
| Alan | Tür | Not |
| --- | --- | --- |
| `externalId`, `issueDate`, `total` | | zorunlu |
| `number` | metin | fatura numarası |
| `dueDate` | tarih | vade; pazaryeri satışlarında beklenen hakediş tarihi. Yoksa `issueDate` |
| `documentType` | `E_INVOICE` \| `E_ARCHIVE` \| `PAPER` \| `OTHER` | |
| `status` | `APPROVED` \| `SUBMITTED` \| `REJECTED` \| `CANCELLED` \| `DRAFT` \| `ERROR` | iptalde `CANCELLED` |
| `isCreditNote` | doğru/yanlış | iade faturası |
| `currency`, `subtotal`, `vat` | | |
| `customerExternalId` / `customer` | | alıcı (fatura anındaki bilgi) |
| `einvoice` | nesne | `{ "provider": "trendyol-efaturam", "uuid": "ETTN" }` — firmanın e-belge bağlantısı varsa orijinal PDF otomatik arşivlenir |
| `order` | nesne | `{ "channel": "trendyol", "externalOrderId": "…" }` — siparişin fatura durumu `INVOICED` olur |
| `lines[]` | | `name` zorunlu; `quantity`, `unit`, `unitPrice` (KDV hariç), `vatRate`, `discount`, `vat`, `total` (KDV dahil), `sku`, `productExternalId` |
| `payments[]` | | `externalId`, `amount`, `paidAt`, `method`, `note` — ödeme durumu buradan hesaplanır; listede olmayan önceki ödemeler kaldırılır |

### Gider / gelen fatura (`expenses[]`)
| Alan | Tür | Not |
| --- | --- | --- |
| `externalId`, `issueDate`, `total`, `supplierName` | | zorunlu |
| `kind` | `EXPENSE` \| `RECEIPT` \| `INCOMING_E_INVOICE` \| `OTHER` | |
| `number`, `dueDate`, `currency`, `subtotal`, `vat`, `supplierTaxId`, `supplierExternalId` | | |
| `category` | metin | ör. `KARGO`, `REKLAM`, `KOMISYON`, `YAZILIM` |
| `paymentStatus`, `paid` | | `UNKNOWN` \| `UNPAID` \| `PARTIAL` \| `PAID` |
| `einvoiceUuid` | metin | gelen e-faturanın ETTN'i; Heyşirket'in sağlayıcıdan otomatik aldığı belgeyle **tek kayıtta birleşir** |
| `lines[]`, `note`, `metadata` | | |

### Kasa-banka hareketi (`transactions[]`)
`{ "externalId": "…", "direction": "INFLOW"|"OUTFLOW", "amount": 120.5, "currency": "TRY", "date": "2026-10-01",
"description": "…", "counterparty": "…", "account": { "externalId": "iyzico", "name": "iyzico", "type": "BANK"|"CASH" },
"expenseExternalId": "…" }` — fatura tahsilatlarını burada **tekrar** göndermeyin (`invoices[].payments` yeterlidir).

### E-ticaret siparişi (`orders[]`)
| Alan | Tür | Not |
| --- | --- | --- |
| `channel` | metin | `trendyol`, `hepsiburada`, `pazarama`, `n11`, `idefix`, `amazon-tr`, `woocommerce`, `shopify`, `ticimax`, `ideasoft`, `tiktok` ya da kendi kodunuz |
| `externalOrderId` | metin | zorunlu; Trendyol için **paket numarası** (`shipmentPackageId`) |
| `orderNumber`, `orderDate` | | `orderDate` zorunlu |
| `orderStatus` | `NEW` \| `PENDING_APPROVAL` \| `APPROVED` \| `COMPLETED` \| `CANCELLED` \| `RETURNED` | |
| `fulfillmentStatus` | `UNFULFILLED` \| `READY_TO_SHIP` \| `SHIPPED` \| `DELIVERED` | |
| `billingStatus` | `NOT_READY` \| `READY` \| `INVOICED` \| `NOT_REQUIRED` | |
| `currency`, `subtotal`, `shipping`, `discount`, `commission`, `total` | | |
| `customer`, `shippingAddress`, `summary` | nesne | |
| `items[]` | | `externalLineId`, `sku`, `name`, `quantity`, `unitPrice`, `discount`, `vatRate` |
| `shipments[]` | | `carrier`, `trackingNumber`, `status`, `shippedAt`, `deliveredAt`, `trackingUrl` |

### Silme (`deleted`)
`externalId` listeleriyle bildirilir: cari, tedarikçi ve ürün **pasife alınır** (geçmiş korunur); bu kaynaktan gelen gider ve
kasa-banka hareketi silinir. Faturalar silinmez; `status: "CANCELLED"` gönderin.

## Yanıt ve hata kodları

```json
{
  "ok": true,
  "runId": "…",
  "stats": { "customers": { "created": 3, "updated": 10 }, "products": { "created": 2, "updated": 40 } },
  "errors": [ { "type": "products", "externalId": "55", "code": "DUPLICATE_SKU", "message": "Bu stok kodu (SKU) firmada başka bir ürüne ait." } ]
}
```

Bir kaydın hatası diğerlerini durdurmaz. Mesajlar Türkçedir ve kullanıcıya gösterilebilir.

| Kayıt `code` | Anlamı | Ne yapmalı |
| --- | --- | --- |
| `VALIDATION` | alan eksik/geçersiz | mesajdaki alanı düzeltip tekrar gönderin |
| `DUPLICATE_SKU`, `DUPLICATE_BARCODE` | SKU/barkod başka üründe | benzersiz kod gönderin ya da barkodu boş bırakın |
| `DUPLICATE` | benzersizlik çakışması | kimlikleri kontrol edin |
| `REFERENCE` | bağlı kayıt nedeniyle yazılamadı | önce bağlı kaydı gönderin |
| `NOT_FOUND` | stok için ürün yok | önce `products[]` gönderin |
| `WRITE_FAILED` | geçici yazma hatası | aynı sayfayı tekrar gönderin |

| HTTP | `code` | Ne yapmalı |
| --- | --- | --- |
| 401 | `API_KEY_INVALID` | anahtarı kontrol edin / yenisini oluşturun |
| 402 | `SUBSCRIPTION_PAYMENT_REQUIRED` | firma aboneliği ödeme bekliyor; durun |
| 413 | | sayfayı küçültün |
| 422 | `INVALID_BODY` | gövdeyi düzeltin (`source`, sayfa sınırları) |
| 423 | `BUSINESS_SUSPENDED` | firma erişimi durdurulmuş; durun |
| 429 | `RATE_LIMITED` / `DAILY_QUOTA` | `Retry-After` kadar bekleyin |
| 5xx | `WRITE_FAILED` | üstel geri çekilmeyle tekrar deneyin |

## Değişiklik akışı (Heyşirket → sizin sisteminiz)

`GET /api/v1/changes?after=<seq>&limit=200[&types=inventory.movement,product.updated]`

```json
{ "events": [ { "seq": 41, "type": "inventory.movement", "entityType": "inventory_movement", "entityId": "…", "createdAt": "2026-10-13 09:12:00",
    "data": { "productExternalProvider": "api:magazam", "productExternalId": "123", "sku": "S1", "direction": "IN", "quantity": 5, "warehouseCode": "ANA" } } ],
  "next": 41, "hasMore": false }
```

Akışa yalnız Heyşirket'te yapılan değişiklikler düşer; bu API ile yazılanlar **geri yansıtılmaz** (döngü
oluşmaz). `next` değerini saklayın ve sonraki çağrıda `after` olarak gönderin; `hasMore: true` ise hemen tekrar
çağırın. Kendi kayıtlarınızı `externalProvider` = `api:<source>` olanlarla eşleyin.

| Tür | Ne zaman | Önemli alanlar |
| --- | --- | --- |
| `inventory.movement` | stok girişi/çıkışı/sayım (fatura ile düşen stok dahil) | `direction` (`IN` +, `OUT` −, `ADJUSTMENT` işaretli, `RESERVE`/`RELEASE` bilgi), `quantity`, `productExternalId`, `sku` |
| `product.created` / `product.updated` | ürün/varyant eklendi/değişti (yeni beden, fiyat, satışa kapatma/açma) | `id`, `externalId` (yoksa Heyşirket'te açılmış), ad, SKU, barkod, fiyat, KDV, `isActive`, `attributes`, `familyExternalId`, `imageUrl` |
| `family.created` / `family.updated` | ürün ailesi eklendi/değişti/pasife alındı | `id`, `externalId`, ad, açıklama, marka, kategori, görsel, `isActive` |
| `customer.created` / `customer.updated` | cari eklendi/değişti | `id`, `externalId`, unvan, vergi no, iletişim |
| `supplier.created` / `supplier.updated` | tedarikçi eklendi/değişti | `id`, `externalId`, unvan, vergi no, iletişim, web adresi, `isActive` |
| `invoice.created` / `invoice.updated` | Heyşirket'te fatura kesildi / durum, numara, ödeme durumu değişti | `id`, `externalId`, `number`, `status`, `providerId` (ETTN), `paymentStatus`, tutarlar |
| `payment.created` / `payment.voided` | tahsilat kaydı / iptali | `invoiceExternalId`, `amount`, `paidAt`, `method` |
| `expense.created` / `expense.updated` | gider eklendi/değişti | `id`, `apiExternalId`, tutarlar, tedarikçi, kategori, ödeme durumu |
| `order.updated` | e-ticaret siparişinde onay/kargo/tamamlama | `channel`, `externalOrderId`, `action`, durumlar, `trackingNumber` |

**Uygulama sırası:** her turda **önce** akışı okuyup uygulayın, **sonra** kendi değişikliklerinizi gönderin.
Heyşirket'te açılan ürün/varyant/aile için kendi kaydınızı oluşturun ve bir sonraki gönderimde `heysirketId` ile
eşleyin. Stok olaylarını **fark** olarak uygulayın; sonra mutlak stok gönderdiğinizde Heyşirket sıfır fark görür.

## Entegrasyon kontrol listesi

- [ ] Her sistem için ayrı anahtar; anahtar yalnız ortam değişkeninde.
- [ ] `GET /ping` başarılı.
- [ ] Tüm sayfalar `?dryRun=1` ile hatasız.
- [ ] İlk aktarım sayfalı, kaldığı yerden devam edebiliyor, günlük kotaya uyuyor.
- [ ] Yalnız değişen kayıtlar gönderiliyor (parmak izi / değişiklik zamanı).
- [ ] Fatura satırlarının toplamı fatura toplamına eşit; iptaller `CANCELLED`.
- [ ] Varyantlar `family` + `attributes` ile, görseller https.
- [ ] Akış önce okunuyor, stok fark olarak uygulanıyor, `next` kalıcı saklanıyor.
- [ ] 429'da `Retry-After`'a uyuluyor, 5xx'te geri çekiliyor.
- [ ] Yönetim ekranınızda son çalışma ve hatalar görünüyor; Heyşirket'te **Ayarlar → API ve senkron** ile karşılaştırıldı.

## Sık sorulanlar

**Aynı kaydı iki kez gönderirsem ne olur?** Güncellenir; kopya oluşmaz.

**Pazaryeri faturalarım gecikmiş görünüyor.** `dueDate` olarak beklenen hakediş tarihini, ödendiğinde de `payments[]` ile tahsilatı gönderin.

**Ürünlerim Heyşirket'te tek tek görünüyor.** Varyantları `family` ve `attributes` ile gönderin; aile tek satırda toplanır.

**Heyşirket'te stok girdim, sistemime nasıl gelir?** `GET /changes` akışındaki `inventory.movement` olayını fark olarak uygulayın.

**Büyük kataloğum var.** İlk aktarım günlük kotaya göre birkaç güne yayılır; `DAILY_QUOTA` aldığınızda kalan kayıtları ertesi gün gönderin.
