Kolay Deniz Market API
Yatlara hizmet veren cash & carry marketin sipariş ve teslimat API'si.
https://api.kolaydenizmarket.com/v1
Tüm yollar bu adrese eklenir. Aşağıdaki referansta yollar sürüm önekinden
sonrasını gösterir — /health gerçekte https://api.kolaydenizmarket.com/v1/health'dir.
curl -s https://api.kolaydenizmarket.com/v1/catalog/categories Sözleşme kuralları
Kolay Deniz Market backend'inin dış paylaşıma açık REST arayüzü.
Anlatımlı referans, davranış notları ve entegrasyon kontrol listesi için API.md dosyasına bakın. Bu spec ile o doküman çeliştiğinde, çalışan sistemin davranışı esastır.
Sözleşme kuralları:
- Tüm parasal alanlar tam sayı kuruştur (12550 = 125,50 ₺). Ürün fiyatları KDV dahil satış fiyatıdır.
- Anlık zamanlar ISO-8601 UTC string'dir. Takvim tarihleri (
YYYY-MM-DD) ve slot dakikaları Europe/Istanbul yereldir. - 2xx olmayan her yanıt
ApiErrorzarfını kullanır; istemci mantığıerrorkoduna bakmalıdır, HTTP statüsüne veyamessagemetnine değil. - Yanıtlara haber verilmeden yeni alan eklenebilir; bilinmeyen alanlar yok sayılmalıdır.
Kimlik doğrulama
Authorization: Bearer <accessToken>. Access token'ın varsayılan ömrü 15 dakikadır; POST /auth/refresh ile yenilenir.
Her uç, referansta hangi kimliği istediğini rozetinde yazar: Bearer personel/müşteri token'ı, x-api-key satıcı makine anahtarı, Herkese açık kimlik istemez. Giriş akışının kendisi Auth bölümündedir.
Satıcı makine anahtarı
Satıcı makine anahtarı — x-api-key: kdm_<ortam>_<önek>_<gizli>.
Tek parçadır: ayrı "API key + secret key" çifti yoktur, anahtarın tamamı tek başlıkta gider. <ortam> üretimde live, diğer her yerde test; böylece test anahtarının üretime yapıştırılması sessizce yetkisiz kalmak yerine görünür biçimde yanlış olur.
Anahtar yalnızca üretildiği anda bir kez gösterilir; sunucuda argon2 ile hash'lenip saklandığı için sonradan kurtarılamaz, kaybolursa yenisi kesilir. Yetkiler anahtara bağlı kapsamlarla (scope) sınırlıdır.
Hata modeli
2xx olmayan her yanıt aynı zarfı kullanır:
error— makine tarafından okunacak, sabit kod. İstemci mantığı bu alana bakmalıdır, HTTP statüsüne veyamessage'a değil.message— insan okur; opsiyonel, metni haber verilmeden değişebilir.details— yalnızca doğrulama hatalarında; alan bazlı sorunlar.- Bazı hatalar ek bağlam taşır (ör.
slot_range_too_wide→maxDays,category_has_products→products,unique_constraint_violation→fields).
{
"error": "validation_failed",
"message": "…",
"details": { "fieldErrors": { "priceKurus": ["Expected number, received string"] } }
} Hata kodu kataloğu
| Kod | HTTP | Anlamı |
|---|---|---|
missing_token | 401 | Authorization: Bearer header'ı yok |
invalid_token | 401 | Access token geçersiz, süresi dolmuş veya beklenen claim'leri taşımıyor |
unauthenticated | 401 | Rol kontrolü kimliksiz istekte tetiklendi |
insufficient_role | 403 | Kimlik doğru, rol bu uca yetkili değil |
invalid_credentials | 401 | E-posta/parola hatalı |
account_inactive | 401 / 403 | Hesap pasife alınmış |
invalid_refresh_token | 401 | Refresh token bilinmiyor |
refresh_token_expired | 401 | Refresh token süresi dolmuş |
refresh_token_rotated | 401 | Bu token zaten yenilenmiş |
refresh_token_reused | 401 | Tekrar kullanım tespit edildi; oturum zinciri iptal edildi |
| Kod | HTTP | Anlamı |
|---|---|---|
otp_resend_too_soon | 429 | 60 sn bekleme süresi dolmadı (retryAfterSeconds) |
otp_too_many_attempts | 429 | 3 yanlış deneme aşıldı; yeni kod istenmeli |
otp_invalid | 400 | Kod hatalı |
otp_expired | 400 | Kodun 180 sn ömrü doldu |
otp_not_permitted | 403 | Bu numara OTP ile giriş yapamaz (personel hesabı) |
otp_send_failed | 502 | SMS sağlayıcısı kodu iletemedi |
| Kod | HTTP | Anlamı |
|---|---|---|
product_not_found | 404 | Ürün yok veya pasif |
category_not_found | 404 | Kategori yok |
parent_category_not_found | 400 | parentId geçersiz |
category_cycle | 400 | Kategori kendini ata olarak alamaz |
category_too_deep | 400 | Ağaç derinlik sınırı aşıldı |
category_has_children | 409 | Alt kategorileri olan kategori silinemez (children) |
category_has_products | 409 | Ürünü olan kategori silinemez (products) |
too_many_slugs | 400 | /catalog/stock çağrısında 200 slug sınırı aşıldı |
| Kod | HTTP | Anlamı |
|---|---|---|
product_stock_not_found | 404 | Bu (ürün, şube) çifti için raf kaydı yok |
adjust_below_reserved | 409 | İşlem onHand'i reserved'ın altına düşürürdü; yanıtta güncel onHand, reserved ve istenen değer |
branch_not_found | 404 | branch alanındaki şube kodu tanınmıyor |
| Kod | HTTP | Anlamı |
|---|---|---|
marina_not_found | 404 | Marina yok |
anchorage_not_found | 404 | Demirleme bölgesi yok |
branch_not_found | 404 | Şube kodu tanınmıyor |
no_active_branch | 404 | Sistemde aktif şube yok |
pin_outside_anchorage | 400 | GPS pini, bölgenin radiusM yarıçapı dışında |
location_not_serviceable | 400 | Adresin bağlı olduğu yer artık servis dışı |
location_in_use | 409 | Kayıtlı adreslerce kullanılan marina/bölge silinemez (count) |
delivery_location_not_found | 404 | Teslimat adresi yok veya bu kullanıcıya ait değil |
vessel_not_found | 404 | Tekne yok veya bu kullanıcıya ait değil |
slot_not_found | 404 | Slot yok (slotId) |
slot_template_not_found | 404 | Şablon yok |
slot_template_overlap | 409 | Aynı gün içinde çakışan şablon |
slot_capacity_below_reserved | 409 | Kapasite, mevcut rezervasyon sayısının altına çekilemez |
slot_unavailable | 409 | Slot dolu, kapalı veya cut-off geçmiş |
slot_range_too_wide | 400 | Admin slot aralığı 400 günü aşıyor (maxDays) |
| Kod | HTTP | Anlamı |
|---|---|---|
user_not_found | 404 | Kullanıcı yok |
customer_not_found | 404 | Müşteri yok |
transfer_not_found | 404 | Transfer partneri yok |
email_taken | 409 | E-posta başka bir hesapta kayıtlı |
| Kod | HTTP | Anlamı |
|---|---|---|
not_accepting_orders | 409 | İşletme şu an sipariş almıyor |
below_minimum_order | 409 | Sepet asgari tutarın altında |
slot_unavailable | 409 | Slot dolu ya da kapalı |
slot_cutoff_passed | 409 | Slotun son sipariş saati geçti |
insufficient_stock | 409 | Bir veya daha çok kalem yetersiz (details) |
location_not_serviceable | 409 | Teslim yeri servis alanı dışında |
product_unavailable | 404 / 409 | Ürün satışta değil |
delivery_location_not_found | 404 | Teslim yeri yok ya da sizin değil |
slot_not_found | 404 | Slot yok |
invalid_idempotency_key | 400 | Idempotency-Key 200 karakteri aşıyor |
order_not_found | 404 | Sipariş yok ya da sizin değil |
cancel_not_allowed | 409 | Bu durumdan müşteri iptali yapılamaz (status) |
order_status_conflict | 409 | Beklenen durumda değil (expected, actual) |
order_not_cancellable | 404 | Sipariş iptal edilebilir durumda değil |
order_not_reslottable | 404 | Siparişin slotu değiştirilemez |
slot_unchanged | 400 | Yeni slot mevcut slotla aynı |
order_total_mismatch | 409 | Sunucu toplamı istemcininkiyle uyuşmuyor |
transfer_inactive | 409 | Transfer partneri pasif |
| Kod | HTTP | Anlamı |
|---|---|---|
order_not_pending_payment | 409 | Sipariş ödeme bekleyen durumda değil |
reservation_expired | 409 | Stok rezervasyonunun süresi doldu |
payment_attempt_in_flight | 409 | Aynı sipariş için uçuşta bir deneme var |
payment_init_failed | 502 | Sağlayıcı ödeme oturumu açmadı |
payment_not_found | 404 | Ödeme kaydı yok |
unknown_payment_provider | 400 | Callback yolundaki sağlayıcı tanınmıyor |
reconcile_unavailable | 502 | Sağlayıcı doğrulaması yapılamadı — sonuç bilinmiyor sayılır |
no_captured_payment | 404 | Tahsil edilmiş ödeme yok, iade açılamaz |
nothing_to_refund | 409 | İade edilecek tutar kalmadı |
invalid_refund_amount | 409 | Tutar sıfır ya da negatif |
refund_exceeds_payment | 409 | Tutar tahsil edileni aşıyor |
refund_not_allocatable | 409 | Tutar kalemlere dağıtılamıyor |
refund_target_ambiguous | 409 | Hem orderItemIds hem amountKurus gönderildi |
refund_target_missing | 409 | İkisinden hiçbiri gönderilmedi |
refund_not_found | 404 | İade kaydı yok |
refund_not_retryable | 409 | İade yeniden denenebilir durumda değil |
| Kod | HTTP | Anlamı |
|---|---|---|
seller_not_found | 404 | Satıcı yok |
seller_code_taken | 409 | code başka bir satıcıda kayıtlı |
seller_inactive | 409 | Satıcı pasif — şubeye bağlanamaz |
platform_seller_exists | 409 | Platforma ait satıcı zaten var, ikincisi olamaz |
integration_key_not_found | 404 | Anahtar yok ya da bu satıcının değil |
seller_cannot_serve_anchorage | 409 | Satıcı demirleme bölgesine hizmet veremiyor |
| Kod | HTTP | Anlamı |
|---|---|---|
missing_api_key | 401 | x-api-key başlığı yok |
invalid_api_key | 401 | Anahtar çözümlenemedi, bilinmiyor, iptal edilmiş ya da satıcı kapalı — tek kod, ayrıştırılmaz |
insufficient_scope | 403 | Anahtar geçerli, bu ucun kapsamı yok (missing) |
order_not_found | 404 | Sipariş yok ya da çağıran satıcının değil |
order_item_not_found | 404 | Kalem bu siparişte yok |
order_not_picking | 404 / 409 | Sipariş PICKING değil; önce accept çağrılmalı |
order_status_conflict | 409 | Beklenen durumda değil (expected, actual) |
picked_qty_above_ordered | 409 | Toplanan adet sipariş adedinin üstünde |
picked_qty_cannot_increase | 409 | Bildirilen adet yükseltilemez — yalnızca azaltılabilir |
| Kod | HTTP | Anlamı |
|---|---|---|
validation_failed | 400 | Gövde/query şemaya uymuyor (details) |
not_found | 404 | Kayıt bulunamadı |
unique_constraint_violation | 409 | Benzersizlik ihlali (fields) |
foreign_key_violation | 409 | Referans verilen kayıt yok ya da hâlâ kullanımda |
internal_error | 500 | Beklenmeyen sunucu hatası — tekrar denenebilir |
Hız sınırları
| Kapsam | Sınır |
|---|---|
| Genel (tüm uçlar) | 600 istek / 60 sn |
POST /v1/auth/otp/request | 5 / 60 sn (telefon başına) |
POST /v1/auth/otp/verify | 10 / 60 sn (telefon başına) |
POST /v1/auth/staff/login | 10 / 60 sn (e-posta başına) |
POST /v1/auth/refresh | 60 / 60 sn |
POST /v1/feedback | 5 / 60 sn (IP başına) |
Sayfalama
Liste uçları aynı zarfı döner:
Query parametreleri: page (≥1, varsayılan 1), perPage (1–100, varsayılan 24). search parametreleri en fazla 64 karakterdir ve %, _, \ karakterleri sunucuda temizlenir.
{ "items": [ … ], "page": 1, "perPage": 24, "total": 137, "totalPages": 6 }