İçeriğe geç
KURUMSAL Kurumsal teknoloji · İşletmenize özel mühendislik Kurumsal Yazılım · Yönetilen Sunucular · Kurumsal E-posta · LiteSpeed + CloudLinux · Imunify360 Güvenlik · cPanel Yönetim · Uygun pakette 3 Gbps'ye kadar ağ profili
AIOR

Kargo API Entegrasyonu: Gönderi, Barkod, Takip, İade Kodu ve Desi

  • Konu başlatıcısı Konu başlatıcısı Aior
  • Başlangıç tarihi Başlangıç tarihi

Aior

Administrator

Yetkili üye
Katıldı
2 Nis 2023
Mesajlar
929
Tepki puanı
2
Puan
18
Yaş
41
Konum
Turkey
Web sitesi
aior.com
Konu sahibi

Bir e-ticaret sitesini, ERP'yi ya da depo yönetim sistemini (WMS) kargo firmasına bağlamak tek bir "gönderi oluştur" çağrısıyla bitmez. Ödenen siparişe gönderi açmak, kargo barkodunu yazdırmak, paketi kuryeye teslim etmek, takip olaylarını müşteriye yansıtmak, iade kodu oluşturmak, tahsilatlı kargonun parasını eşleştirmek ve ay sonunda kargo faturasını kendi hesabınızla karşılaştırmak aynı entegrasyonun parçalarıdır. Bu rehberde kargo API entegrasyonunu bu sırayla ve Türkiye'deki taşıyıcıların çalışma biçimine göre ele alıyoruz.

