Skip to content
ENTERPRISE Enterprise technology · Engineered for your business Enterprise Software · Managed Servers · Business E-mail · LiteSpeed + CloudLinux · Imunify360 Security · cPanel Control · Network profile up to 3 Gbps on eligible plans
AIOR

Trendyol API Integration: Products, Stock and Price, Orders, Webhooks

Aior

Administrator

Staff member
Joined
Apr 2, 2023
Messages
929
Reaction score
2
Points
18
Age
41
Location
Turkey
Website
aior.com
Thread owner

Bu rehber, hazır bir entegratör yazılımı almak yerine kendi Trendyol satıcı entegrasyonunu yazan ya da mevcut entegrasyonundaki hataları ayıklayan geliştiriciler ve şirket içi ekipler için hazırlandı. Amaç; ERP'nizi, depo yönetim sisteminizi (WMS) ya da e-ticaret sitenizi Trendyol Pazaryeri (Partner) API'sine bağlayıp ürün, stok-fiyat, sipariş, kargo etiketi, fatura ve iade akışlarını otomatikleştirmek. Anlatılanlar, developers.trendyol.com adresindeki resmî dokümantasyonun Ekim 2026 sonundaki hâline dayanıyor. Eski kodlara ya da blog yazılarına bakıyorsanız iki değişikliği bilmeniz gerekir: Dokümantasyon, Ürün V1 servisleri ve eski /orders sipariş listeleme uç noktası (endpoint) için 15 Ekim 2026'yı son tarih olarak belirledi; yeni kod yalnızca Ürün V2 ve /v2/orders kullanmalı. Ayrıca 14 Eylül 2026'dan bu yana ürün servislerindeki istek sınırları (rate limit) uç nokta bazında değil, servis grubu bazında ve listeleme limitinize göre uygulanıyor. Pazaryerinde satışın günlük operasyon tarafını Pazaryerlerinde satış: operasyonel taraf konusunda ele aldık; bu yazı API'ye odaklanıyor.

Kendi entegrasyonunuz mu, entegratör mü, dosya yükleme mi?​

SeçenekNe zaman uygun?Dikkat edilecekler
Kendi entegrasyonunuz (User-Agent: "{sellerId} - SelfIntegration")Stok ve fiyat zaten bir ERP veya WMS'de tutuluyorsa, kodu sürdürecek bir geliştirici varsa ve hazır araçların karşılamadığı akışlarınız (çoklu depo, set ürün, kendi fatura hattınız) bulunuyorsaTrendyol kod desteği vermediğini açıkça belirtiyor; API değişikliklerini sizin izlemeniz gerekir
Entegratör yazılımıBirden çok pazaryeri, yazılım ekibi olmaması, hızlı başlangıç ihtiyacıAbonelik ya da kullanım ücreti, entegratörün veri modeli, Trendyol bir şeyi değiştirdiğinde entegratörün güncellemesini beklemek
Satıcı Paneli'nin toplu işlem araçları veya XML/Excel tabanlı servislerKüçük katalog, az sipariş, seyrek değişen stokElle yapılan adımlar, yavaş stok güncellemesi, kampanyalarda aşırı satış (overselling) riski
Entegrasyonu kendiniz yazmak, iş aslında zaten çalıştırdığınız sistemleri birbirine bağlamaksa ve sipariş hacmi elle çalışmayı ya da sipariş başına ücreti pahalı hâle getiriyorsa kendini öder. Gizli maliyet bakımdır: Yalnızca 2026'da changelog sayfasında Ürün V2 geçişi, 10.000 kayıt pencereli /v2/orders, grup bazlı istek sınırları, yeni menşei (origin) alanı, hızlı teslimat alanlarında değişiklik, fatura için paymentMethod alanı, Trendyol Luxe için kanal alanı ve yenilenen iade red sebepleri duyuruldu. Bu sayfayı okuyup değişiklikleri zamanında devreye alacak birinin olması şart.

Mimari: tek doğruluk kaynağı, kuyruklar ve idempotent işleme​

Trendyol'u bir satış kanalı olarak görün, asla ana veri kaynağı olarak değil. İçerik, stok ve fiyat ERP'nizde, PIM'inizde ya da kendi veritabanınızda durur; entegrasyon değişiklikleri dışarı yayınlar, siparişleri, iadeleri ve hakedişleri içeri çeker.
Code:
ERP / WMS / PIM (ana veri: ürün, stok, fiyat)
   |  değişiklik günlüğü veya outbox: yalnızca değişen kayıtlar
   v
kuyruk ---> katalog işçisi ---> Ürün V2 uç noktaları ---> batchRequestId
       ---> stok işçisi    ---> price-and-inventory  ---> batchRequestId
            batch takipçisi: toplu işlem sonucunu sorgular, FAILED kalemleri göreve çevirir

Trendyol webhook ---> alıcı (kimlik kontrolü, ham olayı sakla, 200 OK) ---> kuyruk
mutabakat işi (birkaç dakikada bir orders/stream) ---------------------> kuyruk
kuyruk ---> sipariş işçisi (idempotent: shipmentPackageId + status + lastModifiedDate)
       ---> ERP / WMS: stok ayır, topla, faturala, etiketle, gönder
  • Eşleme tabloları (mapping). Kendi stok kodunuzun yanında barcode (stok, fiyat ve siparişte anahtar), stockCode, productMainId (varyantları gruplayan "model kodu"), contentId, categoryId, brandId, özellik ve değer ID'leri, adres ID'leri ve kargo firması kodları dursun. Reddedilen toplu isteklerin çoğu eksik ya da bayatlamış bir eşlemeden çıkar.
  • Uç nokta başına değil, limit grubu başına bir hız sınırlayıcı. Ürün yazma, ürün okuma ve stok-fiyat güncelleme servisleri kendi içlerinde tek bir bütçeyi paylaşır (ayrıntısı aşağıda).
  • İdempotent tüketiciler. Webhook'lar yeniden dener, mutabakat işi aynı paketleri tekrar okur, işçiler yarıda çöker; her işleyici aynı olayı iki kez işlediğinde de aynı sonucu vermeli.
  • Her yazma işlemi doğrulamayla biter. Ürün ve stok-fiyat çağrıları sonuç değil, batchRequestId döndürür.
  • Sır içermeyen loglar. Gövdeleri batchRequestId veya shipmentPackageId ile saklayın ama Authorization başlığını maskeleyin. Sipariş verisinde ad, adres, telefon ve bazen T.C. kimlik numarası bulunur; KVKK (6698 sayılı Kanun) gereği erişimi sınırlayın, veriyi şifreli saklayın, bir saklama süresi belirleyin.
  • İçeride UTC, dönüşüm kenarda. Zaman damgaları milisaniye cinsinden epoch değerleridir; bazıları GMT+3, bazıları GMT olarak belgelenmiş.

İstek bütçesini hesaplamak​

Kayıt değil, çağrı sayın. Varsayımlar: en düşük listeleme limiti kademesi (50.000 ürün), 20.000 aktif barkod, iki haftada yaklaşık 3.000 paket değişikliği ve karar bekleyen 60 iade.
İşÇağrıSınırlayan ne?
20.000 barkodun tam stok-fiyat gönderimi1.000'er kalemlik 20 istekInventory & Price Write, bu kademede dakikada 350: darboğaz değil
5.000 ürün oluşturma5 istek ve batch sorgularıVeri kalitesi ve onay süresi
Son 14 günde değişen paketleri stream ile yeniden okumasize=200 ile yaklaşık 15 istekÇağrılar arasında önerilen 5 saniye: yaklaşık 75 saniye
60 iadeyi tek tek onaylama60 istekDakikada 5: yaklaşık 12 dakika
Bu örnekte darboğaz katalog değil, iade kuyruğu. Barkod başına fiyat sınırı (dakikada 30) ise ancak her rakip hareketinde fiyat gönderen bir fiyatlama aracında devreye girer.

Kimlik doğrulama, başlıklar ve test ortamı​

  • Kimlik bilgileri: Satıcı ID, API Key ve API Secret, Satıcı Paneli'nde Hesap Bilgilerim > Entegrasyon Bilgileri sayfasındadır ve yalnızca ana kullanıcıya (admin rolü) görünür. Aynı sayfadaki "Entegrasyon Referans Kodu" destek taleplerinde istenir; API anahtarı kadar gizli tutun.
  • Basic Authentication: Kullanıcı adı olarak API Key, parola olarak API Secret kullanılır. Satıcı ID URL yolunda yer alır.
  • User-Agent zorunludur: Kendi yazılımınız için "{sellerId} - SelfIntegration", entegratör için "{sellerId} - {EntegratörAdı}" (alfanümerik, en fazla 30 karakter). User-Agent göndermeyen istekler 403 ile engellenir.
  • Canlı ortam: https://apigw.trendyol.com; IP yetkilendirmesi gerekmez, ancak Trendyol bir IP'nin çeşitli nedenlerle engellenebileceğini belirtiyor.
  • Test ortamı (stage): https://stageapigw.trendyol.com; ayrı hesap (panel: stagepartner.trendyol.com) ve ayrı anahtarlar. Stage yalnızca yetkilendirilmiş IPv4 çıkış adreslerine yanıt verir, aksi hâlde 503 döner. Yetkilendirmeyi satıcı paneli üzerinden destek talebiyle isteyebilirsiniz (doküman IP'nin 24 saat içinde tanımlandığını söylüyor) ya da Test Ortam IP Whitelist Yönetimi servisleriyle kendiniz yönetebilirsiniz. Bu servisler canlı ağ geçidinde, canlı satıcı ID'nizle çağrılır. Sınırlar: en fazla 7 IPv4 adresi ve günde en fazla 7 ekleme; her kaydın bir expiresAt (son geçerlilik) tarihi vardır.
