İçeriğe geç
SEVKORA API Temel model v1 Değişiklikler

Public API v1 sözleşmesi Başlarken

Temel model

Taban yol ve içerik tipi

Tüm uçlar /api/v1 altındadır (örneklerde {{base_url}} = dağıtım ortamının kökü + /api/v1). İstek/yanıt gövdeleri JSON'dur; istemci Accept: application/json gönderir, yazma isteklerinde Content-Type: application/json zorunludur. Bozuk JSON 400 döner, 500'e düşmez.

Kimlik doğrulama (DEC-018)

Her istek Authorization: Bearer <anahtar> başlığı taşır. Anahtarlar Sanctum personal access token altyapısıyla tenant bazlı üretilir, SHA-256 hash'iyle saklanır ve yalnız üretim anında bir kez gösterilir; iptal ve rotasyon zorunludur (REQ-008). Anahtar YÖNETİMİ (üretme/iptal/rotasyon) app içindendir; public API'de anahtar CRUD ucu YOKTUR (Kargonomi paritesi: referansta da token edinme ucu belgelenmemiş). Token istekleri stateless'tır: CSRF başlığı gerekmez, oturum cookie'si kurulmaz. Bu yüzeyde kimlik tek kademedir: her anahtar bir kullanıcıya, kullanıcı bir tenant'a bağlıdır ve istek başka hiçbir kimlik taşımaz.

Tenant kapsaması

Anahtar bir kullanıcıya, kullanıcı bir tenant'a bağlıdır; kimlik doğrulama zinciri her isteği anahtarın tenant'ına kapsar (SPA ile aynı ara katman, bugünkü kod). Listeler bu kapsamla sınırlıdır; tekil uçlarda başka tenant'ın kaydı ve biçimsiz ULID 404 döner (IDOR: varlık sızdırılmaz). Kimliksiz/geçersiz anahtar 401; tenant bağlamı kurulamayan kullanıcı 403 (deny by default).

SPA ile aynı çekirdek (TASK-063)

Gönderi uçlarının SPA ile aynı iş kurallarını uyguladığı vaadi artık MEKANİK olarak kilitlidir (warehouse 8c kalıbı): iptal edilebilir durum kümesi iki yüzey için TEK tanımdır ve taşıyıcı hatasının HTTP statü eşlemesi TEK evdedir; tek yüzeyde yapılan bir sapma test paketini kırar.

Sürümleme

URI sürümlemesi: /api/v1. v1 içinde yalnız geriye uyumlu genişleme yapılır: yeni uç, yeni isteğe bağlı alan, yanıt gövdesine yeni alan, status enum'una yeni değer eklenebilir; mevcut alan kaldırılmaz, tipi/anlamı değiştirilmez. Tüketici bilinmeyen yanıt alanlarını ve bilinmeyen status değerlerini toleransla işlemelidir (Hyrum farkındalığı). Kırıcı değişiklik yeni kök altında (/api/v2) yayınlanır; v1 duyurulu bir geçiş süresi boyunca yaşar (expand-migrate-contract).

Ortak hata zarfı

Hata gövdesi Laravel biçimindedir: her hatada message; alan hatalarında ek errors{alan: [mesaj, ...]}.

Temel model çizelgesi
Kod Anlam Gövde
401 Anahtar yok/geçersiz/iptal {"message": "Unauthenticated."}
403 Anahtar geçerli ama tenant bağlamı kurulamadı {"message": "..."}
404 Kayıt yok, başka tenant'ın veya biçimsiz ULID {"message": "..."}
405 Uç, isteğin HTTP yöntemini desteklemiyor {"message": "..."} + Allow: <yöntemler> başlığı; desteklenen yöntemler bu başlıktan okunur
409 Idempotency çakışması (aynı anahtar, farklı gövde; ya da aynı anahtarla İŞLEM SÜRÜYOR), PA-04 capability çakışması (taşıyıcı updateShipment desteklemiyor) {"message": "..."}
413 İstek gövdesi sunucunun kabul ettiği boyutu aşıyor; istek uca ulaşmadan reddedilir {"message": "..."}
422 Doğrulama/iş kuralı/taşıyıcı reddi {"message": "...", "errors": {...}}; taşıyıcı reddi ve iş kuralı ihlali yalnız message taşıyabilir
429 Oran limiti {"message": "..."} + Retry-After: <saniye>; ileti Türkçedir ve bilgilendiricidir, bekleme süresi başlıktan okunur
502 Taşıyıcı çağrısı sonuçlanmadı: taşıyıcıya ulaşılamadı ya da taşıyıcı erişimi reddetti (canlı taşıyıcı çağrısı olan uçlar) {"message": "...", "code": "..."}; code dört değerden biridir: carrier_unavailable (geçici, yeniden denenebilir), carrier_credential_rejected (erişim düzeltilmeden yeniden denemek yardımcı olmaz), carrier_response_unrecognized (taşıyıcı cevap verdi ama cevap kullanılamadı; yeniden deneme VAAT EDİLMEZ, TASK-480) ya da carrier_outcome_unknown (YALNIZ onay ucunda: yanıt ALINAMADI ve siparişin oluşup oluşmadığı doğrulanamadı, TASK-490). Sonuncusu da EKLEMEDİR: message okuyan istemci değişmeden çalışır; Sevkora kaydı değişmedi. Küme koddaki dallara MEKANİK olarak bağlıdır ve İKİ EVDE sayılır: ile