Önce bir uyarı. Yurtiçi Kargo, Aras Kargo, DHL eCommerce (Mayıs 2025'e kadarki adıyla MNG Kargo), Sürat Kargo ve PTT Kargo gibi taşıyıcılar web servis dokümanlarını genellikle sözleşmeli müşterilerine verir. Servisler taşıyıcıya göre SOAP (WSDL) ya da REST/JSON olabilir; uç nokta adları, alan adları ve durum kodları taşıyıcıdan taşıyıcıya değişir ve zamanla güncellenir. Bu yüzden bu yazıda hiçbir taşıyıcının uç noktasını ya da alan adını vermiyor, ortak deseni anlatıyoruz. Aras Kargo da entegrasyon sayfasında ayrıntılar için satış ya da müşteri temsilcisine yönlendiriyor. Sözleşme aşamasında güncel entegrasyon dokümanını, test hesabını, etiket şartnamesini ve durum kodu listesini birlikte isteyin.

Entegrasyon seçenekleri: doğrudan API, kargo entegratörü, pazaryeri, panel​

SeçenekNe zaman uygun?Güçlü yanıDikkat edilecekler ve maliyet kalemleri
Doğrudan taşıyıcı API'siBir ya da iki taşıyıcı, düzenli hacim, ekipte geliştirici varSözleşme fiyatı ve verinin tamamı doğrudan sizde; aracı ücreti yokHer taşıyıcı için ayrı kimlik doğrulama, durum kodu, etiket biçimi ve bakım; bazı taşıyıcılarda IP kısıtlaması
Kargo entegratörü (çok taşıyıcılı aracı)Birden çok taşıyıcı, hızlı başlangıç, sınırlı geliştirici kapasitesiTek API, tek etiket biçimi, normalize edilmiş durumlar; bazılarında entegratörün kendi anlaşmalı fiyatlarıGönderi başına ücret ya da abonelik; ek bir bağımlılık; kişisel veriler üçüncü bir taraftan geçer (KVKK kapsamında veri işleyen sözleşmesi)
Pazaryeri anlaşmalı kargoPazaryerinden gelen siparişlerAyrı kargo sözleşmesi gerekmez; barkodu pazaryeri üretirYalnızca o pazaryerinin siparişlerinde geçerli; etiket, takip ve iade pazaryerinin kurallarıyla yürür; ücret genellikle hakedişinizden düşülür
Taşıyıcı paneli ve toplu yükleme (Excel/CSV)Düşük hacim, geliştirici yokKod gerektirmez, aynı gün başlanırElle veri girişi hataları; takip bilgisi sisteminize kendiliğinden dönmez; personel zamanı
Seçimi şu ölçütler belirler:
  • Hacim ve tepe noktası: Günlük ortalama kadar kampanya günlerindeki tepe hacim de önemlidir; panelden elle giriş tam o günlerde tıkanır.
  • Taşıyıcı sayısı: Tek taşıyıcıya bağlı kalan işletme, o taşıyıcının yoğunluk ya da arıza gününde onunla birlikte durur. İleride ikinci bir taşıyıcı ekleyecekseniz iç veri modelinizi şimdiden taşıyıcıdan bağımsız kurun.
  • Geliştirici kapasitesi: Doğrudan entegrasyonun asıl maliyeti ilk yazım değil, taşıyıcı servis sürümünü, durum kodlarını ya da etiket şablonunu değiştirdiğinde yapılan bakımdır.
  • Etiketin basıldığı yer: Termal yazıcılı bir paketleme masası ZPL ister; ofis yazıcısıyla çalışan küçük bir ekip için PDF yeterlidir.
  • Tahsilatlı gönderi ve iade: İkisi de taşıyıcıyla ayrı sözleşme ve ek alanlar gerektirir. Entegratörün ya da e-ticaret platformunuzun kargo modülünün bunları destekleyip desteklemediğini baştan sorun.
Pratikte birçok işletme karma bir düzenle çalışır: Pazaryeri siparişleri pazaryerinin barkoduyla, kendi sitesinin siparişleri doğrudan API ya da entegratör üzerinden gider. Bu durumda bile siparişin geldiği kanala bakmadan tek bir iç gönderi modeli tutmak raporlamayı ve müşteri hizmetlerini sadeleştirir. Webhook, REST, kuyruk ve iPaaS gibi genel entegrasyon desenleri için tedarikçiye bağımlı kalmadan temiz web platform entegrasyonu konumuza bakabilirsiniz.

Uçtan uca akış: siparişten mutabakata​

  1. Sipariş onaylanır. Kartla ödenen siparişte ödeme onayı, kapıda ödemeli siparişte sipariş teyidi tetikleyicidir. Gönderi oluşturma isteğini ödeme sayfasının içinde değil, bir iş kuyruğunda çalıştırın; taşıyıcının servisi yavaşladığında müşteri beklemesin.
  2. Paket hazırlanır. Koli ölçüleri ve ağırlık ya paketleme masasında ölçülür ya da koli ana verisinden gelir. Sipariş birden fazla pakete bölünüyorsa her paket bir sıra numarası alır.
  3. Gönderi oluşturulur. Tipik içerik: gönderici (müşteri ya da sözleşme kodunuz), alıcı adı, cep telefonu, il, ilçe, mahalle ve açık adres, parça sayısı, her parçanın desisi ve kilogramı, ödeme tipi (gönderici ödemeli ya da alıcı ödemeli), varsa tahsilat tutarı ve sizin referans numaranız. Bazı taşıyıcılar fatura ya da irsaliye numarası, içerik açıklaması gibi ek alanlar da ister.
  4. Barkod ve etiket gelir. Yanıtta taşıyıcıya göre bir takip numarası, parça barkodları ve PDF, ZPL ya da görüntü biçiminde etiket bulunur. Bazı yöntemlerde etiketi, taşıyıcının verdiği şablon ve numaralarla siz üretirsiniz.
  5. Paket teslim edilir. Kurye paketi depodan alır (adresten alım) ya da paket şubeye bırakılır. Adresten alımda taşıyıcı bir belge düzenler; bu belge DHL eCommerce'in sözlüğünde Ambar Tesellüm Fişi, Sürat Kargo'nun terimlerinde Kargo Kabul Formu olarak geçer. Belgeyi o gün oluşturduğunuz gönderi listesiyle karşılaştırın. Gönderi, taşıyıcının ilk kabul okutmasından sonra yola çıkmış sayılır; o ana kadar yalnızca oluşturulmuş bir kayıttır.
  6. Takip olayları işlenir. Kabul, transfer merkezi, varış şubesi, dağıtımda, teslim edildi; ya da teslim edilemedi, şubede bekliyor, iade yolunda. Her olay bir iç duruma çevrilir ve gerekiyorsa müşteriye bildirilir.
  7. Gönderi kapanır. Teslimde sipariş tamamlanır; göndericiye iade edilen pakette stok ve geri ödeme süreci başlar.
  8. Mutabakat yapılır. Taşıyıcının faturasındaki her satır (desi, kilogram, ek hizmetler, tutar) sizin hesapladığınız beklenen ücretle; tahsilatlı gönderilerde hesabınıza geçen tutar, teslim edilen gönderilerle karşılaştırılır.

Veri modeli: gönderi tablosu, idempotency anahtarı, durum eşleme ve olay günlüğü​

Tek bir taşıyıcıyla çalışsanız bile iç modelinizi taşıyıcıdan bağımsız kurun ve taşıyıcıya özgü her şeyi bir adaptör katmanında tutun. Üç kimliği birbirine karıştırmayın: sizin referans numaranız (sipariş no + paket sırası), taşıyıcının takip numarası ve parça barkodları. Hepsini metin (string) olarak saklayın. Sayıya çevrilen değerler baştaki sıfırları kaybeder; uzunluk ve biçim de taşıyıcıya göre değişir (örneğin Sürat Kargo takip numarasını, faturada yer alan 14 haneli numara olarak tanımlıyor; başka taşıyıcılarda biçim farklıdır).

Idempotency anahtarı: Bu anahtar, aynı istek tekrarlandığında ikinci bir kayıt açılmasını önler. Gönderi oluşturma çağrısı zaman aşımına uğradığında kayıt taşıyıcı tarafında oluşmuş olabilir; körlemesine yeniden denemek aynı paket için ikinci bir barkod, bazen de faturada ikinci bir satır demektir. Sipariş no + paket sırası değerini (örneğin SIP-104233-1) kendi tablonuzda benzersiz anahtar yapın ve taşıyıcıya referans alanında gönderin. Yeniden denemeden önce bu referansla sorgulayın; taşıyıcı referansla sorgulamayı desteklemiyorsa durumu belirsiz kalan kayıtları elle kontrol kuyruğuna alın. Taşıyıcının aynı referansla gelen ikinci isteği reddedip reddetmediğini test ortamında deneyerek öğrenin.

SQL:
-- PostgreSQL örneği; tablo ve alan adları bizim modelimizdir, bir taşıyıcının değil
CREATE TABLE shipments (
  id              bigserial PRIMARY KEY,
  order_id        text NOT NULL,
  package_seq     int  NOT NULL,
  idempotency_key text NOT NULL UNIQUE,   -- 'SIP-104233-1'
  carrier         text NOT NULL,
  tracking_number text,                   -- metin: baştaki sıfırlar korunur
  status          text NOT NULL DEFAULT 'DRAFT',
  cod_amount      numeric(12,2),          -- para için float değil
  expected_charge numeric(12,2),
  created_at      timestamptz NOT NULL DEFAULT now(),
  UNIQUE (carrier, tracking_number)
);

CREATE TABLE carrier_status_map (
  carrier         text NOT NULL,
  carrier_code    text NOT NULL,          -- taşıyıcının durum kodu ya da metni
  internal_status text NOT NULL,          -- IN_TRANSIT, DELIVERED ...
  is_terminal     boolean NOT NULL DEFAULT false,
  notify_customer boolean NOT NULL DEFAULT false,
  PRIMARY KEY (carrier, carrier_code)
);

CREATE TABLE shipment_events (
  id           bigserial PRIMARY KEY,
  shipment_id  bigint NOT NULL REFERENCES shipments(id),
  carrier_code text NOT NULL,
  event_time   timestamptz NOT NULL,
  location     text,
  raw          jsonb NOT NULL,            -- ham yanıt: itiraz ve hata ayıklama için
  UNIQUE (shipment_id, carrier_code, event_time)
);
Çok parçalı gönderide parçaların ölçü, ağırlık ve barkodlarını ayrı bir tabloda tutun. Olay tablosu yalnızca ekleme yapılan (append-only) bir günlüktür: Taşıyıcının ham yanıtını saklamak, bir desi itirazında ya da "kargom nerede" şikâyetinde elinize kanıt verir. Durum eşleme tablosu, taşıyıcının kodlarını iç durumlarınıza çevirir:
Taşıyıcıda tipik ifade (örnek)İç durumSon durum mu?Müşteriye bildirim
Kayıt oluşturuldu, kargo henüz teslim alınmadıCREATEDHayırHayır
Kargo teslim alındı, çıkış şubesindeHANDED_OVERHayırEvet, takip bağlantısıyla
Transfer merkezinde, yoldaIN_TRANSITHayırHayır
Dağıtıma çıktı, kuryedeOUT_FOR_DELIVERYHayırEvet
Teslim edilemedi, ertesi güne kaldı (devir)DELIVERY_FAILEDHayırEvet, nedeniyle
Şubede alıcıyı bekliyorAWAITING_PICKUPHayırEvet, şube adresiyle
Teslim edildiDELIVEREDEvetEvet
Göndericiye iade yolunda / iade edildiRETURNING / RETURNEDYalnızca RETURNEDİç ekibe
Eşleme tablosunda karşılığı olmayan bir kod geldiğinde olayı atmayın; UNKNOWN olarak kaydedip alarm üretin. Taşıyıcı yeni bir durum kodu eklediğinde bunu ilk böyle fark edersiniz. Aşağıdaki nesne bizim normalize gönderi modelimizdir, herhangi bir taşıyıcının API şeması değildir; adaptör, taşıyıcının yanıtını bu biçime çevirir:
JSON:
{
  "idempotency_key": "SIP-104233-1",
  "order_id": "SIP-104233",
  "package_seq": 1,
  "carrier": "carrier_a",
  "service": "standard",
  "payment_type": "sender_pays",
  "cod": { "amount": "1249.90", "currency": "TRY", "method": "cash_or_card" },
  "receiver": {
    "name": "Ayşe Yılmaz",
    "phone_e164": "+905321234567",
    "province": "Bursa",
    "district": "Nilüfer",
    "neighbourhood": "Görükle",
    "address_line": "Örnek Sok. No: 12 D: 5"
  },
  "parcels": [
    { "seq": 1, "length_cm": 40, "width_cm": 30, "height_cm": 25,
      "weight_kg": "6.0", "desi": "10", "barcode": null }
  ],
  "tracking_number": null,
  "label": { "format": "zpl", "dpi": 203, "storage_key": null },
  "status": "CREATED",
  "status_at": "2026-10-27T09:14:05+03:00",
  "expected_charge": { "amount": null, "currency": "TRY", "tariff_version": "2026-10" }
}

Adres kalitesi: il, ilçe, mahalle, telefon ve alan uzunlukları​

Teslim edilemeyen gönderilerin sık görülen bir nedeni, ödeme sayfasında serbest metin olarak alınan adrestir. Sorunların çoğu gönderi oluşturulmadan önce yakalanabilir:
  • İl ve ilçe: Serbest metin yerine açılır listeden seçtirin ve listeyi taşıyıcının kabul ettiği il/ilçe listesiyle eşleyin. Taşıyıcının tanımadığı bir ilçe adı ya gönderi oluşturma hatası verir ya da paketi yanlış şubeye gönderir.
  • Eski "Merkez" ilçeleri: 6360 sayılı Kanun'la (2012) büyükşehir yapılan bazı illerde "Merkez" ilçesi kaldırıldı; örneğin Balıkesir'in merkezi Karesi ve Altıeylül adlı iki ilçeye bölündü. Müşteri "Balıkesir / Merkez" yazdıysa tahmin yürütmeyin; mahalleye göre doğru ilçeyi seçtirin ya da kaydı kontrole alın. Büyükşehir olmayan illerde "Merkez" hâlâ geçerli bir ilçe adıdır; kontrolü bu yüzden il bazındaki listeyle yapın.
  • Türkçe karakter ve büyük-küçük harf: "Şişli", "SISLI" ve "sisli" aynı ilçedir. Python'da "Şişli".upper() sonucu "ŞIŞLI" olur, "İ".lower() ise iki karakterlik bir dize döndürür. Karşılaştırmayı bu yüzden Türkçe kurallarını bilen bir katlama (folding) fonksiyonuyla yapın.
  • Mahalle: "Mah." ve "Mh." kısaltmalarını ve "Mahallesi" sözcüğünü atarak karşılaştırın. Doğru mahalle, doğru ilçeyi ve doğru dağıtım şubesini bulmanın en güvenilir yoludur.
  • Posta kodu: Beş hanelidir ve ilk iki hanesi il plaka kodudur (Bursa için 16). Posta kodu ile il uyuşmuyorsa adresi işaretleyin.
  • Telefon: Cep numarasını içeride E.164 biçiminde (+905XXXXXXXXX) saklayın, taşıyıcıya dokümanda istenen biçimde (başında 0 ile, 0 olmadan ya da +90 ile) gönderin. Geçersiz numara, SMS bildiriminin gitmemesi ve kuryenin alıcıya ulaşamaması demektir.
  • Alan uzunlukları: Doküman ad, adres ve açıklama alanları için en fazla karakter sayısını tanımlar. Sondan kırpılan bir adres, Türk adreslerinin sonunda duran "No: 12 D: 5" kısmını kaybeder ve paket kapıya ulaşmaz. Göndermeden önce uzunluğu doğrulayın; kısaltmanız gerekiyorsa sayıları değil, "Mahallesi → Mah.", "Caddesi → Cad.", "Sokak → Sok." gibi sözcükleri kısaltın.
Python:
import re
import unicodedata

ASCII_FOLD = str.maketrans("çğıöşü", "cgiosu")

def tr_lower(s: str) -> str:
    # str.lower() Türkçe I/İ kuralını bilmez; önce bu iki harfi elle çeviriyoruz
    return s.replace("I", "ı").replace("İ", "i").lower()

def key(s: str) -> str:
    """Karşılaştırma anahtarı: Türkçe küçük harf, ASCII'ye katlama, 'Mah.' gibi ekleri atma."""
    s = unicodedata.normalize("NFC", s).strip()
    s = tr_lower(s).translate(ASCII_FOLD)
    s = re.sub(r"\b(mahallesi|mah|mh)\b\.?", " ", s)
    return re.sub(r"[^a-z0-9]+", " ", s).strip()

# Taşıyıcının kabul ettiği il/ilçe listesinden doldurulur (burada kısaltılmış örnek)
DISTRICTS = {
    key("Bursa"): ["Nilüfer", "Osmangazi", "Yıldırım", "Gemlik"],
    key("Balıkesir"): ["Karesi", "Altıeylül", "Bandırma"],
}

def match_district(province: str, raw: str):
    hits = [d for d in DISTRICTS.get(key(province), []) if key(d) == key(raw)]
    return hits[0] if len(hits) == 1 else None   # None: elle kontrol kuyruğuna

def tr_mobile_e164(raw: str):
    d = re.sub(r"\D", "", raw)
    for prefix in ("0090", "90", "0"):
        if d.startswith(prefix) and len(d) - len(prefix) == 10:
            d = d[len(prefix):]
            break
    return "+90" + d if len(d) == 10 and d.startswith("5") else None

print(match_district("BURSA", "NILUFER"))     # Nilüfer
print(match_district("Balıkesir", "Merkez"))  # None: mahalleye göre Karesi ya da Altıeylül
print(tr_mobile_e164("0 (532) 123 45 67"))    # +905321234567
print(tr_mobile_e164("+90 224 123 45 67"))    # None: sabit hat, SMS gitmez

Desi hesaplama: formül, yuvarlama ve fiyatı belirleyen kalemler​

Desi, paketin hacimsel ağırlığıdır. Yurt içi gönderilerde yaygın formül şudur:
Kod:
desi = en (cm) x boy (cm) x yükseklik (cm) / 3000
faturalanan değer = max(desi, gerçek ağırlık kg), tarifedeki adıma yukarı yuvarlanır
Sürat Kargo'nun fiyat hesaplama sayfası ve DHL eCommerce'in kargo terimleri sözlüğü yurt içi için 3000 bölenini veriyor. Sürat ayrıca kilogram ile desinin karşılaştırılıp yüksek olanın fiyatlandırıldığını ve çok parçalı gönderilerde hesabın her parça için ayrı yapıldığını yazıyor. Yurt dışında bölen değişiyor: Sürat 5000, DHL eCommerce'in sözlüğü 6000 veriyor; DHL Express de hacimsel ağırlığı 5000 ile hesaplıyor. Küçük paket sınıfları da farklı: DHL eCommerce'te Mİ (manifesto içi) sınıfı 0-1 kg/ds paketleri kapsarken Sürat aynı adı 2 desiden küçük paketler için kullanıyor. Kısacası bölen, yuvarlama adımı (tam desi ya da yarım desi), asgari değer ve sınıf sınırları taşıyıcıya, hizmete ve sözleşmenize göre değişir; desi hesaplamanızı bu değerleri parametre alacak biçimde kurun.

Çözümlü örnek: 40 x 30 x 25 cm bir koli 30.000 cm³ eder; 3000'e bölündüğünde 10 desi. İçindeki ürün 6 kg ise faturalanan değer 10'dur, yani 4 desilik havanın parasını ödüyorsunuz. Aynı ürün 35 x 30 x 20 cm bir koliye sığıyorsa 21.000 / 3000 = 7 desi olur ve faturalanan değer yüzde 30 düşer. Tersi de olabilir: 25 x 20 x 15 cm koli 2,5 desidir, ama içindeki ürün 8 kg geldiği için 8 üzerinden faturalanır. Yuvarlamanın etkisi için 30 x 20 x 11 cm koliye bakın: 2,2 desi, tam desiye yukarı yuvarlayan tarifede 3, yarım desi adımında 2,5 olur.

Fiyatı yalnızca desi belirlemez. Sürat, ücretin alım ve teslim noktaları arasındaki kilometre mesafesine ve adresten alım ya da adrese teslim yapılıp yapılmadığına göre de değiştiğini belirtiyor. Tahsilat bedeli ve adresten alım gibi ek hizmetler sözleşmenize göre ayrıca faturalanabilir. Aşağıdaki küçük hesaplayıcı bu kuralları parametre olarak alır:
Python:
from fractions import Fraction
from math import ceil

def F(x):
    return Fraction(str(x))  # 0.1 gibi değerlerde kayan nokta hatası olmasın

def round_up(value, step):
    step = F(step)
    return ceil(value / step) * step

def desi(length_cm, width_cm, height_cm, divisor=3000):
    return F(length_cm) * F(width_cm) * F(height_cm) / divisor

def billable(length_cm, width_cm, height_cm, weight_kg, divisor=3000, step=1, minimum=1):
    """Tek parça için faturalanan değer: max(desi, kg), tarifedeki adıma yukarı yuvarlanır."""
    d = desi(length_cm, width_cm, height_cm, divisor)
    return d, max(round_up(max(d, F(weight_kg)), step), F(minimum))

# Çok parçalı gönderide her parça ayrı hesaplanır
for parca in [(40, 30, 25, 6), (35, 30, 20, 6), (25, 20, 15, 8), (30, 20, 11, 1.2)]:
    for step in (1, 0.5):
        d, b = billable(*parca, step=step)
        print(parca, f"desi={float(d):.2f}", f"adım={step}", f"faturalanan={float(b):g}")
Ambalaj tarafında yapılabilecekler:
  • Az sayıda standart koli boyutu tanımlayın ve WMS'te ürüne sığan en küçük koliyi önerin.
  • Boşluğu dolgu malzemesiyle doldurmak yerine ürüne yakın ölçüde koli kullanın; şişkin bir koli ölçüde birkaç santim, faturada birkaç desi demektir.
  • Taşıyıcı paketi kabulde ya da aktarma merkezinde yeniden ölçebilir. Hangi ölçümün esas alınacağı ve itiraz süresi sözleşmenizde yazılı olsun.
  • Sık gönderilen ürünlerin koli ölçülerini ana veride tutun ve paketleme masasında ara ara kontrol edin.

Kargo barkodu yazdırma: PDF mi ZPL mi, termal yazıcı ve toplu basım​

Taşıyıcılar etiketi genellikle iki yoldan biriyle verir: yanıtla birlikte hazır bir etiket (PDF, ZPL ya da görüntü) veya sizin basacağınız barkod numarası ile etiket şartnamesi. Aras Kargo entegrasyon seçenekleri arasında "sevkiyat etiketinin müşteri tarafından üretilmesi"ni ayrıca sayıyor; DHL eCommerce de "self barkod" adıyla gönderenin barkodlu gönderi formunu kendisinin ürettiği bir yöntem sunuyor. Etiketi kendiniz üretiyorsanız şartnameye harfiyen uyun ve canlıya geçmeden önce test etiketlerini taşıyıcının el terminaliyle okutun.
ÖlçütPDFZPL
YazıcıHer yazıcı: lazer, mürekkep püskürtmeli, sürücüsü olan termalZebra ve ZPL uyumlu termal yazıcılar
Basım yoluTarayıcının ya da işletim sisteminin yazdırma penceresiHam (raw) veri: yerel ajan, TCP 9100 portu, CUPS raw
Toplu basımSayfa işleme ve ölçekleme büyük partilerde yavaşlatırYazıcı komutları kendisi işler; toplu basımda hızlıdır
Tipik hata"Sayfaya sığdır" ölçeklemesi barkodu okunmaz hâle getirirÇözünürlük uyuşmazlığı: 203 dpi için hazırlanmış etiket 300 dpi yazıcıda küçük çıkar
Termal yazıcılarda iki yaygın çözünürlük vardır: 203 dpi (milimetrede 8 nokta) ve 300 dpi (milimetrede 12 nokta). ZPL koordinatları varsayılan olarak nokta (dot) cinsindendir; 100 mm genişliğindeki bir etiket 203 dpi'da 800, 300 dpi'da yaklaşık 1200 noktadır. Taşıyıcıdan yazıcınızın çözünürlüğüne uygun şablonu isteyin. Zebra'nın ^MU komutu 200 dpi için hazırlanmış bir formatı 300 dpi'a çevirebilir, ama sonucu her zaman okutarak doğrulayın. Kargo etiketlerinde çoğunlukla şeritsiz, direkt termal etiket kullanılır; etiket boyutunu (10 x 10 cm ya da 10 x 15 cm gibi) taşıyıcının şartnamesinden alın.

Aşağıdaki ZPL yalnızca yapıyı gösteren genel bir örnektir; gerçek etiketin düzeni, barkod sembolojisi ve içeriği taşıyıcının şartnamesinden gelir. ^CI28 UTF-8 kodlamasını seçer; Zebra'nın belgesine göre bu değer V60.14.x, V50.14.x ve sonraki firmware sürümlerinde desteklenir. Türkçe harflerin (ğ, ş, ı, İ) doğru basıldığını kendi yazıcınızda mutlaka deneyin.
Kod:
^XA
^CI28
^PW800
^LL800
^FO30,30^A0N,32,32^FDGönderen: Örnek Ticaret A.Ş.^FS
^FO30,72^A0N,26,26^FB740,2,0,L,0^FDOrganize Sanayi Bölgesi, Nilüfer / BURSA^FS
^FO30,140^GB740,3,3^FS
^FO30,165^A0N,40,40^FDAlıcı: Ayşe Yılmaz^FS
^FO30,220^A0N,30,30^FB740,3,0,L,0^FDGörükle Mah. Örnek Sok. No: 12 D: 5 Nilüfer / BURSA^FS
^FO30,335^A0N,30,30^FDParça: 1/1   Desi: 10   Ödeme: Gönderici^FS
^FO30,390^GB740,3,3^FS
^FO100,430^BY3^BCN,180,Y,N,N^FD123456789012^FS
^FO30,720^A0N,28,28^FDRef: SIP-104233-1^FS
^XZ
Basım yolları:
  • Tarayıcıdan PDF: En kolay yoldur. Yazdırma penceresinde ölçeği yüzde 100'e ("gerçek boyut") alın, kâğıt boyutunu etiket boyutuna ayarlayın, üst ve alt bilgiyi kapatın.
  • Yerel yazdırma ajanı: Tarayıcı ZPL'yi yazıcıya kendi başına gönderemez. QZ Tray gibi bir ajan ya da Zebra'nın Browser Print aracı paketleme bilgisayarında çalışır; web uygulaması yerel bir bağlantı üzerinden ham veriyi yazıcıya iletir.
  • Sunucudan ağ yazıcısına: Zebra ağ yazıcıları ham veriyi TCP 9100 portundan kabul eder; depo ağında sunucu etiketi doğrudan yazıcıya gönderebilir.
Bash:
# Ağdaki Zebra yazıcıya ham ZPL gönderme (IP adresi örnektir)
nc -w 3 192.168.10.50 9100 < etiket.zpl

# CUPS kuyruğu üzerinden filtrelemeden (raw) gönderme
lp -d depo_zebra -o raw etiket.zpl
Toplu basımda etiketleri paketleme sırasına göre dizin ve tek bir birleşik PDF ya da art arda eklenmiş bir ZPL akışı olarak gönderin. Yalnızca gönderisi başarıyla oluşturulan paketler için basın; paketleme masasında etiket barkodunu sipariş barkoduyla birlikte okutarak eşleşmeyi doğrulayın. Yeniden basımda saklanan etiketi kullanın, yeni gönderi oluşturmayın. Bir pakete yeni etiket yapıştırıyorsanız eskisini mutlaka sökün: Taşıyıcı sözlüklerinde "çapraz kargo" diye geçen durum, paketin üzerinde başka bir gönderinin barkodu bulunduğu için yanlış varış merkezine gitmesidir.

Kargo takip entegrasyonu: sorgulama sıklığı, webhook ve takılan gönderiler​

Taşıyıcıların çoğu takip için sorgulama (polling) servisi sunar; bazı taşıyıcılar ve entegratörler durum değişikliklerini sizin verdiğiniz bir adrese anlık bildirim (push, webhook) olarak da gönderebilir. Hangisini kullanırsanız kullanın, doğruluk kaynağı (source of truth) sizin olay günlüğünüzdür.
Gönderi durumuBaşlangıç aralığıNot
Oluşturuldu, kabul okutması yok2-4 saatte bir24 saat geçtiyse depoya uyarı: Paket teslim edilmemiş olabilir
Yolda (transfer)4-6 saatte birHer transfer olayında müşteriye mesaj atmayın
Varış şubesinde, dağıtımda1-2 saatte bir"Dağıtımda" ve "teslim edilemedi" bildirimleri zamanında gitsin
Teslim edildi, iade tamamlandıSorgu dururGeç gelen düzeltmeler için bir gün sonra son bir kontrol
Hata durumunda üstel geri çekilme (exponential backoff) uygulayın: 1, 2, 4, 8 dakika ve en fazla 60 dakika, araya rastgele sapma (jitter) ekleyerek. Taşıyıcı toplu sorguyu destekliyorsa takip numaralarını gruplayın ve sözleşmedeki istek sınırlarına (rate limit) uyun.

Boyutlandırma örneği: Günde 1.000 gönderi çıkaran ve gönderileri 2-4 gün yolda kalan bir işletmede her an 2.000-4.000 açık gönderi bulunur. Gönderi başına günde 4-6 sorguyla bu, günde 8.000-24.000 takip çağrısı eder. Toplu sorgu ve anlık bildirim bu sayıyı belirgin biçimde düşürür.

Anlık bildirim sunuluyorsa imzayı doğrulayın, hızlıca 200 dönün, asıl işi kuyrukta yapın ve aynı olayın iki kez gelebileceğini varsayın. Güvenli alıcı tasarımını webhook alıcı tasarımı, retry ve audit konusunda ayrıntılı anlattık. Kaçan bildirimleri yakalamak için açık gönderileri günde bir kez yine de sorgulayın.

Müşteri bildirimleri: Dört an çoğu zaman yeterlidir: kargoya verildi (takip bağlantısıyla), dağıtıma çıktı, teslim edilemedi ya da şubede bekliyor (nedeni ve şube bilgisiyle), teslim edildi. Takip bağlantısını taşıyıcının sitesine değil, kendi takip sayfanıza verin. Örneğin mngkargo.com.tr bugün dhlecommerce.com.tr'ye yönleniyor; marka ya da adres değişikliklerinde eski e-postalardaki bağlantılar sizin kontrolünüzde olmaz. Telefon ihbarlı gönderiler şubede sınırlı bir süre bekletilir (DHL eCommerce'in sözlüğünde en fazla 3 gün), sonra göndericiye döner; "şubede bekliyor" bildirimini bu yüzden atlamayın. Kargo durum mesajlarına kampanya içeriği eklerseniz mesaj ticari elektronik ileti sayılabilir ve İYS'de kayıtlı onay gerektirebilir; metinleri hukuk ekibinizle netleştirin. Satın alma sonrası deneyimin müşteri tarafı için kargo entegrasyonu ve iadeler konumuza bakın.

