REST API · JSON · v1

Hepiyiol Tedarikçi Entegrasyon API'si — v1

Bu doküman, Hepiyiol platformunda ürün satan anlaşmalı tedarikçi firmaların (ecza deposu, ilaç/sağlık ürünü tedarikçisi vb.) kendi sistemlerini platforma bağlaması için hazırlanmıştır.

API ile firmanız:

  1. Ürün kataloğunda barkod ile ürün arayabilir,
  2. Kendi ilanlarını (stok, fiyat, miad) düzenli olarak toplu güncelleyebilir veya satıştan kaldırabilir,
  3. Kendisine gelen siparişleri ve faturası henüz yüklenmemiş siparişleri listeleyebilir, onaylayabilir, gerekirse iptal edebilir,
  4. Sipariş detayındaki alıcı TCKN / VKN, vergi dairesi, ticari unvan ve kurumsal/bireysel ayrımına göre e-Fatura veya e-Arşiv kesip siparişe PDF / UBL-XML / HTML / görsel dosya veya harici HTTPS fatura linki yükleyebilir,
  5. Siparişi platformun kargo anlaşmasıyla (DHL eCommerce / MNG Kargo) barkod + etiket oluşturarak gönderebilir veya kendi kargo anlaşmasıyla gönderip takip numarasını ve kargo hareketlerini bildirebilir,
  6. Müşterilerin açtığı iade ve iptal taleplerini (RMA / Claims) sorgulayabilir, onaylayabilir, depoya ulaşan iade kargosunu teslim alındı olarak işaretleyebilir veya gerekçeyle reddedebilir,
  7. Sipariş, fatura, iade/iptal ve kargo değişikliklerinden webhook (anlık bildirim) ya da olay akışı (polling) ile haberdar olabilir.
  • Temel yol/api/integration/v1
  • Uç sayısı33
  • İstek limiti120 / dk
  • Sayfa boyutuen fazla 100
Kimlik doğrulama

Her istekte X-Api-Key başlığı; yalnızca HTTPS, isteğe bağlı IP kısıtlaması.

Biçim

JSON / UTF-8, camelCase alanlar; ISO-8601 tarih (Türkiye saati, UTC+3).

Bildirimler

HMAC-SHA256 imzalı webhook + yedek olarak olay akışı (polling).

Hızlı başlangıç

Bağlantınızı ve API anahtarınızı GET /ping ile doğrulayın.

Bash
curl -sS "https://mordepo-api.azurewebsites.net/api/integration/v1/ping" \
  -H "X-Api-Key: $HEPIYIOL_API_KEY"

Başarılı yanıt 200 ve "status": "ok" döner. API anahtarınız hesap açılışında Hepiyiol tarafından güvenli kanaldan iletilir.

1Genel bilgiler#