422 alan hatası örneği (PA-03 isteğinde buyer_name ve parcels[0].desi gönderilmediğinde; message ilk alan hatasını ve kalan hata sayısını taşır):

json
{
  "message": "Alıcı adı alanı zorunludur. (ve 1 hata daha)",
  "errors": {
    "buyer_name": ["Alıcı adı alanı zorunludur."],
    "parcels.0.desi": ["Koli desisi alanı zorunludur."]
  }
}

Hiçbir doğrulama/tip karmaşası 500 üretmez; hiçbir hata gövdesi credential, iç yol veya başka tenant'a dair iz taşımaz.

Oran sınırlama

Limit anahtar (token) başınadır ve dakikalık penceredir. Kesinleşen değer (TASK-026; eski açık nokta 1): TEK limit, varsayılan 120 istek/dk, yapılandırmayla ayarlanır; okuma/yazma ayrımı yapılmaz (YAGNI: ihtiyaç doğarsa geriye uyumlu daraltılır). Cookie oturumu v1'e girerse pencere kullanıcı kimliğiyle anahtarlanır. Aşımda 429 + Retry-After başlığı (saniye). Taşıyıcıya inen uçlarda (PA-03/04/05/06) taşıyıcının kendi limitleri ayrıca geçerlidir: taşıyıcının oran limiti aşımı Sevkora 429'u olarak YANSIMAZ; adaptör içi yeniden denemeler tükenirse istemciye 502 döner (09-integrations hata taksonomisi).

Sayfalama

Sayfalı listeler Laravel sayfalayıcı zarfını Kargonomi paritesindeki data[] / links / meta biçimiyle döner:

json
{
  "data": ["..."],
  "links": {"first": "...", "last": "...", "prev": null, "next": "..."},
  "meta": {
    "current_page": 1, "from": 1, "last_page": 3,
    "links": [{"url": null, "label": "&laquo; Previous", "active": false}],
    "path": "{{base_url}}/shipments", "per_page": 15, "to": 15, "total": 42
  }
}

page (>=1) ve per_page (1..100, varsayılan 15) parametreleri; sınır aşımı sessiz kırpılmaz, 422 döner (SPA paritesi).

Kimlikler, tarihler, sayılar

Tüm kaynak kimlikleri ULID'dir (26 karakter, sıralanabilir, tahmin edilemez; DEC-016). Tarihler ISO-8601 UTC'dir: 2026-07-23T10:15:00Z (saniye hassasiyeti; v1 resource katmanında sabitlenir). Ondalık alanlar (order_price, desi) hassasiyet kaybını önlemek için iki basamaklı string döner: "12.50".

Gövde işleme kuralı

Her uç yalnız sözleşmesinde tanımlı alanları işler (doğrulanan beyaz liste); tanımsız alanlar yok sayılır ve kayda ASLA yazılmaz (tenant_id, canonical_status gibi sunucu alanları gövdeden set edilemez). Tanımlı bir alanın tip/biçim ihlali her zaman 422'dir.

Idempotency-Key (kritik POST'lar)

POST /api/v1/shipments (PA-03) Idempotency-Key başlığını ZORUNLU kılar (yoksa 422, errors.idempotency_key). Kurallar:

  • Başlık değeri istemci üretimidir (örn. UUID/ULID), 1..255 karakter; kapsamı tenant'tır.
  • Sunucu anahtar + istek gövdesi hash'i + üretilen yanıtı saklar. Aynı anahtar + AYNI gövde ile tekrar: kayıtlı yanıt aynen döner (aynı durum kodu ve gövde; ikinci gönderi OLUŞMAZ) ve yanıt Idempotency-Replayed: true başlığı taşır. Aynı anahtar + FARKLI gövde: 409. Aynı anahtarla ilk istek HÂLÂ sürüyorsa (kayıtlı yanıt henüz yok): 409 "işlem sürüyor"; istemci sonucu bekleyip yeniden dener.
  • Yalnız 2xx/4xx yanıtlar saklanır; 5xx (örn. 502 taşıyıcıya ulaşılamadı) SAKLANMAZ; aynı anahtar yeniden denenebilir. Tek 4xx istisnası "işlem sürüyor" 409 yanıtlarıdır (PA-19, PA-40): onlar da saklanmaz. İstemci her zaman AYNI anahtarla yeniden dener; istek, süren işlem bitince ya da bekleme penceresi dolunca ilerler. Onay uçlarında süreci yarıda kesilmiş ve yanıtı hiç yazılamamış bir isteğin anahtarı da bekleme penceresi (varsayılan 600 sn) dolunca aynı anahtarla yeniden koşar; aynı anda iki deneme gelirse biri ilerler, öteki saklanmayan 409 alır. Diğer uçlarda böyle bir anahtar 24 saatlik saklama süresi boyunca "işlem sürüyor" döner. Diğer 4xx yanıtlar saklanır.
  • Kayıt saklama süresi (TASK-026; eski açık nokta 3): 24 saat, yapılandırılabilir; süresi geçen kayıt istek anında tembel silinir.
  • Diğer POST uçlarında başlık isteğe bağlıdır; gönderilirse aynı sözleşmeyle işlenir. İptal (PA-05) doğal olarak güvenlidir: kayıt path'teki kimlikle hedeflenir, tekrarı durum kuralından 422 döner; taşıyıcı katmanındaki delivery_no global tekilliği çift oluşturmayı ayrıca DB seviyesinde keser (09-integrations idempotensi).