Takılan gönderi alarmları (başlangıç eşikleri):
  • Oluşturulduktan sonra 24 saat içinde kabul okutması almayan gönderi: Paket depoda kalmış ya da etiket düşmüş olabilir.
  • Yolda 48-72 saattir yeni olay almayan gönderi.
  • Art arda iki "teslim edilemedi" olayı: Adres ya da telefon büyük olasılıkla hatalıdır, müşteriyi arayın.
  • Şubedeki bekleme süresinin sonuna yaklaşan gönderi.
Eşikleri bölgeye göre ayarlayın. Aras Kargo'nun "mobil alan", Sürat Kargo'nun "mobil dağıtım alanı" dediği yerlere her gün değil, haftanın belirli günlerinde hizmet verilir; bu adreslerde gecikme alarmı daha geç çalışmalıdır.

İade kodu oluşturma ve iade gönderisi​

Müşterinin yazıcısı olmadığını varsayın. Türkiye'de yaygın çözüm iade kodudur: Satıcı iade talebini onayladığında taşıyıcının sisteminde (API ya da panel üzerinden) bir iade gönderisi kaydı açar, taşıyıcı bir iade kodu döner ve satıcı bu kodu müşteriye SMS ya da e-postayla iletir. Müşteri paketi şubeye, kargo dolabına ya da anlaşmalı teslim noktasına götürüp kodu verir; etiketi taşıyıcı basar. Örneğin Yurtiçi Kargo, iade koduyla şubelerinin yanı sıra akıllı kargo dolaplarından ve anlaşmalı esnaftan oluşan teslim noktalarından da iade kabul ettiğini duyuruyor; diğer taşıyıcıların benzer ürünlerini temsilcinize sorun.
  • Bağlantı: İade gönderisini ayrı bir kayıt olarak tutun ama orijinal siparişe ve orijinal gönderiye bağlayın (örneğin return_of_shipment_id ve rma_id alanlarıyla). İade gönderisinde gönderici müşteri, alıcı sizin deponuzdur; takip olayları aynı akıştan geçer.
  • Ödeme tipi: İade, sözleşmenizdeki iade ürünüyle ya da sözleşme kodunuzla alıcı ödemeli gider. Müşteri paketi kodsuz ve "ücret alıcılı" gönderirse taşıyıcı, sözleşme fiyatınız yerine standart tarifesini uygulayabilir.
  • Kodun ömrü: Kodun bir geçerlilik süresi olup olmadığını ve kullanılmayan kodun nasıl iptal edildiğini dokümandan öğrenin; süresi dolan kod için müşteriye yenisini üretin.
  • Kimlik: Kargo kabulünde göndericinin kimlik ve iletişim bilgilerinin alınması yasal zorunluluktur; DHL eCommerce'in sözlüğü bu konuda 5549 sayılı Kanun'a ve 2016 tarihli bir BTK kararına atıf yapıyor. İade talimatına "şubede kimlik bilgisi istenecektir" notunu ekleyin.
  • Kapanış: İade gönderisi deponuza teslim edildiğinde ürün kontrolünü ve geri ödeme sürecini tetikleyin. İade politikası, süreler ve iade kargo ücretini kimin ödeyeceği kargo entegrasyonunun değil, iade sürecinin konusudur; bunları Return Flow alt forumunda ele alıyoruz.