Kimlik bilgilerini ve başlıkları sınamak için ilk çağrı:
Bash:
export TY_BASE="https://apigw.trendyol.com"     # test: https://stageapigw.trendyol.com
export TY_SELLER_ID="123456"                     # yer tutucu
export TY_API_KEY="..."                          # sır kasasından okuyun, asla git'ten değil
export TY_API_SECRET="..."

curl -sS "$TY_BASE/integration/product/sellers/$TY_SELLER_ID/products/approved?page=0&size=1" \
  -u "$TY_API_KEY:$TY_API_SECRET" \
  -H "User-Agent: $TY_SELLER_ID - SelfIntegration" \
  -H "Accept: application/json"
Test anahtarlarının canlıya hiç ulaşamaması için ortamları yapılandırmada ayırın:
YAML:
trendyol:
  prod:
    base_url: https://apigw.trendyol.com
    seller_id: ${TY_PROD_SELLER_ID}
    api_key: ${TY_PROD_API_KEY}
    api_secret: ${TY_PROD_API_SECRET}
  stage:
    base_url: https://stageapigw.trendyol.com
    seller_id: ${TY_STAGE_SELLER_ID}    # test hesabı canlıdakinden farklıdır
    api_key: ${TY_STAGE_API_KEY}
    api_secret: ${TY_STAGE_API_SECRET}
  integrator_name: SelfIntegration       # User-Agent: "{seller_id} - SelfIntegration"
  limits_per_minute: { product_read: 1000, product_write: 200, inventory_price_write: 350, order_list: 30, claim_approve: 5 }   # en düşük kademe

14 Eylül 2026'dan itibaren istek sınırları​

Servis Limitleri sayfası sınırları listeleme limiti kademenize (50.000, 75.000, 150.000 veya 500.000 ürün ya da limitsiz) bağlıyor:
GrupKapsamDakikada istek, en düşük kademeden limitsize
Product Integration ReadÜrün filtreleme, toplu işlem kontrolü, marka, kategori, özellik ve değer listeleri, adresler, güncelleme sonucu kontrolü1.000 - 2.000
Product Integration WriteÜrün yaratma, güncelleme, silme, arşivleme, kilit kaldırma, marka yaratma, buybox kontrolü200 - 600
Inventory & Price WriteStok ve fiyat güncelleme350 - 2.000
Sipariş paketleriSipariş Paketlerini Çekme30 - 100
İadelerİade onaylama; ret talebi oluşturmaHer biri 5
Ayrıca aynı barkod için fiyat güncellemesi dakikada 30 ile sınırlı (fazlası batch sonucunda hata olarak döner). Yetkilendirme sayfası da aynı uç noktaya 10 saniyede en fazla 50 istek atılabildiğini, sonrasında "too.many.requests" içeren 429 döndüğünü yazıyor. İşçi sayısını belirlemeden önce kendi kademenizin değerlerine bakın; tablodakiler Ekim 2026'da belgelenmiş rakamlardır.

Uç nokta haritası​

Yollar, ortamın temel adresine eklenir.
İş (dokümandaki servis adı)Metot ve yol
Kategori ağacı (getCategoryTree)GET /integration/product/product-categories
Kategori özellik listesi v2, özellik değerleri v2GET /integration/product/categories/{categoryId}/attributes, .../attributes/{attributeId}/values
Marka listesi, marka yaratmaGET /integration/product/brands, POST /integration/product/sellers/{sellerId}/brands
İade ve sevkiyat adresleriGET /integration/sellers/{sellerId}/addresses
Ürün yaratma v2POST /integration/product/sellers/{sellerId}/v2/products
Toplu işlem kontrolü (getBatchRequestResult)GET /integration/product/sellers/{sellerId}/products/batch-requests/{batchRequestId}
Onaylı ve onaysız ürün filtreleme v2GET .../sellers/{sellerId}/products/approved, .../products/unapproved
Stok ve fiyat güncelleme (updatePriceAndInventory)POST /integration/inventory/sellers/{sellerId}/products/price-and-inventory
Sipariş paketlerini çekme (getShipmentPackages)GET /integration/order/sellers/{sellerId}/v2/orders
Akış ile çekme (getShipmentPackagesStream)GET /integration/order/sellers/{sellerId}/orders/stream
Paket statü bildirimi (updatePackage)PUT /integration/order/sellers/{sellerId}/shipment-packages/{packageId}
Fatura linki, fatura dosyasıPOST /integration/sellers/{sellerId}/seller-invoice-links, .../seller-invoice-file
Ortak etiket (createCommonLabel, getCommonLabel)POST, GET /integration/sellers/{sellerId}/common-label/{cargoTrackingNumber}
Webhook/integration/webhook/sellers/{sellerId}/webhooks
İadeler (getClaims)GET /integration/order/sellers/{sellerId}/claims

Katalog: kategori, özellik ve ürün yaratma​