KonuDeğer
Temel adres (base URL)https://mordepo-api.azurewebsites.net/api/integration/v1
BiçimJSON (Content-Type: application/json; charset=utf-8)
Alan adlarıcamelCase (orderId, trackingNumber …)
Karakter setiUTF-8 (Türkçe karakterler desteklenir)
Para birimiTRY, ondalık ayıracı nokta (189.90) — tutarlar KDV dahildir
Tarih/saatISO-8601 (2026-11-06T14:30:00). Yanıtlardaki tarih/saatler Türkiye saatidir (UTC+3). İstekte saat dilimi belirtilmezse Türkiye saati kabul edilir.
KimliklerGUID (23a4baff-72be-4105-b962-f792d65ecba6)
İstek limitiVarsayılan dakikada 120 istek (API anahtarı başına)
Sayfalamapage (1'den başlar), pageSize (en fazla 100, varsayılan 50)
Swagger / OpenAPIhttps://mordepo-api.azurewebsites.net/swagger → "integration" dokümanı
Güncel dokümanhepiyiol.com/entegrasyon-api

Sayfalı yanıtların ortak biçimi:

JSON
{ "items": [ ... ], "page": 1, "pageSize": 50, "totalCount": 132 }

2Kimlik doğrulama ve güvenlik#

2.1API anahtarı#

Her istekte X-Api-Key başlığı gönderilmelidir:

HTTP
GET /api/integration/v1/ping HTTP/1.1
Host: mordepo-api.azurewebsites.net
X-Api-Key: mdp_live_96f70cda42fe_EYChxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  • Anahtar, firma hesabı açıldığında Hepiyiol yöneticisi tarafından yalnızca bir kez gösterilir ve güvenli bir kanal ile iletilir. Platform anahtarın kendisini saklamaz (yalnızca özetini saklar); kaybedilirse yenisi üretilir ve eskisi anında geçersiz olur.
  • Anahtarı yalnızca sunucu tarafında saklayınız; tarayıcı/mobil uygulama koduna, log'lara veya kaynak kod deposuna koymayınız.
  • Tüm istekler HTTPS üzerinden yapılmalıdır.

2.2IP kısıtlaması (önerilir)#

Hesabınız için sabit çıkış IP adreslerinizi bildirirseniz, API yalnızca bu adreslerden gelen istekleri kabul eder (tek IP veya CIDR, ör. 85.105.10.20, 10.20.0.0/24). İzin verilmeyen IP'den gelen istekler 403 forbidden alır.

2.3İstek limiti#

Limit aşıldığında 429 Too Many Requests döner, Retry-After: 60 başlığı eklenir:

JSON
{ "error": { "code": "rate_limited", "message": "İstek limiti aşıldı. Lütfen 1 dakika sonra tekrar deneyiniz." } }

Toplu işlemler için tek tek istek yerine toplu uçları (PUT /listings, 1000 kayda kadar) kullanınız.

2.4Veri kapsamı#

Bir API anahtarı yalnızca firmanıza bağlı deponun ilanlarını ve siparişlerini görebilir/değiştirebilir. Başka bir firmaya ait sipariş kimliği gönderilirse 404 not_found döner.

3Hata biçimi ve HTTP durum kodları#

Tüm hatalar aynı biçimdedir:

JSON
{
  "error": {
    "code": "validation_error",
    "message": "Sipariş 'shipped' durumunda; onaylanamaz.",
    "details": null
  }
}
HTTPerror.codeAnlamı / Ne yapmalı
200–Başarılı
201–Kayıt oluşturuldu (gönderi)
202–Talep alındı, yönetici onayı bekleniyor (iptal talebi)
207–Toplu işlemde kısmi başarı (bazı kayıtlar hatalı; errors alanını inceleyiniz)
400invalid_body, invalid_queryİstek gövdesi/parametreleri eksik veya hatalı
401unauthorizedX-Api-Key yok veya geçersiz
403forbiddenHesap pasif, IP izni yok veya işlem hesabınızın kargo moduna uygun değil
404not_foundKayıt yok veya firmanıza ait değil
422validation_errorİş kuralı hatası (mesajı kullanıcıya/operasyona gösterebilirsiniz)
429rate_limitedİstek limiti aşıldı; Retry-After kadar bekleyiniz
500internal_errorBeklenmeyen hata. Mesajdaki izleme kodunu destek talebinize ekleyiniz
503unavailableEntegrasyon API'si geçici olarak kapalı

Yeniden deneme önerisi: 429, 500, 502, 503, 504 ve zaman aşımlarında artan aralıklarla (ör. 2 sn, 10 sn, 60 sn) tekrar deneyiniz. 4xx (429 hariç) hatalarını tekrar denemeyiniz; isteği düzeltiniz. Onay, iptal ve gönderi oluşturma uçları tekrar çağrılmaya karşı güvenlidir (aynı sipariş için mükerrer gönderi açılmaz).

4Önerilen entegrasyon akışı#

TaraflarFirma SistemiHepiyiol APIKargo (DHL eCom/MNG veya firmanın kargosu)→ istek   ⇢ bildirim / asenkron
1Firma Sistemi→Hepiyiol APIGET /ping (bağlantı testi)
2Firma Sistemi→Hepiyiol APIPUT /webhook (bildirim adresi)
TekrarDüzenli (ör. 5-15 dk) veya stok değiştikçe
3Firma Sistemi→Hepiyiol APIPUT /listings (stok, fiyat, miad)
4Hepiyiol API⇢Firma Sistemiwebhook order.created (yeni sipariş)
5Firma Sistemi→Hepiyiol APIGET /orders/{id} (detay, vergi/fatura bilgileri, kalemler)
DurumSipariş "waiting_approval" ise
6Firma Sistemi→Hepiyiol APIPOST /orders/{id}/approve
7Firma Sistemi→Hepiyiol APIPUT /orders/{id}/invoice veya POST /orders/{id}/invoice/upload (e-Fatura / e-Arşiv)
DurumPlatform kargosu
8Firma Sistemi→Hepiyiol APIPOST /orders/{id}/shipments/platform
9Hepiyiol API→Kargo (DHL eCom/MNG veya firmanın kargosu)Kargo kaydı + barkod
10Firma Sistemi→Hepiyiol APIGET .../label?format=html|zpl (etiketi yazdır)
11Kargo (DHL eCom/MNG veya firmanın kargosu)⇢Hepiyiol APIKargo hareketleri (otomatik takip)
Aksi haldeFirmanın kendi kargosu
12Firma Sistemi→Kargo (DHL eCom/MNG veya firmanın kargosu)Kendi kargo anlaşmanızla gönderim
13Firma Sistemi→Hepiyiol APIPOST /orders/{id}/shipments (takip no)
14Firma Sistemi→Hepiyiol APIPOST .../shipments/{sid}/events (hareket / teslim)
15Hepiyiol API⇢Firma Sistemiwebhook order.invoice_uploaded / order.shipped / shipment.updated / order.delivered

Stok senkronizasyonu önerisi

  • Değişen ürünleri anlık (veya 5–15 dakikada bir) PUT /listings ile gönderiniz.
  • Günde bir kez tüm aktif stok listenizi gönderip, listenizde artık olmayan barkodları POST /listings/deactivate ile kapatınız (GET /listings?active=true ile platformdaki aktif ilanlarınızı karşılaştırabilirsiniz).
  • Stok 0 olan ürünü quantity: 0 ile göndermeniz yeterlidir; ilan otomatik olarak satışa kapatılır.

Sipariş ve fatura takibi önerisi

  • Birincil yöntem webhook'tur. Ek güvence için birkaç dakikada bir GET /events?after=<son sequence> ile kaçan olay olup olmadığını kontrol ediniz (bkz. Bölüm 12).
  • Alternatif: GET /orders?updatedSince=<son kontrol zamanı> ile değişen siparişleri çekebilirsiniz.
  • ERP / muhasebe tarafında henüz faturalanmamış siparişleri düzenli toplamak için GET /orders/uninvoiced (veya GET /orders?hasInvoice=false) ucunu kullanıp kesilen e-Fatura / e-Arşiv belgesini PUT /orders/{orderId}/invoice ya da POST /orders/{orderId}/invoice/upload ile yükleyiniz (bkz. Bölüm 8).
  • Müşteri iade/iptal taleplerini return.* webhook olaylarıyla anlık alabilir veya GET /returns?status=received,awaiting_product ile açık RMA kuyruğunuzu çekebilirsiniz (bkz. Bölüm 10).

5Hesap uçları#

5.1Bağlantı ve kimlik testi#GET/ping

JSON
{
  "status": "ok",
  "serverTime": "2026-11-06T22:47:20.442953+03:00",
  "partner": {
    "id": "8b4b9b93-4746-447b-b16d-c37841a4c4ee",
    "name": "Sancar Sağlık",
    "code": "SANCAR",
    "cargoMode": "hybrid",
    "listingUserType": 0,
    "allowOrderCancellation": false,
    "webhookEnabled": true
  }
}
AlanAçıklama
cargoModeplatform: siparişleri platformun kargo anlaşmasıyla gönderirsiniz · partner: kendi kargo anlaşmanızla gönderirsiniz · hybrid: sipariş bazında ikisinden birini seçebilirsiniz
listingUserTypeİlanlarınızın satış kanalı: 0 = son tüketici (B2C), 1 = eczane (B2B)
allowOrderCancellationtrue ise iptal isteğiniz anında uygulanır; false ise talep olarak yöneticiye iletilir (202)

5.2Webhook ayarı#GET/webhook

JSON
{ "url": "https://entegrasyon.firma.com/hepiyiol/webhook", "enabled": true, "hasSecret": true }

5.3Webhook adresini güncelle#PUT/webhook

JSON
{ "url": "https://entegrasyon.firma.com/hepiyiol/webhook", "enabled": true }
  • Adres https:// olmalı ve herkese açık bir adres olmalıdır (yerel/iç ağ adresleri reddedilir — 422).
  • url: null veya enabled: false ile bildirimler durdurulur (olaylar yine de olay akışında tutulur).

5.4İmza anahtarını yenile#POST/webhook/rotate-secret

JSON
{ "secret": "whsec_3f9a…" }

Yeni anahtar yalnızca bu yanıtta döner; eski anahtar anında geçersiz olur. Yenilemeden hemen sonra sisteminizdeki anahtarı güncelleyiniz.

5.5Test bildirimi gönder#POST/webhook/test

Kayıtlı adrese imzalı bir webhook.test olayı gönderir ve sonucu döner:

JSON
{ "success": true, "statusCode": 200, "error": null, "durationMs": 142 }

6Ürün kataloğu ve ilanlar#

Kavramlar

  • Ürün (product): Platform kataloğundaki ürün (barkod tekildir). Katalogda olmayan bir barkod için ilan açılamaz; yeni ürün eklenmesi için bizimle iletişime geçiniz.
  • İlan (listing): Firmanızın bir ürünü satışa sunduğu kayıt (stok, fiyat, miad). Bir ilan barkod + firmanızın deposu + satış kanalı (listingUserType) ile tekil olarak tanımlanır. Aynı barkod için tekrar gönderim mevcut ilanı günceller.

6.1Katalogda ürün ara#GET/products

ParametreAçıklama
barcodeBarkod ile tam eşleşme
searchÜrün adında arama (en az 3 karakter)
page, pageSizeSayfalama

barcode veya search parametrelerinden biri zorunludur.

HTTP
GET /api/integration/v1/products?barcode=8690000000011
JSON
{
  "items": [
    {
      "productId": "1c05196a-db4b-4407-8dee-76914a7e129e",
      "barcode": "8690000000011",
      "name": "Vitamin C 1000mg",
      "vatRate": 10.0,
      "referenceMarketPrice": 250.0
    }
  ],
  "page": 1, "pageSize": 50, "totalCount": 1
}

6.2İlanlarım#GET/listings

ParametreAçıklama
barcodeBelirli bir barkod
activetrue: yalnızca satışta olanlar, false: yalnızca kapalı olanlar
page, pageSizeSayfalama
JSON
{
  "items": [
    {
      "listingId": "5eaadc6c-8806-4ec4-8c10-ac805befeba8",
      "productId": "1c05196a-db4b-4407-8dee-76914a7e129e",
      "barcode": "8690000000011",
      "productName": "Vitamin C 1000mg",
      "quantity": 100,
      "maxQuantity": 10,
      "deadline": "1227",
      "marketPrice": 250.0,
      "warehousePrice": 200.0,
      "isActive": true,
      "updatedAt": "2026-11-06T19:36:48.982539"
    }
  ],
  "page": 1, "pageSize": 50, "totalCount": 1
}

6.3İlan ekle / güncelle (toplu)#PUT/listings

Tek istekte en fazla 1000 kayıt.

JSON
{
  "items": [
    {
      "barcode": "8690000000011",
      "quantity": 100,
      "maxQuantity": 10,
      "deadline": "2027-12",
      "marketPrice": 249.90,
      "warehousePrice": 200.00
    },
    {
      "barcode": "8690000000028",
      "quantity": 0
    }
  ]
}
AlanZorunluAçıklama
barcodeEvetKatalogdaki ürün barkodu. Aynı istekte aynı barkod bir kez bulunmalıdır.
quantityEvetSatılabilir stok adedi (0 – 1.000.000). 0 gönderilirse ilan satışa kapatılır.
maxQuantityHayırTek siparişte alınabilecek en fazla adet
deadlineYeni ilan için evetSon kullanma tarihi (miad). Kabul edilen biçimler: 0627, 06/27, 06/2027, 2027-06, 2027-06-30. Platformda AAYY biçiminde saklanır.
marketPriceYeni ilan için evetTüketiciye satış fiyatı, KDV dahil
warehousePriceHayırDepo fiyatı (bilgi amaçlı)

Mevcut bir ilanı güncellerken gönderilmeyen (null) maxQuantity, deadline, marketPrice ve warehousePrice alanları mevcut değerini korur; yalnızca barcode + quantity göndererek stok güncellemesi yapabilirsiniz. quantity > 0 gönderilen ilan tekrar satışa açılır.

Yanıt

HTTPDurum
200Tüm kayıtlar başarılı
207Bir kısmı başarılı, bir kısmı hatalı
422Hiçbir kayıt işlenemedi
JSON
{
  "received": 2,
  "succeeded": 1,
  "failed": 1,
  "errors": [
    {
      "barcode": "8699504010015",
      "error": "Barkod ürün kataloğunda bulunamadı. Ürünün kataloğa eklenmesi için bizimle iletişime geçiniz."
    }
  ]
}

Olası kayıt hataları: Geçersiz barkod., Aynı barkod istekte birden fazla kez gönderilmiş., quantity 0 ile 1.000.000 arasında olmalıdır., maxQuantity negatif olamaz., Fiyatlar pozitif olmalıdır., Yeni ilan için marketPrice zorunludur., Yeni ilan için deadline (miad) zorunludur., Geçersiz miad (deadline)…, Barkod ürün kataloğunda bulunamadı…

6.4İlanları satıştan kaldır#POST/listings/deactivate

JSON
{ "barcodes": ["8690000000011", "8690000000028"] }
JSON
{ "deactivated": 1, "notFound": ["8690000000028"] }

7Siparişler#

Platformdaki her sipariş, bir depoya ait alt siparişlerden oluşur. Bu API'deki "sipariş" (orderId) firmanıza düşen alt siparişi ifade eder; orderNumber müşterinin gördüğü sipariş numarasıdır (ör. MD.26.501).

7.1Sipariş listesi#GET/orders

ParametreAçıklama
statusBir veya virgülle ayrılmış birden fazla durum kodu (ör. waiting_approval,preparing). Bkz. 13.1
updatedSinceBu tarihten sonra oluşturulan/güncellenen siparişler (ör. 2026-11-06T00:00:00)
createdFromSipariş oluşturulma başlangıç tarihi (CreatedOn >= createdFrom)
createdToSipariş oluşturulma bitiş tarihi (CreatedOn <= createdTo)
hasInvoicefalse: faturası henüz yüklenmemiş siparişler · true: faturası yüklenmiş siparişler
invoiceNumberFatura numarasında arama (büyük/küçük harf duyarsız kısmi eşleşme, ör. MDP2026)
hasOpenReturntrue: üzerinde sonuçlanmamış müşteri iade/iptal talebi bulunan siparişler · false: açık talebi olmayanlar
page, pageSizeSayfalama (en yeni güncellenen önce)
JSON
{
  "items": [
    {
      "orderId": "23a4baff-72be-4105-b962-f792d65ecba6",
      "orderNumber": "MD.26.501",
      "statusId": 3,
      "status": "shipped",
      "statusName": "Kargoda",
      "createdAt": "2026-11-06T19:36:48.984881",
      "updatedAt": "2026-11-06T22:46:15.636112",
      "itemCount": 1,
      "totalQuantity": 2,
      "amounts": {
        "itemsTotal": 500.0,
        "vatTotal": 45.45,
        "discountTotal": 0.0,
        "shippingFee": 30.0,
        "grandTotal": 530.0,
        "currency": "TRY"
      },
      "fulfillmentMode": "hybrid",
      "hasInvoice": true,
      "invoiceNumber": "MDP2026000001452",
      "invoice": {
        "invoiceId": "9a7d2c10-4a8e-4d1b-8b02-71c92218b511",
        "orderId": "23a4baff-72be-4105-b962-f792d65ecba6",
        "invoiceNumber": "MDP2026000001452",
        "invoiceType": "earsiv",
        "ettn": "550e8400-e29b-41d4-a716-446655440000",
        "invoiceDate": "2026-11-06T20:15:00",
        "totalAmount": 530.0,
        "vatAmount": 48.18,
        "currency": "TRY",
        "hasFile": true,
        "fileName": "MDP2026000001452.pdf",
        "contentType": "application/pdf",
        "fileSizeBytes": 84210,
        "downloadPath": "/api/integration/v1/orders/23a4baff-72be-4105-b962-f792d65ecba6/invoice/file",
        "externalUrl": null,
        "uploadedAt": "2026-11-06T20:16:04.112000"
      },
      "hasOpenReturn": false,
      "shipment": {
        "shipmentId": "bdc65348-6699-4a5f-97d2-c609e87e76bb",
        "providerCode": "MNG",
        "carrierName": "DHL eCommerce (MNG Kargo)",
        "shippedBy": "platform",
        "trackingNumber": "614118757013",
        "trackingUrl": "https://…/614118757013",
        "status": "in_transit",
        "statusName": "Transfer Aşamasında",
        "hasLabel": true,
        "shippedAt": "2026-11-06T12:00:00",
        "deliveredAt": null
      }
    }
  ],
  "page": 1, "pageSize": 50, "totalCount": 1
}
AlanAçıklama
amounts.itemsTotalÜrün satırlarının toplamı (KDV dahil, indirim düşülmüş)
amounts.vatTotalBu toplamın içindeki KDV (bilgi amaçlı)
amounts.shippingFeeKargo ücreti: müşteriden sepet başına tek ücret alınır; birden çok depodan oluşan siparişte bu ücretin ürün tutarı oranında sizin siparişinize düşen payıdır
amounts.grandTotalitemsTotal + shippingFee
fulfillmentModeHesabınızın kargo modu (platform / partner / hybrid)
hasInvoiceSiparişe fatura yüklenip yüklenmediği (true / false)
invoiceNumberYüklenen faturanın resmi numarası; fatura yoksa null
invoiceYüklenen faturanın özet/detay nesnesi (bkz. Bölüm 8); fatura yoksa null
hasOpenReturnSipariş üzerinde açık (sonuçlanmamış) bir müşteri iade/iptal talebi olup olmadığı (true / false)
shipmentSiparişin güncel (aktif) gönderisi; yoksa null

7.2Faturası henüz yüklenmemiş siparişler#GET/orders/uninvoiced

ERP / ön muhasebe yazılımlarının fatura kesilecek sipariş kuyruğunu tek uçtan çekmesi için hazırlanmış kısayoldur.

  • Yalnızca hasInvoice == false olan siparişleri döner.
  • status parametresi gönderilmezse varsayılan olarak yalnızca faturalanabilir aktif durumları filtreler: waiting_approval,preparing,shipped,delivered (iptal edilen cancelled ve iade edilen refunded siparişler hariç tutulur).
  • İsterseniz status=preparing,shipped, updatedSince, createdFrom, createdTo, page, pageSize parametreleriyle daraltabilirsiniz.
HTTP
GET /api/integration/v1/orders/uninvoiced?status=preparing,shipped&page=1&pageSize=50

Yanıt biçimi GET /orders (7.1) ile birebir aynıdır (items, page, pageSize, totalCount).

7.3Sipariş detayı#GET/orders/{orderId}

Listedeki alanlara ek olarak müşteri kimlik/vergi bilgileri, teslimat ve fatura adresleri, kalemler, fatura nesnesi, tüm gönderiler ve o an yapılabilecek işlemler döner:

JSON
{
  "orderId": "23a4baff-72be-4105-b962-f792d65ecba6",
  "orderNumber": "MD.26.501",
  "statusId": 2,
  "status": "preparing",
  "statusName": "Hazırlanıyor / Kargolanmayı Bekliyor",
  "createdAt": "2026-11-06T19:36:48.984881",
  "updatedAt": "2026-11-06T20:01:10.120000",
  "itemCount": 1,
  "totalQuantity": 2,
  "amounts": { "itemsTotal": 500.0, "vatTotal": 45.45, "discountTotal": 0.0, "shippingFee": 30.0, "grandTotal": 530.0, "currency": "TRY" },
  "fulfillmentMode": "hybrid",
  "hasInvoice": false,
  "invoiceNumber": null,
  "invoice": null,
  "hasOpenReturn": false,
  "shipment": null,
  "customer": {
    "fullName": "Ayşe Yılmaz",
    "phone": "05321112233",
    "email": "ayse@ornek.com",
    "taxNumber": "11111111110",
    "taxOffice": null,
    "gln": null,
    "isCorporate": false
  },
  "shippingAddress": {
    "title": "Ev Adresim",
    "fullName": "Ayşe Yılmaz",
    "phone": "05321112233",
    "city": "İstanbul",
    "district": "Kadıköy",
    "address": "Caferağa Mah. Moda Cad. No:1",
    "taxNumber": null,
    "taxOffice": null,
    "isCorporate": false
  },
  "invoiceAddress": {
    "title": "Ayşe Yılmaz",
    "fullName": "Ayşe Yılmaz",
    "phone": "05321112233",
    "city": "İstanbul",
    "district": "Kadıköy",
    "address": "Caferağa Mah. Moda Cad. No:1",
    "taxNumber": "11111111110",
    "taxOffice": null,
    "isCorporate": false
  },
  "items": [
    {
      "lineId": "191534f9-ebc2-41e3-bca2-26f498ba81e2",
      "listingId": "5eaadc6c-8806-4ec4-8c10-ac805befeba8",
      "productId": "1c05196a-db4b-4407-8dee-76914a7e129e",
      "barcode": "8690000000011",
      "productName": "Vitamin C 1000mg",
      "quantity": 2,
      "unitPrice": 227.27,
      "vatRate": 10.0,
      "unitPriceWithVat": 250.0,
      "lineTotal": 500.0,
      "deadline": "1227"
    }
  ],
  "shipments": [],
  "returns": [],
  "actions": {
    "canApprove": false,
    "canCancel": true,
    "canCreatePlatformShipment": true,
    "canRegisterOwnShipment": true,
    "canUploadInvoice": true
  }
}

Fatura kesimi için alıcı alanları (customer ve invoiceAddress):

AlanAçıklama
invoiceAddress.titleFatura unvanı / başlığı (kurumsal alıcıda ticari unvan veya eczane adı)
invoiceAddress.taxNumber11 haneli TCKN veya 10 haneli VKN (fatura adresinde girilmemişse alıcı hesabındaki değer döner)
invoiceAddress.taxOfficeVergi dairesi adı (kurumsal/eczane alıcılarda dolu; bireysel alıcılarda null)
invoiceAddress.isCorporatetrue: kurumsal / eczane alıcı (VKN veya vergi dairesi mevcut) · false: bireysel tüketici (e-Arşiv)
customer.glnEczane alıcılarda 13 haneli GLN numarası (İTS / B2B süreçleri için); bireysel üyelerde null
actions.canUploadInvoiceSiparişe fatura yüklenip güncellenebileceğini belirtir (true / false)

Kişisel veri: Müşteri ad, TCKN/VKN, telefon ve adres bilgileri yalnızca siparişin faturalandırılması, hazırlanması ve teslimatı amacıyla paylaşılır (KVKK / VUK). Bu verileri başka amaçla kullanmayınız, gereğinden uzun saklamayınız ve log'lamayınız.

actions alanı, siparişin o anki durumuna ve hesabınızın kargo moduna göre hangi işlemleri yapabileceğinizi gösterir; arayüzünüzde butonları buna göre açıp kapatabilirsiniz.

7.4Siparişi onayla#POST/orders/{orderId}/approve

Gövde gerekmez. Yalnızca waiting_approval durumundaki siparişler onaylanabilir; onay sonrası sipariş preparing durumuna geçer. Zaten preparing durumundaki siparişte tekrar çağrılırsa hata vermez (idempotent). Yanıt: güncel sipariş detayı (7.3).

Ödeme sonrası siparişler çoğunlukla doğrudan preparing durumunda oluşur; bu durumda onay gerekmez.

7.5Siparişi iptal et#POST/orders/{orderId}/cancel

Stok yetersizliği vb. nedenlerle siparişi karşılayamıyorsanız kullanınız. Yalnızca henüz kargoya verilmemiş (waiting_approval / preparing, aktif gönderisi olmayan) siparişler iptal edilebilir.

JSON
{ "reason": "Ürün stokta kalmadı." }

reason zorunludur (en fazla 500 karakter).

YanıtDurum
200 + "result": "cancelled"Sipariş iptal edildi, müşteriye ödeme iadesi başlatıldı (hesabınızda otomatik iptal yetkisi açıksa)
202 + "result": "cancel_requested"İptal talebiniz Hepiyiol operasyon ekibine iletildi; iptal gerçekleştiğinde order.cancelled olayı gelir
422Sipariş bu durumda iptal edilemez
JSON
{
  "result": "cancel_requested",
  "message": "İptal talebiniz alındı; müşteri hizmetlerimiz siparişi inceleyip iptal/iade işlemini başlatacaktır.",
  "order": { "...": "sipariş detayı" }
}

7.6Siparişin iade / iptal talepleri#GET/orders/{orderId}/returns

Belirli bir alt siparişe ait geçmiş ve açık tüm müşteri iade/iptal taleplerini (PartnerReturnSummaryDto dizisi, en yeni önce) döner. Şema ve detay uçları için bkz. Bölüm 10.

8Faturalar (e-Fatura / e-Arşiv)#

Siparişe ait e-Fatura veya e-Arşiv belgesini platforma yüklemek için iki yöntem desteklenir (ERP / entegratör altyapınıza uygun olanı seçebilirsiniz):

YöntemUçNe zaman tercih edilmeli
A. JSON ile fatura kaydı (externalUrl ve/veya fileBase64)PUT /orders/{orderId}/invoicee-Fatura entegratörünüzün (İzibiz, Foriba, Logo, EDM, QNB eFinans, Uyumsoft vb.) görüntüleme linkini göndermek veya tek JSON isteğinde Base64 PDF/UBL-XML iletmek istediğinizde
B. Doğrudan dosya yükleme (multipart/form-data)POST /orders/{orderId}/invoice/uploadHam PDF, UBL-TR XML, e-Arşiv HTML veya PNG/JPG dosyasını Base64'e çevirmeden doğrudan yüklemek istediğinizde

Temel kurallar ve güvenlik

  • Her alt sipariş (orderId) için tek bir aktif fatura kaydı tutulur. Aynı sipariş için PUT veya POST .../upload tekrar çağrıldığında mevcut fatura idempotent olarak güncellenir (yeni dosya gönderilirse eski dosya otomatik temizlenir).
  • En az bir belge kaynağı zorunludur: İlk kayıtta externalUrl (herkese açık https:// fatura adresi) veya fatura dosyası (fileBase64 / multipart file) gönderilmelidir; ikisi birden de gönderilebilir.
  • Desteklenen dosya biçimleri ve boyut: PDF (%PDF-), UBL-TR XML, e-Arşiv HTML, PNG, JPEG — en fazla 10 MB. Dosya içeriği sunucuda magic-byte kontrolünden geçirilir; uzantısı değiştirilmiş geçersiz/çalıştırılabilir dosyalar 422 ile reddedilir.
  • Gizlilik: Yüklenen fatura dosyaları halka açık CDN'de tutulmaz; özel (private) depolamada saklanır ve yalnızca yetkili API uçları üzerinden alıcı müşteriye, ilgili tedarikçiye ve platform operasyonuna sunulur.
  • Otomatik senkronizasyon: Fatura yüklendiğinde müşterinin "Siparişlerim → e-Faturamı Görüntüle" ekranında anında görünür olur; varsa aktif kargo kaydındaki fatura numarası alanı da otomatik doldurulur ve order.invoice_uploaded olayı üretilir.

Fatura nesnesi#

JSON
{
  "invoiceId": "9a7d2c10-4a8e-4d1b-8b02-71c92218b511",
  "orderId": "23a4baff-72be-4105-b962-f792d65ecba6",
  "invoiceNumber": "MDP2026000001452",
  "invoiceType": "earsiv",
  "ettn": "550e8400-e29b-41d4-a716-446655440000",
  "invoiceDate": "2026-11-06T20:15:00",
  "totalAmount": 530.00,
  "vatAmount": 48.18,
  "currency": "TRY",
  "hasFile": true,
  "fileName": "MDP2026000001452.pdf",
  "contentType": "application/pdf",
  "fileSizeBytes": 84210,
  "downloadPath": "/api/integration/v1/orders/23a4baff-72be-4105-b962-f792d65ecba6/invoice/file",
  "externalUrl": "https://earsiv.entegrator.com.tr/goruntule?ettn=550e8400-e29b-41d4-a716-446655440000",
  "uploadedAt": "2026-11-06T20:16:04.112000"
}

8.1Sipariş faturasını sorgula#GET/orders/{orderId}/invoice

Siparişe yüklenmiş faturanın üst verisini (fatura nesnesi) döner. Henüz fatura yüklenmemişse 404 not_found döner.

8.2Fatura kaydet / güncelle (JSON)#PUT/orders/{orderId}/invoice

Harici https:// fatura linki ve/veya Base64 kodlu fatura dosyası ile fatura kaydeder ya da günceller.

Örnek 1 — Base64 PDF dosyası ile yükleme:

JSON
{
  "invoiceNumber": "MDP2026000001452",
  "invoiceType": "earsiv",
  "ettn": "550e8400-e29b-41d4-a716-446655440000",
  "invoiceDate": "2026-11-06T20:15:00",
  "totalAmount": 530.00,
  "vatAmount": 48.18,
  "currency": "TRY",
  "fileName": "MDP2026000001452.pdf",
  "contentType": "application/pdf",
  "fileBase64": "JVBERi0xLjcKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyA+PgplbmRvYmoKJSVFT0Y="
}

Örnek 2 — Özel entegratör görüntüleme linki (externalUrl) ile yükleme:

JSON
{
  "invoiceNumber": "MDP2026000001453",
  "invoiceType": "efatura",
  "ettn": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "invoiceDate": "2026-11-06T20:20:00",
  "totalAmount": 1250.00,
  "vatAmount": 113.64,
  "externalUrl": "https://portal.ornekentegrator.com.tr/fatura/goruntule?ettn=7c9e6679-7425-40de-944b-e07fc1f90ae7"
}
AlanZorunluAçıklama
invoiceNumberEvetGİB resmi fatura numarası (en fazla 100 karakter, ör. MDP2026000001452)
invoiceTypeHayırearsiv veya efatura. Boş bırakılırsa alıcı tipine göre otomatik belirlenir (eczane/kurumsal → efatura, bireysel → earsiv)
ettnHayır (önerilir)GİB Evrensel Tekil Tanımlama Numarası (UUID, 8–64 karakter)
invoiceDateHayırFatura düzenleme tarihi (ISO-8601; boşsa yükleme anı kaydedilir)
totalAmountHayırKDV dahil fatura genel toplamı
vatAmountHayırToplam KDV tutarı (totalAmount değerinden büyük olamaz)
currencyHayırPara birimi (varsayılan TRY)
externalUrlKoşullu*Herkese açık https:// fatura görüntüleme/indirme linki (yerel/iç ağ IP'leri güvenlik nedeniyle reddedilir)
fileBase64Koşullu*Ham Base64 veya data:application/pdf;base64,... biçiminde kodlanmış dosya içeriği (en fazla 10 MB)
fileNameHayırDosya adı (ör. MDP2026000001452.pdf; boşsa invoiceNumber + algılanan uzantı kullanılır)
contentTypeHayırBildirilen MIME tipi (gerçek tip dosya imzasından doğrulanır)

\* İlk kayıtta externalUrl veya fileBase64 alanlarından en az biri dolu olmalıdır. Mevcut faturayı güncellerken yalnızca üst veriyi (ör. ettn, totalAmount) değiştirmek isterseniz önceden yüklenmiş dosya korunur.

Yanıt: 200 + güncel fatura nesnesi.

8.3Fatura dosyası yükle (multipart/form-data)#POST/orders/{orderId}/invoice/upload

Ham dosyayı Base64 dönüşümü olmadan doğrudan multipart/form-data olarak yükler.

Form alanıZorunluAçıklama
fileEvetFatura dosyası (PDF, UBL-XML, HTML, PNG, JPG — en fazla 10 MB)
invoiceNumberEvetGİB resmi fatura numarası
invoiceTypeHayırearsiv veya efatura
ettnHayırGİB ETTN (UUID)
invoiceDateHayırISO-8601 fatura tarihi
totalAmountHayırKDV dahil toplam tutar
vatAmountHayırKDV tutarı
currencyHayırPara birimi (TRY)
externalUrlHayırEk olarak harici https:// görüntüleme linki
Bash
curl -X POST "https://mordepo-api.azurewebsites.net/api/integration/v1/orders/23a4baff-72be-4105-b962-f792d65ecba6/invoice/upload" \
  -H "X-Api-Key: $HEPIYIOL_API_KEY" \
  -F "file=@MDP2026000001452.pdf;type=application/pdf" \
  -F "invoiceNumber=MDP2026000001452" \
  -F "invoiceType=earsiv" \
  -F "ettn=550e8400-e29b-41d4-a716-446655440000" \
  -F "invoiceDate=2026-11-06T20:15:00" \
  -F "totalAmount=530.00" \
  -F "vatAmount=48.18"

Yanıt: 200 + güncel fatura nesnesi.

8.4Fatura dosyasını indir#GET/orders/{orderId}/invoice/file

Platforma yüklenmiş (hasFile: true) fatura dosyasının ikili (binary) içeriğini döner (Content-Type: application/pdf, application/xml vb.). Dosya yüklenmemişse (yalnızca externalUrl varsa veya hiç fatura yoksa) 404 not_found döner.

8.5Fatura kaydını sil#DELETE/orders/{orderId}/invoice

Hatalı kesilmiş/iptal edilmiş bir faturayı siparişten kaldırır ve yüklenmiş özel dosyayı siler. Ardından yeni faturayı 8.2 veya 8.3 ile yükleyebilirsiniz.

JSON
{ "deleted": true }

9Kargo / gönderiler#

Hesabınızın kargo moduna göre iki yöntemden biri (hybrid modda ikisi de) kullanılabilir:

YöntemUçKargo modu
A. Platform kargosu (DHL eCommerce / MNG Kargo anlaşması)POST /orders/{id}/shipments/platformplatform, hybrid
B. Firmanın kendi kargosuPOST /orders/{id}/shipmentspartner, hybrid

Bir siparişin aynı anda yalnızca bir aktif gönderisi olabilir. Kendi kargonuzla bildirdiğiniz gönderinin bilgileri (kargo firması, takip no, link, fatura no) 9.7 ile düzenlenebilir. Yöntem değiştirmek (kendi kargosu ↔ platform kargosu) için mevcut gönderi iptal edilip (9.6) yenisi açılır.

Gönderi nesnesi#

JSON
{
  "shipmentId": "bdc65348-6699-4a5f-97d2-c609e87e76bb",
  "orderId": "23a4baff-72be-4105-b962-f792d65ecba6",
  "providerCode": "MNG",
  "carrierName": "DHL eCommerce (MNG Kargo)",
  "shippedBy": "platform",
  "referenceId": "MD26501-23A4",
  "trackingNumber": "614118757013",
  "trackingUrl": "https://…/614118757013",
  "barcodes": ["C@6B@H21FMLRPNAAA6J"],
  "hasLabel": true,
  "status": "in_transit",
  "statusName": "Transfer Aşamasında",
  "statusDescription": "Transfer Aşamasında",
  "isActive": true,
  "pieceCount": 2,
  "desi": 4.00,
  "kg": 3.00,
  "createdAt": "2026-11-06T22:46:15.011178",
  "shippedAt": "2026-11-06T12:00:00",
  "deliveredAt": null,
  "deliveredTo": null,
  "cancelledAt": null,
  "lastError": null,
  "events": [
    { "date": "2026-11-06T12:00:00", "status": "in_transit", "statusName": "Transfer Aşamasında", "description": "Transfer Aşamasında", "location": "HUB", "source": "carrier" },
    { "date": "2026-11-06T10:00:00", "status": "label_created", "statusName": "Barkod Oluşturuldu", "description": "Gönderi Hazırlandı", "location": "BAĞCILAR", "source": "carrier" }
  ]
}
AlanAçıklama
shippedByplatform (platform kargosu), partner (firmanın kendi kargosu), manual (Hepiyiol operasyonunca girilen)
referenceIdKargo firmasına iletilen sipariş referansı (platform gönderilerinde)
barcodesPaket barkodları (parça sayısı kadar)
statusGönderi durum kodu — bkz. 13.2
lastErrorKargo siparişi açıldı ancak barkod henüz alınamadıysa nedeni (sistem otomatik tekrar dener)
eventsKargo hareketleri (en yeni önce). source: carrier (kargo firması), partner (siz), admin:…, system

9.1Siparişin gönderileri#GET/orders/{orderId}/shipments

İptal edilmiş eski gönderiler dahil tüm gönderileri (gönderi nesnesi dizisi) döner.

9.2Platform kargosu ile gönderi + barkod oluştur#POST/orders/{orderId}/shipments/platform

Siparişi platformun DHL eCommerce (MNG Kargo) anlaşmasıyla gönderir: kargo firmasında sipariş açılır, barkod alınır, etiket hazırlanır. Alıcı adres/telefon bilgileri siparişten otomatik alınır.

JSON
{
  "pieceCount": 2,
  "desi": 4,
  "kg": 3,
  "content": "Sağlık ürünü",
  "invoiceNumber": "ABC2026000123"
}
AlanZorunluAçıklama
pieceCountHayır (vars. 1)Koli/paket adedi; her paket için ayrı barkod üretilir
desiHayırToplam desi (paketlere eşit bölünür). Boşsa varsayılan
kgHayırToplam ağırlık. Boşsa varsayılan
contentHayırİçerik açıklaması
invoiceNumberHayırFatura / irsaliye numarası

Yanıt: 201 + gönderi nesnesi (status: "label_created"). Ardından:

  1. Etiketi indirip yazdırınız (9.5) ve pakete yapıştırınız,
  2. Paketi DHL eCommerce / MNG şubesine teslim ediniz veya kurye ile alımı bekleyiniz,
  3. Kargo hareketleri otomatik olarak (yaklaşık 10–15 dakikada bir) kargo firmasından alınır; kargo teslim alındığında sipariş shipped, teslim edildiğinde delivered olur ve size webhook gönderilir.

Nadiren kargo firması siparişi kabul edip barkodu geciktirebilir. Bu durumda status: "order_created" ve lastError dolu döner; sistem barkodu otomatik olarak tekrar dener ve hazır olduğunda shipment.updated olayı gönderilir.

Olası hatalar: 403 (hesabınız yalnızca kendi kargonuzla çalışıyor), 422 (sipariş gönderime uygun değil, adres/telefon eksik, aktif gönderi zaten var, kargo firması hatası — mesajda nedeni yer alır).

9.3Kendi kargonuzla gönderiyi bildir#POST/orders/{orderId}/shipments

Siparişi kendi kargo anlaşmanızla gönderdiğinizde takip bilgisini bildirin. Sipariş anında shipped (Kargoda) durumuna geçer ve müşteri bilgilendirilir.

JSON
{
  "carrierName": "Aras Kargo",
  "trackingNumber": "ARS998877",
  "trackingUrl": "https://kargotakip.araskargo.com.tr/?code=ARS998877",
  "invoiceNumber": "ABC2026000124",
  "shippedAt": "2026-11-06T16:30:00"
}
AlanZorunluAçıklama
carrierNameEvetKargo firması adı
trackingNumberEvetTakip numarası
trackingUrlHayır (önerilir)Müşterinin takip edebileceği adres
invoiceNumberHayırFatura / irsaliye no
shippedAtHayırKargoya veriliş zamanı (boşsa şimdi)

Yanıt: 201 + gönderi nesnesi (shippedBy: "partner", status: "in_transit").

9.4Kargo hareketi / teslimat bildir#POST/orders/{orderId}/shipments/{shipmentId}/events

Yalnızca kendi kargonuzla gönderdiğiniz (shippedBy: "partner") gönderiler içindir. Platform gönderilerinin hareketleri kargo firmasından otomatik alınır (403).

JSON
{
  "status": "delivered",
  "description": "Alıcıya teslim edildi",
  "location": "Kadıköy Şube",
  "occurredAt": "2026-11-07T11:20:00",
  "deliveredTo": "Ayşe Yılmaz"
}
AlanZorunluAçıklama
statusEvetin_transit, at_delivery_branch, out_for_delivery, delivered, delivery_failed, returning, returned
descriptionHayırAçıklama
locationHayırKonum / şube
occurredAtHayırHareket zamanı (boşsa şimdi)
deliveredToHayırTeslim alan kişi (delivered için önerilir)

delivered bildirildiğinde sipariş delivered (Tamamlandı) durumuna geçer. Yanıt: güncel gönderi nesnesi.

9.5Kargo etiketi#GET/orders/{orderId}/shipments/{shipmentId}/label?format=…

formatİçerikKullanım
html (varsayılan)text/htmlTarayıcıda açıp 10x15 cm etiket olarak yazdırma (barkod + alıcı + gönderici bilgisi)
zpltext/plainZebra vb. termal yazıcılara doğrudan gönderim (platform gönderilerinde kargo firmasının resmi etiketi)
pngimage/pngGörsel etiket (platformda etkinse)

9.6Gönderiyi iptal et#POST/orders/{orderId}/shipments/{shipmentId}/cancel

JSON
{ "reason": "Yanlış koli adedi" }
  • Platform gönderileri yalnızca paket kargo şubesine teslim edilmeden önce iptal edilebilir; kargo firmasındaki kayıt da iptal edilir.
  • Kendi kargonuzla bildirdiğiniz gönderi de iptal edilebilir; sipariş tekrar preparing durumuna döner ve yeni gönderi (kendi kargonuzla veya platform kargosuyla) açabilirsiniz. Yalnızca bilgileri düzeltmek için iptal yerine 9.7'yi kullanınız.

Yanıt: gönderi nesnesi (status: "cancelled", isActive: false).

9.7Kendi kargonuzun bilgilerini düzenle#PATCH/orders/{orderId}/shipments/{shipmentId}

Kendi kargonuzla bildirdiğiniz (shippedBy: "partner") aktif gönderinin bilgilerini düzeltir. Yalnızca gönderdiğiniz alanlar değişir; sipariş durumu değişmez (shipped olarak kalır).

JSON
{
  "carrierName": "Yurtiçi Kargo",
  "trackingNumber": "YK123456789",
  "trackingUrl": "https://www.yurticikargo.com/tr/online-servisler/gonderi-sorgula?code=YK123456789",
  "invoiceNumber": "ABC2026000125",
  "shippedAt": "2026-11-06T17:00:00"
}
AlanAçıklama
carrierNameKargo firması adı (boş olamaz)
trackingNumberYeni takip numarası. Değişir ve trackingUrl gönderilmezse eski link silinir
trackingUrlTakip linki ("" gönderilirse silinir)
invoiceNumberFatura / irsaliye no
shippedAtKargoya veriş zamanı
  • Yanıt: 200 + güncel gönderi nesnesi. Müşterinin sipariş takibindeki bilgi de güncellenir, shipment.updated olayı üretilir.
  • Platform kargosu gönderileri düzenlenemez (403); bilgileri kargo firmasından gelir.
  • İptal edilmiş, teslim edilmiş veya iade edilmiş gönderi düzenlenemez (422).

10İade ve iptal talepleri (RMA)#

Müşteriler sipariş durumuna göre iki tür talep oluşturabilir:

typetypeIdNe zaman açılabilirAkış özeti
cancel1Sipariş henüz kargoya verilmeden önce (waiting_approval veya preparing)received → onaylandığında sipariş iptal edilir ve tam ödeme iadesi başlatılır (completed)
return2Sipariş teslim edildikten (delivered) sonraki 14 gün içinde (satır/adet seçerek)received → approve (awaiting_product) → müşteri iade kargosunu gönderir → receive (product_received) → platform finans kontrolü sonrası ödeme iadesi tamamlanır (completed)

Yetki ve finansal güvenlik sınırları

  • Teslimat sonrası iade (return): Firmanız talebi onaylayabilir (approve — müşteriye kargo gönderim talimatı iletilir), kargo deponuza ulaştığında teslim alabilir (receive) veya inceleme sonucunda gerekçeyle reddedebilir (reject). Fiziksel teslim alım (product_received) sonrasındaki kart/ödeme sağlayıcı para iadesi (completed), mutabakat güvenliği için Hepiyiol finans operasyonu tarafından gerçekleştirilir ve tamamlandığında return.completed olayı gönderilir.
  • Kargo öncesi iptal (cancel): İptal talebinin onaylanması siparişi anında iptal edip ödeme iadesi başlattığından, POST /returns/{returnId}/approve çağrısı cancel tipindeki taleplerde yalnızca hesabınızda allowOrderCancellation: true yetkisi açıksa doğrudan uygulanır (actions.canApprove: true). Yetki kapalıysa iptal onayı müşteri hizmetlerimiz tarafından sonuçlandırılır; firmanız gerekirse talebi reddedebilir (reject).
  • Tüm durum geçiş uçları (approve, receive, reject) idempotent'tir: talep zaten hedef durumdaysa hata üretmeden güncel talep detayını döner.

Talep özet nesnesi#

JSON
{
  "returnId": "c8d12a90-4f88-4c79-a611-94e8bc1102a4",
  "requestNo": "IAD-2026-000142",
  "orderId": "23a4baff-72be-4105-b962-f792d65ecba6",
  "orderNumber": "MD.26.501",
  "typeId": 2,
  "type": "return",
  "typeName": "İade Talebi",
  "statusId": 2,
  "status": "awaiting_product",
  "statusName": "Onaylandı, Ürün Bekleniyor",
  "reasonId": 3,
  "reason": "damaged",
  "reasonName": "Hasarlı / Kusurlu Ürün",
  "isOpen": true,
  "itemCount": 1,
  "totalQuantity": 1,
  "requestedAmount": 250.00,
  "refundAmount": null,
  "currency": "TRY",
  "returnCarrier": "MNG Kargo",
  "returnTrackingNumber": "614998877665",
  "createdAt": "2026-11-08T14:10:00",
  "updatedAt": "2026-11-08T15:05:22",
  "resolvedAt": null
}

10.1İade ve iptal taleplerini listele#GET/returns

Firmanızın deposuna ait siparişler için açılmış tüm müşteri iade ve iptal taleplerini sayfalı listeler.

ParametreAçıklama
statusBir veya virgülle ayrılmış durum kodları (ör. received,awaiting_product). Bkz. 13.4
typecancel (kargo öncesi iptal) veya return (teslimat sonrası iade)
orderIdYalnızca belirli bir alt siparişe ait talepler
searchTalep numarası (IPT-... / IAD-...), sipariş numarası (MD.26...) veya iade kargo takip numarası
updatedSinceBu tarihten sonra oluşturulan veya güncellenen talepler
createdFrom, createdToTalep oluşturulma tarih aralığı
page, pageSizeSayfalama (varsayılan 50, en fazla 200)
HTTP
GET /api/integration/v1/returns?status=received,awaiting_product&page=1&pageSize=50

Yanıt: { "items": [ ... ], "page": 1, "pageSize": 50, "totalCount": 1 } (her kayıt bir talep özet nesnesidir).

10.2Talep detayı, kalemler ve geçmiş#GET/returns/{returnId}

Talep özet alanlarına ek olarak müşteri adı/açıklaması, iade kalemleri, durum geçmişi ve o an izinli işlemler (actions) döner:

JSON
{
  "returnId": "c8d12a90-4f88-4c79-a611-94e8bc1102a4",
  "requestNo": "IAD-2026-000142",
  "orderId": "23a4baff-72be-4105-b962-f792d65ecba6",
  "orderNumber": "MD.26.501",
  "typeId": 2,
  "type": "return",
  "typeName": "İade Talebi",
  "statusId": 2,
  "status": "awaiting_product",
  "statusName": "Onaylandı, Ürün Bekleniyor",
  "reasonId": 3,
  "reason": "damaged",
  "reasonName": "Hasarlı / Kusurlu Ürün",
  "isOpen": true,
  "itemCount": 1,
  "totalQuantity": 1,
  "requestedAmount": 250.00,
  "refundAmount": null,
  "currency": "TRY",
  "returnCarrier": "MNG Kargo",
  "returnTrackingNumber": "614998877665",
  "createdAt": "2026-11-08T14:10:00",
  "updatedAt": "2026-11-08T15:05:22",
  "resolvedAt": null,
  "customerName": "Ayşe Yılmaz",
  "customerNote": "Kutu ezik ulaştı.",
  "returnInstructions": "Ürünleri orijinal ambalajında ve faturasıyla birlikte gönderiniz.",
  "rejectReason": null,
  "approvedAt": "2026-11-08T14:30:00",
  "trackingUpdatedAt": "2026-11-08T15:05:22",
  "receivedAt": null,
  "refundedAt": null,
  "items": [
    {
      "lineId": "191534f9-ebc2-41e3-bca2-26f498ba81e2",
      "productId": "1c05196a-db4b-4407-8dee-76914a7e129e",
      "barcode": "8690000000011",
      "productName": "Vitamin C 1000mg",
      "orderedQuantity": 2,
      "quantity": 1,
      "unitPrice": 250.00,
      "lineTotal": 250.00
    }
  ],
  "events": [
    {
      "date": "2026-11-08T15:05:22",
      "type": "tracking_updated",
      "title": "İade kargo bilgisi girildi",
      "description": "MNG Kargo · 614998877665",
      "fromStatus": "awaiting_product",
      "toStatus": "awaiting_product"
    },
    {
      "date": "2026-11-08T14:30:00",
      "type": "approved",
      "title": "Talep onaylandı, ürün bekleniyor",
      "description": null,
      "fromStatus": "received",
      "toStatus": "awaiting_product"
    }
  ],
  "actions": {
    "canApprove": false,
    "canReject": true,
    "canMarkReceived": true,
    "approveCancelsOrderImmediately": false
  }
}

10.3Talebi onayla#POST/returns/{returnId}/approve

received durumundaki talebi onaylar:

  • return (iade) talebinde: Durum awaiting_product olur ve müşteriye e-posta/SMS ile gönderim talimatı iletilir. İsteğe bağlı instructions gönderilmezse standart talimat metni kullanılır.
  • cancel (iptal) talebinde: Hesabınızda allowOrderCancellation: true yetkisi açıksa sipariş iptal edilir, müşteriye tam ödeme iadesi başlatılır ve talep completed durumuna geçer.
JSON
{
  "instructions": "Ürünleri faturasıyla birlikte MNG Kargo anlaşma kodumuzla karşı ödemeli gönderebilirsiniz."
}

Yanıt: 200 + güncel talep detayı (10.2).

10.4İade ürününü teslim al#POST/returns/{returnId}/receive

Müşterinin gönderdiği iade paketi deponuza ulaştığında awaiting_product durumundaki return talebini product_received (Ürün Teslim Alındı) durumuna geçirir. Ardından Hepiyiol finans ekibi tutar iadesini tamamlar (return.completed).

JSON
{
  "note": "Koli ve ambalaj sağlam şekilde depoya teslim alındı."
}

Yanıt: 200 + güncel talep detayı (10.2).

10.5Talebi reddet#POST/returns/{returnId}/reject

Sonuçlanmamış (received, awaiting_product veya product_received) bir talebi gerekçe belirterek rejected durumuna alır. reason müşteriye bildirileceği için açık ve kurumsal bir dille yazılmalıdır (zorunlu, 3–1000 karakter).

JSON
{
  "reason": "Ürünün koruyucu emniyet bandı açılmış olduğundan hijyen kuralları gereği iade kabul edilememektedir."
}

Yanıt: 200 + güncel talep detayı (10.2).

11Webhook (anlık bildirim)#

11.1İstek biçimi#

Olay gerçekleştiğinde kayıtlı adresinize POST isteği gönderilir:

HTTP
POST /hepiyiol/webhook HTTP/1.1
Content-Type: application/json; charset=utf-8
User-Agent: Hepiyiol-Webhook/1.0
X-Hepiyiol-Event: order.shipped
X-Hepiyiol-Delivery: df36f0e7-8925-4095-b29d-d5e1f3b38829
X-Hepiyiol-Sequence: 2
X-Hepiyiol-Timestamp: 1793995153
X-Hepiyiol-Signature: sha256=5c1f0f6d0b…

{
  "id": "df36f0e7-8925-4095-b29d-d5e1f3b38829",
  "sequence": 2,
  "type": "order.shipped",
  "createdAt": "2026-11-06T22:39:13.182254",
  "data": {
    "order": { "orderId": "6eeccb90-…", "orderNumber": "MD.26.502", "status": "shipped", "...": "sipariş özeti (7.1)" },
    "previousStatus": "preparing",
    "status": "shipped"
  }
}
BaşlıkAçıklama
X-Hepiyiol-EventOlay tipi
X-Hepiyiol-DeliveryOlay kimliği (gövdedeki id ile aynı; tekrar denemelerde değişmez)
X-Hepiyiol-SequenceFirmanıza özel artan sıra numarası
X-Hepiyiol-Timestampİmza zamanı (Unix saniye, UTC)
X-Hepiyiol-Signaturesha256= + HMAC-SHA256 imzası

11.2Olay tipleri#

OlayNe zamandata içeriği
order.createdFirmanıza yeni sipariş düştüğünde (ödeme tamamlandıktan sonra)order (tam detay, 7.3)
order.approvedOnay bekleyen sipariş onaylandığındaorder (özet), previousStatus, status
order.shippedSipariş kargoya verildiğindeorder, previousStatus, status
order.deliveredSipariş teslim edildiğinde / tamamlandığındaorder, previousStatus, status
order.cancelledSipariş iptal edildiğindeorder, previousStatus, status
order.status_changedDiğer durum değişiklikleri (ör. iade)order, previousStatus, status
order.invoice_uploadedSiparişe fatura yüklendiğinde veya güncellendiğinde (API veya yönetim/depo panelinden)order (özet), invoice (fatura nesnesi)
order.invoice_deletedSiparişteki fatura kaydı silindiğindeorder (özet), invoice (null)
return.requestedMüşteri yeni bir iptal veya iade talebi açtığındaorder (özet), returnRequest (talep özeti, Bölüm 10)
return.approvedİade talebi onaylandığında (awaiting_product)order (özet), returnRequest
return.tracking_updatedMüşteri iade kargo firması ve takip numarasını girdiğinde/güncellediğindeorder (özet), returnRequest
return.receivedİade kargosu depoda teslim alındığında (product_received)order (özet), returnRequest
return.completedİptal veya iade talebi sonuçlanıp ödeme iadesi tamamlandığında (completed)order (özet), returnRequest
return.rejectedİade veya iptal talebi reddedildiğinde (rejected)order (özet), returnRequest
return.cancelledMüşteri açık talebini geri çektiğinde (cancelled_by_customer)order (özet), returnRequest
shipment.createdGönderi/barkod oluşturulduğundaorder (özet), shipment (özet)
shipment.updatedKargo durumu değiştiğinde (transfer, dağıtımda, teslim edilemedi vb.)order, shipment
shipment.cancelledGönderi iptal edildiğindeorder, shipment
webhook.testPOST /webhook/test iletest verisi

Yeni olay tipleri ileride eklenebilir; tanımadığınız tipleri 2xx döndürerek yok sayınız.

11.3İmza doğrulama (zorunlu)#

İmza şu şekilde hesaplanır:

Metin
signature = "sha256=" + hex( HMAC_SHA256( webhookSecret, X-Hepiyiol-Timestamp + "." + <ham istek gövdesi> ) )
  • İmzayı ham gövde (byte'lar değiştirilmeden, JSON parse edilmeden önce) üzerinden hesaplayınız.
  • Karşılaştırmayı sabit zamanlı (constant-time) yapınız.
  • Tekrar saldırılarına karşı X-Hepiyiol-Timestamp değeri şimdiki zamandan 5 dakikadan eski/yeniyse isteği reddediniz.
  • İmza geçersizse 401 döndürünüz ve işlemi yapmayınız.

C# (.NET)

C#
using System.Security.Cryptography;
using System.Text;

static bool VerifyHepiyiolSignature(string secret, string timestamp, string rawBody, string signatureHeader)
{
    if (!long.TryParse(timestamp, out var ts) ||
        Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - ts) > 300)
        return false;

    using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
    var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes($"{timestamp}.{rawBody}"));
    var expected = "sha256=" + Convert.ToHexString(hash).ToLowerInvariant();

    return CryptographicOperations.FixedTimeEquals(
        Encoding.UTF8.GetBytes(expected), Encoding.UTF8.GetBytes(signatureHeader ?? ""));
}

Node.js (Express)

JavaScript
const crypto = require('crypto');
const express = require('express');
const app = express();

app.post('/hepiyiol/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const ts = req.get('X-Hepiyiol-Timestamp');
  const sig = req.get('X-Hepiyiol-Signature') || '';
  const raw = req.body.toString('utf8');

  if (!ts || Math.abs(Date.now() / 1000 - Number(ts)) > 300) return res.sendStatus(401);

  const expected = 'sha256=' + crypto.createHmac('sha256', process.env.HEPIYIOL_WEBHOOK_SECRET)
    .update(`${ts}.${raw}`).digest('hex');
  if (sig.length !== expected.length ||
      !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) return res.sendStatus(401);

  const event = JSON.parse(raw);
  // event.id daha önce işlendiyse tekrar işlemeyin (idempotency)
  queue.push(event);            // ağır işleri kuyruğa atın
  res.sendStatus(200);          // 15 sn içinde 2xx dönün
});