Tahsilatlı kargo (kapıda ödeme, COD)​

Tahsilatlı gönderide taşıyıcı ürün bedelini teslim sırasında alıcıdan tahsil eder ve sözleşmedeki takvime göre hesabınıza aktarır. Aras, Sürat ve DHL eCommerce bu hizmet için ayrıca sözleşme şart koşuyor; Aras nakit ve kredi kartıyla tahsilattan söz ediyor. Entegrasyonda dikkat edilecek noktalar:
  • Alanlar: Tahsilat tutarı, para birimi ve tahsilat tipi (nakit, kart). Tutarı kayan noktalı sayı (float) olarak değil, ondalık ya da kuruş cinsinden tam sayı olarak tutun; kapıda ödeme hizmet bedeli alıyorsanız tutara dahil edin.
  • Tutar değişikliği: Gönderi oluşturulduktan sonra sepet değişirse tahsilat tutarının nasıl güncelleneceğini (güncelleme mi, iptal edip yeniden oluşturma mı) dokümandan öğrenin.
  • Çok parçalı gönderi: Tahsilatın hangi parçaya bağlandığı ve kısmi teslimde ne olacağı taşıyıcıya göre değişir; test ortamında deneyin.
  • Mutabakat: Taşıyıcının tahsilat raporundaki her satırı takip numarası üzerinden siparişle eşleyin. Teslim edildiği hâlde parası gelmeyen, eksik gelen ve iade edildiği hâlde tahsil edilmiş görünen gönderiler için ayrı bir istisna raporu tutun.
  • Riskler: Kapıda reddedilen gönderi genellikle iki yönlü kargo ücreti doğurur; sahte siparişler bu maliyeti büyütür. Sipariş sonrası SMS ile teyit, kapıda ödeme için tutar sınırı ve sık reddeden müşterilere bu seçeneği kapatmak yaygın önlemlerdir.

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

