Public API v1 sözleşmesi Gönderiler PA-06
Etiket çıktısı
GET/api/v1/shipments/{id}/label
Amaç
Gönderinin barkod/etiket çıktısını taşıyıcıdan almak (canlı taşıyıcı çağrısıdır) VE etiket-anında gönderi ücretini bakiyeden düşmek (TASK-047; REQ-005, DEC-038/DEC-043/DEC-044). Kargonomi "Barkod Çıktısı Alma" eşleniğidir; ad, taşıyıcı sözleşmesindeki getLabel ile hizalıdır.
Yetki
Bearer anahtar; policy label yeteneği (salt-okuma view'dan AYRI; RISK-008/TASK-054, PA-05 cancel ile aynı kalıp; uç PARA KESER, 403 yolunda ücret kesilmez); başka tenant'ın kaydı 404 (IDOR).
Parametreler
id (path, ULID); format (query, ZORUNLU): pdf | zpl | png | jpeg. Varsayılan biçim BİLİNÇLİ yoktur (çapa required kuralını VE seçenek kümesini birlikte tutar: bir varsayılan eklemek sometimes/nullable ya da bir öndeğer gerektirir ve literali kırar) (POLA: taşıyıcılar arası sessiz biçim değişimi olmaz): hepsijet dördünü de, tex yalnız zpl üretir; hesabın taşıyıcısı desteklemiyorsa 422 (errors.format, desteklenen biçimler mesajda). Koli sayısını sunucu gönderi kaydından geçirir; parametre değildir.
`desi` (query, İSTEĞE BAĞLI; TASK-220; DEC-175/DEC-174)
ücretin hesaplandığı desiyi istekle taşımanızı sağlar. Gönderildiğinde PA-04 ölçü düzeltmesiyle birebir aynı katılıkta doğrulanır: pozitif, sayısal, gt:0, ve DEC-316 uyarınca gönderinin koli satırlarıyla ÇELİŞMEYEN ve gönderiye YAZILIR, çünkü shipment_charges satırı desiden türer (Yurtiçi kademesi ise koli başına desi ile kg'nin büyüğünden seçilir; ağırlık girilmezse desiden): desi gönderide durmazsa kesilen ücret sonradan gönderiyle mutabakat edilemez (denetim boşluğu). Yazma, uca yeni bir yetki sınıfı GETİRMEZ: uç bugünkü label yeteneğiyle yetkilenmeye devam eder (update aranmaz); label tutan çağıran zaten cüzdandan para keser, yazma ödenen işlemin doğrudan sonucudur. Gönderilmediğinde gönderinin kendi desisi kullanılır: davranış bugünküyle aynıdır ve alanı bilmeyen istemciler etkilenmez. Alanın YOKLUĞU ile BOZUK bir değer ayrı muamele görür: desi= ya da desi=abc sessizce "yok" sayılmaz, 422 errors.desi döner; aksi hâlde bir yazım hatası amaçlanmamış bir ücretle sonuçlanabilirdi.
KENDİ HESABI gönderisinde bu uç ÜCRET KESMEZ ve `desi` KABUL ETMEZ (TASK-412; DEC-363, kullanıcı kararı 2026-09-04)
Gönderi billing_mode=carrier_direct ile oluşturulduysa (tenant'ın kendi taşıyıcı hesabı) etiket alınırken bakiye düşülmez, shipment_charges satırı yazılmaz, defter dokunulmaz ve yanıttaki charge alanı null döner. desi parametresi bu gönderilerde uç sözleşmesinde YOKTUR: gönderilirse DEĞERİNE BAKILMADAN 422 errors.desi alır ve mesaj ölçünün PA-04 ölçü güncellemesiyle yazılacağını söyler. İki gerekçe: (1) alanın buradaki tek işi ücreti üretmekti ve ücret yoktur, (2) alanın gönderiye yazılması DEC-174 ile "ödenen işlemin doğrudan sonucu" diye meşrulaştırılmış ve TAM BU GEREKÇEYLE update yetkisi aranmamıştı; ödeme ortadan kalkınca yazmak, yalnız label tutan bir çağırana sessizce yazma yetkisi vermek olurdu. Sessizce yok saymak seçilmedi çünkü tenant ölçüyü düzelttiğini SANIR, oysa kayıt değişmemiştir.
Sürüm notu (DEC-175; expand-migrate-contract)
Bu alan v1'e "Sürümleme" bölümünün açıkça izin verdiği biçimde, yeni isteğe bağlı alan olarak girer; mevcut çağıranlar için kırıcı değildir. Alanı ZORUNLU kılmak ("zorunlu hâle gelen yeni bir istek alanı") aynı bölümün kırıcı saydığı sınıftadır ve v1'e GİRMEZ: zorunluluk /api/v2 köküne ERTELENMİŞTİR ve v1 duyurulu bir geçiş süresi yaşayacaktır. Ölçülen gerekçe: zorunluluk, desisi zaten dolu gönderiler için desi göndermeyen TÜM mevcut çağıranları da 422'ye düşürüyordu (RISK-062). DEC-170'in diğer iki hükmü değişmeden yaşar: PA-04 ölçü düzeltmesi yerinde kalır ve beyan edilmiş varsayılan desi REDDEDİLMİŞTİR; desi hiçbir yerde yoksa uç fail-closed 422 verir.
TERMİNAL-DURUM ön koşulu (TASK-062; SHP-05)
gönderinin canonical_status değeri CANCELLED veya RETURNED ise uç 422 {message} döner ve HİÇBİR charge YAZILMAZ; kapı format doğrulamasından SONRA, taşıyıcı hesabı/capability kapılarından ve ücret kesiminden ÖNCE koşar (iptal/güncelleme uçlarındaki durum-kapısı kalıbı). Bu kapı olmadan para tutarlılığı tamamen taşıyıcının reddine kalırdı: iptal edilip ücreti İADE EDİLMİŞ gönderide settle edilmiş charge REUSE EDİLMEZ, dolayısıyla tekrar etiket isteği YENİ bir attempt açıp bakiyeden yeniden keserdi. Terminal olmayan diğer durumlarda etiket alınabilir (kapı bir durum beyaz listesi değil, KAPALI-durum reddidir).
Sıralama (strict-prepaid, DEC-043)
önce YEREL kapılar (terminal durum/ hesap/kayıt/capability: taşıyıcıya inilmez), ardından ücret bakiyeden ATOMİK + İDEMPOTENT kesilir (taşıyıcı label isteğinden ÖNCE), ardından taşıyıcı getLabel, sonra taşıyıcı etiket ÜRETEMEZSE bu istekte kesilen charge net-sıfıra REVERSAL edilir (reuse edilen önceki başarılı charge iade EDİLMEZ). Ücret + fiyat politikası girdileri IMMUTABLE shipment_charges snapshot'ına yazılır; aynı gönderiye retry AYNI teklifi kullanır (bir etiket = bir charge; DEC-044).
Başarı 200
{"data": {"format": "ZPL", "content_base64": "...", "reference_label": null, "per_parcel": {"<koli-barkodu>": "..."}, "charge": {"fee_minor": 1550, "vat_rate_percent": 20, "vat_minor": 310, "total_minor": 1860, "currency": "TRY", "policy_version": "..."}}}; content_base64 gönderinin tam etiketi; per_parcel koli bazlı içerik (yoksa boş nesne); reference_label dönen belgenin REFERANS (sipariş) etiketi olup olmadığıdır (TASK-472; DEC-439 (b), DEC-457 (c)); taşıyıcı gönderi barkodunu üretemediğinde true olur ve tüketici belgeyi normal etiket gibi sunmamalıdır: şube kabulde tekrar okutur. ANAHTAR HER ZAMAN VARDIR; taşıyıcı bu olguyu bildirmiyorsa değeri nulldır ve null "normal etiket" DEMEK DEĞİLDİR. Alan ADİTİF eklendi: okumayan mevcut istemciler etkilenmez. charge etiket-anında kesilen ücret + onu üreten fiyat sürümü (immutable snapshot'tan, tam sayı kuruş). fee_minor NET taşıyıcı ücretidir ve anlamı hiç değişmedi; cüzdandan fiilen düşen tutar `total_minor`dır (TASK-448; REQ-026, DEC-405 (b)) ve vat_rate_percent ile vat_minor o toplamın KDV bileşenini adıyla taşır. Tüketici kendi çarpmasını yapmaz ve yapmamalıdır. Üç alan ADİTİF eklendi: alanı okumayan mevcut istemciler etkilenmez. KDV'den ÖNCE kesilmiş bir snapshot okunuyorsa vat_rate_percent ve vat_minor nulldır ve total_minor net tutarın kendisidir: o kesimde KDV alınmadı. Kendi hesabı gönderisinde charge null döner: anahtar HER ZAMAN vardır, değeri yoktur. Anahtarın düşürülmesiyle null dönmesi aynı şey DEĞİLDİR; ikincisi "bu gönderiden ücret alınmadı" der.
Hatalar
401, 404, 422 (errors.format biçim geçersiz/taşıyıcı desteklemiyor; errors.desi gönderilen desi pozitif sayı değil ya da gönderi kendi hesabı yoluyla ücretlendiriliyor), 422 {message} (taşıyıcı reddi, örn. etiket henüz üretilmemiş), 422 `{message}` fail-closed (charge YAPILMADAN): gönderi TERMİNAL durumda (CANCELLED/RETURNED) VEYA geçerli/aktif fiyat politikası yok VEYA ne istekte ne gönderide desi var VEYA desi NEGATİF VEYA yetersiz bakiye (strict-prepaid: etiket oluşmaz, kredi/negatif bakiye yok), 429, 502. Desi hiçbir yerde yoksa mesaj çareyi adıyla söyler: fail-closed gerekçesinin yanında isteğe desi eklenebileceği ve PA-04 ölçü güncellemesinin yolu bildirilir; susan bir 422, kullanıcıyı ne yapacağını bilmeden bırakıyordu (DEC-170'in "kullanıcı karar anına getirilir" amacı v1'de bu cümleyle karşılanır). Negatif desi (fail-fast; güven sınırı): desi ayrıştırma bir güven sınırıdır ve İŞARET SESSİZCE SOYULMAZ: negatif desi mutlak değere çevrilip ücretlendirilmez, fiyatlama hatasıyla REDDEDİLİR (mesajda değer; charge yok). Kural her iki fiyat stratejisinde de aynıdır (genel yapılandırma tarifesi ve tarife kartı); işaretli sıfır (-0.00) sıfırdır ve reddedilmez. Üretim varsayılanı: aktif fiyat politikası tanımlı DEĞİLSE tüm etiketler fail-closed 422 döner; ticari onaylı bir fiyat politikası sürümü (go-live adımı 14-operations "Fiyat politikası") tanımlanana dek ücret kesilmez (10-security "Para hareketi").
ETİKET BELGESİ BU UÇTAN YENİDEN DÖNMEZ; SEVKORA PANELİ İÇİN SÜRELİ VE ŞİFRELİ SAKLANIR (TASK-532; DEC-521 (b)(c))
Bu bir uygulama ayrıntısı değil, tüketicinin BİLMESİ GEREKEN bir tasarım olgusudur ve üç sonucu vardır. (1) Bütçe: başarılı her label isteği taşıyıcıya gerçek iş çağrısı yazar (MNG'de getorder + createbarcode), yani bir döngü içinde yeniden denemek taşıyıcı kotası harcar; belgeyi ilk aldığınızda saklamak ÇAĞIRANIN sorumluluğudur. (2) Hata davranışı: dönen hata canlı taşıyıcı cevabının o ANKİ hâlidir, önbellekten okunmuş bir kayıt değildir. (3) Saklama: belgeyi bir daha vermeyen taşıyıcıda Sevkora etiketi ilk alışta şifreli olarak saklar, çünkü aynı gönderinin etiketi Sevkora panelinden de yeniden basılabilmelidir. Saklanan belge gönderi teslim edildiğinde, iptal ya da iade edildiğinde ve alıcı verisi anonimleştirildiğinde silinir. Gönderi açık kalsa bile etiketin alındığı andan 30 gün sonra belge panelden de indirilemez ve şifreli kopya ardından gelen ilk günlük temizlikte (her gün 03:25) silinir; saklama bu yüzden 30 günü yaklaşık bir güne kadar aşabilir (DEC-537). Bu uç onu döndürmez ve etiketi alınmış gönderide ikinci istek yine 422 ile biter.
502 CÜMLESİ TAŞIYICININ KENDİ GEREKÇESİNİ TAŞIR (TASK-492 KK-3; DEC-473)
Taşıyıcı cevabında bir gerekçe BİLDİRDİYSE message onu adıyla aktarır ("Taşıyıcının bildirdiği neden:" ön ekiyle); bildirmediyse cümle eskisi gibi "yanıtı kullanılamadı" der. Statü (502) ve `code` (`carrier_response_unrecognized`) DEĞİŞMEZ, çünkü dalın TEK çıkışı vardır ve kodu bir kez yazar, yani istemci sözleşmesi yerinde durur ve değişen yalnız insanın okuduğu cümledir. Tek çıkış bilerek seçildi: iki ayrı return yazmak yukarıdaki ortak hata zarfı tablosunun DEĞER kümesini sayan çapasını sessizce bozardı. Ölçülen gerekçe: 2026-09-18'de MNG etiket ucu HTTP 200 dönüp barkodu BOŞ bıraktı ve nedenini aynı gövdede düz Türkçe yazdı; ürün o metni okuyup atıyor, kullanıcıya "yanıtı kullanılamadı" diyordu; ölçümle YANLIŞ olduğu görülen bir cümle. Dal taşıyıcıya özel DEĞİLDİR: hata yüküne carrier_reason yazan her adaptör bu cümleyi kazanır.
Panel eşleniği (TASK-444)
Sevkora paneli aynı etiketi GET /api/shipments/{id}/label?format=zpl yolundan alır. Ücret kuralı, durum kapısı ve hata eşlemesi bu uçla tek evdedir; panel yanıtı, etiketi panelde çizmek için ek bir document alanı taşır. Bu uçtaki zarf değişmedi: document burada yoktur.
curl "{{base_url}}/shipments/01K1GNDR000000000000000001/label?format=pdf" \
-H "Accept: application/json" \
-H "Authorization: Bearer SEVKORA_API_ANAHTARINIZ"
# Desi istekle taşınabilir (isteğe bağlı): gönderiye YAZILIR ve ücret ondan türer.
curl "{{base_url}}/shipments/01K1GNDR000000000000000001/label?format=pdf&desi=2.5" \
-H "Accept: application/json" \
-H "Authorization: Bearer SEVKORA_API_ANAHTARINIZ"