PHP

PHP
$raw = file_get_contents('php://input');
$ts  = $_SERVER['HTTP_X_HEPIYIOL_TIMESTAMP'] ?? '';
$sig = $_SERVER['HTTP_X_HEPIYIOL_SIGNATURE'] ?? '';

if (!ctype_digit($ts) || abs(time() - (int)$ts) > 300) { http_response_code(401); exit; }

$expected = 'sha256=' . hash_hmac('sha256', $ts . '.' . $raw, getenv('HEPIYIOL_WEBHOOK_SECRET'));
if (!hash_equals($expected, $sig)) { http_response_code(401); exit; }

$event = json_decode($raw, true);
// $event['id'] ile mükerrer kontrolü yapıp işleyin
http_response_code(200);

11.4Teslim, tekrar deneme ve sıralama#

  • Adresiniz 15 saniye içinde 2xx dönmelidir. Ağır işlemleri kuyruğa alıp hemen yanıt veriniz.
  • 2xx dışındaki yanıtlar, zaman aşımı ve bağlantı hataları başarısız sayılır ve şu aralıklarla tekrar denenir: 1 dk, 5 dk, 15 dk, 1 sa, 3 sa, 6 sa, 12 sa, 24 sa (toplam 8 deneme). Sonrasında olay "teslim edilemedi" olarak işaretlenir; Hepiyiol operasyon ekibi elle yeniden gönderebilir, siz de olay akışından alabilirsiniz.
  • Yönlendirmeler (3xx) izlenmez; adresiniz doğrudan 2xx dönmelidir.
  • Aynı olay birden fazla kez gelebilir (en az bir kez teslim). id alanına göre mükerrer kontrolü yapınız.
  • Olayların geliş sırası garanti değildir. Sıralama için sequence değerini kullanınız; şüphede kalırsanız GET /orders/{orderId} ile güncel durumu çekiniz (en güvenilir kaynak her zaman API'dir).

12Olay akışı (polling)#

#GET/events?after={sequence}&limit={n}

Webhook'a alternatif veya yedek olarak, firmanıza ait tüm olayları sırayla okuyabilirsiniz. Webhook kapalı olsa bile olaylar kaydedilir.

ParametreAçıklama
afterSon işlediğiniz sequence değeri (ilk çağrıda 0)
limitSayfa boyutu (1–500, varsayılan 100)
JSON
{
  "events": [
    {
      "id": "22a78df8-3b2b-444d-94c7-87ce48f9d4b9",
      "sequence": 1,
      "type": "shipment.created",
      "createdAt": "2026-11-06T22:39:13.112975",
      "data": { "order": { "...": "..." }, "shipment": { "...": "..." } }
    }
  ],
  "nextCursor": 1,
  "hasMore": false
}

Kullanım: nextCursor değerini saklayınız ve bir sonraki çağrıda after olarak gönderiniz. hasMore: true ise hemen tekrar çağırınız; false ise birkaç dakika sonra tekrar kontrol ediniz.

13Kod ve durum tabloları#

13.1Sipariş durumları#

statusIdstatusAçıklamaFirma ne yapmalı
1waiting_approvalOnay bekliyorapprove veya cancel
2preparingHazırlanıyor / kargolanmayı bekliyorSiparişi hazırlayıp fatura ve gönderi oluşturun
3shippedKargodaHenüz yüklenmediyse faturayı yükleyin; teslimatı takip edin
4deliveredTeslim edildi / tamamlandıHenüz yüklenmediyse faturayı yükleyin
5cancelledİptal edildiHazırlığı durdurun
6waiting_customer_approvalMüşteri/eczane onayı bekleniyorBekleyin
7refundedİade edildi–

payment_pending (0) durumundaki, ödemesi tamamlanmamış siparişler firmalara gösterilmez.

13.2Gönderi durumları#

statusAçıklamaSon durum mu?
order_createdKargo firmasında sipariş açıldı, barkod bekleniyor
label_createdBarkod/etiket oluşturuldu, kargoya teslim bekleniyor
in_transitKargoya verildi / transfer aşamasında
at_delivery_branchVarış şubesinde
out_for_deliveryDağıtımda
deliveredTeslim edildiEvet
delivery_failedTeslim edilemedi
returningİade sürecinde (göndericiye dönüyor)
returnedGöndericiye iade edildiEvet
support_neededKargo firması müdahale gerektiren durum bildirdi
cancelledGönderi iptal edildiEvet
errorHata

Gönderi ↔ sipariş ilişkisi: gönderi in_transit veya sonrası bir duruma geçtiğinde sipariş shipped, delivered olduğunda sipariş delivered olur.

13.3Kargo modları#

cargoModeAçıklamaKullanılacak uçlar
platformGönderiler platformun DHL eCommerce (MNG Kargo) anlaşmasıyla yapılır; kargo ücreti ve takibi platformdadırshipments/platform, label, cancel
partnerFirma kendi kargo anlaşmasıyla gönderir, takip no ve hareketleri bildirirshipments, shipments/{id}/events, cancel
hybridSipariş bazında ikisinden biri seçilebilirHepsi

Kargo modu hesap açılışında Hepiyiol ile birlikte belirlenir; değişiklik için bizimle iletişime geçiniz.

13.4İade / iptal talep durumları ve nedenleri#

Talep durumları (status)

statusIdstatusAçıklamaAçık mı (isOpen)?Firma ne yapmalı
1receivedTalep alındı (inceleme bekliyor)Evetapprove veya reject
2awaiting_productOnaylandı, müşteriden iade kargosu bekleniyorEvetPaket depoya ulaştığında receive (veya inceleme sonrası reject)
3product_receivedİade ürünü depoda teslim alındıEvetKalite kontrol sorunluysa reject; uygunsa platform finans ekibi iadeyi tamamlar
4completedİade / iptal tamamlandı, ödeme iade edildiHayırİade gider pusulası / muhasebe kaydını işleyin
5rejectedTalep reddedildiHayır–
6cancelled_by_customerMüşteri talebini geri çektiHayır–

Talep nedenleri (reason)

reasonIdreasonAçıklama
1changed_mindVazgeçtim
2wrong_itemYanlış ürün gönderildi
3damagedHasarlı / kusurlu ürün
4missing_itemEksik ürün
5expiryMiadı yakın / geçmiş
6otherDiğer (customerNote alanında açıklama yer alır)

14Canlıya geçiş kontrol listesi#

Hepiyiol tarafından iletilecekler

  • API temel adresi ve Swagger adresi
  • API anahtarı (mdp_live_…) — güvenli kanaldan, bir kez
  • Webhook imza anahtarı (whsec_…) — webhook adresi tanımlıysa
  • Hesap ayarları: kargo modu, satış kanalı (B2C/eczane), otomatik iptal yetkisi

Firmanızdan istenenler

  • Teknik ve operasyonel iletişim kişisi (ad, e-posta, telefon)
  • Sabit çıkış IP adresleri (IP kısıtlaması için)
  • Webhook adresi (https://…), herkese açık ve 15 sn içinde 2xx dönen
  • Kendi kargonuzla gönderim yapacaksanız: kullandığınız kargo firmaları

Test senaryoları (önerilen)

  1. GET /ping → 200
  2. POST /webhook/test → sisteminizde imza doğrulamasıyla alındı
  3. GET /products?barcode=… ile 2–3 ürününüzü doğrulayın
  4. PUT /listings ile bir ilan açın, GET /listings ile kontrol edin, quantity: 0 ile kapatın
  5. Test siparişi (Hepiyiol ile koordineli) → order.created webhook'u → GET /orders/{id} (vergi / fatura adresi kontrolü)
  6. GET /orders/uninvoiced ile siparişin faturasız listede geldiğini doğrulayın; PUT /orders/{id}/invoice veya POST /orders/{id}/invoice/upload ile test faturasını yükleyip listeden düştüğünü ve GET /orders/{id}/invoice yanıtını kontrol edin
  7. Kargo modunuza göre gönderi oluşturun; platform kargosunda etiketi (html ve/veya zpl) yazdırın
  8. Kendi kargonuzda delivered hareketi bildirin → order.delivered webhook'u
  9. Teslim edilmiş test siparişi için iade talebi açtırın → return.requested webhook'u → GET /returns → POST /returns/{returnId}/approve → POST /returns/{returnId}/receive akışını doğrulayın
  10. Webhook adresinizi geçici olarak kapatıp GET /events ile kaçan olayları okuyun

Destek: Hata bildirimlerinde istek zamanı, uç adresi, sipariş numarası ve (varsa) internal_error mesajındaki izleme kodunu iletiniz. API anahtarınızı hiçbir zaman e-posta/mesaj içinde paylaşmayınız.

© 2026 HepiyiolEntegrasyon desteği için hesap yöneticinizle iletişime geçin.