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, ...]}.
| 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):
{
"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:
{
"data": ["..."],
"links": {"first": "...", "last": "...", "prev": null, "next": "..."},
"meta": {
"current_page": 1, "from": 1, "last_page": 3,
"links": [{"url": null, "label": "« 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: truebaş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_noglobal tekilliği çift oluşturmayı ayrıca DB seviyesinde keser (09-integrations idempotensi).