Taşıyıcıdan isteyin:
  • Güncel entegrasyon dokümanı ve servis sürümü, test ortamı adresi ve test hesabı.
  • IP izin listesi (whitelist) süreci; sunucunuzun sabit bir çıkış IP'si olmalıdır.
  • Durum kodu listesi, etiket şartnamesi ve örnek etiket, istek sınırları, teknik destek kanalı.
Test senaryoları:
  • Tek parça, çok parça, tahsilatlı ve alıcı ödemeli gönderi; uzun adres, Türkçe karakterli ad.
  • Hatalı ilçe ve eksik telefon; zaman aşımından sonra yeniden deneme (aynı referansla ikinci kayıt oluşuyor mu?).
  • Kabulden önce iptal, etiketin yeniden basımı, iade kodu üretimi ve kullanımı.
  • Gerçek yazıcıdan basılan etiketin taşıyıcı şubesinde el terminaliyle okutulması.
Canlıya geçerken:
  • Canlı kimlik bilgileri sır yönetiminde (secret store); test ve canlı ayarları ayrı.
  • Takılan gönderi alarmları, hata oranı ve kuyruk uzunluğu için pano hazır.
  • Taşıyıcı servisi çöktüğünde siparişlerin kuyrukta bekleyeceği ve gerekirse gönderilerin panelden elle açılacağı bir prosedür yazılı.
  • İlk günlerde düşük hacimle başlayın; ilk faturayı satır satır kendi beklentinizle karşılaştırın.
  • Kişisel veriler: Taşıyıcıya ve entegratöre yalnızca gerekli alanları gönderin, günlüklerde (log) telefon ve adresi maskeleyin, kargo firmasıyla paylaşımı KVKK aydınlatma metninizde belirtin.

Sorun giderme​

BelirtiOlası nedenÇözüm
Testte çalışıyor, canlıda yetkilendirme hatasıCanlı kullanıcı adı, şifre ya da müşteri kodu farklı; sunucunun çıkış IP'si izin listesinde değil ya da değiştiOrtam ayarlarını ayırın; sabit çıkış IP'si (NAT ağ geçidi) kullanın ve taşıyıcıya bildirin
Aynı paket için iki barkodZaman aşımından sonra körlemesine yeniden denemeIdempotency anahtarı, yeniden denemeden önce referansla sorgu, fazla kaydı kabulden önce iptal
"İlçe bulunamadı" hatası ya da yanlış şubeye yönlendirmeSerbest metin ilçe, eski "Merkez" adları, Türkçe karakter farkıAçılır liste, taşıyıcı listesiyle eşleme tablosu, eşleşmeyenler için elle kontrol kuyruğu
Etiket okunmuyorPDF ölçeklenmiş, dpi uyuşmazlığı, düşük baskı koyuluğu, barkodun üzerinde parlak bantYüzde 100 ölçek, doğru dpi şablonu, yazıcı koyuluk ayarı; bandı barkodun üzerine yapıştırmayın
Durumlar güncellenmiyorKabul okutması yapılmamış; sorgu işi durmuş; eşleme tablosunda olmayan kod düşürülüyor; webhook imza hatasıKabul alarmı, iş izleme, UNKNOWN durumunda alarm, imza hatalarını günlüğe yazma
Faturada beklenenden yüksek desiBeyan edilen ölçü eski ya da yanlış; şişkin koli; taşıyıcının kendi ölçümü esas alınmışKoli ana verisini düzeltin, paketlemede ölçüp fotoğraflayın, sözleşmedeki süre içinde kanıtla itiraz edin
Tahsilat tutarı hesaba eksik geçtiKesintiler, kısmi teslim, iade edilen gönderiTahsilat raporunu takip numarası üzerinden siparişle eşleyin; farkları taşıyıcıyla gönderi bazında kapatın

Sık sorulan sorular​

Doğrudan API mi, kargo entegratörü mü?
Bir ya da iki taşıyıcıyla, düzenli hacimle çalışıyorsanız ve bakımı üstlenecek bir geliştiriciniz varsa doğrudan API daha az aracı ve daha çok kontrol demektir. Birden çok taşıyıcı, hızlı başlangıç ya da küçük bir ekip söz konusuysa entegratör daha mantıklıdır; gönderi başına ücretini kendi hacminizle çarparak karşılaştırın. İç modeliniz taşıyıcıdan bağımsızsa sonradan geçiş kolaylaşır.

Hangi kargo firması en ucuz?
Genel bir cevabı yok. Fiyat; sözleşmenize, hacminize, gönderilerinizin desi dağılımına, mesafe gruplarına ve ek hizmetlere bağlıdır. Son üç ayın gönderilerini (desi, kg, il) tekliflerdeki tarifelerle yeniden fiyatlayın; en ucuz görünen tarife sizin desi profilinizde pahalı çıkabilir.

Toplu kargo etiketi nasıl basılır?
Etiketleri paketleme sırasına göre tek bir birleşik PDF ya da ZPL akışı olarak gönderin; termal yazıcı ve ZPL toplu basımda belirgin biçimde hızlıdır. Yalnızca başarıyla oluşturulan gönderiler için basın ve paketlemede barkodları okutarak her etiketin doğru siparişe ait olduğunu doğrulayın.

Kargo takibini ne sıklıkla sorgulamalıyım?
Başlangıç olarak yoldaki gönderiler için 4-6 saatte bir, dağıtım günündeki gönderiler için 1-2 saatte bir yeterlidir. Teslim edilen gönderilerde sorguyu durdurun, taşıyıcının istek sınırlarına uyun ve varsa anlık bildirimi tercih edin.

Müşterinin yazıcısı yoksa iade nasıl yapılır?
İade kodu kullanın: Taşıyıcının sisteminde iade kaydı açın ve kodu müşteriye SMS ya da e-postayla gönderin. Müşteri paketi şubeye, kargo dolabına ya da teslim noktasına götürür; etiketi orada taşıyıcı basar.

Sonuç ve sonraki adımlar​

Sağlam bir kargo entegrasyonu üç şeye dayanır: taşıyıcıdan bağımsız bir iç model, temiz adres verisi ve her gönderiyi kapanana kadar izleyen bir olay günlüğü. Etiket, takip, iade ve tahsilat bu temelin üzerine eklenir.
  1. Gönderi profilinizi çıkarın: satış kanalları, günlük hacim ve tepe günler, desi dağılımı, tahsilatlı gönderi ve iade oranı.
  2. Seçeneği belirleyin; taşıyıcıdan entegrasyon dokümanını, test hesabını ve etiket şartnamesini isteyin.
  3. Gönderi, olay ve durum eşleme tablolarını kurun; idempotency anahtarını ilk günden ekleyin.
  4. Ödeme sayfasındaki adres formunu il, ilçe ve mahalle listeleri üzerine yeniden kurun.
  5. Test senaryolarını çalıştırın, etiketi şubede okutun, düşük hacimle canlıya geçin ve ilk faturayı satır satır eşleştirin.
Kargo, ERP ya da pazaryeri entegrasyonunuzda ikinci bir göze ihtiyaç duyarsanız AIOR yazılım mühendisliği ekibi yardımcı olabilir.

Connecting an online store, ERP or warehouse management system (WMS) to a cargo carrier takes more than a single "create shipment" call. Opening a shipment for a paid order, printing the barcode label, handing the parcel to the courier, turning tracking events into customer updates, issuing return codes, matching cash-on-delivery remittances and checking the monthly carrier invoice against your own numbers are all part of the same integration. This guide covers a cargo API integration in Turkey in that order, based on how Turkish carriers actually work.

A caveat first. Carriers such as Yurtiçi Kargo, Aras Kargo, DHL eCommerce (MNG Kargo until May 2025), Sürat Kargo and PTT Kargo usually give their web service documentation only to contracted customers. Depending on the carrier, the services are SOAP (WSDL) or REST/JSON, and endpoint names, field names and status codes differ from carrier to carrier and change over time. So this article names no carrier's endpoints or fields; it describes the common pattern. Aras Kargo's own integration page, for instance, refers you to your sales or customer representative for the details. When you sign, ask for the current integration document, a test account, the label specification and the status code list together.

Integration options: direct API, multi-carrier aggregator, marketplace, carrier panel​

