1Genel bilgiler#
| Konu | Değer |
|---|---|
| Temel adres (base URL) | https://mordepo-api.azurewebsites.net/api/integration/v1 |
| Biçim | JSON (Content-Type: application/json; charset=utf-8) |
| Alan adları | camelCase (orderId, trackingNumber …) |
| Karakter seti | UTF-8 (Türkçe karakterler desteklenir) |
| Para birimi | TRY, ondalık ayıracı nokta (189.90) — tutarlar KDV dahildir |
| Tarih/saat | ISO-8601 (2026-11-06T14:30:00). Yanıtlardaki tarih/saatler Türkiye saatidir (UTC+3). İstekte saat dilimi belirtilmezse Türkiye saati kabul edilir. |
| Kimlikler | GUID (23a4baff-72be-4105-b962-f792d65ecba6) |
| İstek limiti | Varsayılan dakikada 120 istek (API anahtarı başına) |
| Sayfalama | page (1'den başlar), pageSize (en fazla 100, varsayılan 50) |
| Swagger / OpenAPI | https://mordepo-api.azurewebsites.net/swagger → "integration" dokümanı |
| Güncel doküman | hepiyiol.com/entegrasyon-api |
Sayfalı yanıtların ortak biçimi:
{ "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:
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:
{ "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:
{
"error": {
"code": "validation_error",
"message": "Sipariş 'shipped' durumunda; onaylanamaz.",
"details": null
}
}| HTTP | error.code | Anlamı / 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) |
| 400 | invalid_body, invalid_query | İstek gövdesi/parametreleri eksik veya hatalı |
| 401 | unauthorized | X-Api-Key yok veya geçersiz |
| 403 | forbidden | Hesap pasif, IP izni yok veya işlem hesabınızın kargo moduna uygun değil |
| 404 | not_found | Kayıt yok veya firmanıza ait değil |
| 422 | validation_error | İş kuralı hatası (mesajı kullanıcıya/operasyona gösterebilirsiniz) |
| 429 | rate_limited | İstek limiti aşıldı; Retry-After kadar bekleyiniz |
| 500 | internal_error | Beklenmeyen hata. Mesajdaki izleme kodunu destek talebinize ekleyiniz |
| 503 | unavailable | Entegrasyon 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ışı#
Stok senkronizasyonu önerisi
- Değişen ürünleri anlık (veya 5–15 dakikada bir)
PUT /listingsile gönderiniz. - Günde bir kez tüm aktif stok listenizi gönderip, listenizde artık olmayan barkodları
POST /listings/deactivateile kapatınız (GET /listings?active=trueile platformdaki aktif ilanlarınızı karşılaştırabilirsiniz). - Stok 0 olan ürünü
quantity: 0ile 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(veyaGET /orders?hasInvoice=false) ucunu kullanıp kesilen e-Fatura / e-Arşiv belgesiniPUT /orders/{orderId}/invoiceya daPOST /orders/{orderId}/invoice/uploadile yükleyiniz (bkz. Bölüm 8). - Müşteri iade/iptal taleplerini
return.*webhook olaylarıyla anlık alabilir veyaGET /returns?status=received,awaiting_productile açık RMA kuyruğunuzu çekebilirsiniz (bkz. Bölüm 10).
5Hesap uçları#
5.1Bağlantı ve kimlik testi#GET/ping
{
"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
}
}| Alan | Açıklama |
|---|---|
cargoMode | platform: 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) |
allowOrderCancellation | true ise iptal isteğiniz anında uygulanır; false ise talep olarak yöneticiye iletilir (202) |
5.2Webhook ayarı#GET/webhook
{ "url": "https://entegrasyon.firma.com/hepiyiol/webhook", "enabled": true, "hasSecret": true }5.3Webhook adresini güncelle#PUT/webhook
{ "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: nullveyaenabled: falseile bildirimler durdurulur (olaylar yine de olay akışında tutulur).
5.4İmza anahtarını yenile#POST/webhook/rotate-secret
{ "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:
{ "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
| Parametre | Açıklama |
|---|---|
barcode | Barkod ile tam eşleşme |
search | Ürün adında arama (en az 3 karakter) |
page, pageSize | Sayfalama |
barcode veya search parametrelerinden biri zorunludur.
GET /api/integration/v1/products?barcode=8690000000011{
"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
| Parametre | Açıklama |
|---|---|
barcode | Belirli bir barkod |
active | true: yalnızca satışta olanlar, false: yalnızca kapalı olanlar |
page, pageSize | Sayfalama |
{
"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.
{
"items": [
{
"barcode": "8690000000011",
"quantity": 100,
"maxQuantity": 10,
"deadline": "2027-12",
"marketPrice": 249.90,
"warehousePrice": 200.00
},
{
"barcode": "8690000000028",
"quantity": 0
}
]
}| Alan | Zorunlu | Açıklama |
|---|---|---|
barcode | Evet | Katalogdaki ürün barkodu. Aynı istekte aynı barkod bir kez bulunmalıdır. |
quantity | Evet | Satılabilir stok adedi (0 – 1.000.000). 0 gönderilirse ilan satışa kapatılır. |
maxQuantity | Hayır | Tek siparişte alınabilecek en fazla adet |
deadline | Yeni ilan için evet | Son kullanma tarihi (miad). Kabul edilen biçimler: 0627, 06/27, 06/2027, 2027-06, 2027-06-30. Platformda AAYY biçiminde saklanır. |
marketPrice | Yeni ilan için evet | Tüketiciye satış fiyatı, KDV dahil |
warehousePrice | Hayır | Depo 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
| HTTP | Durum |
|---|---|
200 | Tüm kayıtlar başarılı |
207 | Bir kısmı başarılı, bir kısmı hatalı |
422 | Hiçbir kayıt işlenemedi |
{
"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
{ "barcodes": ["8690000000011", "8690000000028"] }{ "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
| Parametre | Açıklama |
|---|---|
status | Bir veya virgülle ayrılmış birden fazla durum kodu (ör. waiting_approval,preparing). Bkz. 13.1 |
updatedSince | Bu tarihten sonra oluşturulan/güncellenen siparişler (ör. 2026-11-06T00:00:00) |
createdFrom | Sipariş oluşturulma başlangıç tarihi (CreatedOn >= createdFrom) |
createdTo | Sipariş oluşturulma bitiş tarihi (CreatedOn <= createdTo) |
hasInvoice | false: faturası henüz yüklenmemiş siparişler · true: faturası yüklenmiş siparişler |
invoiceNumber | Fatura numarasında arama (büyük/küçük harf duyarsız kısmi eşleşme, ör. MDP2026) |
hasOpenReturn | true: üzerinde sonuçlanmamış müşteri iade/iptal talebi bulunan siparişler · false: açık talebi olmayanlar |
page, pageSize | Sayfalama (en yeni güncellenen önce) |
{
"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
}| Alan | Açıklama |
|---|---|
amounts.itemsTotal | Ürün satırlarının toplamı (KDV dahil, indirim düşülmüş) |
amounts.vatTotal | Bu toplamın içindeki KDV (bilgi amaçlı) |
amounts.shippingFee | Kargo ü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.grandTotal | itemsTotal + shippingFee |
fulfillmentMode | Hesabınızın kargo modu (platform / partner / hybrid) |
hasInvoice | Siparişe fatura yüklenip yüklenmediği (true / false) |
invoiceNumber | Yüklenen faturanın resmi numarası; fatura yoksa null |
invoice | Yüklenen faturanın özet/detay nesnesi (bkz. Bölüm 8); fatura yoksa null |
hasOpenReturn | Sipariş üzerinde açık (sonuçlanmamış) bir müşteri iade/iptal talebi olup olmadığı (true / false) |
shipment | Sipariş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 == falseolan siparişleri döner. statusparametresi gönderilmezse varsayılan olarak yalnızca faturalanabilir aktif durumları filtreler:waiting_approval,preparing,shipped,delivered(iptal edilencancelledve iade edilenrefundedsiparişler hariç tutulur).- İsterseniz
status=preparing,shipped,updatedSince,createdFrom,createdTo,page,pageSizeparametreleriyle daraltabilirsiniz.
GET /api/integration/v1/orders/uninvoiced?status=preparing,shipped&page=1&pageSize=50Yanı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:
{
"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):
| Alan | Açıklama |
|---|---|
invoiceAddress.title | Fatura unvanı / başlığı (kurumsal alıcıda ticari unvan veya eczane adı) |
invoiceAddress.taxNumber | 11 haneli TCKN veya 10 haneli VKN (fatura adresinde girilmemişse alıcı hesabındaki değer döner) |
invoiceAddress.taxOffice | Vergi dairesi adı (kurumsal/eczane alıcılarda dolu; bireysel alıcılarda null) |
invoiceAddress.isCorporate | true: kurumsal / eczane alıcı (VKN veya vergi dairesi mevcut) · false: bireysel tüketici (e-Arşiv) |
customer.gln | Eczane alıcılarda 13 haneli GLN numarası (İTS / B2B süreçleri için); bireysel üyelerde null |
actions.canUploadInvoice | Sipariş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.
{ "reason": "Ürün stokta kalmadı." }reason zorunludur (en fazla 500 karakter).
| Yanıt | Durum |
|---|---|
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 |
422 | Sipariş bu durumda iptal edilemez |
{
"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öntem | Uç | Ne zaman tercih edilmeli |
|---|---|---|
A. JSON ile fatura kaydı (externalUrl ve/veya fileBase64) | PUT /orders/{orderId}/invoice | e-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/upload | Ham 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çinPUTveyaPOST .../uploadtekrar ç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çıkhttps://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 dosyalar422ile 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_uploadedolayı üretilir.
Fatura nesnesi#
{
"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:
{
"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:
{
"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"
}| Alan | Zorunlu | Açıklama |
|---|---|---|
invoiceNumber | Evet | GİB resmi fatura numarası (en fazla 100 karakter, ör. MDP2026000001452) |
invoiceType | Hayır | earsiv veya efatura. Boş bırakılırsa alıcı tipine göre otomatik belirlenir (eczane/kurumsal → efatura, bireysel → earsiv) |
ettn | Hayır (önerilir) | GİB Evrensel Tekil Tanımlama Numarası (UUID, 8–64 karakter) |
invoiceDate | Hayır | Fatura düzenleme tarihi (ISO-8601; boşsa yükleme anı kaydedilir) |
totalAmount | Hayır | KDV dahil fatura genel toplamı |
vatAmount | Hayır | Toplam KDV tutarı (totalAmount değerinden büyük olamaz) |
currency | Hayır | Para birimi (varsayılan TRY) |
externalUrl | Koşullu* | Herkese açık https:// fatura görüntüleme/indirme linki (yerel/iç ağ IP'leri güvenlik nedeniyle reddedilir) |
fileBase64 | Koşullu* | Ham Base64 veya data:application/pdf;base64,... biçiminde kodlanmış dosya içeriği (en fazla 10 MB) |
fileName | Hayır | Dosya adı (ör. MDP2026000001452.pdf; boşsa invoiceNumber + algılanan uzantı kullanılır) |
contentType | Hayır | Bildirilen 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ı | Zorunlu | Açıklama |
|---|---|---|
file | Evet | Fatura dosyası (PDF, UBL-XML, HTML, PNG, JPG — en fazla 10 MB) |
invoiceNumber | Evet | GİB resmi fatura numarası |
invoiceType | Hayır | earsiv veya efatura |
ettn | Hayır | GİB ETTN (UUID) |
invoiceDate | Hayır | ISO-8601 fatura tarihi |
totalAmount | Hayır | KDV dahil toplam tutar |
vatAmount | Hayır | KDV tutarı |
currency | Hayır | Para birimi (TRY) |
externalUrl | Hayır | Ek olarak harici https:// görüntüleme linki |
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.
{ "deleted": true }9Kargo / gönderiler#
Hesabınızın kargo moduna göre iki yöntemden biri (hybrid modda ikisi de) kullanılabilir:
| Yöntem | Uç | Kargo modu |
|---|---|---|
| A. Platform kargosu (DHL eCommerce / MNG Kargo anlaşması) | POST /orders/{id}/shipments/platform | platform, hybrid |
| B. Firmanın kendi kargosu | POST /orders/{id}/shipments | partner, 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#
{
"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" }
]
}| Alan | Açıklama |
|---|---|
shippedBy | platform (platform kargosu), partner (firmanın kendi kargosu), manual (Hepiyiol operasyonunca girilen) |
referenceId | Kargo firmasına iletilen sipariş referansı (platform gönderilerinde) |
barcodes | Paket barkodları (parça sayısı kadar) |
status | Gönderi durum kodu — bkz. 13.2 |
lastError | Kargo siparişi açıldı ancak barkod henüz alınamadıysa nedeni (sistem otomatik tekrar dener) |
events | Kargo 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.
{
"pieceCount": 2,
"desi": 4,
"kg": 3,
"content": "Sağlık ürünü",
"invoiceNumber": "ABC2026000123"
}| Alan | Zorunlu | Açıklama |
|---|---|---|
pieceCount | Hayır (vars. 1) | Koli/paket adedi; her paket için ayrı barkod üretilir |
desi | Hayır | Toplam desi (paketlere eşit bölünür). Boşsa varsayılan |
kg | Hayır | Toplam ağırlık. Boşsa varsayılan |
content | Hayır | İçerik açıklaması |
invoiceNumber | Hayır | Fatura / irsaliye numarası |
Yanıt: 201 + gönderi nesnesi (status: "label_created"). Ardından:
- Etiketi indirip yazdırınız (9.5) ve pakete yapıştırınız,
- Paketi DHL eCommerce / MNG şubesine teslim ediniz veya kurye ile alımı bekleyiniz,
- 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ğindedeliveredolur 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.
{
"carrierName": "Aras Kargo",
"trackingNumber": "ARS998877",
"trackingUrl": "https://kargotakip.araskargo.com.tr/?code=ARS998877",
"invoiceNumber": "ABC2026000124",
"shippedAt": "2026-11-06T16:30:00"
}| Alan | Zorunlu | Açıklama |
|---|---|---|
carrierName | Evet | Kargo firması adı |
trackingNumber | Evet | Takip numarası |
trackingUrl | Hayır (önerilir) | Müşterinin takip edebileceği adres |
invoiceNumber | Hayır | Fatura / irsaliye no |
shippedAt | Hayır | Kargoya 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).
{
"status": "delivered",
"description": "Alıcıya teslim edildi",
"location": "Kadıköy Şube",
"occurredAt": "2026-11-07T11:20:00",
"deliveredTo": "Ayşe Yılmaz"
}| Alan | Zorunlu | Açıklama |
|---|---|---|
status | Evet | in_transit, at_delivery_branch, out_for_delivery, delivered, delivery_failed, returning, returned |
description | Hayır | Açıklama |
location | Hayır | Konum / şube |
occurredAt | Hayır | Hareket zamanı (boşsa şimdi) |
deliveredTo | Hayır | Teslim 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 | İçerik | Kullanım |
|---|---|---|
html (varsayılan) | text/html | Tarayıcıda açıp 10x15 cm etiket olarak yazdırma (barkod + alıcı + gönderici bilgisi) |
zpl | text/plain | Zebra vb. termal yazıcılara doğrudan gönderim (platform gönderilerinde kargo firmasının resmi etiketi) |
png | image/png | Görsel etiket (platformda etkinse) |
9.6Gönderiyi iptal et#POST/orders/{orderId}/shipments/{shipmentId}/cancel
{ "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
preparingdurumuna 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).
{
"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"
}| Alan | Açıklama |
|---|---|
carrierName | Kargo firması adı (boş olamaz) |
trackingNumber | Yeni takip numarası. Değişir ve trackingUrl gönderilmezse eski link silinir |
trackingUrl | Takip linki ("" gönderilirse silinir) |
invoiceNumber | Fatura / irsaliye no |
shippedAt | Kargoya veriş zamanı |
- Yanıt:
200+ güncel gönderi nesnesi. Müşterinin sipariş takibindeki bilgi de güncellenir,shipment.updatedolayı ü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:
type | typeId | Ne zaman açılabilir | Akış özeti |
|---|---|---|---|
cancel | 1 | Sipariş henüz kargoya verilmeden önce (waiting_approval veya preparing) | received → onaylandığında sipariş iptal edilir ve tam ödeme iadesi başlatılır (completed) |
return | 2 | Sipariş 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ığındareturn.completedolayı 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ıcanceltipindeki taleplerde yalnızca hesabınızdaallowOrderCancellation: trueyetkisi 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#
{
"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.
| Parametre | Açıklama |
|---|---|
status | Bir veya virgülle ayrılmış durum kodları (ör. received,awaiting_product). Bkz. 13.4 |
type | cancel (kargo öncesi iptal) veya return (teslimat sonrası iade) |
orderId | Yalnızca belirli bir alt siparişe ait talepler |
search | Talep numarası (IPT-... / IAD-...), sipariş numarası (MD.26...) veya iade kargo takip numarası |
updatedSince | Bu tarihten sonra oluşturulan veya güncellenen talepler |
createdFrom, createdTo | Talep oluşturulma tarih aralığı |
page, pageSize | Sayfalama (varsayılan 50, en fazla 200) |
GET /api/integration/v1/returns?status=received,awaiting_product&page=1&pageSize=50Yanı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:
{
"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: Durumawaiting_productolur ve müşteriye e-posta/SMS ile gönderim talimatı iletilir. İsteğe bağlıinstructionsgönderilmezse standart talimat metni kullanılır.cancel(iptal) talebinde: HesabınızdaallowOrderCancellation: trueyetkisi açıksa sipariş iptal edilir, müşteriye tam ödeme iadesi başlatılır ve talepcompleteddurumuna geçer.
{
"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).
{
"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).
{
"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:
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ık | Açıklama |
|---|---|
X-Hepiyiol-Event | Olay tipi |
X-Hepiyiol-Delivery | Olay kimliği (gövdedeki id ile aynı; tekrar denemelerde değişmez) |
X-Hepiyiol-Sequence | Firmanıza özel artan sıra numarası |
X-Hepiyiol-Timestamp | İmza zamanı (Unix saniye, UTC) |
X-Hepiyiol-Signature | sha256= + HMAC-SHA256 imzası |
11.2Olay tipleri#
| Olay | Ne zaman | data içeriği |
|---|---|---|
order.created | Firmanıza yeni sipariş düştüğünde (ödeme tamamlandıktan sonra) | order (tam detay, 7.3) |
order.approved | Onay bekleyen sipariş onaylandığında | order (özet), previousStatus, status |
order.shipped | Sipariş kargoya verildiğinde | order, previousStatus, status |
order.delivered | Sipariş teslim edildiğinde / tamamlandığında | order, previousStatus, status |
order.cancelled | Sipariş iptal edildiğinde | order, previousStatus, status |
order.status_changed | Diğer durum değişiklikleri (ör. iade) | order, previousStatus, status |
order.invoice_uploaded | Siparişe fatura yüklendiğinde veya güncellendiğinde (API veya yönetim/depo panelinden) | order (özet), invoice (fatura nesnesi) |
order.invoice_deleted | Siparişteki fatura kaydı silindiğinde | order (özet), invoice (null) |
return.requested | Müşteri yeni bir iptal veya iade talebi açtığında | order (özet), returnRequest (talep özeti, Bölüm 10) |
return.approved | İade talebi onaylandığında (awaiting_product) | order (özet), returnRequest |
return.tracking_updated | Müşteri iade kargo firması ve takip numarasını girdiğinde/güncellediğinde | order (ö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.cancelled | Müşteri açık talebini geri çektiğinde (cancelled_by_customer) | order (özet), returnRequest |
shipment.created | Gönderi/barkod oluşturulduğunda | order (özet), shipment (özet) |
shipment.updated | Kargo durumu değiştiğinde (transfer, dağıtımda, teslim edilemedi vb.) | order, shipment |
shipment.cancelled | Gönderi iptal edildiğinde | order, shipment |
webhook.test | POST /webhook/test ile | test 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:
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-Timestampdeğeri şimdiki zamandan 5 dakikadan eski/yeniyse isteği reddediniz. - İmza geçersizse
401döndürünüz ve işlemi yapmayınız.
C# (.NET)
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)
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
$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
2xxdönmelidir. Ağır işlemleri kuyruğa alıp hemen yanıt veriniz. 2xxdışı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
2xxdönmelidir. - Aynı olay birden fazla kez gelebilir (en az bir kez teslim).
idalanına göre mükerrer kontrolü yapınız. - Olayların geliş sırası garanti değildir. Sıralama için
sequencedeğerini kullanınız; şüphede kalırsanızGET /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.
| Parametre | Açıklama |
|---|---|
after | Son işlediğiniz sequence değeri (ilk çağrıda 0) |
limit | Sayfa boyutu (1–500, varsayılan 100) |
{
"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ı#
statusId | status | Açıklama | Firma ne yapmalı |
|---|---|---|---|
| 1 | waiting_approval | Onay bekliyor | approve veya cancel |
| 2 | preparing | Hazırlanıyor / kargolanmayı bekliyor | Siparişi hazırlayıp fatura ve gönderi oluşturun |
| 3 | shipped | Kargoda | Henüz yüklenmediyse faturayı yükleyin; teslimatı takip edin |
| 4 | delivered | Teslim edildi / tamamlandı | Henüz yüklenmediyse faturayı yükleyin |
| 5 | cancelled | İptal edildi | Hazırlığı durdurun |
| 6 | waiting_customer_approval | Müşteri/eczane onayı bekleniyor | Bekleyin |
| 7 | refunded | İade edildi | – |
payment_pending (0) durumundaki, ödemesi tamamlanmamış siparişler firmalara gösterilmez.
13.2Gönderi durumları#
status | Açıklama | Son durum mu? |
|---|---|---|
order_created | Kargo firmasında sipariş açıldı, barkod bekleniyor | |
label_created | Barkod/etiket oluşturuldu, kargoya teslim bekleniyor | |
in_transit | Kargoya verildi / transfer aşamasında | |
at_delivery_branch | Varış şubesinde | |
out_for_delivery | Dağıtımda | |
delivered | Teslim edildi | Evet |
delivery_failed | Teslim edilemedi | |
returning | İade sürecinde (göndericiye dönüyor) | |
returned | Göndericiye iade edildi | Evet |
support_needed | Kargo firması müdahale gerektiren durum bildirdi | |
cancelled | Gönderi iptal edildi | Evet |
error | Hata |
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ı#
cargoMode | Açıklama | Kullanılacak uçlar |
|---|---|---|
platform | Gönderiler platformun DHL eCommerce (MNG Kargo) anlaşmasıyla yapılır; kargo ücreti ve takibi platformdadır | shipments/platform, label, cancel |
partner | Firma kendi kargo anlaşmasıyla gönderir, takip no ve hareketleri bildirir | shipments, shipments/{id}/events, cancel |
hybrid | Sipariş bazında ikisinden biri seçilebilir | Hepsi |
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)
statusId | status | Açıklama | Açık mı (isOpen)? | Firma ne yapmalı |
|---|---|---|---|---|
| 1 | received | Talep alındı (inceleme bekliyor) | Evet | approve veya reject |
| 2 | awaiting_product | Onaylandı, müşteriden iade kargosu bekleniyor | Evet | Paket depoya ulaştığında receive (veya inceleme sonrası reject) |
| 3 | product_received | İade ürünü depoda teslim alındı | Evet | Kalite kontrol sorunluysa reject; uygunsa platform finans ekibi iadeyi tamamlar |
| 4 | completed | İade / iptal tamamlandı, ödeme iade edildi | Hayır | İade gider pusulası / muhasebe kaydını işleyin |
| 5 | rejected | Talep reddedildi | Hayır | – |
| 6 | cancelled_by_customer | Müşteri talebini geri çekti | Hayır | – |
Talep nedenleri (reason)
reasonId | reason | Açıklama |
|---|---|---|
| 1 | changed_mind | Vazgeçtim |
| 2 | wrong_item | Yanlış ürün gönderildi |
| 3 | damaged | Hasarlı / kusurlu ürün |
| 4 | missing_item | Eksik ürün |
| 5 | expiry | Miadı yakın / geçmiş |
| 6 | other | Diğ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çinde2xxdönen - Kendi kargonuzla gönderim yapacaksanız: kullandığınız kargo firmaları
Test senaryoları (önerilen)
GET /ping→200POST /webhook/test→ sisteminizde imza doğrulamasıyla alındıGET /products?barcode=…ile 2–3 ürününüzü doğrulayınPUT /listingsile bir ilan açın,GET /listingsile kontrol edin,quantity: 0ile kapatın- Test siparişi (Hepiyiol ile koordineli) →
order.createdwebhook'u →GET /orders/{id}(vergi / fatura adresi kontrolü) GET /orders/uninvoicedile siparişin faturasız listede geldiğini doğrulayın;PUT /orders/{id}/invoiceveyaPOST /orders/{id}/invoice/uploadile test faturasını yükleyip listeden düştüğünü veGET /orders/{id}/invoiceyanıtını kontrol edin- Kargo modunuza göre gönderi oluşturun; platform kargosunda etiketi (
htmlve/veyazpl) yazdırın - Kendi kargonuzda
deliveredhareketi bildirin →order.deliveredwebhook'u - Teslim edilmiş test siparişi için iade talebi açtırın →
return.requestedwebhook'u →GET /returns→POST /returns/{returnId}/approve→POST /returns/{returnId}/receiveakışını doğrulayın - Webhook adresinizi geçici olarak kapatıp
GET /eventsile 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.