REST API ve Webhook

escMedya e-ticaret mağazanızı ERP, muhasebe, depo ve kargo yazılımlarına bağlayın: ürün, stok, fiyat, sipariş ve müşteri verisine erişin; sipariş ve stok değişince anında bildirim alın.

Sürüm v1 JSON · HTTPS Ticaret ve Kurumsal paketlerde

Hızlı başlangıç

  1. Mağaza panelinde Yönetim → API Anahtarları sayfasından bir anahtar oluşturun. Veri güncelleyecekseniz Yazma izni ver'i işaretleyin. Anahtar yalnızca bir kez gösterilir.
  2. Bağlantıyı deneyin:
Komut satırı
curl https://eticaret.escmedya.com.tr/api/v1/ben \
  -H "Authorization: Bearer esc_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
Yanıt · 200
{
  "magaza": { "id": 63, "ad": "Örnek Mağaza", "alanAdi": "ornekmagaza.com" },
  "anahtar": { "id": 4, "ad": "Logo ERP", "onek": "esc_a1B2c3D4", "yazmaIzni": true },
  "hizSiniri": { "dakikalik": 120 }
}

REST API ve webhook Ticaret ve Kurumsal paketlerde açıktır. Diğer paketlerde uçlar 403 paket_izni_yok döner.

Kimlik doğrulama