OptionWhen it fitsStrengthWatch out for, and cost drivers
Direct carrier APIOne or two carriers, steady volume, developers in houseContract rates and complete data, no intermediary feeSeparate authentication, status codes, label format and maintenance for each carrier; some carriers restrict access by IP
Multi-carrier aggregator (kargo entegratörü)Several carriers, fast start, limited developer timeOne API, one label format, normalized statuses; some offer their own negotiated ratesPer-label fee or subscription; one more dependency; personal data passes through a third party (a processor agreement under KVKK, Türkiye's data protection law)
Marketplace-managed shippingOrders that come in from a marketplaceNo carrier contract needed; the marketplace issues the barcodeOnly for that marketplace's orders; labels, tracking and returns follow its rules; fees are usually deducted from your payouts
Carrier panel plus bulk upload (Excel/CSV)Low volume, no developerNo code, start the same dayTyping errors; tracking does not flow back into your systems; staff time
What decides it:
  • Volume and peaks: Campaign-day peaks matter as much as the daily average, and manual panel entry breaks down on exactly those days.
  • Number of carriers: A merchant tied to one carrier stops when that carrier is overloaded or down. If you might add a second carrier later, make your internal model carrier-neutral now.
  • Developer capacity: The real cost of a direct integration is not the first build but the maintenance whenever the carrier changes its service version, status codes or label template.
  • Where labels are printed: A packing station with thermal printers wants ZPL; a small team on an office printer is fine with PDF.
  • COD and returns: Both need a separate agreement with the carrier and extra fields. Ask early whether the aggregator, or your store platform's shipping module, supports them.
Many merchants end up with a mix: marketplace orders ship on the marketplace's barcode, while web-shop orders go through a direct API or an aggregator. Even then, one internal shipment model for every sales channel keeps reporting and customer service simple. For general integration patterns (webhooks, REST, queues, iPaaS), see our thread on integrating web platforms without vendor lock-in.

End-to-end flow: from paid order to reconciliation​

  1. The order is confirmed. For card payments the trigger is the payment confirmation; for cash-on-delivery orders it is your order confirmation. Run shipment creation in a job queue, not inside the checkout request, so a slow carrier never keeps a customer waiting.
  2. The parcel is packed. Box dimensions and weight are either measured at the packing station or taken from packaging master data. If an order is split, each package gets a sequence number.
  3. The shipment is created. Typical content: the sender (your customer or contract code), receiver name, mobile number, province (il), district (ilçe), neighbourhood (mahalle) and street address, number of pieces, desi and kilograms per piece, payment type (sender pays or receiver pays), the COD amount if any and your own reference number. Some carriers also ask for an invoice or dispatch note number or a content description.
  4. The barcode and label come back. Depending on the carrier, the response carries a tracking number, piece barcodes and a label as PDF, ZPL or an image. In some setups you render the label yourself from the carrier's template and number range.
  5. The parcel is handed over. A courier collects it from your warehouse (pickup from address) or you drop it at a branch. On a pickup the carrier issues a receipt document, called Ambar Tesellüm Fişi in DHL eCommerce's glossary and Kargo Kabul Formu in Sürat Kargo's; check it against the list of shipments you created that day. A shipment is really on its way only after the carrier's first acceptance scan; until then it is just a record.
  6. Tracking events are processed. Accepted, at a transfer centre, at the delivery branch, out for delivery, delivered; or delivery failed, waiting at the branch, returning. Each event is mapped to an internal status and, where it matters, to a customer message.
  7. The shipment closes. Delivery completes the order; a parcel returned to sender starts the restock and refund process.
  8. Reconciliation. Each line of the carrier invoice (desi, kilograms, extra services, amount) is compared with the expected charge you calculated; for COD, the money remitted to your account is matched against delivered shipments.

Data model: shipments, idempotency key, status mapping, event log​

Even with a single carrier, keep your internal model carrier-neutral and push everything carrier-specific into an adapter layer. Keep three identifiers apart: your reference (order number plus package sequence), the carrier's tracking number and the piece barcodes. Store all of them as strings. Numbers lose their leading zeros, and length and format vary by carrier (Sürat Kargo, for example, defines its tracking number as the 14-digit number printed on its shipping invoice; other carriers use other formats).

Idempotency key: When a create-shipment call times out, the carrier may have created the record anyway. Retrying blindly means a second barcode for the same parcel and sometimes a second invoice line. Make order number plus package sequence (for example SIP-104233-1) a unique key in your own table and send it to the carrier in the reference field. Before retrying, query by that reference; if the carrier cannot search by reference, put the uncertain records into a manual review queue. Find out in the test environment whether the carrier rejects a second request with the same reference.

SQL:
-- PostgreSQL example; table and column names are our own model, not a carrier's
CREATE TABLE shipments (
  id              bigserial PRIMARY KEY,
  order_id        text NOT NULL,
  package_seq     int  NOT NULL,
  idempotency_key text NOT NULL UNIQUE,   -- 'SIP-104233-1'
  carrier         text NOT NULL,
  tracking_number text,                   -- string: keeps leading zeros
  status          text NOT NULL DEFAULT 'DRAFT',
  cod_amount      numeric(12,2),          -- never float for money
  expected_charge numeric(12,2),
  created_at      timestamptz NOT NULL DEFAULT now(),
  UNIQUE (carrier, tracking_number)
);

CREATE TABLE carrier_status_map (
  carrier         text NOT NULL,
  carrier_code    text NOT NULL,          -- the carrier's status code or text
  internal_status text NOT NULL,          -- IN_TRANSIT, DELIVERED ...
  is_terminal     boolean NOT NULL DEFAULT false,
  notify_customer boolean NOT NULL DEFAULT false,
  PRIMARY KEY (carrier, carrier_code)
);

CREATE TABLE shipment_events (
  id           bigserial PRIMARY KEY,
  shipment_id  bigint NOT NULL REFERENCES shipments(id),
  carrier_code text NOT NULL,
  event_time   timestamptz NOT NULL,
  location     text,
  raw          jsonb NOT NULL,            -- raw response: evidence for disputes and debugging
  UNIQUE (shipment_id, carrier_code, event_time)
);
For multi-piece shipments, keep each piece's dimensions, weight and barcode in a separate table. The event table is append-only: storing the carrier's raw response gives you evidence in a desi dispute or a "where is my parcel" complaint. The status mapping table translates carrier codes into your internal statuses:
Typical carrier wording (example)Internal statusTerminal?Customer message
Record created, parcel not collected yetCREATEDNoNo
Parcel accepted, at origin branchHANDED_OVERNoYes, with tracking link
At transfer centre, on the wayIN_TRANSITNoNo
Out for delivery, with courierOUT_FOR_DELIVERYNoYes
Not delivered, carried over to next day (devir)DELIVERY_FAILEDNoYes, with reason
Waiting for the receiver at the branchAWAITING_PICKUPNoYes, with branch address
DeliveredDELIVEREDYesYes
Returning to sender / returnedRETURNING / RETURNEDRETURNED onlyInternal team
When a code arrives that the mapping table does not know, do not drop the event: store it as UNKNOWN and raise an alert. That is how you find out first when a carrier adds a new status code. The object below is our own normalized shipment model, not any carrier's API schema; the adapter converts each carrier response into this shape:
JSON:
{
  "idempotency_key": "SIP-104233-1",
  "order_id": "SIP-104233",
  "package_seq": 1,
  "carrier": "carrier_a",
  "service": "standard",
  "payment_type": "sender_pays",
  "cod": { "amount": "1249.90", "currency": "TRY", "method": "cash_or_card" },
  "receiver": {
    "name": "Ayşe Yılmaz",
    "phone_e164": "+905321234567",
    "province": "Bursa",
    "district": "Nilüfer",
    "neighbourhood": "Görükle",
    "address_line": "Örnek Sok. No: 12 D: 5"
  },
  "parcels": [
    { "seq": 1, "length_cm": 40, "width_cm": 30, "height_cm": 25,
      "weight_kg": "6.0", "desi": "10", "barcode": null }
  ],
  "tracking_number": null,
  "label": { "format": "zpl", "dpi": 203, "storage_key": null },
  "status": "CREATED",
  "status_at": "2026-10-27T09:14:05+03:00",
  "expected_charge": { "amount": null, "currency": "TRY", "tariff_version": "2026-10" }
}

Address quality: province, district, neighbourhood, phone, field lengths​

A common reason for failed deliveries is an address typed as free text at checkout. Most of these problems can be caught before the shipment is created:
  • Province and district (il, ilçe): Use drop-downs instead of free text, and map your list to the carrier's accepted province and district list. A district name the carrier does not recognise either fails shipment creation or routes the parcel to the wrong branch.
  • Old "Merkez" districts: Law No. 6360 (2012) abolished the "Merkez" (central) district in several provinces it made metropolitan; Balıkesir's centre, for example, was split into two districts, Karesi and Altıeylül. If a customer writes "Balıkesir / Merkez", do not guess: let them pick the right district by neighbourhood or send the record for review. In provinces without a metropolitan municipality, "Merkez" is still a valid district, so check against the per-province list.
  • Turkish characters and case: "Şişli", "SISLI" and "sisli" are the same district. In Python, "Şişli".upper() returns "ŞIŞLI" and "İ".lower() returns a two-character string, so compare with a folding function that knows the Turkish rules.
  • Neighbourhood (mahalle): Strip "Mah.", "Mh." and "Mahallesi" before comparing. The right neighbourhood is the most reliable way to find the right district and the right delivery branch.
  • Postal code: Five digits, and the first two are the province's licence plate code (16 for Bursa). Flag the address when the postal code and the province disagree.
  • Phone: Store mobile numbers as E.164 (+905XXXXXXXXX) internally and send them in whatever format the carrier's document asks for (with a leading 0, without it, or with +90). An invalid number means no SMS notification and a courier who cannot reach the receiver.
  • Field lengths: The document sets maximum lengths for name, address and description fields. An address truncated from the end loses the "No: 12 D: 5" part (building and flat number) that Turkish addresses end with, and the parcel never reaches the door. Validate length before sending; if you must shorten, abbreviate words such as "Mahallesi → Mah.", "Caddesi → Cad." and "Sokak → Sok.", never the numbers.
Python:
import re
import unicodedata

ASCII_FOLD = str.maketrans("çğıöşü", "cgiosu")

def tr_lower(s: str) -> str:
    # str.lower() does not know the Turkish I/İ rule, so map those two letters first
    return s.replace("I", "ı").replace("İ", "i").lower()

def key(s: str) -> str:
    """Comparison key: Turkish lower case, ASCII folding, suffixes like 'Mah.' removed."""
    s = unicodedata.normalize("NFC", s).strip()
    s = tr_lower(s).translate(ASCII_FOLD)
    s = re.sub(r"\b(mahallesi|mah|mh)\b\.?", " ", s)
    return re.sub(r"[^a-z0-9]+", " ", s).strip()

# Filled from the carrier's accepted province/district list (shortened example)
DISTRICTS = {
    key("Bursa"): ["Nilüfer", "Osmangazi", "Yıldırım", "Gemlik"],
    key("Balıkesir"): ["Karesi", "Altıeylül", "Bandırma"],
}

def match_district(province: str, raw: str):
    hits = [d for d in DISTRICTS.get(key(province), []) if key(d) == key(raw)]
    return hits[0] if len(hits) == 1 else None   # None: send to the manual review queue

def tr_mobile_e164(raw: str):
    d = re.sub(r"\D", "", raw)
    for prefix in ("0090", "90", "0"):
        if d.startswith(prefix) and len(d) - len(prefix) == 10:
            d = d[len(prefix):]
            break
    return "+90" + d if len(d) == 10 and d.startswith("5") else None

print(match_district("BURSA", "NILUFER"))     # Nilüfer
print(match_district("Balıkesir", "Merkez"))  # None: Karesi or Altıeylül, by neighbourhood
print(tr_mobile_e164("0 (532) 123 45 67"))    # +905321234567
print(tr_mobile_e164("+90 224 123 45 67"))    # None: landline, no SMS

Desi: volumetric weight, rounding and what drives the price​

Desi is the unit Turkish carriers use for volumetric weight. The common domestic formula:
Kod:
desi = length (cm) x width (cm) x height (cm) / 3000
billable = max(desi, actual weight in kg), rounded up to the tariff's step
Sürat Kargo's price calculation page and DHL eCommerce's glossary both use 3000 for domestic shipments. Sürat also states that kilograms and desi are compared and the higher one is priced, and that multi-piece shipments are calculated piece by piece. International divisors differ: Sürat gives 5000, DHL eCommerce's glossary gives 6000, and DHL Express calculates volumetric weight with 5000. Small-parcel classes differ too: in DHL eCommerce's glossary the Mİ (manifesto içi) class covers 0-1 kg/ds parcels, while Sürat uses the same name for parcels under 2 desi. In short, the divisor, the rounding step (whole or half desi), the minimum and the class limits depend on the carrier, the service and your contract, so make them parameters of your desi calculation.

Worked example: A 40 x 30 x 25 cm box is 30,000 cm³, which divided by 3000 gives 10 desi. If the product inside weighs 6 kg, you are billed for 10, so you pay for 4 desi of air. If the product fits a 35 x 30 x 20 cm box, that is 21,000 / 3000 = 7 desi, a 30 percent drop in billable weight. It also works the other way round: a 25 x 20 x 15 cm box is 2.5 desi, but with an 8 kg product inside it is billed at 8. To see what rounding does, take a 30 x 20 x 11 cm box: 2.2 desi becomes 3 on a tariff that rounds up to whole desi and 2.5 on one that uses half-desi steps.

Desi is not the only price driver. Sürat states that the price also depends on the distance in kilometres between the pickup and delivery points, and on whether it collects from and delivers to an address. Extra services such as COD collection and pickup may be billed separately under your contract. The small calculator below takes these rules as parameters:
Python:
from fractions import Fraction
from math import ceil

def F(x):
    return Fraction(str(x))  # avoids floating-point surprises with values like 0.1

def round_up(value, step):
    step = F(step)
    return ceil(value / step) * step

def desi(length_cm, width_cm, height_cm, divisor=3000):
    return F(length_cm) * F(width_cm) * F(height_cm) / divisor

def billable(length_cm, width_cm, height_cm, weight_kg, divisor=3000, step=1, minimum=1):
    """Billable value for one piece: max(desi, kg), rounded up to the tariff step."""
    d = desi(length_cm, width_cm, height_cm, divisor)
    return d, max(round_up(max(d, F(weight_kg)), step), F(minimum))

# In a multi-piece shipment each piece is calculated separately
for parcel in [(40, 30, 25, 6), (35, 30, 20, 6), (25, 20, 15, 8), (30, 20, 11, 1.2)]:
    for step in (1, 0.5):
        d, b = billable(*parcel, step=step)
        print(parcel, f"desi={float(d):.2f}", f"step={step}", f"billable={float(b):g}")
On the packaging side:
  • Define a small set of standard box sizes and have the WMS suggest the smallest one that fits.
  • Use boxes close to the product size instead of filling the space with void fill; a bulging box is a few centimetres on the tape measure and a few desi on the invoice.
  • The carrier may re-measure the parcel at acceptance or at a hub. Your contract should say whose measurement counts and how long you have to dispute.
  • Keep box dimensions for frequently shipped products in master data and spot-check them at the packing station.

Shipping labels: PDF or ZPL, thermal printers and bulk printing​

Carriers usually deliver the label in one of two ways: a ready-made label in the response (PDF, ZPL or an image), or a barcode number plus a label specification for you to print. Aras Kargo lists customer-generated shipping labels (Sevkiyat Etiketinin Müşteri Tarafından Üretilmesi) as a separate integration option, and DHL eCommerce offers a "self barkod" method in which the sender produces the barcoded shipment form. If you render labels yourself, follow the specification to the letter and have the carrier scan your test labels with a handheld terminal before go-live.
CriterionPDFZPL
PrinterAny printer: laser, inkjet, thermal with a driverZebra and ZPL-compatible thermal printers
Print pathBrowser or operating system print dialogRaw data: local agent, TCP port 9100, CUPS raw
Bulk printingRendering and scaling slow down large batchesThe printer interprets the commands itself; fast in bulk
Typical failure"Fit to page" scaling makes the barcode unscannableResolution mismatch: a label designed for 203 dpi prints smaller on a 300 dpi printer
Thermal printers come in two common resolutions: 203 dpi (8 dots per mm) and 300 dpi (12 dots per mm). ZPL coordinates are in dots by default, so a 100 mm wide label is 800 dots at 203 dpi and about 1200 at 300 dpi. Ask the carrier for the template that matches your printer. Zebra's ^MU command can convert a format designed for 200 dpi to 300 dpi, but always verify the result by scanning it. Shipping labels are usually direct thermal, with no ribbon; take the label size (for example 10 x 10 cm or 10 x 15 cm) from the carrier's specification.

The ZPL below is a generic example that only shows the structure; the real layout, barcode symbology and content come from the carrier's specification. ^CI28 selects UTF-8 encoding; according to Zebra's documentation, that value is supported in firmware V60.14.x, V50.14.x and later. Always test on your own printer that Turkish letters (ğ, ş, ı, İ) print correctly.
Kod:
^XA
^CI28
^PW800
^LL800
^FO30,30^A0N,32,32^FDGönderen: Örnek Ticaret A.Ş.^FS
^FO30,72^A0N,26,26^FB740,2,0,L,0^FDOrganize Sanayi Bölgesi, Nilüfer / BURSA^FS
^FO30,140^GB740,3,3^FS
^FO30,165^A0N,40,40^FDAlıcı: Ayşe Yılmaz^FS
^FO30,220^A0N,30,30^FB740,3,0,L,0^FDGörükle Mah. Örnek Sok. No: 12 D: 5 Nilüfer / BURSA^FS
^FO30,335^A0N,30,30^FDParça: 1/1   Desi: 10   Ödeme: Gönderici^FS
^FO30,390^GB740,3,3^FS
^FO100,430^BY3^BCN,180,Y,N,N^FD123456789012^FS
^FO30,720^A0N,28,28^FDRef: SIP-104233-1^FS
^XZ
Ways to print:
  • PDF from the browser: The simplest route. In the print dialog set the scale to 100 percent ("actual size"), set the paper size to the label size and switch off headers and footers.
  • Local print agent: A browser cannot send ZPL to a printer on its own. An agent such as QZ Tray, or Zebra's Browser Print, runs on the packing PC, and the web app passes the raw data to the printer through a local connection.
  • Server to network printer: Zebra network printers accept raw data on TCP port 9100, so on the warehouse network a server can send labels straight to the printer.
Bash:
# Send raw ZPL to a networked Zebra printer (example IP address)
nc -w 3 192.168.10.50 9100 < label.zpl

# Send through a CUPS queue without filtering (raw)
lp -d warehouse_zebra -o raw label.zpl
For bulk printing, sort labels in packing order and send one merged PDF or a concatenated ZPL stream. Print only for parcels whose shipment was created successfully, and at the packing station scan the label barcode together with the order barcode to confirm the match. A reprint uses the stored label; never create a new shipment just to reprint. When you relabel a parcel, remove the old label: what Turkish carrier glossaries call "çapraz kargo" is a parcel that went to the wrong destination because it carried another shipment's barcode.

Shipment tracking integration: polling, webhooks and stuck parcels​

Most carriers offer a query service for tracking; some carriers and aggregators can also push status changes to a URL you provide (push, webhook). Whichever you use, your own event log is the source of truth.
Shipment stateStarting intervalNote
Created, no acceptance scanEvery 2-4 hoursAfter 24 hours, alert the warehouse: the parcel may not have been handed over
In transitEvery 4-6 hoursDo not message the customer on every transfer event
At delivery branch, out for deliveryEvery 1-2 hours"Out for delivery" and "delivery failed" messages must go out on time
Delivered, return completedStopOne last check a day later to catch late corrections
On errors, use exponential backoff: 1, 2, 4, 8 minutes up to a maximum of 60, with random jitter. If the carrier supports batch queries, group tracking numbers, and stay within the rate limits in your contract.

Sizing example: A merchant shipping 1,000 parcels a day, with parcels spending 2-4 days in transit, has 2,000-4,000 open shipments at any moment. At 4-6 queries per shipment per day, that is 8,000-24,000 tracking calls a day. Batch queries and push notifications cut that number sharply.

If push is offered, verify the signature, return 200 quickly, do the real work in a queue and assume the same event may arrive twice. We covered receiver design in detail in secure webhook receivers, retries and audit. Still poll open shipments once a day to catch missed pushes.

Customer notifications: Four moments are usually enough: shipped (with a tracking link), out for delivery, delivery failed or waiting at a branch (with the reason and branch details), delivered. Point the tracking link at your own tracking page rather than the carrier's site. mngkargo.com.tr, for example, now redirects to dhlecommerce.com.tr; when a carrier rebrands or moves its pages, links in old e-mails are out of your control. Phone-notice shipments (telefon ihbarlı), which the receiver collects at the branch, are held for a limited time (at most 3 days in DHL eCommerce's glossary) and then go back to the sender, so do not skip the "waiting at the branch" message. In Türkiye, adding promotional content to a shipping update can turn it into a commercial electronic message that needs consent registered in İYS, the national message management system; agree the wording with your legal team. For the customer side of the post-purchase experience, see shipping integration and returns.