Ürün yaratma (V1'deki adıyla ürün aktarma) asenkron çalışır ve referans verilerde (kategori, özellik, marka) hata kabul etmez; bu yüzden önce sözlükleri kurun:
  1. Kategoriler: Yalnızca en alt seviyedeki (yaprak) kategoriler ürün kabul eder. Doküman kategori ağacını ve özellikleri haftalık yenilemenizi öneriyor.
  2. Özellikler (attribute): Her kategori için required (zorunlu), allowCustom (ID yerine customAttributeValue ile serbest metin gönderilir), allowMultipleAttributeValues (birden fazla değer), slicer (ayrı ürün kartı açar, genelde renk) ve varianter (aynı kart üzerindeki varyant, genelde beden; kategori başına bir tane) bilgisi gelir.
  3. Değerler, markalar, adresler: Değer servisini sayfalayarak (size en fazla 1.000) çekin; brandId'yi marka listesinden alın ya da markayı yaratın; shipmentAddressId ve returningAddressId'yi adres servisinden okuyun.
Bir yaratma isteği en fazla 1.000 kalem alır. Aynı modelin varyantları productMainId'yi paylaşır; barcode, stockCode ve varianter ya da slicer değerinde ayrışır. Aşağıdaki ID'lerin hepsi yer tutucudur:
JSON:
{
  "items": [
    {
      "barcode": "DEMO-USBC-1M-BLK",
      "title": "USB-C - USB-C Şarj Kablosu 1 m 60 W Siyah",
      "productMainId": "DEMO-USBC-1M",
      "brandId": 1234567,
      "categoryId": 7654,
      "quantity": 40,
      "stockCode": "USBC-1M-BLK",
      "dimensionalWeight": 1,
      "description": "Örgü kaplı USB-C kablo, 1 m, 60 W şarj desteği.",
      "listPrice": 299.90,
      "salePrice": 249.90,
      "vatRate": 20,
      "images": [{ "url": "https://cdn.example.com/usbc-1m-blk-1.jpg" }],
      "attributes": [
        { "attributeId": 47, "customAttributeValue": "Siyah" },
        { "attributeId": 1111, "attributeValueId": 22222 }
      ],
      "shipmentAddressId": 111,
      "returningAddressId": 222
    }
  ]
}
Göndermeden önce kendi tarafınızda doğrulayın: barcode en fazla 40 karakter, özel karakter olarak yalnızca ".", "-" ve "_" (aradaki boşluklar silinip birleştirilir; stok-fiyat çağrılarında bu kaydedilmiş hâli kullanmalısınız); title en fazla 100; productMainId en fazla 40; description en fazla 30.000 karakter ve HTML içerebilir; görseller https adresli, barkod başına en fazla 8 adet, dokümanda 1200×1800 piksel ve 96 dpi olarak tarif ediliyor; listPrice, salePrice'tan düşük olamaz; vatRate tam sayı bir oran (dokümanda 0, 1, 10 ve 20 örnekleri var). Hızlı teslimat deliveryOption.deliveryDuration ile verilir: "Bugün Kargoda" için 0, "En Geç Yarın Kargoda" için 1; Ağustos 2026'dan beri fastDeliveryType işlenmiyor. İsteğe bağlı yeni bir origin (iki harfli ülke kodu) alanı da eklendi; ancak Ekim 2026 duyurusuna göre menşei bilgisi, kategoride zorunlu olduğu yerde hâlâ attributes altında gönderilmeli.

Toplu işlem sonucunu (batch result) sorgulamak​

Yaratma yanıtı yalnızca bir batchRequestId'dir; Trendyol'un Sıkça Sorulan Sorular sayfası da bunun işlemin başarılı olduğu anlamına gelmediğini açıkça yazıyor. Toplu işlem COMPLETED olana kadar sorgulayın. Stok-fiyat işlemlerinde batch düzeyinde status dönmez; orada her kalemin SUCCESS ya da FAILED olduğuna bakılır. Sonuçlar 4 saat boyunca sorgulanabilir.
Python:
import time
import requests

def make_session(seller_id, api_key, api_secret):
    s = requests.Session()
    s.auth = (api_key, api_secret)
    s.headers.update({"User-Agent": f"{seller_id} - SelfIntegration",
                      "Accept": "application/json"})
    return s

def wait_for_batch(s, base, seller_id, batch_id, timeout_s=1800):
    url = f"{base}/integration/product/sellers/{seller_id}/products/batch-requests/{batch_id}"
    delay, deadline = 5, time.monotonic() + timeout_s
    while time.monotonic() < deadline:
        r = s.get(url, timeout=30)
        if r.status_code != 429:
            r.raise_for_status()
            body = r.json()
            items = body.get("items") or []
            done = body.get("status") == "COMPLETED" or (
                items and all(it.get("status") in ("SUCCESS", "FAILED") for it in items))
            if done:
                return [(it.get("requestItem", {}).get("barcode"), it.get("status"),
                         it.get("failureReasons", [])) for it in items]
        time.sleep(delay)
        delay = min(delay * 2, 120)
    raise TimeoutError(f"batch {batch_id} hâlâ işleniyor")

Onay, güncelleme, arşivleme ve silme​

  • Başarılı kalemler içerik onayına girer. Onaysız ürün filtresi pendingApproval (onay bekliyor) ya da rejected (reddedildi) gösterir; reddedilen ürünü düzeltip unapproved-bulk-update ile yeniden gönderirsiniz. Onaylı ürünler onSale, notOnSale, archived, locked veya blacklisted statüsündedir. Sayfalama page × size = 10.000'de durur; ötesi için yanıttaki nextPageToken kullanılır.
  • Onaylı ürünler content-bulk-update, variant-bulk-update (stockCode, KDV oranı, adresler, desi) ve delivery-info-bulk-update ile güncellenir. Barcode, productMainId, brandId, categoryId ve slicer/varianter değerleri değiştirilemez. İki tuzak var: Tek bir özelliği değiştirecekseniz tüm özellikleri göndermeniz gerekir ve null gönderilen alan üründen silinir. İçerik kontrolünün sonucu contentId bazında update-audits uç noktasından okunur.
  • Arşivleme (archive-state) ürünü silmeden gizler. Yalnızca onay bekleyen ürünler ile bir günden uzun süredir arşivde duran ve Trendyol tarafından satışı durdurulmamış onaylı ürünler silinebilir. Çok düşük ya da çok yüksek fiyat, kritik fiyat hatası veya tedarik edememe yüzünden kilitlenen ürünlerin kilidi, sebep giderildikten sonra kilit kaldırma servisiyle açılır.
Yaratma kalemleri çoğunlukla şu nedenlerle FAILED döner: yaprak olmayan categoryId, eksik zorunlu özellik, başka bir kategoriye ait değer ID'si, allowCustom false iken serbest metin, https olmayan görsel, salePrice'tan düşük listPrice ya da izin verilmeyen karakter içeren barkod. Geri kalanların çoğunu bayat sözlük verisi üretir.

Stok ve fiyat senkronizasyonu (updatePriceAndInventory)​

POST /integration/inventory/sellers/{sellerId}/products/price-and-inventory istek başına en fazla 1.000 barkod alır; bir kalemde yalnızca quantity ya da yalnızca fiyatlar olabilir. quantity satılabilir stoktur: Trendyol sipariş geldikçe düşürür, sizin bir sonraki değerinizle değiştirir; doküman ürün başına üst sınırı 20.000 adet olarak veriyor. listPrice üstü çizili fiyat (PSF), salePrice satış fiyatıdır (TSF).
JSON:
{
  "items": [
    { "barcode": "DEMO-USBC-1M-BLK", "quantity": 37, "listPrice": 299.90, "salePrice": 249.90 },
    { "barcode": "DEMO-USBC-1M-WHT", "quantity": 0 },
    { "barcode": "DEMO-USBC-2M-BLK", "listPrice": 329.90, "salePrice": 289.90 }
  ]
}
  • Fark (delta) gönderin. Aynı gövde 15 dakika içinde tekrar gelirse "15 dakika boyunca aynı isteği tekrarlı olarak atamazsınız!" hatası döner. Yalnızca son kabul edilen gönderimden bu yana değişen barkodları yollayın.
  • Fiyat güncellemelerini birleştirin. Aynı barkod için dakikada 30'dan fazla fiyat güncellemesi hata verir; her döngüde barkod başına yalnızca son fiyatı tutun.
  • 429 ve 5xx'te geri çekilin. Rastgele sapmalı (jitter) üstel bekleme (backoff) kullanın ve deneme sayısına üst sınır koyun. Diğer 4xx yanıtları veri sorunudur: düzeltin, yeniden denemeyin.
  • Zaman aşımından sonra önce doğrulayın. Aynı gövdeyi hemen yeniden göndermek 15 dakika kuralına takılabilir; bu hata zaten ilk isteğin ulaştığını gösterir. Körlemesine yeniden göndermek yerine batch sonucuna ya da stok-fiyat filtresine bakın.
  • Her gün mutabakat yapın: Onaylı ürün stok ve fiyat filtresiyle (size en fazla 100, 10.000'den sonrası nextPageToken ile) Trendyol'daki değerleri çekip ana verinizle karşılaştırın, farkları gönderin.
Python:
import hashlib, json, random, time

def push_deltas(s, base, seller_id, changes, recently_sent):
    """changes: barcode ile birlikte quantity ve/veya fiyat içeren sözlükler.
    recently_sent: özet -> unix zamanı, çalıştırmalar arasında saklanır."""
    url = f"{base}/integration/inventory/sellers/{seller_id}/products/price-and-inventory"
    batch_ids = []
    for start in range(0, len(changes), 1000):
        body = {"items": changes[start:start + 1000]}
        digest = hashlib.sha256(json.dumps(body, sort_keys=True).encode()).hexdigest()
        if time.time() - recently_sent.get(digest, 0) < 15 * 60:
            continue                     # aynı gövde 15 dakikadan kısa süre önce kabul edildi
        for attempt in range(6):
            r = s.post(url, json=body, timeout=30)
            if r.status_code == 429 or r.status_code >= 500:
                time.sleep(min(60, 2 ** attempt) + random.random())
                continue
            r.raise_for_status()         # diğer 4xx: veriyi düzeltin, yeniden denemeyin
            batch_ids.append(r.json()["batchRequestId"])
            recently_sent[digest] = time.time()
            break
    return batch_ids
Stok tamponu. Elinizdekinden azını yayınlayın: yayınlanan = max(0, eldeki − ayrılmış − tampon). Awaiting (ödeme kontrolü süren) statüsündeki siparişler stoğu şimdiden ayırmalı; doküman bu statünün yalnızca stok işlemleri için kullanılmasını, paket Created olmadan gönderim yapılmamasını söylüyor. Tampon için pratik bir başlangıç: barkodun en yoğun dakikadaki satış adedi ile uçtan uca en kötü senkron gecikmenizin (dakika) çarpımı, yukarı yuvarlanmış hâliyle. Aynı stok başka kanallarda da satılıyorsa payı büyütün ve her kampanyadan sonra değeri gözden geçirin. Komisyon ve kâr marjı hesabı senkron işçisinin değil fiyatlama mantığınızın işidir (her sipariş satırı uygulanan komisyon oranını da bildirir).

Siparişler: listeleme, statüler, paketler, fatura ve etiket​

Konu/v2/orders (getShipmentPackages)/orders/stream (getShipmentPackagesStream)
Ne için?Hedefli sorgular: bir orderNumber, paket ID'leri, bir statü, yakın tarihli bir aralıkPeriyodik senkronizasyon, kesinti sonrası açığı kapatma, dışa aktarım
Sayfalamapage ve size (en fazla 200); sorgu başına en fazla 10.000 paket (size=200 ile 0-49. sayfalar)Opak nextCursor ve hasMore; imleç (cursor) kullanılırken filtre değişirse 400 döner
Zaman aralığıVarsayılan son bir hafta, sorgu başına en fazla iki hafta, son bir ayın verisilastModifiedStartDate/EndDate ile sorgu başına en fazla 14 gün, son 3 ayın verisi
Sıralama ve hızorderByField=PackageLastModifiedDate, ASC veya DESC; kademeye göre dakikada 30-100 istekSabit: lastModifiedDate azalan; istekler arasında en az 5 saniye önerilir
Stream'i dolaşan bir mutabakat işi:
Python:
def changed_packages(s, base, seller_id, since_ms, until_ms):
    url = f"{base}/integration/order/sellers/{seller_id}/orders/stream"
    params = {"lastModifiedStartDate": since_ms, "lastModifiedEndDate": until_ms, "size": 200}
    while True:
        r = s.get(url, params=params, timeout=60)
        if r.status_code == 429:
            time.sleep(30)
            continue
        r.raise_for_status()
        page = r.json()
        yield from page.get("content", [])
        if not page.get("hasMore"):
            return
        params["nextCursor"] = page["nextCursor"]   # opak değer: olduğu gibi geri gönderin
        time.sleep(5)
Bunu birkaç dakikada bir, her pencereyi bir öncekinin bitişinden birkaç dakika önce başlatarak çalıştırın; idempotent işçi daha önce uyguladıklarını atlasın.

Paket statüsüAnlamı ve yapılacak iş
Awaiting, VerifiedÖdeme kontrolü sürüyor: stoğu ayırın, Created olana kadar başka işlem yapmayın
CreatedGönderime hazır: hazırlığa başlayın
Picking, InvoicedSizin bildirdiğiniz statüler, bu sırayla
Shipped, AtCollectionPointKargoda ya da teslim noktasında bekliyor
DeliveredSon statü
UnDelivered, ReturnedTeslim edilemedi; Returned (son statü) paketin size geri döndüğünü gösterir
Cancelled, UnSuppliedİptal, tedarik edememe dâhil: stok ayırmasını bırakın
UnPackedPaket bölündü; yerini yeni paketler aldı
İş birimi sipariş değil, sipariş paketidir (shipmentPackageId). Kısmi iptal ya da bölme, aynı orderNumber altında yeni ID'li ve yeni kargo takip numaralı paketler oluşturur; createdBy alanı cancel veya split olur, originPackageIds ilk pakete işaret eder. Siparişi "bir orderNumber, birden çok paket" olarak modelleyin ve bir paket ID'sinin sipariş boyunca yaşayacağını varsaymayın. Eşlemeye değer diğer alanlar: lines[].lineId (her statü çağrısında gerekir), channelId (1 standart mağaza, 25 Trendyol Luxe), commercial ile invoiceAddress içindeki şirket adı, vergi numarası, vergi dairesi ve eInvoiceAvailable (e-Fatura mükellefi mi), Eylül 2026'da fatura için eklenen paymentMethod, identityNumber (altın, gübre ve 5.000 TL üzeri siparişlerde gelir) ve mikro ihracat için micro. customerEmail her sipariş için üretilen kriptolu (maskelenmiş) bir adrestir; tekrar gelen müşteriyi customerId ile tanıyın.

Picking, Invoiced, tedarik edememe ve paket bölme​

Paket statü bildirimi PUT /integration/order/sellers/{sellerId}/shipment-packages/{packageId} adresine yapılır; önce Picking, sonra Invoiced:
JSON:
{
  "lines": [{ "lineId": 4765111111, "quantity": 1 }],
  "params": { "invoiceNumber": "ABC2026000000123" },
  "status": "Invoiced"
}
Picking için aynı gövdeyi "status": "Picking" ve boş params ile gönderin. Gönderemeyeceğiniz satırlar için PUT .../shipment-packages/{packageId}/items/unsupplied çağrısına satırları ve bir reasonId ekleyin (500 stok tükendi, 501 kusurlu/defolu ürün, 502 hatalı fiyat, 504 entegrasyon hatası, 505 toplu alım, 506 mücbir sebep). Paketin tamamı iptal edilirse paket Cancelled olur; kısmi iptalde kalan satırlar yeni bir pakete taşınır. Birden fazla koliyle göndermek için split, multi-split, quantity-split ya da split-packages uç noktalarından birini kullanın; asıl paket UnPacked olur, yeni paketler asenkron oluşur. Bu yüzden etiket basmadan önce paketleri yeniden çekin.

Fatura​

Faturanın kendisi e-Fatura ya da e-Arşiv altyapınızdan çıkar; Trendyol'a ise faturanın PDF dosyasını siparişteki kriptolu e-posta adresine gönderirsiniz ya da iki çağrıdan birini kullanırsınız:
  • Fatura linki gönderme (sendInvoiceLink): POST .../seller-invoice-links; gövdede invoiceLink, shipmentPackageId, invoiceDateTime (10 haneli saniye ya da 13 haneli milisaniye) ve invoiceNumber bulunur, başarılı yanıt 201'dir. Numara ve tarih mikro ihracat ile Trendyol Yurt Dışı Aracılığı paketlerinde zorunludur; fatura numarası üç alfanümerik karakter, bir yıl ve dokuz rakamdan oluşan 16 karakterlik kalıba uymalıdır. Doküman, linkin yasal zorunluluk gereği 10 yıl erişilebilir kalmasını istiyor. 409, paketin zaten faturalandığını ya da linkin başka bir pakete gönderildiğini gösterir.
  • Fatura dosyası gönderme: POST .../seller-invoice-file; multipart form-data ile shipmentPackageId ve file (PDF, JPEG veya PNG, en fazla 10 MB, ileri tarihli olamaz).

Etiket ve kargo firmaları​

Trendyol'un ödediği Trendyol Express (TEX) ya da Aras Kargo gönderilerinde ortak etiket isteyin: POST .../common-label/{cargoTrackingNumber} çağrısına {"format": "ZPL", "boxQuantity": 2} gibi bir gövde gönderin, ardından aynı yola GET isteğiyle koli başına bir ZPL etiketi alın. Doküman bunu Picking ya da Invoiced bildiriminden sonra yapmanızı öneriyor. Tek format ZPL olduğu için bu dili anlayan bir termal etiket yazıcısı gerekir. Siparişte whoPays = 1 geliyorsa gönderi kendi kargo anlaşmanızla yapılır ve etiket o kargo firmasından alınır. cargoTrackingNumber, Satıcı Paneli etiketlerinde kullanılan CODE128 barkodudur. Kargo firmasını değiştirmek için PUT .../shipment-packages/{packageId}/cargo-providers çağrısına YKMP, ARASMP veya TEXMP gibi bir kod gönderin; bu işlem bir paket için 5 dakikada bir kez yapılabilir ve TEX kotanız doluysa TEX'e geçiş isteği geçersiz olur.

Sipariş paketleri için webhook​

Webhook, paketin tamamını getShipmentPackages modeliyle, abone olduğunuz statülerden birine geçtiğinde adresinize gönderir: CREATED, PICKING, INVOICED, SHIPPED, CANCELLED, DELIVERED, UNDELIVERED, RETURNED, UNSUPPLIED, AWAITING, UNPACKED, AT_COLLECTION_POINT veya VERIFIED.
  • Yaratma: POST /integration/webhook/sellers/{sellerId}/webhooks; gövdede url, authenticationType (username ve password ile BASIC_AUTHENTICATION ya da x-api-key başlığında gelen apiKey ile API_KEY) ve subscribedStatuses. Boş liste, sonradan eklenecekler dâhil tüm statülere abone olmak demektir. GET ile listelenir; .../webhooks/{id} üzerinde PUT güncelleme, DELETE silme yapar; .../activate ve .../deactivate aktife ve pasife alır.
  • Sınırlar: Satıcı başına pasifler dâhil en fazla 15 webhook; URL "Trendyol", "Dolap" veya "localhost" ifadesi içeremez.
  • Yeniden deneme: Başarısız gönderimler başarılı olana kadar 5 dakikada bir tekrarlanır (doküman bunun ileride değişeceğini söylüyor). SSS'ye göre 13 hatadan sonra webhook pasife alınır ve iki e-posta gönderilir; alıcıyı düzeltip yeniden aktife alırsınız.
Yine de sorgulamayı bırakmayın. Trendyol webhook'la birlikte periyodik senkronizasyonu öneriyor. Changelog'da da Eylül ve Ekim 2026'da belli bir zaman aralığındaki siparişlerin servis yanıtlarına ya da webhook'lara düşmediği kesintiler görülüyor; 2 ve 8 Eylül 2026'daki kesintilerde satıcılardan o aralığı yeniden sorgulamaları istendi. Webhook hız, stream mutabakatı eksiksizlik sağlar.
Python:
import hmac, json, os
from flask import Flask, request, abort

app = Flask(__name__)
WEBHOOK_KEY = os.environ["TY_WEBHOOK_KEY"]      # webhook'u yaratırken verdiğiniz apiKey

@app.post("/hooks/trendyol/packages")
def trendyol_packages():
    if not hmac.compare_digest(request.headers.get("x-api-key", ""), WEBHOOK_KEY):
        abort(401)
    body = request.get_json(silent=True) or {}
    # Doküman sayfalı getShipmentPackages zarfını gösteriyor; tek paketi de kabul edin.
    packages = body["content"] if isinstance(body.get("content"), list) else [body]
    for pkg in packages:
        # tekil anahtar (shipmentPackageId, status, lastModifiedDate), INSERT ... ON CONFLICT DO NOTHING
        save_event_once(pkg["shipmentPackageId"], pkg.get("status"),
                        pkg.get("lastModifiedDate") or 0, json.dumps(pkg))
    return "ok", 200
İşçi bir olayı yalnızca lastModifiedDate değeri elindekinden yeniyse uygular; çünkü yeniden denemeler eski bir statüyü yenisinden sonra getirebilir. Alıcının güvenliği (TLS, sır rotasyonu, tekrar oynatma koruması, denetim izi) Webhook'lar 2026: güvenli alıcı tasarımı, retry ve audit yaklaşımı konusunda, webhook, sorgulama ve ara katman seçimi ise Webhook, API, iPaaS: vendor lock-in olmadan temiz web platform entegrasyonu konusunda anlatılıyor.

İadeler (claims)​

  • İadesi oluşturulan siparişleri çekme (getClaims): claimItemStatus (Created, WaitingInAction, Accepted, Cancelled, Rejected, Unresolved, InAnalysis), lastModifiedDate üzerinde startDate/endDate ya da claimIds ile filtreleyin; yeni iadeler için Created sorgulayın. claimDate GMT'dir, Satıcı Paneli ile eşlemek için üç saat ekleyin.
  • İade onaylama (approveClaimLineItems): PUT .../claims/{claimId}/items/approve ve claimLineItemIdList; yalnızca WaitingInAction statüsünde. Bazı onaylar Accepted'e geçmeden önce WaitingFraudCheck statüsünden geçer.
  • Ret talebi (createClaimIssue): Sebebi GET /integration/order/claim-issue-reasons ile alın, ardından POST .../claims/{claimId}/issue çağrısına claimIssueReasonId, claimItemIdList ve en fazla 500 karakterlik description'ı sorgu parametresi, kanıtları ise multipart dosya (her biri en fazla 5 MB) olarak ekleyin. Dosya, 1651 (iade paketi elime ulaşmadı) gibi birkaç sebep dışında zorunludur; 1651, WaitingInAction'ın ilk 24 saatinde seçilemez.
  • Sebep listesini koda gömmeyin: 8 Ekim 2026'da Trendyol bazı sebepleri (251 ve 1701 dâhil) kaldırdı, 2077, 2078 ve 2079'u ekledi. Listeyi servisten yükleyin.
  • İki işlemi de kuyruğa alın: Onay ve ret talebi servisleri dakikada 5 istekle sınırlı.
İade kodu olmadan gelen paketler için ayrı bir createClaim (iade talebi oluşturma) servisi var.

Müşteri soruları ve finans, kısaca​

Sorular: GET /integration/qna/sellers/{sellerId}/questions/filter?status=WAITING_FOR_ANSWER (tarih vermezseniz son bir hafta, sorgu başına en fazla iki hafta, size en fazla 50). Yanıt POST .../questions/{id}/answers ve {"text": "..."} ile verilir; metin 10-2.000 karakter olmalı ve yayımlanmadan önce yasaklı kelime kontrolünden geçer.

Finans: /integration/finance/che/sellers/{sellerId}/ altındaki Cari Hesap Ekstresi servisleri settlements (satış, iade, indirim, kupon, komisyon düzeltmeleri; transactionType veya transactionTypes zorunlu), otherfinancials (hakediş ödemeleri, virman, faturalar, kesintiler) ve payment-order (ödenmiş ödeme emirleri, sayfa başına 10) verir. En fazla 15 günlük tarih aralığıyla, paymentDate ile ya da bir banka ödemesini kapsadığı siparişlerle eşlemenin anahtarı olan paymentOrderId ile filtreleyin. Kayıtlar teslimattan sonra oluşur; doküman, ödeme emirlerinin istisnalar dışında her çarşamba o hafta vadesi gelen siparişler için oluştuğunu söylüyor. Sınır: dakikada 100 istek.

Test ve canlıya geçiş kontrol listesi​

Test ortamında POST /integration/test/order/orders/core bir test siparişi yaratır (test satıcı ID'si SellerID başlığında, kimlik doğrulama aynı satıcıyla; kurumsal faturalı sipariş için commercial, mikro ihracat için microRegion). PUT /integration/test/order/sellers/{sellerId}/shipment-packages/{packageId}/status ise siparişi Shipped, AtCollectionPoint, Delivered, UnDelivered veya Returned statüsüne yalnızca ileri yönde taşır. Yalnızca stage'de çalışan iki servis daha test iadesini WaitingInAction'a çeker ve müşteri sorusu oluşturur.
  1. Her istekte User-Agent var; anahtarlar sır kasasından geliyor; canlı ve test ayarları karışamıyor.
  2. Yalnızca yaprak kategoriler kullanılıyor; özellik önbellekleri haftalık yenileniyor; her stok kodu barcode, productMainId ve contentId ile eşlenmiş.
  3. Her yazma işlemi batch sonucuna kadar izleniyor; FAILED kalemler bir insana ulaşıyor.
  4. Stok-fiyat gönderimleri delta; 15 dakika içinde aynı gövde gitmiyor; her limit grubu için bir sınırlayıcı var; 429 alındığında bekleme (backoff) uygulanıyor.
  5. Stok tamponu tanımlı; Awaiting siparişler stok ayırıyor ama gönderilmiyor.
  6. Siparişler webhook ve stream mutabakatıyla geliyor; işleme idempotent; yerine yenisi gelen paketler (iptal, bölme) ele alınıyor.
  7. Picking, Invoiced, fatura linki ya da dosyası, etiket ve gönderim stage'de uçtan uca, 409 durumu dâhil denendi.
  8. İadeler dakikada 5 isteğe uyan bir kuyruktan geçiyor; sebepler servisten yükleniyor.
  9. 401, 403, 429 ve 5xx artışlarında, FAILED kalemlerde ve "webhook pasife alındı" e-postasında alarm çalıyor.
  10. Changelog'un ve API durum sayfasının (dokümandaki Api HealthCheck) bir sahibi var.

Sorun giderme​

BelirtiOlası nedenÇözüm
401 ClientApiAuthenticationExceptionYanlış anahtar ya da secret, canlıda test anahtarı (veya tersi), anahtar ve secret yer değiştirmişOrtamı kontrol edin; kullanıcı adı = API Key, parola = API Secret
403User-Agent eksik; hata kodları sayfası yanlış uç nokta ya da parametreyi de sayıyorHer istekte "{sellerId} - SelfIntegration" gönderin; yolu dokümanla karşılaştırın
Yalnızca stage'de 503Çıkış IP'niz yetkilendirilmemiş ya da kaydın süresi dolmuşIPv4 adresini talep ya da whitelist servisiyle ekleyin; expiresAt'i izleyin
Yurt dışındaki sunucudan canlıda zaman aşımıİngilizce dokümanın yurt dışı internet sağlayıcıları için andığı durumIP adresinizle Partner Support üzerinden talep açın
429 too.many.requestsGrup sınırı ya da tek uç noktada 10 saniyede 50 istekGrup başına sınırlayıcı, geri çekilme, daha az ve daha dolu batch
426 ya da "scheduled brownout" mesajıKullanımdan kalkan uç noktalar (Ürün V1, eski /orders)Ürün V2 ve /v2/orders'a geçin
"15 dakika boyunca aynı isteği..."15 dakika içinde aynı stok-fiyat gövdesiDelta gönderin; önceki batch'i doğrulayın
Batch kalemi FAILEDEksik ya da geçersiz özellik, yaprak olmayan kategori, görsel adresi, salePrice'tan düşük listPrice, hatalı barkodfailureReasons'ı okuyun, sözlükleri yenileyin, yeniden gönderin
/v2/orders'ta eksik siparişİki haftalık ya da bir aylık pencerenin dışında veya 10.000 paketin ötesindeStream'i ya da daha dar aralıkları kullanın
Saatler üç saat kaymışorderDate ve sorgu tarihleri GMT+3, packageHistories.createdDate ve claimDate GMT olarak belgelenmişGirişte UTC'ye çevirin; saati bilinen bir stage siparişiyle bir kez doğrulayın
Paket ID'si artık geçersizKısmi iptal ya da bölme paketi değiştirdiorderNumber ile yeniden okuyun; originPackageIds'i izleyin
Fatura linkinde 409Paket zaten faturalı ya da link başka pakette kullanılmışinvoiceStatus'a bakın; her pakete tekil bir link
Webhook pasife düştüArt arda başarısız gönderimlerAlıcıyı düzeltin, .../activate çağırın, aradaki boşluğu stream ile okuyun

Sıkça sorulan sorular​

Trendyol'a bağlanmak için entegratör şart mı?
Hayır. Her satıcı kendi anahtarları ve "SelfIntegration" User-Agent'ıyla API'yi çağırabilir. Yazılım ekibi olmadan birden çok pazaryerinde satıyorsanız entegratör mantıklıdır. Her iki durumda da Trendyol kod desteği vermediğini belirtiyor.

Trendyol test ortamı (sandbox) var mı?
Var: stageapigw.trendyol.com adresindeki stage ortamı; ayrı hesabı, ayrı anahtarları ve IP yetkilendirmesi var. Orada test siparişi yaratabilir, teslimat statülerinde ilerletebilir, test iadesini WaitingInAction'a çekebilir ve müşteri sorusu oluşturabilirsiniz.

Stoğu ne sıklıkla senkronize etmeliyim?
Değişiklikleri oldukları anda küçük delta paketleriyle gönderin, günde bir kez de tam mutabakat yapın. Trendyol sabit bir aralık vermiyor; pratik sınırlar grup istek sınırı, 15 dakika kuralı ve barkod başına dakikada 30 fiyat güncellemesi.

Siparişleri yalnızca webhook ile alabilir miyim?
Önerilmez. Trendyol webhook'un yanında periyodik senkronizasyonu öneriyor ve 2026'da changelog'da kesintiler sonrasında satıcılardan birden fazla kez sipariş aralıklarını yeniden sorgulamalarını istedi.

Trendyol Express etiketleri nasıl alınır?
Trendyol'un ödediği TEX ya da Aras Kargo gönderilerinde createCommonLabel ile ortak etiket isteyip getCommonLabel ile koli başına bir ZPL etiketi indirirsiniz. Kendi kargo anlaşmanızla (whoPays = 1) çalışıyorsanız etiket kargo firmanızdan gelir.

Sonuç ve sonraki adımlar​

Şu sırayla ilerleyin: kimlik bilgileri ve stage erişimi; eşleme tablolarıyla salt okunur sözlükler; batch takibiyle ürün yaratma; delta stok-fiyat senkronizasyonu; stream ile sipariş çekme; statü ve fatura çağrıları; etiket; webhook; en son iade, soru ve finans. Trendyol'u ana veri rolünden uzak tutun, her yazma işlemini doğrulayın ve changelog'a bir sahip atayın. Bağlantıyı şirket içinde yazıp sürdürmek istemiyorsanız AIOR, Trendyol entegrasyonu hizmetini proje olarak sunuyor.

This guide is for developers and in-house teams who build or debug their own Trendyol seller integration instead of buying an integrator's software: connecting an ERP, a warehouse system or a web shop to Trendyol's Marketplace (Partner) API for listings, stock and price, orders, labels, invoices and returns. It follows the official documentation at developers.trendyol.com as of late October 2026. If you are reading older code or blog posts, note two changes: the docs set 15 October 2026 as the end date for the Product V1 endpoints and the old /orders listing endpoint, so new code should use only Product V2 and /v2/orders; and since 14 September 2026 product rate limits are shared per service group and scale with your listing limit. The day-to-day side of marketplace selling is covered in Selling on marketplaces: the operational side; this article stays with the API.

Own integration, integrator or file uploads?​

OptionFits whenWatch out for
Your own integration (User-Agent "{sellerId} - SelfIntegration")An ERP or WMS already owns stock and prices, a developer can maintain the code, and you need workflows packaged tools don't cover (several warehouses, bundles, your own invoicing pipeline)Trendyol states that it does not provide code support; you track API changes yourself
Integrator software (entegratör)Several marketplaces, no developers, a quick startSubscription or usage fees, the integrator's data model, waiting for its update after a Trendyol change
Seller Center bulk tools or XML/Excel feed servicesA small catalogue, few orders, stock that rarely changesManual steps, slow stock updates, oversell risk during campaigns
Building it yourself pays off when the integration is really a connector between systems you already run and order volume makes manual work or per-order fees expensive. The hidden cost is maintenance: in 2026 alone the changelog announced the Product V2 migration, /v2/orders with a 10,000-record window, grouped rate limits, a new origin field, a change to the fast-delivery fields, a paymentMethod field for invoicing, a channel field for Trendyol Luxe and a revised list of return rejection reasons. Someone has to read it and ship those changes on time.

Architecture: one source of truth, queues and idempotency​

Treat Trendyol as a sales channel, never as the master of your data. Content, stock and price live in your ERP, PIM or database; the integration publishes changes outward and pulls orders, returns and settlements inward.
Code:
ERP / WMS / PIM (master data: product, stock, price)
   |  change log or outbox: only rows that changed
   v
queue ---> catalogue worker ---> Product V2 endpoints ---> batchRequestId
      ---> inventory worker ---> price-and-inventory  ---> batchRequestId
           batch tracker: polls batch results, turns FAILED items into tasks

Trendyol webhook ---> receiver (auth check, store raw event, 200 OK) ---> queue
reconciler (orders/stream every few minutes) --------------------------> queue
queue ---> order worker (idempotent on shipmentPackageId + status + lastModifiedDate)
      ---> ERP / WMS: reserve stock, pick, invoice, label, ship
  • Mapping tables. Store your SKU next to barcode (the key for stock, price and orders), stockCode, productMainId (the "model code" that groups variants), contentId, categoryId, brandId, attribute and value IDs, address IDs and carrier codes. Most rejected batches trace back to a stale or missing mapping.
  • One rate limiter per limit group. Product writes, product reads and stock-price updates each share a budget across several endpoints (see below).
  • Idempotent consumers. Webhooks retry, the reconciler re-reads packages and workers crash halfway, so every handler must give the same result when it runs twice.
  • Every write ends in a verification. Product and stock-price calls return a batchRequestId, not a result.
  • Logs without secrets. Keep bodies with their batchRequestId or shipmentPackageId but mask the Authorization header. Order payloads hold names, addresses, phone numbers and sometimes a Turkish ID number, so apply KVKK (Law No. 6698): limited access, encryption at rest, a retention period.
  • UTC inside, conversions at the edge. Timestamps are epoch milliseconds, some documented as GMT+3 and some as GMT.

Sizing the request budget​

Count calls, not records. Assumptions: the lowest listing-limit tier (50,000 products), 20,000 active barcodes, about 3,000 package changes in two weeks and 60 returns awaiting a decision.
JobCallsWhat limits it
Full stock-price push for 20,000 barcodes20 requests of 1,000 itemsInventory & Price Write, 350 per minute at this tier: no constraint
Create 5,000 products5 requests plus batch pollingData quality and approval time
Re-read 14 days of changed packages via the streamAbout 15 requests at size 200Recommended 5 seconds between calls: about 75 seconds
Approve 60 returns, one claim per call60 requests5 per minute: about 12 minutes
Here the bottleneck is the returns queue, not the catalogue. The per-barcode price limit (30 per minute) only bites when a repricer fires on every competitor move.

Authentication, headers and the stage environment​

  • Credentials: seller ID, API key and API secret are in Seller Center under Hesap Bilgilerim > Entegrasyon Bilgileri, visible only to the master (admin) user. The "Entegrasyon Referans Kodu" on the same page is requested in support tickets; keep it as secret as the key.
  • Basic authentication: username = API key, password = API secret. The seller ID goes into the URL path.
  • User-Agent is mandatory: "{sellerId} - SelfIntegration", or "{sellerId} - {IntegratorName}" for an integrator (alphanumeric, at most 30 characters). Requests without it are blocked with 403.
  • Production: https://apigw.trendyol.com, no IP allow-listing (though Trendyol notes an IP can be blocked).
  • Stage: https://stageapigw.trendyol.com with a separate account (panel: stagepartner.trendyol.com) and separate keys. Stage answers only allow-listed IPv4 egress addresses, otherwise 503. Ask through a support ticket (the docs say the IP is defined within 24 hours) or use the IP whitelist API, called on the production gateway with your production seller ID: at most 7 IPv4 addresses, 7 additions per day, each entry with an expiresAt date.
A first call to test credentials and headers:
Bash:
export TY_BASE="https://apigw.trendyol.com"     # stage: https://stageapigw.trendyol.com
export TY_SELLER_ID="123456"                     # placeholder
export TY_API_KEY="..."                          # from a secret store, never from git
export TY_API_SECRET="..."

curl -sS "$TY_BASE/integration/product/sellers/$TY_SELLER_ID/products/approved?page=0&size=1" \
  -u "$TY_API_KEY:$TY_API_SECRET" \
  -H "User-Agent: $TY_SELLER_ID - SelfIntegration" \
  -H "Accept: application/json"
Keep the environments apart in configuration so stage keys never reach production:
YAML:
trendyol:
  prod:
    base_url: https://apigw.trendyol.com
    seller_id: ${TY_PROD_SELLER_ID}
    api_key: ${TY_PROD_API_KEY}
    api_secret: ${TY_PROD_API_SECRET}
  stage:
    base_url: https://stageapigw.trendyol.com
    seller_id: ${TY_STAGE_SELLER_ID}    # the stage account differs from prod
    api_key: ${TY_STAGE_API_KEY}
    api_secret: ${TY_STAGE_API_SECRET}
  integrator_name: SelfIntegration       # User-Agent: "{seller_id} - SelfIntegration"
  limits_per_minute: { product_read: 1000, product_write: 200, inventory_price_write: 350, order_list: 30, claim_approve: 5 }   # lowest tier

Rate limits since 14 September 2026​

The Service Limitations page ties limits to your listing-limit tier (50,000, 75,000, 150,000 or 500,000 products, or unlimited):
GroupIncludesRequests per minute, lowest to unlimited tier
Product Integration ReadProduct filters, batch result, brands, categories, attributes, values, addresses, update audits1,000 to 2,000
Product Integration WriteCreate, update, delete, archive, unlock, brand creation, buybox check200 to 600
Inventory & Price WriteStock and price update350 to 2,000
Order packagesgetShipmentPackages30 to 100
ClaimsApprove; create claim issue5 each
Price updates for one barcode are also capped at 30 per minute (the excess fails in the batch result), and the authorization page states a general limit of 50 requests per 10 seconds to the same endpoint, answered with 429 "too.many.requests". Check your own tier before sizing workers; these are the figures documented in October 2026.

Endpoint map​

Paths hang off the environment's base URL.
Task (service name in the docs)Method and path
Category tree (getCategoryTree)GET /integration/product/product-categories
Category attributes v2, attribute values v2GET /integration/product/categories/{categoryId}/attributes, .../attributes/{attributeId}/values
Brands, brand creationGET /integration/product/brands, POST /integration/product/sellers/{sellerId}/brands
Shipment and return addressesGET /integration/sellers/{sellerId}/addresses
Create products v2POST /integration/product/sellers/{sellerId}/v2/products
Batch result (getBatchRequestResult)GET /integration/product/sellers/{sellerId}/products/batch-requests/{batchRequestId}
Approved and unapproved products v2GET .../sellers/{sellerId}/products/approved, .../products/unapproved
Stock and price (updatePriceAndInventory)POST /integration/inventory/sellers/{sellerId}/products/price-and-inventory
Order packages (getShipmentPackages)GET /integration/order/sellers/{sellerId}/v2/orders
Order stream (getShipmentPackagesStream)GET /integration/order/sellers/{sellerId}/orders/stream
Picking and Invoiced (updatePackage)PUT /integration/order/sellers/{sellerId}/shipment-packages/{packageId}
Invoice link, invoice filePOST /integration/sellers/{sellerId}/seller-invoice-links, .../seller-invoice-file
Common label (createCommonLabel, getCommonLabel)POST, GET /integration/sellers/{sellerId}/common-label/{cargoTrackingNumber}
Webhooks/integration/webhook/sellers/{sellerId}/webhooks
Claims (getClaims)GET /integration/order/sellers/{sellerId}/claims

Catalogue: categories, attributes and product creation​

Product creation (createProducts in V1, now Product V2) is asynchronous and unforgiving about reference data such as categories, attributes and brands, so build the lookups first:
  1. Categories: only leaf categories accept products. The docs recommend refreshing the tree and the attributes weekly.
  2. Attributes: per category you get required, allowCustom (send free text in customAttributeValue instead of an ID), allowMultipleAttributeValues, slicer (a separate product card, typically colour) and varianter (a variant on the same card, typically size; one per category).
  3. Values, brands, addresses: page through the values service (size up to 1,000), resolve brandId from the brand list or create the brand, and take shipmentAddressId and returningAddressId from the addresses service.
A create request takes up to 1,000 items. Variants share productMainId and differ in barcode, stockCode and the varianter or slicer value. All IDs below are placeholders:
JSON:
{
  "items": [
    {
      "barcode": "DEMO-USBC-1M-BLK",
      "title": "USB-C - USB-C Şarj Kablosu 1 m 60 W Siyah",
      "productMainId": "DEMO-USBC-1M",
      "brandId": 1234567,
      "categoryId": 7654,
      "quantity": 40,
      "stockCode": "USBC-1M-BLK",
      "dimensionalWeight": 1,
      "description": "Örgü kaplı USB-C kablo, 1 m, 60 W şarj desteği.",
      "listPrice": 299.90,
      "salePrice": 249.90,
      "vatRate": 20,
      "images": [{ "url": "https://cdn.example.com/usbc-1m-blk-1.jpg" }],
      "attributes": [
        { "attributeId": 47, "customAttributeValue": "Siyah" },
        { "attributeId": 1111, "attributeValueId": 22222 }
      ],
      "shipmentAddressId": 111,
      "returningAddressId": 222
    }
  ]
}
Validate before sending: barcode up to 40 characters with ".", "-" and "_" as the only special characters (inner spaces are removed, and stock-price calls must use the stored form); title up to 100; productMainId up to 40; description up to 30,000, HTML allowed; https image URLs, at most 8 per barcode, documented at 1200×1800 px and 96 dpi; listPrice not below salePrice; vatRate an integer rate (the docs show 0, 1, 10 and 20). Fast delivery is set with deliveryOption.deliveryDuration: 0 for "Bugün Kargoda" (ships today), 1 for "En Geç Yarın Kargoda" (ships by tomorrow); fastDeliveryType has been ignored since August 2026. A new optional origin field (two-letter country code) exists, but after an October 2026 announcement the origin (Menşei) value must still go under attributes wherever the category requires it.

Polling the batch result​

The create response is just a batchRequestId, and Trendyol's FAQ is explicit that getting one does not mean success. Poll until the batch is COMPLETED; stock-price batches have no batch-level status, so check that every item is SUCCESS or FAILED. Results remain available for 4 hours.
Python:
import time
import requests

def make_session(seller_id, api_key, api_secret):
    s = requests.Session()
    s.auth = (api_key, api_secret)
    s.headers.update({"User-Agent": f"{seller_id} - SelfIntegration",
                      "Accept": "application/json"})
    return s

def wait_for_batch(s, base, seller_id, batch_id, timeout_s=1800):
    url = f"{base}/integration/product/sellers/{seller_id}/products/batch-requests/{batch_id}"
    delay, deadline = 5, time.monotonic() + timeout_s
    while time.monotonic() < deadline:
        r = s.get(url, timeout=30)
        if r.status_code != 429:
            r.raise_for_status()
            body = r.json()
            items = body.get("items") or []
            done = body.get("status") == "COMPLETED" or (
                items and all(it.get("status") in ("SUCCESS", "FAILED") for it in items))
            if done:
                return [(it.get("requestItem", {}).get("barcode"), it.get("status"),
                         it.get("failureReasons", [])) for it in items]
        time.sleep(delay)
        delay = min(delay * 2, 120)
    raise TimeoutError(f"batch {batch_id} still in progress")

Approval, updates, archive and delete​

  • Successful items enter content approval. The unapproved filter shows pendingApproval or rejected; fix a rejected item and resubmit it with unapproved-bulk-update. Approved products carry onSale, notOnSale, archived, locked or blacklisted. Paging stops at page × size = 10,000; beyond that, pass the returned nextPageToken.
  • Approved products are changed through content-bulk-update, variant-bulk-update (stockCode, VAT rate, addresses, desi) and delivery-info-bulk-update. Barcode, productMainId, brandId, categoryId and slicer or varianter values are fixed. Two traps: changing one attribute means sending all of them, and a field sent as null is deleted. The review outcome per contentId comes from update-audits.
  • Archiving (archive-state) hides a product without deleting it. Only products awaiting approval, or approved ones archived for more than a day and not stopped by Trendyol, can be deleted. Products locked because the price looked too low or too high, after a critical price error or after unsupplied orders can be unlocked once the cause is fixed.
Create items typically fail on a non-leaf categoryId, a missing required attribute, a value ID from another category, free text where allowCustom is false, a non-https image, listPrice below salePrice or a barcode with disallowed characters. Stale lookups cause most of the rest.

Stock and price sync (updatePriceAndInventory)​

POST /integration/inventory/sellers/{sellerId}/products/price-and-inventory takes up to 1,000 barcodes, and an item may carry only quantity or only prices. quantity is sellable stock: Trendyol lowers it as orders arrive and replaces it with your next value, capped in the docs at 20,000 units per product. listPrice is the crossed-out price, salePrice the selling price.
JSON:
{
  "items": [
    { "barcode": "DEMO-USBC-1M-BLK", "quantity": 37, "listPrice": 299.90, "salePrice": 249.90 },
    { "barcode": "DEMO-USBC-1M-WHT", "quantity": 0 },
    { "barcode": "DEMO-USBC-2M-BLK", "listPrice": 329.90, "salePrice": 289.90 }
  ]
}
  • Send deltas. An identical body within 15 minutes is refused with "15 dakika boyunca aynı isteği tekrarlı olarak atamazsınız!" ("you cannot send the same request repeatedly for 15 minutes"). Send only barcodes changed since the last accepted push.
  • Coalesce prices. Above 30 price updates per minute for one barcode, items fail; keep only the latest price per cycle.
  • Back off on 429 and 5xx with exponential delays and jitter, and cap the attempts. Other 4xx responses are data problems: fix, don't retry.
  • After a timeout, verify before resending. An identical resend may hit the 15-minute rule, which itself shows the first request arrived. Check the batch result or the inventory-and-price filter instead.
  • Reconcile daily with the approved inventory-and-price filter (size up to 100, then nextPageToken past 10,000) and push the differences.
Python:
import hashlib, json, random, time

def push_deltas(s, base, seller_id, changes, recently_sent):
    """changes: dicts with barcode plus quantity and/or prices.
    recently_sent: digest -> unix time, persisted between runs."""
    url = f"{base}/integration/inventory/sellers/{seller_id}/products/price-and-inventory"
    batch_ids = []
    for start in range(0, len(changes), 1000):
        body = {"items": changes[start:start + 1000]}
        digest = hashlib.sha256(json.dumps(body, sort_keys=True).encode()).hexdigest()
        if time.time() - recently_sent.get(digest, 0) < 15 * 60:
            continue                     # identical body accepted less than 15 min ago
        for attempt in range(6):
            r = s.post(url, json=body, timeout=30)
            if r.status_code == 429 or r.status_code >= 500:
                time.sleep(min(60, 2 ** attempt) + random.random())
                continue
            r.raise_for_status()         # other 4xx: fix the data, don't retry
            batch_ids.append(r.json()["batchRequestId"])
            recently_sent[digest] = time.time()
            break
    return batch_ids
Stock buffer. Publish less than you hold: published = max(0, on hand − reserved − buffer). Orders in Awaiting (payment still being checked) should already reserve stock; the docs say to use that status only for stock and not to ship before Created. A practical starting buffer is the barcode's peak sales per minute times your worst-case end-to-end sync delay in minutes, rounded up, with more headroom when the same units sell on other channels; review it after each campaign. Commission and margin maths belong in pricing logic, not in the sync worker (each order line does report its commission rate).

Orders: listing, statuses, packages, invoices and labels​

Aspect/v2/orders (getShipmentPackages)/orders/stream (getShipmentPackagesStream)
Use forTargeted lookups: an orderNumber, package IDs, a status, a recent windowPeriodic sync, catching up after downtime, exports
Pagingpage and size (max 200); at most 10,000 packages per query (pages 0 to 49 at size 200)Opaque nextCursor and hasMore; changing the filter mid-cursor returns 400
Time windowLast week by default, at most two weeks per query, data from the last monthAt most 14 days per query on lastModifiedStartDate/EndDate, data from the last 3 months
Order and pacingorderByField=PackageLastModifiedDate, ASC or DESC; 30 to 100 requests per minute by tierFixed lastModifiedDate descending; at least 5 seconds between requests recommended
A reconciler that walks the stream:
Python:
def changed_packages(s, base, seller_id, since_ms, until_ms):
    url = f"{base}/integration/order/sellers/{seller_id}/orders/stream"
    params = {"lastModifiedStartDate": since_ms, "lastModifiedEndDate": until_ms, "size": 200}
    while True:
        r = s.get(url, params=params, timeout=60)
        if r.status_code == 429:
            time.sleep(30)
            continue
        r.raise_for_status()
        page = r.json()
        yield from page.get("content", [])
        if not page.get("hasMore"):
            return
        params["nextCursor"] = page["nextCursor"]   # opaque: pass it back unchanged
        time.sleep(5)
Run it every few minutes, starting each window a few minutes before the previous one ended, and let the idempotent worker skip what it has already applied.

Package statusMeaning and action
Awaiting, VerifiedPayment check in progress: reserve stock, nothing else until Created
CreatedReady to ship: start fulfilment
Picking, InvoicedSent by you, in that order
Shipped, AtCollectionPointWith the carrier, or waiting at a pick-up point
DeliveredFinal
UnDelivered, ReturnedDelivery failed; Returned (final) means it came back to you
Cancelled, UnSuppliedCancelled, including unsupplied: release the reservation
UnPackedSplit; new packages replace it
The unit of work is the shipment package (shipmentPackageId), not the order. A partial cancellation or a split creates packages with new IDs and new tracking numbers under the same orderNumber; createdBy shows cancel or split, and originPackageIds points to the original. Model one orderNumber with many packages and never assume a package ID lives as long as the order. Also map lines[].lineId (needed for every status call), channelId (1 core storefront, 25 Trendyol Luxe), commercial with the company, tax number, tax office and eInvoiceAvailable in invoiceAddress, paymentMethod (added in September 2026 for invoicing), identityNumber (sent for gold, fertiliser and orders above 5,000 TL) and micro for micro export. customerEmail is a masked address generated per order; recognise returning customers by customerId.

Picking, Invoiced, unsupplied and split​

Status updates go to PUT /integration/order/sellers/{sellerId}/shipment-packages/{packageId}, Picking first, then Invoiced:
JSON:
{
  "lines": [{ "lineId": 4765111111, "quantity": 1 }],
  "params": { "invoiceNumber": "ABC2026000000123" },
  "status": "Invoiced"
}
Picking uses the same body with "status": "Picking" and empty params. Lines you cannot ship go to PUT .../shipment-packages/{packageId}/items/unsupplied with a reasonId (500 out of stock, 501 defective, 502 wrong price, 504 integration error, 505 bulk purchase, 506 force majeure): a full cancellation sets the package to Cancelled, a partial one moves the remaining lines to a new package. To ship in several boxes, use split, multi-split, quantity-split or split-packages; the original package becomes UnPacked and the new ones appear asynchronously, so fetch them again before printing labels.

Invoices​

The invoice comes from your e-Fatura or e-Arşiv provider; Trendyol then needs the PDF e-mailed to the order's masked address or one of two calls:
  • Invoice link (sendInvoiceLink): POST .../seller-invoice-links with invoiceLink, shipmentPackageId, invoiceDateTime (10-digit seconds or 13-digit milliseconds) and invoiceNumber, answered with 201. Number and date are mandatory for micro-export and Trendyol Yurt Dışı Aracılığı packages, and the number follows the 16-character pattern of three alphanumerics, a year and nine digits. The docs require the link to stay reachable for 10 years. A 409 means the package already has an invoice or the link was used for another package.
  • Invoice file: POST .../seller-invoice-file as multipart form data with shipmentPackageId and file (PDF, JPEG or PNG, up to 10 MB, not future-dated).

Labels and carriers​

For Trendyol-paid shipments with Trendyol Express (TEX) or Aras Kargo, request a common label with POST .../common-label/{cargoTrackingNumber} and a body such as {"format": "ZPL", "boxQuantity": 2}, then GET the same path for one ZPL label per box, ideally after Picking or Invoiced. ZPL is the only format, so you need a thermal printer that speaks it. When the order has whoPays = 1, the shipment runs on your own carrier agreement and the label comes from that carrier. cargoTrackingNumber is the CODE128 barcode used on Seller Center labels. PUT .../shipment-packages/{packageId}/cargo-providers with a code such as YKMP, ARASMP or TEXMP switches carrier, once per package every 5 minutes; a switch to TEX fails when your TEX quota is full.

Webhooks for order packages​

A webhook pushes the full package, in the getShipmentPackages model, whenever it reaches a subscribed status: CREATED, PICKING, INVOICED, SHIPPED, CANCELLED, DELIVERED, UNDELIVERED, RETURNED, UNSUPPLIED, AWAITING, UNPACKED, AT_COLLECTION_POINT or VERIFIED.
  • Create: POST /integration/webhook/sellers/{sellerId}/webhooks with url, authenticationType (BASIC_AUTHENTICATION with username and password, or API_KEY with apiKey, delivered in the x-api-key header) and subscribedStatuses; an empty list means every status, including future ones. GET lists them; PUT or DELETE .../webhooks/{id} updates or removes one; .../activate and .../deactivate switch it.
  • Limits: 15 webhooks per seller, passive ones included; the URL must not contain "Trendyol", "Dolap" or "localhost".
  • Retries: failed deliveries are retried every 5 minutes until they succeed (the docs say this will change). After repeated failures (13, per the FAQ) the webhook turns passive and two e-mails go out; fix the receiver and reactivate it.
Keep polling anyway. Trendyol recommends periodic syncing alongside webhooks, and its changelog lists incidents in September and October 2026 when orders from a time window were missing from responses or webhooks; for those on 2 and 8 September, sellers were asked to re-query the window. Webhooks give speed, the stream reconciler completeness.
Python:
import hmac, json, os
from flask import Flask, request, abort

app = Flask(__name__)
WEBHOOK_KEY = os.environ["TY_WEBHOOK_KEY"]      # the apiKey you registered

@app.post("/hooks/trendyol/packages")
def trendyol_packages():
    if not hmac.compare_digest(request.headers.get("x-api-key", ""), WEBHOOK_KEY):
        abort(401)
    body = request.get_json(silent=True) or {}
    # The docs show the paged getShipmentPackages envelope; accept a bare package too.
    packages = body["content"] if isinstance(body.get("content"), list) else [body]
    for pkg in packages:
        # unique key (shipmentPackageId, status, lastModifiedDate), INSERT ... ON CONFLICT DO NOTHING
        save_event_once(pkg["shipmentPackageId"], pkg.get("status"),
                        pkg.get("lastModifiedDate") or 0, json.dumps(pkg))
    return "ok", 200
The worker applies an event only if its lastModifiedDate is newer than what it holds, because retries can deliver an older status after a newer one. Receiver hardening (TLS, secret rotation, replay protection, audit) is covered in Webhooks 2026: secure receiver design, retry and audit, and webhooks versus polling and middleware in Webhooks, APIs, iPaaS: integrating web platforms cleanly.

Returns (claims)​

  • List (getClaims): filter by claimItemStatus (Created, WaitingInAction, Accepted, Cancelled, Rejected, Unresolved, InAnalysis), by startDate/endDate on lastModifiedDate, or by claimIds; query Created for new claims. claimDate is GMT, three hours behind Seller Center.
  • Approve (approveClaimLineItems): PUT .../claims/{claimId}/items/approve with claimLineItemIdList, only in WaitingInAction. Some approvals pass through WaitingFraudCheck before Accepted.
  • Reject (createClaimIssue): take a reason from GET /integration/order/claim-issue-reasons, then POST .../claims/{claimId}/issue with claimIssueReasonId, claimItemIdList and a description (up to 500 characters) as query parameters and evidence as multipart files (5 MB each). Files are mandatory except for a few reasons such as 1651 (parcel never arrived), which is blocked in the first 24 hours of WaitingInAction.
  • Load reasons, don't hard-code them: on 8 October 2026 Trendyol retired several (251 and 1701 among them) and added 2077, 2078 and 2079.
  • Queue both actions: approve and issue allow 5 requests per minute each.
Parcels returned without a return code have a separate createClaim endpoint.

Customer questions and finance, briefly​

Questions: GET /integration/qna/sellers/{sellerId}/questions/filter?status=WAITING_FOR_ANSWER (last week by default, two weeks at most per query, size up to 50); answer with POST .../questions/{id}/answers and {"text": "..."} of 10 to 2,000 characters, checked for banned words before publication.

Finance: under /integration/finance/che/sellers/{sellerId}/ you get settlements (sales, returns, discounts, coupons, commission corrections; transactionType or transactionTypes required), otherfinancials (payments, transfers, invoices, deductions) and payment-order (paid payment orders, 10 per page). Filter by a date range of at most 15 days, by paymentDate, or by paymentOrderId, the key for matching a bank payment to its orders. Records appear after delivery; the docs say payment orders are created every Wednesday, with exceptions, for orders due that week. Limit: 100 requests per minute.

Testing and go-live checklist​

On stage, POST /integration/test/order/orders/core creates a test order (stage seller ID in a SellerID header, authenticated as that seller; commercial for a corporate invoice, microRegion for micro export), and PUT /integration/test/order/sellers/{sellerId}/shipment-packages/{packageId}/status moves it through Shipped, AtCollectionPoint, Delivered, UnDelivered or Returned, forward only. Two more stage-only services move a test claim to WaitingInAction and create a customer question.
  1. User-Agent on every request; keys from a secret store; prod and stage settings cannot mix.
  2. Leaf categories only; attribute caches refreshed weekly; every SKU mapped to barcode, productMainId and contentId.
  3. Every write tracked to its batch result; FAILED items reach a person.
  4. Delta stock-price pushes, no identical body within 15 minutes, one limiter per group, backoff on 429.
  5. Stock buffer defined; Awaiting orders reserve stock but are not shipped.
  6. Orders by webhook plus stream reconciliation; idempotent processing; replaced packages handled.
  7. Picking, Invoiced, invoice link or file, label and shipment tested end to end on stage, including a 409.
  8. Claims queued at 5 requests per minute, reasons loaded from the service.
  9. Alerts on bursts of 401, 403, 429 and 5xx, on FAILED items and on the "webhook deactivated" e-mail.
  10. An owner for the changelog and the API status page (Api HealthCheck in the docs).

Troubleshooting​

SymptomLikely causeFix
401 ClientApiAuthenticationExceptionWrong key or secret, stage keys against prod (or the reverse), key and secret swappedCheck the environment; username = key, password = secret
403Missing User-Agent; the error-code page also cites a wrong endpoint or parameterSend "{sellerId} - SelfIntegration" everywhere; compare the path with the docs
503 on stage onlyEgress IP not allow-listed, or its entry expiredAdd the IPv4 by ticket or whitelist API; watch expiresAt
Prod timeouts from a server abroadCase named in the English docs for providers outside TurkeyOpen a Partner Support ticket with your IP
429 too.many.requestsGroup limit, or 50 requests per 10 seconds on one endpointPer-group limiter, backoff, fewer and fuller batches
426 or "scheduled brownout"Retired endpoints (Product V1, old /orders)Migrate to Product V2 and /v2/orders
"15 dakika boyunca aynı isteği..."Identical stock-price body within 15 minutesSend deltas; verify the earlier batch
Batch item FAILEDAttribute missing or invalid, non-leaf category, image URL, listPrice below salePrice, bad barcodeRead failureReasons, refresh lookups, resubmit
Orders missing from /v2/ordersOutside the two-week or one-month window, or past 10,000 packagesUse the stream or narrower windows
Times three hours offorderDate and query dates documented as GMT+3; packageHistories.createdDate and claimDate as GMTNormalise to UTC on input; check once with a stage order of known time
Package ID no longer validA partial cancellation or split replaced itRe-read by orderNumber; follow originPackageIds
409 on the invoice linkAlready invoiced, or the link was used elsewhereCheck invoiceStatus; one unique link per package
Webhook passiveRepeated delivery failuresFix the receiver, call .../activate, re-read the gap via the stream

FAQ​

Do I need an integrator to connect to Trendyol?
No. Any seller can call the API with its own keys and the "SelfIntegration" User-Agent. An integrator makes sense across several marketplaces without in-house developers. Either way, Trendyol states that it does not provide code support.

Is there a sandbox?
Yes: stage, at stageapigw.trendyol.com, with its own account, keys and IP allow-listing. You can create test orders, move them through delivery statuses, push test claims to WaitingInAction and create customer questions there.

How often should I sync stock?
Push changes as they happen in small delta batches and reconcile fully once a day. Trendyol publishes no fixed interval; the practical limits are the group rate limit, the 15-minute duplicate rule and 30 price updates per minute per barcode.

Can I receive orders by webhook only?
Not advisable. Trendyol recommends periodic syncing alongside webhooks, and in 2026 its changelog asked sellers more than once to re-query order windows after incidents.

How do Trendyol Express labels work?
For TEX or Aras Kargo shipments paid by Trendyol, request a common label with createCommonLabel and download the ZPL with getCommonLabel, one label per box. With your own carrier agreement (whoPays = 1), the label comes from your carrier.

Conclusion and next steps​

Build in this order: credentials and stage access; read-only lookups with mapping tables; product creation with batch tracking; delta stock-price sync; order pulling via the stream; status and invoice calls; labels; webhooks; then claims, questions and finance. Keep Trendyol out of the master-data role, verify every write and give the changelog an owner. If you would rather not build and maintain the connector in house, AIOR offers Trendyol integration as a project service.
 
Last edited:

Forum statistics

Threads
925
Messages
932
Members
26
Latest member
Jessicawatson

Members online

No members online now.

Featured content

AIOR
AIOR TECHNOLOGY

Get a quote for all your needs

Hosting · Domain · Servers · Design · Software · Engineering · Industry Solutions

Get a quote

24/7 Support · Quick response

Back
Top