Her istekte anahtarı Authorization başlığında gönderin. Anahtar hangi mağazaya ait olduğunu kendisi belirler; adres olarak platform adresini (https://eticaret.escmedya.com.tr/api/v1) ya da mağazanın kendi alan adını (https://ornekmagaza.com/api/v1) kullanabilirsiniz, sonuç aynıdır.

Authorization: Bearer esc_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  • Salt okunur anahtar yalnızca GET uçlarını çağırabilir. Yazma uçları 403 anahtar_salt_okunur döner.
  • Anahtar sunucuda yalnızca özetiyle saklanır; kaybederseniz geri getirilemez. Yenisini oluşturup eskisini İptal Et ile kapatın. İptal anında geçerlidir.
  • Anahtarı tarayıcıda çalışan koda, mobil uygulamaya ya da herkese açık depolara koymayın. Yalnız sunucudan sunucuya kullanın.
  • Mağazanın aboneliği sona erdiğinde okuma sürer, yazma uçları 403 abonelik_bitti döner.

Genel kurallar

KonuKural
Biçimİstek ve yanıt gövdesi JSON (UTF-8). Alan adları Türkçe, camelCase: stokKodu, siparisNo.
TarihlerISO 8601, saat dilimi ofsetiyle: 2026-10-08T14:30:00+03:00. Filtre parametrelerinde + işaretini URL'de %2B olarak kodlayın ya da UTC (…Z) verin.
Sayfalamasayfa (1'den başlar) ve adet (varsayılan 50, en fazla 100). Liste yanıtı: { veri, sayfa, adet, toplam, sonrakiSayfa }; sonrakiSayfa son sayfada null.
Artımlı çekimÜrün ve siparişlerde guncellenmeSonrasi: yalnızca o andan sonra eklenen ya da değişen kayıtlar. Her turda bir önceki turun başlangıç zamanını gönderin.
SıralamaListeler kimliğe (id) göre artan sırada döner; sayfalar arası kayma olmaz.
Hız sınırıAnahtar başına dakikada 120 istek. Aşılınca 429 hiz_siniri ve Retry-After: 60. Toplu yazma uçları (500 kalem) sayesinde bu sınır pratikte yeterlidir.
ParaTutarlar ondalık sayı, KDV dahil, Türk lirası (paraBirimi ürün bazında).
ÖnbellekYanıtlar Cache-Control: no-store; her istek güncel veriyi döner.

Hatalar

Tüm hatalar aynı biçimde döner:

{ "hata": { "kod": "gecersiz_durum", "mesaj": "durum şunlardan biri olmalı: Beklemede, Onaylandi, …" } }
HTTPkodNe zaman
400gecersiz_parametreSorgu parametresi ya da JSON gövdesi okunamadı (ör. hatalı tarih).
400gecersiz_durumBilinmeyen sipariş durumu.
400bos_istek, cok_kalemToplu uçta kalem yok ya da 500'den fazla.
400eksik_alan, cok_uzun, gecersiz_urlKargo isteğinde zorunlu alan eksik ya da hatalı.
401yetkisizAnahtar yok, hatalı ya da iptal edilmiş.
403paket_izni_yokMağazanın paketi API içermiyor.
403anahtar_salt_okunurSalt okunur anahtarla yazma ucu çağrıldı.
403abonelik_bittiAbonelik sona erdi; yazma kapalı, okuma açık.
404bulunamadiKayıt yok ya da başka bir mağazaya ait.
422gecersiz_gecisSipariş bu durumdan istenen duruma geçemez (bkz. geçiş tablosu).
422kargoya_verilemezİptal ya da iade edilmiş siparişe kargo bilgisi girilemez.
429hiz_siniriDakikalık istek sınırı aşıldı.

GET /ben

Anahtarın bağlı olduğu mağazayı ve yetkisini döner. Bağlantı testi için kullanın (örnek yanıt Hızlı başlangıç'ta).

Ürünler

GET /urunler
ParametreAçıklama
sayfa, adetSayfalama.
guncellenmeSonrasiBu tarihten sonra eklenen ya da değişen ürünler.
stokKodu, barkodÜrünün, varyantının ya da kombinasyonunun koduyla arar.
aktiftrue yalnız satıştakiler, false yalnız kapalılar.
GET /urunler/{id}

Tek ürün. Listeden farkı aciklama (HTML) alanının dolu gelmesidir.

Ürün nesnesi
{
  "id": 1204,
  "urunKodu": "TS-100",
  "stokKodu": "TS-100",
  "barkod": "8690000000011",
  "ad": "Basic Tişört",
  "slug": "basic-tisort",
  "kisaAciklama": "Yüzde yüz pamuk",
  "aciklama": null,
  "fiyat": 499.90,
  "indirimliFiyat": 399.90,
  "indirimBaslangic": null,
  "indirimBitis": "2026-10-31T23:59:00+03:00",
  "kdvOrani": 10,
  "paraBirimi": "TRY",
  "stokMiktari": 42,
  "stokTakibiVar": true,
  "desi": 1.00,
  "agirlik": 0.25,
  "marka": { "id": 7, "ad": "Örnek Marka" },
  "kategoriIdleri": [12, 15],
  "gorseller": ["https://ornekmagaza.com/uploads/63/urunler/ts-100-1.webp"],
  "aktif": true,
  "olusturmaTarihi": "2026-09-01T10:12:00+03:00",
  "guncellemeTarihi": "2026-10-08T09:40:00+03:00",
  "varyantTipleri": [
    {
      "id": 31, "ad": "Beden",
      "degerler": [
        { "id": 101, "deger": "M", "fiyatFarki": 0.00, "stokMiktari": 20, "stokKodu": "TS-100-M", "barkod": "8690000000028", "aktif": true },
        { "id": 102, "deger": "L", "fiyatFarki": 0.00, "stokMiktari": 22, "stokKodu": "TS-100-L", "barkod": "8690000000035", "aktif": true }
      ]
    }
  ],
  "kombinasyonlar": []
}
Varyantlı ürünlerde stok ve fiyat: Tek eksenli varyantta (yalnız beden ya da yalnız renk) stok varyantta tutulur, satış fiyatı fiyat + fiyatFarki'dir. Çok eksenli üründe (renk × beden) stok kombinasyonlar içindedir; her kombinasyon varyantIdleri ile hangi değerlerden oluştuğunu söyler. Ürünün stokMiktari alanı varyant ya da kombinasyon toplamıdır.

Siparişler

GET /siparisler

Site, panel ve pazaryeri (Trendyol, Hepsiburada, N11…) siparişlerinin hepsi; kaynak alanı ayırır.

ParametreAçıklama
sayfa, adetSayfalama.
baslangic, bitisOluşturma tarihi aralığı (bitis hariç).
guncellenmeSonrasiBu tarihten sonra oluşan ya da değişen siparişler.
durumBeklemede, Onaylandi, Hazirlaniyor, Kargoda, TeslimEdildi, IptalEdildi, IadeEdildi.
siparisNoSipariş numarasıyla tam eşleşme.
GET /siparisler/{id}
Sipariş nesnesi
{
  "id": 5821,
  "siparisNo": "ES2610081432",
  "durum": "Onaylandi",
  "odemeDurumu": "Odendi",
  "odemeYontemi": "Kredi Kartı",
  "kaynak": "Site",
  "kaynakSiparisNo": null,
  "musteri": { "id": 311, "misafir": false, "ad": "Ayşe", "soyad": "Yılmaz", "email": "ayse@ornek.com", "telefon": "5551234567" },
  "teslimat": { "ad": "Ayşe", "soyad": "Yılmaz", "telefon": "5551234567", "il": "Ankara", "ilce": "Çankaya", "adres": "…", "postaKodu": "06690" },
  "fatura": { "tip": "Bireysel", "ad": "Ayşe", "soyad": "Yılmaz", "adres": "…", "tcKimlikNo": null, "firmaAdi": null, "vergiDairesi": null, "vergiNo": null, "faturaNo": null },
  "tutarlar": {
    "araToplam": 799.80, "kargoUcreti": 0.00, "indirimTutari": 0.00, "kampanyaIndirimi": 80.00,
    "hediyeCekiIndirimi": 0.00, "puanIndirimi": 0.00, "vadeFarki": 0.00, "toplam": 719.80
  },
  "kuponKodu": null,
  "taksitSayisi": 1,
  "kargo": { "firma": null, "takipNo": null, "takipUrl": null },
  "musteriNotu": null,
  "kalemler": [
    {
      "id": 9120, "urunId": 1204, "varyantId": 101, "kombinasyonId": null,
      "urunAdi": "Basic Tişört", "varyantBilgisi": "Beden: M",
      "stokKodu": "TS-100-M", "barkod": "8690000000028",
      "birimFiyat": 399.90, "miktar": 2, "toplamFiyat": 799.80, "kdvOrani": 10
    }
  ],
  "olusturmaTarihi": "2026-10-08T14:32:10+03:00",
  "guncellemeTarihi": "2026-10-08T14:35:02+03:00"
}
Kalemlerdeki stokKodu ve barkod sırasıyla kombinasyon, varyant ve üründen çözülür: satırı ERP'deki stok kartına bu kodla eşleyin. Misafir siparişte musteri.id boştur, ad ve iletişim siparişten gelir.

Müşteriler

GET /musteriler

Üye müşteriler. Parametreler: sayfa, adet, olusturmaSonrasi, email.

GET /musteriler/{id}

Tek müşteri, kayıtlı adresler ile. Alanlar: id, ad, soyad, email, telefon, grup { id, ad }, epostaIzni, smsIzni, aktif, bakiye, puanBakiye, krediLimiti, vadeGun, olusturmaTarihi. Bayi (B2B) müşterilerde grup, krediLimiti ve vadeGun doludur.

Kategoriler

GET /kategoriler

Kategori ağacının tamamı düz liste olarak (sayfalama yok): { veri: [ { id, ustKategoriId, ad, slug, siraNo, aktif, guncellemeTarihi } ], toplam }. Ağacı ustKategoriId ile kurun; kök kategorilerde boştur.

POST /stok yazma

Toplu stok güncelleme, istek başına en fazla 500 kalem. Her kalem hedefini şunlardan biriyle bulur: stokKodu, barkod, urunId, varyantId, kombinasyonId. Kod verildiğinde arama sırası kombinasyon → varyant → ürün'dür; aynı kod birden fazla yerde varsa kalem hata döner, kimlikle gönderin.

  • miktar: mutlak değer (depodaki sayım). degisim: göreli (+5 ekler, -3 düşer; 0'ın altına inmez). İkisinden tam olarak biri.
  • Varyant ya da kombinasyon stoğu değişince ürünün toplam stoğu yeniden hesaplanır.
  • Değişiklik mağazanın stok geçmişine API kaynağı ve anahtarın adıyla yazılır; bağlı pazaryerlerine bir sonraki senkron turunda (10 dakikada bir) gönderilir.
İstek
POST https://eticaret.escmedya.com.tr/api/v1/stok
{
  "kalemler": [
    { "stokKodu": "TS-100-M", "miktar": 25 },
    { "barkod": "8690000000035", "degisim": -2 },
    { "stokKodu": "YOK-1", "miktar": 3 }
  ]
}
Yanıt · 200
{
  "guncellenen": 2,
  "hatali": 1,
  "sonuclar": [
    { "sira": 0, "durum": "guncellendi", "hedef": { "urunId": 1204, "varyantId": 101, "kombinasyonId": null }, "eskiMiktar": 20, "yeniMiktar": 25 },
    { "sira": 1, "durum": "guncellendi", "hedef": { "urunId": 1204, "varyantId": 102, "kombinasyonId": null }, "eskiMiktar": 22, "yeniMiktar": 20 },
    { "sira": 2, "durum": "hata", "hata": "Bu stok kodu ile ürün bulunamadı: YOK-1" }
  ]
}

Toplu uçlar kalem hatalarında da 200 döner; her kalemin durum'una bakın (guncellendi, degismedi, hata). Bir kalemin hatası diğerlerini durdurmaz.

POST /fiyat yazma

Toplu fiyat güncelleme, en fazla 500 kalem. Hedef bulma /stok ile aynı.

  • Ürün için: fiyat (KDV dahil satış fiyatı) ve/veya indirimliFiyat. indirimliFiyat: 0 indirimi kaldırır; indirimli fiyat satış fiyatından küçük olmalı.
  • Varyant ya da kombinasyon için yalnız fiyatFarki: satış fiyatı = ürün fiyatı + fark.
İstek
POST https://eticaret.escmedya.com.tr/api/v1/fiyat
{
  "kalemler": [
    { "stokKodu": "TS-100", "fiyat": 549.90, "indirimliFiyat": 449.90 },
    { "stokKodu": "TS-100-L", "fiyatFarki": 20 }
  ]
}

POST /siparisler/{id}/durum yazma

İstek
{ "durum": "Hazirlaniyor", "aciklama": "Depoda toplanıyor", "mailGonder": true }

Mağaza panelindeki "Durum Güncelle" ile birebir aynı işler: iptal ve iadede stok, kupon, hediye çeki, sadakat puanı ve bayi bakiyesi geri döner; kapıda ödemeli sipariş teslimde ödendi sayılır; e-fatura eklentisi açıksa otomatik fatura kesilir; mailGonder açıksa müşteriye bilgi maili gider. Değişiklik sipariş geçmişinde anahtarın adıyla görünür. Başarılı yanıt güncel siparişi döner: { mesaj, siparis }.

Geçiş tablosu

Şu anki durumGeçebileceği durumlar
Beklemede, Onaylandi, HazirlaniyorKendi aralarında serbest; Kargoda, TeslimEdildi, IptalEdildi
KargodaTeslimEdildi, IptalEdildi (kargo dönüşü), IadeEdildi
TeslimEdildiIadeEdildi
IptalEdildiOnaylandi (yanlış iptali düzeltme; stok yeniden düşer)
IadeEdildi— (son durum)

Durumu IptalEdildi ya da IadeEdildi yapmak parayı iade etmez, yalnız siparişin ödeme durumunu işaretler. Kartla ödenmiş siparişin parası panelden Ödeme İade ile iade edilir.

POST /siparisler/{id}/kargo yazma

İstek
{ "firma": "Yurtiçi Kargo", "takipNo": "123456789012", "takipUrl": null }

Sipariş Kargoda'ya geçer (zaten kargoda ya da teslim edildiyse durum değişmez, takip bilgisi düzeltilir), müşteriye takip linkli kargo maili gider, e-fatura "kargoya verilince kes" ayarı açıksa fatura kesilir. Takip linki şu firmalar için otomatik üretilir; diğerleri için takipUrl gönderin: Yurtiçi, Aras, MNG, PTT, Sürat, Trendyol Express, UPS, DHL, HepsiJet, FedEx.

Webhook nedir

Webhook, mağazada bir şey olduğunda (yeni sipariş, durum değişikliği, stok değişimi) sizin belirlediğiniz adrese bizim tarafımızdan gönderilen bir POST isteğidir. Siparişleri dakikada bir sorgulamak yerine anında haber alırsınız.

  1. Panelde API Anahtarları → Webhooklar → Webhook Ekle: adres (yalnız https://) ve olaylar.
  2. Gösterilen imza sırrını (whsec_…) saklayın; panelden Sır ile tekrar görebilirsiniz.
  3. Test gönder ile adresinize örnek bir ping olayı gelir.

Adresiniz isteği 10 saniye içinde 2xx ile yanıtlamalı. Uzun işleri (ERP'ye yazma vb.) yanıt verdikten sonra arka planda yapın.

Olaylar

OlayNe zamanveri
siparis.olustuHavale, kapıda ödeme, panel ve pazaryeri siparişlerinde sipariş oluşunca; kartla ödenen site siparişlerinde ödeme tamamlanınca. Ödemesi yarıda kalan kart siparişleri hiç gönderilmez.{ siparis }
siparis.durum_degistiDurum değişince: panel, API, kargo takibi, ödeme ve pazaryeri; nereden olursa.{ eskiDurum, yeniDurum, siparis }
stok.degistiÜrün, varyant ya da kombinasyon stoğu değişince (satış, iptal, panel, API, aktarım, pazaryeri). Aynı hedefin art arda değişiklikleri tek bildirimde birleşebilir.{ urunId, varyantId, kombinasyonId, stokKodu, barkod, oncekiMiktar, yeniMiktar, urunToplamStok, kaynak, degisiklikSayisi }
urun.guncellendiÜrün eklenince ya da bilgisi (ad, fiyat, açıklama, durum…) değişince.{ yeni, urun }
pingPanelden "Test gönder".{ mesaj }

siparis ve urun nesneleri GET /siparisler/{id} ve GET /urunler/{id} ile aynı biçimdedir (ürün açıklaması hariç).

İstek
POST https://erp.sirketiniz.com/escmedya/webhook
Content-Type: application/json; charset=utf-8
User-Agent: escMedya-Webhook/1.0
X-Esc-Olay: siparis.durum_degisti
X-Esc-Teslimat: 0b9c4e1a-3f52-4b8e-9d8a-1c2e7f60a911
X-Esc-Zaman: 1791462600
X-Esc-Imza: q3V1u3m0Vt8yC2pB0m0kq3Fh6N8bX0sQyQm7nY1x9zE=

{
  "id": "0b9c4e1a-3f52-4b8e-9d8a-1c2e7f60a911",
  "olay": "siparis.durum_degisti",
  "olusmaTarihi": "2026-10-08T14:30:00+03:00",
  "magaza": { "id": 63, "ad": "Örnek Mağaza" },
  "veri": {
    "eskiDurum": "Hazirlaniyor",
    "yeniDurum": "Kargoda",
    "siparis": { "id": 5821, "siparisNo": "ES2610081432", "durum": "Kargoda", "…": "…" }
  }
}

İmza doğrulama

Her isteğin bizden geldiğini doğrulayın: X-Esc-Imza = Base64( HMAC-SHA256( sır, X-Esc-Zaman + "." + ham gövde ) ). Gövdeyi JSON olarak ayrıştırıp yeniden yazmadan, geldiği gibi kullanın. X-Esc-Zaman (Unix saniye) 5 dakikadan eskiyse isteği reddedin; karşılaştırmayı sabit zamanlı yapın.

using System.Security.Cryptography;
using System.Text;

static bool ImzaGecerli(string sir, string zaman, string hamGovde, string imza)
{
    if (!long.TryParse(zaman, out var t) || Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - t) > 300)
        return false;

    using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(sir));
    var beklenen = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(zaman + "." + hamGovde)));
    return CryptographicOperations.FixedTimeEquals(Encoding.UTF8.GetBytes(beklenen), Encoding.UTF8.GetBytes(imza));
}

// ASP.NET Core: gövdeyi ham okuyun
// using var okuyucu = new StreamReader(Request.Body);
// var govde = await okuyucu.ReadToEndAsync();
// if (!ImzaGecerli(SIR, Request.Headers["X-Esc-Zaman"], govde, Request.Headers["X-Esc-Imza"])) return Unauthorized();

Teslimat ve tekrar

  • Yeniden deneme: yanıt 2xx değilse ya da 10 saniyede gelmezse 1 dk, 5 dk, 30 dk, 2 sa, 6 sa, 12 sa ve 24 sa sonra yeniden denenir (toplam 8 deneme, yaklaşık 45 saat).
  • Tekrarları ayıklayın: aynı teslimat yeniden denendiğinde X-Esc-Teslimat ve gövdedeki id değişmez. İşlediğiniz kimlikleri saklayıp ikinci kez gelirse yalnızca 200 dönün.
  • Sıra garanti değildir: yeniden denemeler yüzünden bildirimler farklı sırada gelebilir. Siparişin güncel hâli için veri.siparis.guncellemeTarihi'ne bakın ya da GET /siparisler/{id} ile doğrulayın.
  • Otomatik kapanma: art arda 20 teslimat tüm denemelerde başarısız olursa webhook kapanır ve panelde bildirim çıkar. Sorunu giderip panelden yeniden açın.
  • Panel kaydı: son teslimatlar, HTTP kodu ve hata mesajıyla panelde listelenir; başarısız olanları Tekrar gönder ile elle yollayabilirsiniz.
  • Ağ: istekler yönlendirme (3xx) izlemez; adresiniz doğrudan yanıt vermeli. Güvenlik gereği iç ağ ve yerel adreslere gönderim yapılmaz.

Önerilen ERP entegrasyon akışı

  1. İlk eşleştirme: GET /urunler ile tüm kataloğu sayfa sayfa çekin; ürün, varyant ve kombinasyonları ERP stok kartlarına stokKodu ya da barkod ile eşleyin. Kodu olmayan ürünleri panelde tamamlayın.
  2. Stok ve fiyat ERP'den: ERP'deki değişiklikleri POST /stok ve POST /fiyat ile 500'lük partiler hâlinde gönderin. Tam sayımda miktar, hareket bazlı aktarımda degisim kullanın.
  3. Siparişler ERP'ye: siparis.olustu webhook'u ile anında alın. Kaçırma riskine karşı saatlik olarak GET /siparisler?guncellenmeSonrasi=… ile mutabakat yapın.
  4. Sevkiyat mağazaya: depo kargoya verince POST /siparisler/{id}/kargo; müşteri takip maili otomatik alır. Diğer durumlar için POST /siparisler/{id}/durum.
  5. Web satışı stoku: sitede satılan ürünlerin stok düşüşünü stok.degisti ile ERP'ye yansıtın ya da ERP sipariş kalemlerinden kendisi düşsün; ikisini birden yapmayın.
Stokun tek bir sahibi olsun. Hem ERP mutlak stok gönderirken hem de site satışları düşüyorsa, ERP'nin gönderdiği sayı en son sayımı yansıtmalı; aksi halde satılan ürün geri eklenir.

Sürüm notları

TarihDeğişiklik
8 Ekim 2026v1: anahtarlar, okuma uçları (ürün, sipariş, müşteri, kategori), yazma uçları (stok, fiyat, sipariş durumu, kargo), webhook (sipariş, stok, ürün olayları).

v1 içinde yanıtlara yeni alan eklenebilir; mevcut alanlar kaldırılmaz ya da anlamı değiştirilmez. Entegrasyonunuz bilmediği alanları yok saymalı.