Stuck-shipment alerts (starting thresholds):
  • No acceptance scan within 24 hours of creation: the parcel may still be in the warehouse, or the label fell off.
  • No new event for 48-72 hours while in transit.
  • Two "delivery failed" events in a row: the address or phone number is probably wrong, so call the customer.
  • A parcel nearing the end of its holding period at the branch.
Adjust thresholds by area. Places that Aras Kargo calls "mobil alan" and Sürat Kargo calls "mobil dağıtım alanı" are served on certain days of the week rather than daily, so delay alerts for those addresses should fire later.

Returns: a return code (iade kodu) instead of a printed return label​

Assume the customer has no printer. The common Turkish solution is the return code: when the merchant approves a return, it opens a return shipment record in the carrier's system (through the API or the panel), the carrier returns a code, and the merchant sends that code to the customer by SMS or e-mail. The customer takes the parcel to a branch, a parcel locker or a partner drop-off point and gives the code; the carrier prints the label there. Yurtiçi Kargo, for example, announces that it accepts returns with an iade kodu at its branches as well as at smart parcel lockers and partner shops (Teslim Noktası); ask your representative about the equivalent product at other carriers.
  • Linking: Keep the return shipment as its own record, but link it to the original order and the original shipment (for example with return_of_shipment_id and rma_id fields). On a return, the customer is the sender and your warehouse is the receiver; tracking events run through the same flow.
  • Payment type: The return travels receiver-pays under your contract's return product or your contract code. If the customer ships it without the code as receiver-pays (ücret alıcılı), the carrier may charge its standard tariff instead of your contract rate.
  • Code lifetime: Check in the document whether codes expire and how unused codes are cancelled; issue a new code when one expires.
  • ID at the counter: Turkish carriers are required to record the sender's identity and contact details at acceptance; DHL eCommerce's glossary cites Law No. 5549 and a 2016 decision of the BTK board on this. Add "you will be asked for ID details at the branch" to your return instructions.
  • Closing: When the return is delivered to your warehouse, trigger inspection and the refund. Return policy, deadlines and who pays for return shipping belong to the returns process rather than the cargo integration; we cover them in the Return Flow sub-forum.

