Trendyol ve Hepsiburada API Entegrasyonu: Next.js ile Ürün Yönetim Paneli
Trendyol Seller API ve Hepsiburada Merchant API'yi Next.js App Router ile entegre edin. Basic Auth, batchRequestId async onay döngüsü, webhook + polling stratejisi ve Vercel Cron kısıtları.

Önemli Not: Bu yazıdaki teknik bilgiler yazım tarihi itibarıyla geçerlidir. Kullanılan kütüphaneler, API'ler ve servisler zaman içinde değişebilir. Ücretlendirme, yasal düzenleme ve vergi konularında ilgili resmi kaynakları ve uzmanları referans alınız. Bu içerik bilgilendirme amaçlı olup herhangi bir finansal veya hukuki tavsiye niteliği taşımamaktadır.
Türkiye'de bir KOBİ için yazılım geliştiriyorsanız, er ya da geç Trendyol veya Hepsiburada API'siyle yüzleşmek zorunda kalırsınız. Resmi dokümantasyonlar var; ama "Next.js App Router ile nasıl entegre ederim, async ürün onay sürecini nasıl yönetirim, Vercel'de cron job kısıtlarını nasıl aşarım?" sorularının yanıtları dağınık ve eksik.
Bu rehberde sıfırdan bir Ürün Yönetim Paneli mimarisi kuruyoruz. Trendyol ve Hepsiburada API kimlik doğrulaması, webhook + polling stratejisi, batchRequestId ile async ürün onayı döngüsü ve Vercel Cron kısıtlarını detaylıca ele alacağız.
Türkiye E-Ticaret Ekosistemi: Hangi Platformlar Önemli?
2024 verileri Türkiye e-ticaret pazarının yaklaşık 3 trilyon TL GMV'ye ulaştığını gösteriyor (Ticaret Bakanlığı, "E-Ticaretin Görünümü 2025" raporu). 2024 yılında gerçekleşen işlem sayısı 5,91 milyar.
Aktif marketplace'ler (2026):
- Trendyol — pazar lideri, yaklaşık %36 pay
- Hepsiburada — ikinci büyük
- N11 — düşük trafikle faaliyette (Hâlâ açık, 2025'te DMSF Holding'e geçti)
- Çiçeksepeti, Sahibinden (ilan), Letgo (ilan) — niş segmentler
GittiGidiyor hakkında: Platform tamamen kapandı. Yeni listeleme 20 Haziran 2022'de, son alışveriş 18 Temmuz 2022'de sona erdi. Devam eden API yoktur.
N11 hakkında: Amazon N11'i satın almadı — bu yaygın bir yanlış bilgi. Sahiplik zinciri: Doğuş Grubu + SK Planet → Getir kurucusu Nazım Salur (2023) → Borancılı Teknoloji (2024) → DMSF Holding (Abu Dhabi, 2025). API hâlâ erişilebilir, ancak DMSF sonrası developer portal değişiklikleri için güncel dokümantasyonu kontrol edin.
Hedef kitlemiz açısından Trendyol ve Hepsiburada öncelikli entegrasyon noktaları. Bu iki platform için custom bir yönetim paneli kuracağız.
Ne İnşa Ediyoruz?
Ürün Yönetim Paneli — bir KOBİ'nin kendi ürünlerini hem Trendyol hem Hepsiburada'da yönetebileceği basit bir Next.js uygulaması:
- Ürün listesi ve stok görüntüleme
- Trendyol'a ürün gönderme + onay durumu takibi
- Hepsiburada sipariş bildirimleri (webhook)
- Otomatik stok senkronizasyonu (cron job)
Tech stack: Next.js 16 App Router, TypeScript, Drizzle ORM, Bun
Trendyol Seller API
Erişim Alma
Trendyol API erişimi için önce satıcı hesabı açmanız, ardından entegrasyon başvurusunu Seller Panel üzerinden yapmanız gerekiyor. Onay sürecini resmi developers.trendyol.com adresinden takip edin.
Kimlik Doğrulama
Trendyol, HTTP Basic Auth kullanır. Seller Panel → Hesap Bilgilerim → Entegrasyon Bilgileri bölümünden üç credential alırsınız:
supplierId(a.k.a.sellerId)apiKeyapiSecret
Authorization header'ı: Basic Base64(apiKey:apiSecret)
Kritik nokta — User-Agent zorunlu: Trendyol, her istekte özel bir User-Agent header'ı bekler. Bu header olmadan istekler reddedilir:
User-Agent: "<supplierId> - SelfIntegration"
Base URL'ler
Production: https://apigw.trendyol.com
Stage: https://stageapigw.trendyol.com
Önemli: Production ve Stage credential'ları tamamen ayrıdır. Stage ortamı için Trendyol ekibinden ayrıca credential almanız gerekiyor. Ayrıca Stage ortamı IP whitelist zorunlu tutuyor — sunucunuzun IP adresini Trendyol'a bildirmeniz gerekiyor.
TypeScript API Client
Ortam değişkenlerini ve API client'ı ayarlayalım:
// lib/marketplace/trendyol-client.ts
const TRENDYOL_BASE_URL = process.env.TRENDYOL_STAGE === "true"
? "https://stageapigw.trendyol.com"
: "https://apigw.trendyol.com"
interface TrendyolConfig {
supplierId: string
apiKey: string
apiSecret: string
}
function getTrendyolHeaders(config: TrendyolConfig): HeadersInit {
const credentials = Buffer.from(`${config.apiKey}:${config.apiSecret}`).toString("base64")
return {
"Authorization": `Basic ${credentials}`,
"User-Agent": `${config.supplierId} - SelfIntegration`,
"Content-Type": "application/json",
}
}
export async function trendyolFetch<T>(
path: string,
options: RequestInit = {},
): Promise<T> {
const config: TrendyolConfig = {
supplierId: process.env.TRENDYOL_SUPPLIER_ID!,
apiKey: process.env.TRENDYOL_API_KEY!,
apiSecret: process.env.TRENDYOL_API_SECRET!,
}
const url = `${TRENDYOL_BASE_URL}${path}`
const response = await fetch(url, {
...options,
headers: {
...getTrendyolHeaders(config),
...options.headers,
},
})
if (!response.ok) {
const errorText = await response.text()
throw new Error(`Trendyol API error ${response.status}: ${errorText}`)
}
return response.json() as Promise<T>
}
Temel Endpoint'ler
| İşlem | Method | Path |
|---|---|---|
| Ürün oluştur | POST | /integration/product/sellers/{supplierId}/products |
| Ürün güncelle | PUT | /integration/product/sellers/{supplierId}/products |
| Fiyat + stok güncelle | PUT | /integration/product/sellers/{supplierId}/products/price-and-inventory |
| Batch sonucu kontrol | GET | /integration/product/sellers/{supplierId}/batch-requests/{batchRequestId} |
| Siparişleri çek | GET | /integration/order/sellers/{supplierId}/orders |
| Kargo takibi güncelle | PUT | /integration/order/sellers/{supplierId}/shipment-packages/{packageId}/tracking |
| Tedarikçi adresleri | GET | /integration/sellers/{supplierId}/addresses |
Rate Limit
Güncel rate limit bilgisi için resmi dokümantasyonu kontrol edin — bu değerler değişebilir. Araştırma bulguları endpoint başına 50 istek / 10 saniye düzeyine işaret ediyor, ancak bu bilgiyi developers.trendyol.com üzerinden doğrulayın.
Async Ürün Onayı: batchRequestId Döngüsü
Trendyol'un en kritik mimarisi burada. Ürün oluşturma veya güncelleme işlemleri anlık değildir. Trendyol, her ürün yazma çağrısına bir batchRequestId (UUID format) döner. Ürün, Trendyol moderasyonundan geçtikten sonra yayına alınır.
Bu asenkron döngüyü naif bir şekilde ele alırsanız (örneğin bir while döngüsüyle sürekli poll etmek), Vercel'in serverless timeout kısıtlarına çarpar veya rate limit'e takılırsınız.
batchRequestId ile Stok Güncelleme Route Handler
// app/api/trendyol/products/route.ts
import { NextResponse } from "next/server"
import { db } from "@/lib/db"
import { productBatches } from "@/lib/db/schema"
import { trendyolFetch } from "@/lib/marketplace/trendyol-client"
interface PriceInventoryItem {
barcode: string
quantity: number
salePrice: number
listPrice: number
}
interface TrendyolBatchResponse {
batchRequestId: string
}
export async function PUT(request: Request) {
const supplierId = process.env.TRENDYOL_SUPPLIER_ID!
const items: PriceInventoryItem[] = await request.json()
// Trendyol'a fiyat + stok güncellemesi gönder
const result = await trendyolFetch<TrendyolBatchResponse>(
`/integration/product/sellers/${supplierId}/products/price-and-inventory`,
{
method: "PUT",
body: JSON.stringify({ items }),
},
)
// batchRequestId'yi DB'ye kaydet
await db.insert(productBatches).values({
batchRequestId: result.batchRequestId,
status: "PENDING",
itemCount: items.length,
createdAt: new Date(),
})
// Async işlem başlatıldı — hemen yanıt dön
return NextResponse.json({
batchRequestId: result.batchRequestId,
message: "Güncelleme kuyruğa alındı. Onay durumu takip edilecek.",
})
}
Drizzle ORM ile Batch Takip Şeması
// lib/db/schema/product-batches.ts
import { pgTable, text, integer, timestamp } from "drizzle-orm/pg-core"
export const productBatches = pgTable("product_batches", {
id: text("id").primaryKey().default("gen_random_uuid()"),
batchRequestId: text("batch_request_id").notNull().unique(),
platform: text("platform").notNull().default("trendyol"), // "trendyol" | "hepsiburada"
status: text("status").notNull().default("PENDING"), // PENDING | IN_PROGRESS | COMPLETED | FAILED
itemCount: integer("item_count"),
errorDetails: text("error_details"),
createdAt: timestamp("created_at").notNull().defaultNow(),
resolvedAt: timestamp("resolved_at"),
})
Batch Durumu Poll Endpoint'i
// app/api/trendyol/batches/[batchRequestId]/route.ts
import { NextResponse } from "next/server"
import { db } from "@/lib/db"
import { productBatches } from "@/lib/db/schema"
import { trendyolFetch } from "@/lib/marketplace/trendyol-client"
import { eq } from "drizzle-orm"
interface BatchResult {
batchRequestId: string
status: "COMPLETED" | "FAILED" | "IN_PROGRESS"
items: Array<{
requestItem: { barcode: string }
status: "SUCCESS" | "ERROR"
failureReasons?: Array<{ code: string; message: string }>
}>
}
export async function GET(
_request: Request,
{ params }: { params: Promise<{ batchRequestId: string }> },
) {
const { batchRequestId } = await params
const supplierId = process.env.TRENDYOL_SUPPLIER_ID!
const result = await trendyolFetch<BatchResult>(
`/integration/product/sellers/${supplierId}/batch-requests/${batchRequestId}`,
)
// DB'deki kaydı güncelle
await db
.update(productBatches)
.set({
status: result.status,
resolvedAt: result.status !== "IN_PROGRESS" ? new Date() : null,
errorDetails: result.status === "FAILED"
? JSON.stringify(result.items.filter((i) => i.status === "ERROR"))
: null,
})
.where(eq(productBatches.batchRequestId, batchRequestId))
return NextResponse.json(result)
}
Inngest veya QStash ile Durable Execution
Batch durumunu her istekte veya naif bir setTimeout ile poll etmek serverless ortamda mümkün değil. İki sağlam çözüm var:
Seçenek A: Inngest (Karmaşık Step Function)
Inngest, Vercel ile native entegrasyona sahip. Trendyol'un 5-30 dakika sürebilen async onay beklemesini durable execution ile yönetmek için idealdir.
// inngest/functions/trendyol-batch-poll.ts
import { inngest } from "@/lib/inngest"
import { db } from "@/lib/db"
import { productBatches } from "@/lib/db/schema"
import { trendyolFetch } from "@/lib/marketplace/trendyol-client"
import { eq } from "drizzle-orm"
export const trendyolBatchPollFn = inngest.createFunction(
{ id: "trendyol-batch-poll" },
{ event: "trendyol/batch.created" },
async ({ event, step }) => {
const { batchRequestId } = event.data
// İlk kontrol: 5 dakika bekle
await step.sleep("initial-delay", "5 minutes")
for (let attempt = 0; attempt < 10; attempt++) {
const result = await step.run(`check-batch-${attempt}`, async () => {
const supplierId = process.env.TRENDYOL_SUPPLIER_ID!
return trendyolFetch(
`/integration/product/sellers/${supplierId}/batch-requests/${batchRequestId}`,
)
})
if ((result as { status: string }).status === "COMPLETED") {
await db
.update(productBatches)
.set({ status: "COMPLETED", resolvedAt: new Date() })
.where(eq(productBatches.batchRequestId, batchRequestId))
return { success: true }
}
if ((result as { status: string }).status === "FAILED") {
await db
.update(productBatches)
.set({ status: "FAILED", resolvedAt: new Date() })
.where(eq(productBatches.batchRequestId, batchRequestId))
return { success: false, reason: "Trendyol batch başarısız" }
}
// IN_PROGRESS → 3 dakika daha bekle
if (attempt < 9) {
await step.sleep(`retry-delay-${attempt}`, "3 minutes")
}
}
return { success: false, reason: "Maksimum deneme sayısına ulaşıldı" }
},
)
Ürün gönderimi yapan Route Handler'da event'i tetikleyin:
import { inngest } from "@/lib/inngest"
// batchRequestId aldıktan sonra:
await inngest.send({
name: "trendyol/batch.created",
data: { batchRequestId: result.batchRequestId },
})
Seçenek B: QStash (Basit HTTP Kuyruğu)
Upstash QStash, Vercel'in 10 saniyelik timeout sorununu aşmak için daha basit bir çözüm sunar. Ayrıca Vercel Hobby planının cron kısıtlarını bypass etmek için QStash cron kullanabilirsiniz.
// app/api/trendyol/batches/poll-worker/route.ts
// Bu endpoint QStash tarafından çağrılır
import { verifySignatureAppRouter } from "@upstash/qstash/dist/nextjs"
import { NextResponse } from "next/server"
import { db } from "@/lib/db"
import { productBatches } from "@/lib/db/schema"
import { trendyolFetch } from "@/lib/marketplace/trendyol-client"
import { eq, and } from "drizzle-orm"
async function handler(_request: Request) {
const supplierId = process.env.TRENDYOL_SUPPLIER_ID!
// Bekleyen tüm batch'leri kontrol et
const pendingBatches = await db
.select()
.from(productBatches)
.where(
and(
eq(productBatches.status, "PENDING"),
eq(productBatches.platform, "trendyol"),
),
)
for (const batch of pendingBatches) {
try {
const result = await trendyolFetch<{ status: string }>(
`/integration/product/sellers/${supplierId}/batch-requests/${batch.batchRequestId}`,
)
if (result.status !== "IN_PROGRESS") {
await db
.update(productBatches)
.set({
status: result.status,
resolvedAt: new Date(),
})
.where(eq(productBatches.batchRequestId, batch.batchRequestId))
}
} catch {
// Rate limit veya geçici hata — bir sonraki turda dene
}
}
return NextResponse.json({ processed: pendingBatches.length })
}
export const POST = verifySignatureAppRouter(handler)
Webhook + Polling Fallback Stratejisi
Trendyol webhook desteği sunuyor — satıcı başına maksimum 15 webhook tanımlanabilir (pasif olanlar da bu sayıya dahil). Başarısız webhook teslimatları 5 dakikada bir yeniden deneniyor.
Ancak dikkat: Trendyol'un kendi resmi dokümantasyonu bile, webhook'a ek olarak periyodik polling (getshipmentpackage) yapmanızı öneriyor. Webhook teslimatı garantili değil.
Sipariş webhook'u için Route Handler:
// app/api/webhooks/trendyol/route.ts
import { NextResponse } from "next/server"
import { db } from "@/lib/db"
import { orders } from "@/lib/db/schema"
interface TrendyolOrderWebhook {
orderId: string
orderNumber: string
status: string
lines: Array<{
id: string
quantity: number
productName: string
}>
}
export async function POST(request: Request) {
// Trendyol webhook imzası — resmi dokümantasyonu kontrol edin
const payload: TrendyolOrderWebhook = await request.json()
await db.insert(orders).values({
externalId: payload.orderId,
orderNumber: payload.orderNumber,
platform: "trendyol",
status: payload.status,
rawPayload: JSON.stringify(payload),
receivedAt: new Date(),
})
return NextResponse.json({ received: true })
}
Polling fallback — sipariş çekme:
// lib/marketplace/trendyol-sync.ts
export async function syncTrendyolOrders(): Promise<void> {
const supplierId = process.env.TRENDYOL_SUPPLIER_ID!
const since = new Date(Date.now() - 15 * 60 * 1000) // Son 15 dakika
const startDate = since.getTime() // Unix timestamp ms
const result = await trendyolFetch<{ content: unknown[] }>(
`/integration/order/sellers/${supplierId}/orders?startDate=${startDate}&orderByField=CreatedDate&orderByDirection=DESC`,
)
for (const order of result.content) {
// Idempotent upsert — webhook ile gelen sipariş tekrar işlenmez
await upsertOrder(order as Record<string, unknown>, "trendyol")
}
}
Hepsiburada Merchant API
Kimlik Doğrulama
Hepsiburada da HTTP Basic Auth kullanıyor. Seller Portal üzerinden username + password alınıyor.
Authorization: Basic Base64(username:password)
Dikkat: Hepsiburada kimlik doğrulama yapısı yakın zamanda değişti. Eski implementasyonlarınız varsa güncel developer dokümantasyonunu kontrol edin.
Base URL'ler
Production: https://marketplace-api.hepsiburada.com
Test/SIT: https://marketplace-api-sit.hepsiburada.com
SIT ortamı için Hepsiburada Marketplace Integration ekibine başvurmanız gerekiyor. Onay sonrası Merchant ID email ile gönderilir.
Temel Endpoint'ler
POST /product/api/products/import — Ürün yükleme (dosya tabanlı)
GET /product/api/products/all-products-of-merchant — Tüm ürünleri listele
GET /order-items/... — Sipariş yönetimi
Önemli fark: Hepsiburada'da ürün yükleme dosya tabanlı import ile çalışıyor — Trendyol'daki gibi doğrudan JSON API değil. Bu biraz daha yüksek entegrasyon süresi anlamına geliyor.
Hepsiburada API Client
// lib/marketplace/hepsiburada-client.ts
const HB_BASE_URL = process.env.HEPSIBURADA_STAGE === "true"
? "https://marketplace-api-sit.hepsiburada.com"
: "https://marketplace-api.hepsiburada.com"
export async function hepsiburadaFetch<T>(
path: string,
options: RequestInit = {},
): Promise<T> {
const username = process.env.HEPSIBURADA_USERNAME!
const password = process.env.HEPSIBURADA_PASSWORD!
const credentials = Buffer.from(`${username}:${password}`).toString("base64")
const response = await fetch(`${HB_BASE_URL}${path}`, {
...options,
headers: {
"Authorization": `Basic ${credentials}`,
"Content-Type": "application/json",
...options.headers,
},
})
if (!response.ok) {
const errorText = await response.text()
throw new Error(`Hepsiburada API error ${response.status}: ${errorText}`)
}
return response.json() as Promise<T>
}
Hepsiburada Webhook
Hepsiburada webhook desteği Trendyol'a göre daha iyi belgelenmiş. Sipariş bildirimleri için base URL'inizi Hepsiburada'ya bildirirsiniz; platform {baseUrl}/orders endpoint'inize POST atar.
Idempotent işleme zorunlu — tekrar gönderim olabilir. Her webhook payload'ını bir ID ile takip edin:
// app/api/webhooks/hepsiburada/orders/route.ts
import { NextResponse } from "next/server"
import { db } from "@/lib/db"
import { orders } from "@/lib/db/schema"
import { eq } from "drizzle-orm"
export async function POST(request: Request) {
const payload = await request.json()
const externalOrderId = payload.id as string
// Idempotent upsert — aynı sipariş tekrar işlenmez
const existing = await db
.select()
.from(orders)
.where(eq(orders.externalId, externalOrderId))
if (existing.length === 0) {
await db.insert(orders).values({
externalId: externalOrderId,
platform: "hepsiburada",
status: payload.status,
rawPayload: JSON.stringify(payload),
receivedAt: new Date(),
})
}
return NextResponse.json({ received: true })
}
Trendyol vs Hepsiburada Karşılaştırması
| Kriter | Trendyol | Hepsiburada |
|---|---|---|
| Auth | Basic Auth + User-Agent zorunlu | Basic Auth |
| Ürün yükleme | Doğrudan JSON API | Dosya tabanlı import |
| Async onay | batchRequestId ile | Platform bağımlı |
| Webhook | Var (polling fallback önerilir) | Var (first-class) |
| Sandbox | IP whitelist gerekli | Başvuru sonrası |
| Dokümantasyon | İyi (developers.trendyol.com) | Orta-iyi |
| Pazar payı | ~%36 (lider) | İkinci sıra |
Vercel Cron ile Stok Senkronizasyonu
Stok verilerinin her iki platformda güncel kalması için periyodik senkronizasyon gerekiyor.
Vercel Cron Kısıtları
Bu kritik bilgiyi düzgünce anlamamak ciddi sorunlara yol açar:
- Hobby (Ücretsiz plan): Maksimum 2 cron job, her biri günde en fazla 1 kez çalışabilir.
0 * * * *(saatlik) bir cron deploy'da hata verir. - Pro plan: Dakika düzeyinde granülarite (Amazon EventBridge Scheduler üzerinden). Gerçek marketplace polling için Pro gerekli.
- Hobby alternatif: QStash cron ile Vercel kısıtını bypass edebilirsiniz. QStash herhangi bir takvimde sync'i tetikleyebilir.
next.config.ts ile Cron Tanımlama (Pro)
// next.config.ts
import type { NextConfig } from "next"
const nextConfig: NextConfig = {
experimental: {
// Pro plan için cron route'ları
},
}
export default nextConfig
vercel.json:
{
"crons": [
{
"path": "/api/cron/sync-inventory",
"schedule": "*/15 * * * *"
}
]
}
Stok Senkronizasyon Route Handler
// app/api/cron/sync-inventory/route.ts
import { NextResponse } from "next/server"
import { db } from "@/lib/db"
import { products } from "@/lib/db/schema"
import { trendyolFetch } from "@/lib/marketplace/trendyol-client"
export async function GET(request: Request) {
// Vercel Cron güvenlik kontrolü
const authHeader = request.headers.get("authorization")
if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 })
}
const supplierId = process.env.TRENDYOL_SUPPLIER_ID!
// DB'deki güncel stok bilgilerini al
const inventory = await db.select().from(products)
// Trendyol'a batch stok güncelleme gönder
// Rate limit göz önünde bulundurularak batch'lere böl
const BATCH_SIZE = 50
const batches = []
for (let i = 0; i < inventory.length; i += BATCH_SIZE) {
batches.push(inventory.slice(i, i + BATCH_SIZE))
}
const results = []
for (const batch of batches) {
const items = batch.map((p) => ({
barcode: p.barcode,
quantity: p.stock,
salePrice: p.salePrice,
listPrice: p.listPrice,
}))
const result = await trendyolFetch<{ batchRequestId: string }>(
`/integration/product/sellers/${supplierId}/products/price-and-inventory`,
{
method: "PUT",
body: JSON.stringify({ items }),
},
)
results.push(result.batchRequestId)
// Rate limit için kısa bekleme — güncel değer için dokümantasyonu kontrol edin
await new Promise((resolve) => setTimeout(resolve, 500))
}
return NextResponse.json({ synced: inventory.length, batches: results })
}
npm Paket Seçimi
Trendyol için:
@rexven-tech/trendyol-api— Daha aktif bakımlı, ürün/sipariş/finans/webhook kayıt desteği. Önerilen.trendyol-api(myazarc) — TypeScript destekli ama 3 yıldır güncellenmemiş, güncel API sürümleriyle uyumsuz olabilir.
Her iki seçenek için de üretim öncesinde güncel API uyumluluğunu test edin. Özellikle hızlı büyüyen bu platformlarda API değişiklikleri sık olabiliyor — resmi dokümantasyonu baz almak en güvenli yaklaşım.
Ortam Değişkenleri
.env.local:
# Trendyol
TRENDYOL_SUPPLIER_ID=12345
TRENDYOL_API_KEY=your-api-key
TRENDYOL_API_SECRET=your-api-secret
TRENDYOL_STAGE=true
# Hepsiburada
HEPSIBURADA_USERNAME=your-username
HEPSIBURADA_PASSWORD=your-password
HEPSIBURADA_MERCHANT_ID=your-merchant-id
HEPSIBURADA_STAGE=true
# Cron güvenliği
CRON_SECRET=random-secret-string
# Inngest (opsiyonel)
INNGEST_EVENT_KEY=your-inngest-key
INNGEST_SIGNING_KEY=your-signing-key
Sık Hatalar ve Çözümleri
Trendyol 401 Unauthorized:
User-Agentheader'ını eklediğinizden emin olun:"<supplierId> - SelfIntegration"- Stage ve production credential'larını karıştırmayın — tamamen ayrıdırlar
Trendyol Stage'de 403 Forbidden:
- IP whitelist gerekli — sunucunuzun static IP'sini Trendyol'a bildirin
- Yerel geliştirme için ngrok veya benzeri bir tünel servisi kullanın
batchRequestId sonucu hep IN_PROGRESS:
- Moderasyon 5-30 dakika sürebilir; polling interval'i buna göre ayarlayın
- Ürün verilerinde eksik zorunlu alan varsa (kategori, marka, vs.) süreç takılabilir — batch sonuç endpoint'inden hata detaylarını inceleyin
Hepsiburada ürün yükleme başarısız:
- Hepsiburada ürün yükleme dosya tabanlı çalışır — doğrudan JSON body yeterli olmayabilir
- SIT ortamı için Merchant ID'nizi Hepsiburada entegrasyon ekibinden alın
Vercel cron çalışmıyor (Hobby plan):
- Hobby'de saatlik cron desteklenmiyor — günde 1 kez ile sınırlı
- Çözüm: Vercel Pro'ya geçin ya da QStash cron ile kısıtı bypass edin
Rate limit hatası:
- Trendyol'un rate limit bilgisi değişebilir — güncel değeri resmi dokümantasyondan kontrol edin
- Büyük kataloglar için batch'lere bölün ve istekler arasına gecikme ekleyin
Ne Zaman Hazır Entegrasyon Kullanmalı?
Custom geliştirme yapmadan önce hazır marketplace entegrasyon araçlarını değerlendirin:
Hazır çözümler mantıklı olduğunda:
- 10'dan fazla marketplace (Trendyol, Hepsiburada, Çiçeksepeti, N11, Sahibinden) aynı anda yönetilecekse
- Ürün katalog sayısı onbinleri geçiyorsa
- Ekipte marketplace API geliştirme deneyimi yoksa
Custom geliştirme mantıklı olduğunda:
- Yalnızca 1-2 marketplace entegrasyonu gerekiyorsa
- Özel iş mantığı var ve hazır çözümler uymuyor
- Mevcut sistemle (özel ERP, muhasebe yazılımı) derin entegrasyon gerekiyorsa
Dopigo, Sentos, JetStok gibi Türk entegrasyon SaaS'ları bu alanda uzmanlaşmış. Özellikle çok kanallı satış yapan KOBİ'ler için değer sunabilirler.
Sonraki Adımlar
- Hata yönetimi: Her iki platform için exponential backoff ile retry mekanizması ekleyin
- Monitoring: Inngest veya QStash dashboard'ları ile job durumlarını izleyin
- Stok çakışması: Aynı ürün birden fazla platformda satılıyorsa race condition yönetimini planlayın
- N11 entegrasyonu: Düşük öncelikli ama aktif — DMSF sonrası API değişikliklerini developer portal üzerinden takip edin
SSS
Trendyol API erişimi almak ne kadar sürer? Başvuru ve onay süresi değişkendir — Trendyol Seller Panel üzerinden başvuruda bulunun ve güncel bilgi için Trendyol entegrasyon ekibiyle iletişime geçin.
Webhook olmadan sadece polling yeterli olur mu? Teknik olarak evet, ancak yüksek sipariş hacminde polling gecikmeli bildirim anlamına gelir. En iyi yaklaşım: webhook + polling fallback kombinasyonu. Trendyol resmi dokümantasyonu da bu kombinasyonu öneriyor.
Inngest ücretsiz mi? Inngest'in ücretsiz planı var — güncel limit ve ücretlendirme için inngest.com adresini kontrol edin. QStash de Upstash üzerinde ücretsiz tier sunuyor.
Vercel Hobby planıyla marketplace sync mümkün mü? Sınırlı. Günde 1 cron job ile yalnızca günlük senkronizasyon yapabilirsiniz. Gerçek zamanlıya yakın sync için QStash cron veya Vercel Pro gerekli.
Hepsiburada'da ürün güncellemesi neden Trendyol'dan yavaş? Hepsiburada'da ürün yükleme dosya tabanlı bir import sistemiyle çalışıyor. Bu durum Trendyol'un doğrudan JSON API'sine kıyasla daha fazla entegrasyon adımı gerektiriyor.
N11 entegrasyonu hâlâ değerli mi? N11 düşük hacimle de olsa aktif. Eğer müşteriniz N11'de de satış yapıyorsa entegrasyon anlam taşıyabilir, ancak DMSF sonrası API durumunu developer.n11.com üzerinden doğrulayın.
Stage ortamında test için statik IP zorunlu mu? Trendyol Stage için evet — IP whitelist gerekli. Yerel geliştirmede ngrok veya benzeri bir tünel aracı kullanın ve o IP'yi Trendyol'a bildirin.