Cash on delivery (tahsilatlı gönderi)​

With COD, the carrier collects the price from the receiver at delivery and transfers it to your account on the schedule in your contract. Aras, Sürat and DHL eCommerce all require a separate agreement for this service, and Aras mentions both cash and card collection. Points to cover in the integration:
  • Fields: Collection amount, currency and collection type (cash, card). Store the amount as a decimal or as an integer in kuruş, never as a float; if you charge a COD service fee, include it in the amount.
  • Amount changes: If the basket changes after the shipment is created, find out from the document how the amount is changed (an update, or cancel and recreate).
  • Multi-piece shipments: Which piece carries the collection, and what happens on partial delivery, varies by carrier; test it.
  • Reconciliation: Match each line of the carrier's collection report to the order through the tracking number. Keep a separate exception report for shipments that were delivered but not paid, paid short, or returned yet shown as collected.
  • Risks: A parcel refused at the door usually means shipping costs in both directions, and fake orders multiply that cost. Common safeguards are an SMS confirmation after ordering, an amount limit for COD and switching COD off for customers who refuse repeatedly.

Testing and go-live checklist​

Ask the carrier for:
  • The current integration document and service version, the test environment address and a test account.
  • The IP allow-list procedure; your servers need a static egress IP.
  • The status code list, the label specification and a sample label, rate limits and a technical support channel.
Test cases:
  • Single-piece, multi-piece, COD and receiver-pays shipments; a long address and a name with Turkish characters.
  • A wrong district and a missing phone number; a retry after a timeout (does the same reference create a second record?).
  • Cancellation before acceptance, label reprint, return code creation and use.
  • A label printed on your real printer and scanned at a carrier branch with a handheld terminal.
At go-live:
  • Production credentials in a secret store; test and production settings kept apart.
  • A dashboard for stuck-shipment alerts, error rate and queue length.
  • A written procedure for carrier outages: orders wait in the queue and, if needed, shipments are created by hand in the carrier panel.
  • Start with low volume for the first days and check the first invoice line by line against your expected charges.
  • Personal data: send carriers and aggregators only the fields they need, mask phone numbers and addresses in logs, and name the carrier as a recipient in your KVKK privacy notice.

Troubleshooting​

SymptomLikely causeFix
Works in test, authorization error in productionDifferent production username, password or customer code; the server's egress IP is not on the allow list, or it changedSeparate environment settings; use a static egress IP (NAT gateway) and register it with the carrier
Two barcodes for one parcelA blind retry after a timeoutIdempotency key, query by reference before retrying, cancel the extra record before acceptance
"District not found" or routed to the wrong branchFree-text district, old "Merkez" names, Turkish character differencesDrop-downs, a mapping table to the carrier's list, a manual queue for non-matches
Label will not scanScaled PDF, dpi mismatch, low print darkness, glossy tape over the barcode100 percent scale, the right dpi template, the printer's darkness setting; keep tape off the barcode
Statuses stop updatingNo acceptance scan yet; the polling job stopped; codes missing from the mapping table are dropped; webhook signature failuresAcceptance alert, job monitoring, an alert on UNKNOWN status, logging of signature failures
Invoice shows more desi than expectedDeclared dimensions outdated or wrong; bulging box; the carrier's own measurement appliedFix box master data, measure and photograph at packing, dispute with evidence within the contract's window
COD remittance shortDeductions, partial delivery, a returned shipmentMatch the collection report to orders via tracking number; settle differences shipment by shipment with the carrier

FAQ​

Should I use a direct API or an aggregator?
With one or two carriers, steady volume and a developer who will maintain the integration, a direct API means fewer intermediaries and more control. With several carriers, a need for a quick start or a small team, an aggregator makes more sense; multiply its per-label fee by your volume to compare. A carrier-neutral internal model makes switching later much easier.

Which cargo company is the cheapest?
There is no general answer. Price depends on your contract, your volume, the desi profile of your parcels, distance bands and extra services. Re-price the last three months of your shipments (desi, kg, province) with each offer's tariff; the tariff that looks cheapest can turn out to be the most expensive for your desi mix.

How do I print shipping labels in bulk?
Send labels in packing order as one merged PDF or ZPL stream; thermal printers with ZPL are much faster for bulk runs. Print only for shipments that were created successfully, and scan barcodes at packing to confirm that each label belongs to the right order.

How often should I poll tracking?
As a starting point, every 4-6 hours for parcels in transit and every 1-2 hours on delivery day. Stop polling delivered shipments, respect the carrier's rate limits and prefer push notifications where they are available.

How do returns work if the customer has no label printer?
Use a return code: open a return record in the carrier's system and send the code to the customer by SMS or e-mail. The customer drops the parcel at a branch, a locker or a partner point, and the carrier prints the label there.

Conclusion and next steps​

A solid cargo integration rests on three things: a carrier-neutral internal model, clean address data and an event log that follows every shipment until it closes. Labels, tracking, returns and COD build on that base.
  1. Profile your shipping: sales channels, daily volume and peak days, desi distribution, COD and return rates.
  2. Choose the option, then request the integration document, a test account and the label specification from the carrier.
  3. Build the shipment, event and status-mapping tables, with the idempotency key from day one.
  4. Rebuild the checkout address form around province, district and neighbourhood lists.
  5. Run the test cases, have a label scanned at a branch, go live with low volume and reconcile the first invoice line by line.
If you would like a second pair of eyes on a cargo, ERP or marketplace integration, AIOR's software engineering team can help.
 
Son düzenleyen:

Forum istatistikleri

Konular
925
Mesajlar
932
Üyeler
26
En son üye
Jessicawatson

Çevrimiçi üyeler

Şu anda çevrimiçi üye yok.

Öne çıkan içerik

AIOR
AIOR TEKNOLOJİ

Tüm ihtiyaçlarınız için Teklif alın

Hosting · Domain · Sunucu · Tasarım · Yazılım · Mühendislik · Sektörel Çözümler

Teklif al

7/24 Destek · Anında yanıt

Geri
Üst