Geliştirici referansı · 29 Ağustos 2026
CloudUtcu API
Dosya, paylaşım, plan ve destek uçlarının tamamı. Uygulamanızı bu belgeye göre yazın; sunucu tarafındaki kurallar burada yazdığı gibi zorlanıyor.
- KimlikBearer + refresh çerezi
- BiçimJSON (akışlar hariç)
- Genel sınır300 istek / dk / IP
- Token ömrü15 dk / 30 gün
Uygulama geliştirenler için referans. Temel adres: https://cloudutcu.com
Tüm istekler ve yanıtlar JSON (dosya akışları hariç). Hata gövdesi:
{ "error": "kod_adi", "message": "Kullanıcıya gösterilebilir mesaj" }message Türkçedir ve doğrudan gösterilebilir. error programatik kontrol içindir; sık karşılaşılanlar bölüm 12'de listeli.
Tarayıcıdan çağıracaksanız: CORS yalnızca https://cloudutcu.com kaynağına açık ve credentials gerektiriyor. Başka bir origin'den yapılan tarayıcı isteği reddedilir; mobil ve sunucu tarafı istemciler etkilenmez.
1Kimlik doğrulama
Kısa ömürlü access token (15 dakika) + uzun ömürlü refresh token (30 gün).
Korumalı uçlara erişim:
Authorization: Bearer <accessToken>Refresh token httpOnly çerezle taşınır. Mobilde çerez saklayan bir HTTP istemcisi kullanın (OkHttp CookieJar, URLSession varsayılanı) — ya da çerezi hiç kullanmayın: belirtecModu ile refresh token gövdede döner (aşağıda "Çerezsiz (gövde tabanlı) oturum").
POST/api/auth/register
{
"email": "[email protected]",
"password": "EnAz8Karakter1",
"fullName": "Ad Soyad",
"phone": "+905550000000",
"country": "Türkiye"
}Şifre: en az 8 karakter, bir küçük harf, bir büyük harf, bir rakam. Küçük/büyük harf kontrolü Türkçe harfleri de tanır (ş, ı, ğ, ç, ö, ü). phone ve country isteğe bağlı.
201 → { "accessToken": "...", "user": { ... } }
Kayıtta depolama hesabı otomatik açılır, doğrulama e-postası gönderilir. Doğrulama yapılmadan dosya yüklenemez (bölüm 3).
POST/api/auth/login
{ "email": "[email protected]", "password": "..." }İki olası 200 yanıtı var; istemci ikisini de ele almalı.
Normal hesap:
{ "accessToken": "...", "user": { ... } }İki adımlı doğrulaması açık hesap:
{ "totpRequired": true, "challenge": "..." }İkincisinde oturum açılmaz — accessToken yok, çerez yazılmaz. challenge 5 dakika geçerlidir ve yalnızca POST /api/auth/login/2fa ucunda kullanılır; erişim belirteci yerine geçmez (korumalı bir uca sunulursa 401 invalid_token).
401 hatalı bilgi · 403 account_frozen.
Var olmayan hesap için de şifre doğrulama süresi kadar beklenir; yanıt süresinden hangi adreslerin kayıtlı olduğu anlaşılmasın diye.
Dondurulmuş hesap giriş yapamaz: doğru şifreyle bile 403 account_frozen döner ve oturum açılmaz. Kontrol şifre doğrulandıktan *sonra* yapılır — aksi halde yanlış şifreyle bile bu cevap dönerdi ve uç, hesabın var olup olmadığını söyleyen bir numaralandırma aracına dönerdi.
Dondurma açık oturumları da düşürür: yönetim hesabı dondurduğu anda o kullanıcının bütün refresh token'ları iptal edilir, POST /api/auth/refresh de 403 account_frozen döner ve çerez temizlenir. İstemci bu kodu gördüğünde kullanıcıyı çıkışa alıp mesajı göstermeli. İtiraz kanalı açıktır: iletişim formu (POST /api/public/contact) oturum gerektirmez.
POST/api/auth/login/2fa
{ "challenge": "...", "code": "123456" }code doğrulama uygulamasındaki 6 haneli kod veya bir yedek koddur (ABCD-2345; tire ve küçük harf tolere edilir).
200 → { "accessToken": "...", "user": { ... } }
Yedek kod kullanıldıysa yanıt ayrıca yedekKodKullanildi: true ve kalanYedekKod taşır — kullanıcıya kaç kod kaldığını gösterin, tükenmeden yenilemesi için tek uyarı bu.
401 invalid_totp (kod hatalı) · 401 totp_expired (challenge süresi doldu — baştan giriş yapın) · 403 account_frozen.
Kod ±30 saniyelik pencereyi kabul eder (telefon saati kayması için). Sınır: hesap başına 15 dakikada 10 deneme.
Bir kod tek kullanımlıktır (RFC 6238 §5.2): doğrulandıktan sonra aynı kod penceresi bitene kadar tekrar gönderilirse 401 invalid_totp döner. Aynı kural 2FA kapatma ve yedek kod yenileme uçlarında da geçerli.
POST/api/auth/refresh
Gövde {} ve Content-Type: application/json gönderilmelidir. Gövdesiz POST 415 ile reddedilebilir.
200 → { "accessToken": "...", "user": { ... } } · 401 oturum yok (no_session).
Refresh token tek kullanımlıktır. Eşzamanlı yenileme göndermeyin — biri diğerini geçersiz kılar ve kullanıcı düşer. İstemcide tüm yenilemeleri tek bir çağrıda toplayın.
Çerezsiz (gövde tabanlı) oturum
Tarayıcı için doğru olan httpOnly çerez, çerez kavramı olmayan istemcilerde (mobil uygulama, CLI, sunucu tarafı entegrasyon) kullanılamıyor. register, login ve login/2fa uçlarına belirtecModu: true gönderirseniz yenileme belirteci yanıt gövdesinde döner ve çerez yazılmaz:
// POST /api/auth/login {"email":"...","password":"...","belirtecModu":true}
{
"accessToken": "...",
"refreshToken": "...",
"refreshExpiresAt": "2026-09-27T12:00:00.000Z",
"user": { }
}Yenilemek için aynı /api/auth/refresh ucuna belirteci gövdede gönderin; yanıt yine gövdede yeni bir belirteç taşır:
// POST /api/auth/refresh {"refreshToken":"..."}
{ "accessToken": "...", "refreshToken": "...", "refreshExpiresAt": "...", "user": { } }Çıkışta da aynısı: POST /api/auth/logout gövdesinde { "refreshToken": "..." }.
Dikkat edilecekler:
- Rotasyon, tek kullanımlık olma ve hırsızlık tespiti bu akışta da aynen geçerli. Yeni belirteci saklamayı atlarsanız oturum bir sonraki yenilemede düşer.
- Çerez ve gövde aynı anda kullanılmaz.
belirtecModuverildiğinde çerez hiç yazılmaz; verilmediğinde belirteç gövdede hiç dönmez. refreshExpiresAt(30 gün) yeniden giriş isteme anını hesaplamak için. Çerezli akışta bu bilgiyi tarayıcı çerezin kendisinden bilir.- Belirteci işletim sisteminin güvenli deposunda tutun (iOS Keychain, Android Keystore). httpOnly korumasının yerini alacak bir şey yok: gövdeye çıkan belirteci koruma sorumluluğu istemciye geçer.
Uygulama belirteçleri (API anahtarları)
Üçüncü taraf bir entegrasyona kullanıcının şifresini vermeden erişim açar. Şifreyle giriş yapmanın üç sorunu vardı: şifre entegrasyonun elinde kalıyor, yetki daraltılamıyor, tek tek iptal edilemiyordu.
Belirteç clu_ ile başlar ve normal erişim belirteci gibi gönderilir:
Authorization: Bearer clu_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXYönetimi oturum gerektirir — bir belirteç kendini çoğaltamaz, kardeşlerini iptal edemez:
| Uç | Açıklama |
|---|---|
POST /api/anahtarlar | gövde { "name": "Yedekleme betiği", "scopes": ["files:read"], "expiresInDays": 365 } — 201 |
GET /api/anahtarlar | kendi belirteçleriniz + tanınan yetki listesi |
DELETE /api/anahtarlar/:id | iptal — 204, anında geçerli |
Oluşturma yanıtı belirtecin açık halini bir kez döndürür:
{
"deger": "clu_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", // yalnızca burada
"anahtar": { "id": "...", "name": "Yedekleme betiği", "prefix": "abcd1234",
"scopes": ["files:read"], "expiresAt": "...", "lastUsedAt": null }
}Sunucu yalnızca sha256 özetini saklar; "belirteci tekrar göster" diye bir uç yoktur ve olamaz. Kaybederseniz yenisini oluşturup eskisini iptal edin. Listede belirteci prefix tanıtır. Hesap başına en fazla 20 belirteç (400 too_many_keys), oluşturmak doğrulanmış e-posta ister.
#### Yetkiler
| Yetki | Ne açar |
|---|---|
files:read | GET /api/files/* — listeleme, arama, indirme, kota, sürümler |
files:write | yükleme, klasör açma, taşıma, kopyalama, silme, çöp kutusu |
shares:read | GET /api/shares |
shares:write | bağlantı oluşturma ve iptal |
Bilinmeyen bir yetki sessizce atılmaz: 400 invalid_scope. Boş liste 400 no_scopes.
#### Nereye erişebilir
Belirteç yalnızca /api/files ve /api/shares altına girebilir. Bu bir izin listesi: listede olmayan her uç kapalıdır ve yarın eklenen bir uç da kendiliğinden kapalı olur. Hesap ayarları, şifre değiştirme, hesap silme, ödeme, destek ve yönetim uçları hiçbir yetkiyle açılmaz — 403 api_key_not_allowed.
Okuma/yazma ayrımı HTTP yöntemine göre: GET ve HEAD okuma, gerisi yazma sayılır. Tek istisna gövdesinde yol taşıdığı için POST olan iki uç — /api/files/onizleme-anahtari ve /api/files/kucukresim-anahtari — okuma sayılır; yoksa salt okunur bir belirteç önizleme bile açamazdı. Yetki yetmezse 403 insufficient_scope.
#### Diğer davranışlar
- Süre.
expiresInDays: nullsüresiz. Süresi dolmuş belirteç 401api_key_expired. - Donduruldu. Hesap dondurulmuşsa belirteçler de susar (403
account_frozen) — dondurmanın tarayıcı oturumunu kapatıp betikleri çalıştırmaya devam etmesi anlamsız olurdu. lastUsedAten fazla 5 dakikada bir güncellenir; amaç "bu belirteç hâlâ kullanılıyor mu" sorusuna cevap vermek, her çağrıya bir yazma eklemek değil.- Tanınmayan değer 401
invalid_api_key. - Hız sınırları normal oturumla aynı (bölüm 9); belirteç ayrı bir kota açmaz.
Webhook bildirimleri
SSE (yukarıda) yalnızca açık bir sekmeye ve yalnızca "best effort" ulaşır: hiçbir olay saklanmaz, tekrar gönderilmez. Sunucu tarafında çalışan bir entegrasyon için webhook var — aynı olaylar, kalıcı kuyruk ve tekrar denemeyle sizin adresinize gönderilir.
Yönetimi oturum gerektirir (uygulama belirteçlerine kapalı):
| Uç | Açıklama |
|---|---|
POST /api/webhooklar | gövde { "url": "https://…", "events": ["dosya","kota"] } — 201 |
GET /api/webhooklar | abonelikleriniz + tanınan olay listesi |
POST /api/webhooklar/:id/dene | deneme bildirimi hemen gönderir, sonucu döndürür |
POST /api/webhooklar/:id/ac | kendiliğinden kapanmış aboneliği yeniden açar |
POST /api/webhooklar/:id/gizli-yenile | imza anahtarını yeniler (eski imzalar anında geçersiz) |
GET /api/webhooklar/:id/teslimatlar | son 20 teslimat ve durumları |
DELETE /api/webhooklar/:id | 204 |
Hesap başına en fazla 10 abonelik (400 too_many_webhooks).
#### Adres kuralları
Adresi siz yazıyorsunuz, isteği bizim sunucumuz atıyor; bu yüzden adres dar bir süzgeçten geçer:
- Yalnızca
https(400invalid_url_scheme). İmza gövdeyi doğrular ama gizlemez; düz http, olay verisini yoldaki herkese açardı. - İç ağa bakan adres kabul edilmez (400
private_address): özel IPv4/IPv6 aralıkları,127.0.0.1,169.254.169.254,100.64.0.0/10,localhost,*.local. Ad çözümlemesi gönderim anında da denetlenir ve istek çözülen IP'ye bağlanır — "önce genel, sonra iç adres" oyunu (DNS rebinding) işe yaramaz. - Yönlendirme (3xx) izlenmez ve başarı sayılmaz.
- Adreste kullanıcı adı/parola olamaz.
#### Olaylar
| Olay | Ne zaman |
|---|---|
dosya | dosyalarınızda değişiklik (yükleme, silme, taşıma, paylaşıma bırakma) |
paylasim | paylaşım bağlantınızdan indirme yapıldı |
kota | depolama eşiğe yaklaştı veya doldu |
talep | destek talebinize yanıt geldi |
plan | plan süresi hakkında bilgi |
Liste SSE ile aynı kümedir: webhook yeni bir olay evreni açmaz, SSE'nin "yalnızca açık sekme" sınırını kaldırır. Bilinmeyen olay 400 invalid_event, boş liste 400 no_events.
#### Gövde ve imza
İstek POST, gövde JSON:
{
"id": "3f0c…", // teslimat kimliği — tekrar teslimatı ayırt etmek için
"olay": "dosya",
"zaman": 1788001995, // unix saniye
"veri": { "islem": "/api/files/upload" }
}Başlıklar:
| Başlık | İçerik |
|---|---|
x-cloudutcu-olay | olay adı |
x-cloudutcu-teslimat | teslimat kimliği |
x-cloudutcu-imza | t=<unix>,v1=<hmac-sha256 hex> |
İmza, <zaman>.<ham gövde> dizgisinin abonelik gizli anahtarıyla üretilmiş HMAC-SHA256'sıdır. Zaman damgası imzanın içindedir: yalnızca gövde imzalansaydı, bir teslimatı yakalayan biri aynı isteği sonsuza kadar tekrar oynatabilirdi.
// Node
import { createHmac, timingSafeEqual } from 'node:crypto';
const dogrula = (gizli, baslik, hamGovde) => {
const alanlar = Object.fromEntries(baslik.split(',').map((p) => p.split('=')));
const beklenen = createHmac('sha256', gizli)
.update(`${alanlar.t}.${hamGovde}`)
.digest('hex');
return timingSafeEqual(Buffer.from(beklenen), Buffer.from(alanlar.v1));
};Ham gövdeyi imzalayın — JSON'a çevirip yeniden dizgeye döken bir katman imzayı bozar. İmzayı doğrulamayan bir uç, size istek atabilen herkese açıktır. Gizli anahtar yalnızca oluşturma yanıtında bir kez döner.
#### Teslimat, tekrar ve kapanma
- Olay kuyruğa yazılır, isteğin içinde gönderilmez: dosya yükleyen müşterinin yanıt süresi, sizin sunucunuzun ayakta olmasına bağlanamaz.
- Kuyruk dakikada bir boşaltılır; teslimat gecikmesi normalde bir dakikanın altındadır.
- 2xx başarıdır. Değilse artan beklemeyle 6 deneme: 1 dk, 5 dk, 30 dk, 2 saat, 6 saat, 24 saat. Sonrasında teslimat başarısız kapanır.
- İstek 10 saniyede zaman aşımına uğrar. Yanıt gövdesi kullanılmaz (ilk 2 KB yalnızca hata ayıklama kaydına girer).
- Üst üste 20 başarısız teslimattan sonra abonelik kapanır; panelde sebebiyle görünür ve
acucuyla açılır. İlk başarılı teslimat sayacı sıfırlar. - Aynı olay birden fazla aboneliğe gidiyorsa her biri ayrı teslimattır.
- Teslimat en az bir kez ulaşır: zaman aşımına uğrayan ama karşı tarafta işlenen bir istek tekrar gönderilir.
idalanını tekrarı ayırt etmek için kullanın.
Web Push bildirimleri
Tarayıcı kapalıyken de ulaşan bildirim. SSE açık sekme ister, webhook bir sunucu adresi ister; bu üçüncüsü doğrudan kullanıcının cihazına gider.
Bu uçlar tarayıcı içindir — uygulama belirteçlerine kapalıdır ve oturum gerektirir.
| Uç | Açıklama |
|---|---|
GET /api/push/anahtar | VAPID genel anahtarı + abone olunabilir olaylar |
POST /api/push/abone | gövde { "endpoint": "…", "keys": { "p256dh": "…", "auth": "…" }, "events": ["kota"], "label": "Chrome · Android" } — 201 |
GET /api/push | kayıtlı cihazlarınız |
POST /api/push/:id/dene | o cihaza deneme bildirimi gönderir |
DELETE /api/push/:id | cihazı kaldırır — 204 |
Sunucuda VAPID anahtarı tanımlı değilse bütün uçlar 503 push_disabled döner; özellik isteğe bağlıdır.
Olaylar: paylasim, kota, talep, plan. dosya bilerek yok — o olay neredeyse her zaman kullanıcının kendi eyleminden çıkıyor ve saniyeler içinde onlarca kez tetikleniyor; telefonu titreten bir akış, özelliği ilk günde kapattırırdı. Paylaşılan klasöre bırakılan dosya paylasim olayından duyurulur.
endpoint benzersizdir: aynı tarayıcı yeniden abone olduğunda kayıt çoğaltılmaz, güncellenir (sahiplik dâhil — aynı cihazdan başka bir hesaba giren kullanıcının bildirimleri eski hesaba gitmez).
Gövde uçtan uca şifrelidir (RFC 8291, aes128gcm): anahtarlar tarayıcının ürettiği p256dh/auth değerlerinden türer, yani bildirimi taşıyan sağlayıcı (Google, Mozilla, Apple) içeriği okuyamaz. İstek VAPID ile imzalanır (RFC 8292).
Service worker'a ulaşan gövde:
{ "baslik": "Depolama alanınız doluyor", "govde": "Alanınızın %91'i kullanıldı.", "yol": "/dashboard" }Sağlayıcı bir aboneliği tanımazsa (404/410) kayıt silinir: kullanıcı izni geri almış ya da tarayıcı verisini temizlemiştir. Geçici hatada (zaman aşımı, 5xx) silinmez — sağlayıcının beş dakikalık bir kesintisi bütün cihazları listeden düşürmemeli.
Diğer kimlik uçları
| Uç | Açıklama |
|---|---|
POST /api/auth/logout | bu cihazın oturumu |
POST /api/auth/logout-all | tüm cihazlar — gövde { password } |
POST /api/auth/forgot-password | { email } — her durumda { success: true } |
POST /api/auth/reset-password | { token, password } |
POST /api/auth/verify-email | { token } — tek kullanımlık |
POST /api/auth/resend-verification | oturum gerektirir |
GET /api/auth/me | { user } — güncel kullanıcı |
PATCH /api/auth/profile | { fullName?, phone?, country?, birthday?, avatarUrl?, colorScheme? } |
POST /api/auth/change-password | { currentPassword, newPassword } — diğer oturumları kapatır |
GET /api/auth/sessions | son 20 giriş kaydı (yalnızca kendi) |
POST /api/auth/hesabi-sil | hesabı ve dosyaları kalıcı siler — gövde { password } |
colorScheme: blue, purple, green, orange, rose, cyan, amber, teal, red, indigo.
Profil ucu bilinçli olarak dardır: role, currentPlan ve storageLimitBytes kullanıcı tarafından değiştirilemez. Plan yalnızca ödeme ile veya yönetim panelinden değişir.
Hesap silme geri alınamaz. POST /api/auth/hesabi-sil önce depolama hesabını ve bütün dosyaları, sonra kullanıcı kaydını siler; açık oturumlar anında düşer. Şifre istenir çünkü işlem geri alınamaz ve açık unutulmuş bir sekmeden tetiklenebilir. Siparişler silinmez: userId boşa düşer ve faturada görünen e-posta satırda anlık görüntü olarak kalır — fatura kayıtlarının saklanması yasal zorunluluk.
Kullanıcı nesnesi
{
"id": "uuid",
"email": "[email protected]",
"role": "user",
"fullName": "Ad Soyad",
"phone": "+90...",
"country": "Türkiye",
"birthday": null,
"avatarUrl": null,
"colorScheme": "blue",
"emailVerified": true,
"storageLimitBytes": 5368709120,
"currentPlan": "Ücretsiz",
"planExpiresAt": null,
"credits": 0,
"accountFrozen": false,
"totpEnabled": false,
"createdAt": "2026-07-31T..."
}accountFrozen true ise giriş, yenileme, dosya uçları, ödeme başlatma (POST /api/orders/checkout) ve yönetim uçları 403 account_frozen döner. Son ikisi eskiden kapsam dışıydı: dondurma açık oturumları düşürüyor ama elde duran erişim belirtecini geçersiz kılamıyor (imzalı, 15 dakika ömürlü), yani donduruluş ile belirtecin ölümü arasında bir pencere kalıyordu. totpEnabled yalnızca "açık mı" bilgisidir; sır ve yedek kodlar hiçbir uçtan dönmez.
İki adımlı doğrulama (TOTP)
İsteğe bağlıdır; kullanıcı kendi açar. Standart TOTP — SHA-1, 6 hane, 30 saniye — yani Google Authenticator, 1Password, Bitwarden ve benzerleri çalışır.
Kurulum iki aşamalıdır ve bu bilinçlidir: sır üretildiği anda iki faktör açılsaydı, QR'ı taradığını sanıp taramamış bir kullanıcı hesabına kilitlenirdi. İlk kod doğrulanana kadar 2FA devrede değildir.
| Uç | Açıklama |
|---|---|
GET /api/auth/2fa/durum | { enabled, kalanYedekKod } |
POST /api/auth/2fa/kurulum | { password } → { secret, otpauth } — sır üretilir, 2FA henüz açılmaz |
POST /api/auth/2fa/etkinlestir | { code } → { success, yedekKodlar } — ilk kod doğrulanır, 2FA açılır |
POST /api/auth/2fa/kapat | { password, code } — code TOTP ya da yedek kod olabilir |
POST /api/auth/2fa/yedek-kodlar | { password, code } → { yedekKodlar } — eskiler anında geçersiz |
otpauth alanı doğrudan QR'a çevrilebilir. secret elle giriş içindir.
Yedek kodlar bir kez döner. Sunucuda yalnızca argon2 özetleri saklanır — şifreyle aynı muamele, çünkü işlevleri de aynı: tek başlarına hesabı açarlar. On adet üretilir, her biri bir kez kullanılabilir.
Telefonunu ve yedek kodlarını kaybeden kullanıcı için yönetim tarafında sıfırlama vardır; kullanıcıya e-posta gider ve işlem denetim kaydına yazılır.
Hata kodları: wrong_password, invalid_totp, totp_not_started (etkinleştirmeden önce kurulum çağrılmadı), totp_already_enabled, totp_not_enabled.
Oturum kaydı
GET /api/auth/sessions → { "sessions": [ ... ] }
{
"id": "uuid",
"ipAddress": "1.2.3.4",
"userAgent": "...",
"deviceType": "mobile",
"os": "Android",
"browser": "Chrome",
"loggedInAt": "2026-08-24T09:00:00.000Z",
"active": true,
"current": false
}active: bu girişin oturumu hâlâ açık mı (iptal edilmemiş, süresi geçmemiş bir yenileme belirteci var mı). current: isteği yapan oturum.
DELETE /api/auth/sessions/:id tek bir oturumu uzaktan kapatır.
Parola istemez — logout-alldan farklı olarak bu işlem yıkıcı değil, yanlışlıkla kapatılan cihaz yeniden giriş yapar. Şüpheli bir oturumu görür görmez, şifre hatırlamadan kapatabilmek daha değerli.
200 → { "success": true, "kapatilan": 1 } · 400 current_session (kendi oturumunuz — çıkış için /logout kullanın) · 404 açık oturum yok.
404, "başkasının kaydı" ile "zaten kapalı" durumlarını ayırmaz; ayırmak, başka bir hesabın oturum kimliğini doğrulamaya yarardı.
Canlı oturum olayları (SSE)
"Tüm cihazlardan çıkış" gibi bir işlem, açık duran diğer istemcileri anında düşürmeli. EventSource Authorization başlığı gönderemediği için adrese giden dar kapsamlı bir belirteç kullanılır.
POST /api/auth/canli-anahtar (oturum gerektirir) → { "token": "..." } — anahtar 5 dakika ömürlüdür; akış koptuğunda yeniden bağlanmadan önce yeni anahtar alın.
GET /api/auth/canli/:token → text/event-stream.
| Olay | Gövde | Anlamı |
|---|---|---|
revoked | {} | Oturum topluca geçersiz kılındı. Akış kapanır; yerel oturumu kapatın. |
dosya | { islem } | Dosyalarda değişiklik oldu (başka bir sekme veya cihazdan). Açık listeleri tazeleyin. |
paylasim | { ad, indirmeSayisi, kalanHak } | Paylaşım bağlantılarınızdan biri indirildi. kalanHak sınırsızsa null. |
kota | { kullanilanYuzde, kullanilanBytes, toplamBytes } | Depolamanın %90'ı veya fazlası dolu. |
talep | { talepId, konu } | Destek talebinize yanıt geldi. |
plan | { durum: "bitiyor" | "dusuruldu", kalanGun? } | Plan süresi hakkında bilgi. |
event: paylasim
data: {"ad":"rapor.pdf","indirmeSayisi":3,"kalanHak":2}revoked dışındaki olaylar bağlantıyı kapatmaz; akış devam eder.
Yayın best effort: olaylar saklanmaz, kuyruklanmaz, tekrar gönderilmez. Akış kapalıyken olan biteni bir sonraki açılışta normal sorgularla öğrenin — hiçbir olay tek doğruluk kaynağı değildir.
Bağlantı 20 saniyede bir yorum satırıyla canlı tutulur. Hesap başına en fazla 5 eşzamanlı akış açık kalabilir; altıncı bağlantı açılınca en eskisi kapatılır.
2Dosyalar
Oturum gerektirir. Yollar kullanıcıya göreli, / ile başlar. .., ters eğik çizgi ve null bayt reddedilir.
Yazma işlemleri doğrulanmış e-posta gerektirir. Klasör oluşturma, yeniden adlandırma, taşıma, kopyalama, favorileme, silme, çöp kutusu işlemleri, sürüm geri yükleme ve yüklemenin tamamı doğrulanmamış hesapta 400 email_not_verified döner. Listeleme, arama, indirme, önizleme ve kota sorgulama serbesttir — doğrulamayı bekleyen kullanıcı kilitli kalmaz.
İstemcide bu kodu tek bir yerde yakalayıp doğrulama ekranına yönlendirin; kullanıcıya işlem bazında ayrı mesaj göstermeye gerek yok.
GET/api/files?path=/
200 → { "path": "/", "entries": [ ... ] }
{
"name": "belge.pdf",
"path": "/belge.pdf",
"isFolder": false,
"sizeBytes": 12345,
"mimeType": "application/pdf",
"modifiedAt": "2026-07-31T10:00:00.000Z",
"etag": "...",
"fileId": "142857",
"favorite": false
}fileId yol değişse bile sabittir; sürüm geçmişi bu kimlikle sorgulanır.
GET/api/files/degisenler
Son sorgudan bu yana ne değişti? Elinde tam bir kopya tutan istemciler (mobil uygulama, masaüstü senkronizasyon ajanı) içindir; tüm ağacı yeniden listelemek büyük hesaplarda pahalıdır ve silinenleri hiç göstermez.
| Parametre | Açıklama |
|---|---|
path | Hangi klasörün altı. Varsayılan /. |
token | Önceki yanıttan gelen imleç. Verilmezse tüm ağaç döner. |
limit | Sayfa başına en fazla öğe (1–5000). |
{
"path": "/",
"syncToken": "http://sabre.io/ns/sync/1234",
"degisenler": [ /* FileEntry */ ],
"silinenler": ["/Belgeler/eski.pdf"],
"tamYenilemeGerekli": false
}Akış:
- İmleçsiz çağrı → tüm ağaç + bir
syncToken. - Sonraki çağrılar
tokenile → yalnızca değişenler ve silinenler. tamYenilemeGerekli: true→ imleç eskimiş (Nextcloud yeniden indekslenmiş olabilir). Yereldeki kopyayı atıp baştan listeleyin; yanıttaki yenisyncTokengeçerlidir, ondan devam edebilirsiniz.
Altında RFC 6578 sync-collection var, yani doğruluk kaynağı depolamanın kendisi: bu API'nin dışından yapılan bir değişiklik de yakalanır.
GET/api/files/ara?q=fatura
Tüm depolamada ada göre arama (alt klasörler dahil). q en az 2, en fazla 120 karakter. 200 → { "entries": [ ... ] } — girdiler listelemeyle aynı biçimde.
GET/api/files/quota
{ "usedBytes": 0, "totalBytes": 5368709120, "freeBytes": 5368709120, "usedPercent": 0 }POST/api/files/folder
{ "parent": "/", "name": "Yeni Klasör" } → 201 { "path": "/Yeni Klasör" }
Ad içinde \ / : * ? " < > | ve kontrol karakterleri kullanılamaz.
GET/api/files/download?path=/dosya.jpg
Dosya içeriği. Range desteklenir — duraklat/devam ve video akışı için kullanın. Yanıt Content-Disposition: attachment taşır.
Klasör indirmek (zip) için bölüm 4'teki önizleme belirtecini indir=1 ile kullanın; bu uç yalnızca dosya akıtır.
POST/api/files/rename · /move · /copy
{ "path": "/eski.txt", "name": "yeni.txt" }
{ "from": "/dosya.txt", "toDir": "/Klasor", "overwrite": false }Üçü de 200 { "path": "/yeni-yol" } döner. overwrite yalnızca /move ucunda vardır. Bir klasörü kendi içine taşımak/kopyalamak reddedilir (invalid_move, invalid_copy).
Taşıma ve yeniden adlandırmada o dosyanın paylaşım bağlantıları yeni yola taşınır; bağlantılar kırılmaz.
DELETE/api/files
{ "paths": ["/a.txt", "/b.txt"] }Tek istekte en fazla 200 yol.
200 → { "deleted": 2, "results": [{ "path": "/a.txt", "deleted": true }, ...] }
Her dosya için ayrı sonuç döner; başarısız olanda error alanı bulunur. Silme kalıcı değildir, çöp kutusuna gider. Silinen dosyanın paylaşım bağlantıları kaldırılır.
Çöp kutusu
| Uç | Açıklama |
|---|---|
GET /api/files/trash | { entries: [{ id, name, originalPath, deletedAt, sizeBytes, isFolder }] } |
POST /api/files/trash/restore | { id } → { restored: true } |
DELETE /api/files/trash | { id } tek kayıt, {} tümü — geri alınamaz |
id opak bir tanımlayıcıdır, yol değildir. Saklama süresi 30 gün.
Favoriler
| Uç | Açıklama |
|---|---|
GET /api/files/favoriler | { entries: [ ... ] } — listelemeyle aynı biçim |
POST /api/files/favori | { path, favorite: true | false } → { success: true } |
Sürüm geçmişi
GET /api/files/surumler?fileId=142857
{ "versions": [{ "id": "1692000000", "sizeBytes": 12345, "createdAt": "2026-08-14T..." }] }POST /api/files/surumler/geri-yukle — { fileId, versionId } → { success: true }
Geri yükleme mevcut içeriği de bir sürüm olarak saklar, yani geri alınabilir.
3Yükleme
Yükleme de doğrulanmış e-posta gerektirir — kural bütün yazma işlemleri için geçerli, ayrıntısı bölüm 2'nin başında.
Ayrı bir dosya boyutu sınırı yoktur. Tek sınır kullanıcının kotasıdır; kota dolduğunda 413 quota_exceeded döner.
Virüs tarayıcı kontrolü. Yükleme başlatma, tek dosya yükleme ve parçalı yüklemeyi tamamlama uçları, tarayıcı ayakta değilse 503 scanner_unavailable döner. Bu geçici bir durumdur, istek aynen tekrar edilebilir; kullanıcıya "birkaç dakika sonra tekrar deneyin" deyin. Tamamlama reddedilse bile parçalar silinmez: yarım kalan oturum 48 saat durur, tarayıcı toparlandığında aynı uploadId ile tamamlanabilir.
Küçük dosyalar — POST /api/files/upload?dir=/&overwrite=false
multipart/form-data, alan adı file. Akış halinde aktarılır, sunucu belleğine alınmaz.
Tek istekte pratik sınır ~100 MB'dır. Ters vekil gövdeyi 128 MB'da kesiyor (MAX_REQUEST_MB) ve Cloudflare zaten ~100 MB üstünü kendisi reddediyor. Uygulamanın kendi politika sınırı (MAX_UPLOAD_MB) çok daha yüksek ama taşıma katmanı önce devreye girer.
Pratikte: 64 MB'ın üstündeki her dosya için parçalı yüklemeyi kullanın. Web arayüzü de tam bunu yapıyor. Parçalı yüklemede toplam boyut sınırı yoktur, yalnızca kota geçerlidir.
201 → { "path": "/dosya.jpg", "name": "dosya.jpg" } 400 already_exists — overwrite=true göndermediyseniz. 400 no_file — file alanı yoksa.
Büyük dosyalar — parçalı yükleme
Bağlantı koptuğunda baştan başlamamak için büyük dosyalarda bunu kullanın. Önerilen parça boyutu 64 MB; tek parça en fazla 512 MB olabilir.
1. Oturum aç — POST /api/files/upload/baslat
{ "dir": "/", "name": "video.mp4", "uploadId": "istemci-uretir-8-64-karakter" }uploadId istemci tarafından üretilir, [A-Za-z0-9_-]{8,64} olmalıdır. Dosyanın ad/boyut/tarih bilgisinden türetin: aynı dosya için aynı kimlik üretilirse yarım kalan yükleme kaldığı yerden devam eder.
201 → { "uploadId": "...", "path": "/video.mp4" }
2. Durumu sor — GET /api/files/upload/:uploadId/durum?parca=67108864&toplam=3221225472
{ "chunks": [0, 1, 2], "eksik": [3] }parca (parça boyutu) ve toplam (dosya boyutu) verilmelidir. İkisi verildiğinde chunks yalnızca tam yazılmış parçaları içerir, eksik ise yarım kalanları. Bu iki parametre olmadan eski davranış geçerlidir — parçanın var olması yeterli sayılır — ve yarım kalmış bir parça "yüklenmiş" sanılıp atlanır; sonuç, ortasından bayt eksik, sessizce bozuk bir dosyadır. Üretimde tam olarak bu yaşandı.
eksik listesindeki indeksleri de yeniden gönderin.
3. Parça gönder — PUT /api/files/upload/:uploadId/:chunkIndex
Gövde ham baytlar, Content-Type: application/octet-stream. chunkIndex sıfırdan başlar. 204 döner.
İsteğe bağlı ama şiddetle önerilir: parçanın SHA-256 özetini gönderin.
X-Parca-Ozeti: <64 karakter hex>Sunucu yazdığı baytların özetini hesaplar; tutmazsa parçayı siler ve 409 chunk_corrupt döner. Bu kod yeniden denenebilir sayılmalıdır. Başlık gönderilmezse doğrulama yapılmaz (crypto.subtle bulunmayan ortamlar için).
4. Tamamla — POST /api/files/upload/:uploadId/tamamla
{ "dir": "/", "name": "video.mp4", "overwrite": false }201 → { "path": "/video.mp4", "name": "video.mp4" } 400 already_exists · 503 scanner_unavailable
İptal — DELETE /api/files/upload/:uploadId (204), yarım parçaları siler.
4Önizleme ve küçük resim
<img> ve <video> etiketleri Authorization başlığı gönderemez. Bunun için kısa ömürlü, dar kapsamlı belirteçler alınır.
Tek dosya önizlemesi
POST /api/files/onizleme-anahtari — { "path": "/foto.jpg" } → 200 { "token": "..." }. Ömrü 10 dakika, yalnızca o yola bağlıdır.
GET /api/onizleme/:token — oturum gerektirmez. Dosyayı akıtır, Range destekler. Adresi doğrudan <img src> / <video src> içinde kullanın.
Gömülü gösterim yalnızca image/*, video/*, audio/* ve application/pdf türlerine açıktır (Content-Disposition: inline); listede olmayan her tür attachment olarak iner. HTML yükleyip site adına script çalıştırmayı kapatan bilinçli bir sınır — gevşetilmesini beklemeyin.
GET /api/onizleme/:token?indir=1 — aynı belirteçle indirme. Hedef bir klasörse zip olarak akıtılır (application/zip). <a download> de Authorization gönderemediği için indirme akışı bu yol üzerinden kurulur.
Klasör küçük resimleri
POST /api/files/kucukresim-anahtari — { "dir": "/Fotograflar" } → 200 { "token": "..." }. Ömrü 10 dakika. Belirteç dosyaya değil klasöre bağlıdır: 50 resimli bir klasör için 50 ayrı anahtar almanız gerekmez.
GET /api/kucukresim/:token?ad=foto.jpg&boyut=256
ad— klasördeki dosyanın adı (yol değil;/ve..reddedilir).boyut— yalnızca128,256,1024,1920. Varsayılan256.
128/256 kare kırpar (ızgara için), 1024/1920 oranı korur (açılan görüntü için). Büyük fotoğrafta kazanç büyük: 4000×3000 bir görselde orijinal 3539 KB, 1920 px önizleme 95 KB. Tam çözünürlük gerekmedikçe bu ucu kullanın.
Yanıt image/*, cache-control: private, max-age=600.
5Paylaşım bağlantıları
POST/api/shares (oturum gerektirir)
{ "path": "/foto.jpg", "password": "enaz8karakter", "expiresInDays": 7, "maxDownloads": 10 }Klasör paylaşımında bir alan daha: "uploadAllowed": true. Bağlantıyı açan kişi klasöre dosya bırakabilir hâle gelir (aşağıda "Klasöre dosya bırakma").
Plan kuralları sunucuda zorlanır:
| Ücretsiz | Ücretli | |
|---|---|---|
| Süre | 7 gün (zorunlu) | seçilebilir, null = süresiz |
| Parola | yok — 400 plan_required | var, en az 8 karakter |
| İndirme limiti | yok — 400 plan_required | var |
Klasör de paylaşılabilir (aşağıda "Klasör paylaşımı"). Kök klasör paylaşılamaz, var olmayan yol 404. uploadAllowed tek dosya paylaşımında 400 not_a_folder döner — bırakılacak bir yer yok.
Yükleme izni plan gerektirmez: ücretli bir özellik değil, klasörün ne işe yaradığını belirleyen bir ayar; bırakılan dosya zaten paylaşımı açan hesabın kotasından yer kaplar.
201 → { "share": { "id", "token", "name", "isFolder", "expiresAt", "maxDownloads", "downloadCount", "uploadAllowed", ... } }
Paylaşım adresi: https://cloudutcu.com/s/<token>
| Uç | Açıklama |
|---|---|
GET /api/shares | kendi bağlantıları (parola hash'i dönmez, hasPassword döner) |
DELETE /api/shares/:id | iptal — 204 |
Herkese açık uçlar (oturum gerekmez)
GET /api/s/:token → { name, isFolder, hasPassword, expiresAt, zipVar, uploadAllowed } Dosyanın yolu hiçbir zaman dışarı verilmez.
POST /api/s/:token/anahtar — gövde { "password": "..." } (parolalıysa). 200 → { "token": "...", "name": "..." } — bu anahtarla /api/onizleme/:token üzerinden sayfada gösterebilirsiniz. İndirme sayacını artırmaz.
Ne gösterildiği dosya türüne ve paylaşımın indirme sınırına bağlı:
| Tür | maxDownloads yok | maxDownloads var |
|---|---|---|
| Resim (jpg, png, webp, avif, bmp, tif, heic) | en fazla 1920 px küçültülmüş kopya; çizilemezse orijinal | en fazla 1920 px küçültülmüş kopya |
| Video, ses, PDF, GIF, SVG | dosyanın kendisi akıtılır | 404 preview_disabled |
Sebep: önizleme sayacı artırmıyor. Orijinal dosya önizlemeden de gelebilseydi maxDownloads hiçbir şey sınırlamazdı — bağlantıyı açan herkes sayaç hiç artmadan dosyanın tamamını alabilirdi. Ölçek belirtecin içine yazılıyor, yani istemci onu kaldırıp orijinali isteyemez.
İndirme iki adımdır. Tek adımlı POST, <a download> POST atamadığı için istemciyi dosyanın tamamını belleğe toplamaya zorluyordu; parola gövdede gittiği için de GET'e çevrilemiyordu.
POST /api/s/:token/indirme-anahtari — gövde { "password": "..." } (parolalıysa). 200 → { "token": "...", "name": "..." } — 5 dakika ömürlü. Sayacı artırmaz.
#### Klasör paylaşımı
isFolder: true olan bağlantıda içerik gezilebilir.
POST /api/s/:token/liste — gövde { "password": "...", "altYol": "/alt/klasor" } (ikisi de isteğe bağlı). 200:
{
"name": "Rapor",
"altYol": "/alt/klasor",
"entries": [{ "name": "ozet.pdf", "path": "/alt/klasor/ozet.pdf", "isFolder": false,
"sizeBytes": 1024, "mimeType": "application/pdf", "modifiedAt": "..." }]
}Dönen yollar paylaşım köküne göre görelidir; sahibinin gerçek klasör düzeni dışarı verilmez. altYol olarak da bu göreli yolu geri gönderin. Kökün dışına çıkan bir yol 400 invalid_path döner. Listelemek sayacı artırmaz.
Klasörden indirme, aynı indirme-anahtari ucundan iki şekilde:
| Gövde | Sonuç |
|---|---|
{ "altYol": "/alt/ozet.pdf" } | O tek dosya. Sayacı 1 artırır. |
{ "zip": true } | Klasörün tamamı tek arşiv. Sayacı 1 artırır. |
zip yalnızca indirme sınırı olmayan paylaşımlarda çalışır (400 zip_disabled) — tek istek bütün içeriği taşıdığı için sınırlı bir bağlantıda "3 indirme", içeriğin tamamını üç kez vermek anlamına gelirdi. zipVar alanı bunu önceden söyler.
Dosya paylaşımına altYol veya zip gönderilirse 400 not_a_folder; klasör paylaşımında ikisi de yoksa 400 missing_path.
Klasör bağlantılarında önizleme, küçük resim ve video uçları 404 döner.
#### Klasöre dosya bırakma
uploadAllowed: true olan klasör bağlantısında, bağlantıyı açan kişi klasöre dosya ekleyebilir. İndirme gibi bu da iki adımdır: parola bir POST gövdesinde doğrulanır, dosya ayrı bir istekte akar.
POST /api/s/:token/yukleme-anahtari — gövde { "password": "...", "altYol": "/alt/klasor" } (ikisi de isteğe bağlı; altYol verilmezse kök). 200 → { "token": "..." } — 15 dakika ömürlü. Hedef klasör belirtecin içine imzalanır, yani ikinci adımda başka bir yola çevrilemez.
POST /api/s/yukle/:anahtar — multipart/form-data, tek file alanı. 201 → { "name": "ozet.pdf" } — dosyanın kaydedildiği ad.
Kurallar:
- Üzerine yazılmaz. Aynı adda dosya varsa yenisi
ozet (2).pdf,ozet (3).pdfdiye kaydedilir; yanıttakinamegerçek adı söyler. Bırakma izni, var olan bir dosyayı değiştirme izni değildir. 20 kopyadan sonra 400too_many_duplicates. - Yalnızca ekleme. Bağlantı üzerinden silme, yeniden adlandırma veya taşıma yoktur.
- İndirme sayacı artmaz.
maxDownloadsbağlantının kaç kez okunabileceğini söyler; dosya bırakmak onu tüketmez. - Durum her istekte yeniden okunur. Belirteci alıp bekleyen biri, o arada silinmiş, süresi dolmuş veya izni kaldırılmış bir paylaşıma yazamaz — 400
upload_not_allowedya da 404. - Boyut sınırı ve virüs taraması panel yüklemesiyle aynı (bölüm 10); tarayıcı hazır değilse 503
scanner_unavailable. - Bırakılan dosya paylaşımı açan hesabın kotasından yer kaplar.
İzinsiz bir paylaşımda her iki uç da 400 upload_not_allowed döner. Hız sınırı: anahtar için saatte 30, yükleme için saatte 20 istek (IP başına).
GET /api/s/indir/:anahtar — dosyayı attachment olarak akıtır ve indirme sayacını artırır. Süre ve maxDownloads burada tekrar denetlenir, yani anahtarı alıp bekleyen biri süresi dolmuş bir bağlantıyı indiremez.
Parolasız paylaşımlarda iki uç daha var; ikisi de sayacı artırmaz ve parolalı bağlantıda 404 döner (parolanın koruduğu şeyi önizlemeden sızdırmamak için):
| Uç | Açıklama |
|---|---|
GET /api/s/:token/kucukresim | 1024 px önizleme görseli — kart/paylaşım görseli için |
GET /api/s/:token/video | videoyu Range destekli akıtır — WhatsApp/Discord oynatıcısı buradan çeker. maxDownloads konmuş paylaşımda 404 (ham baytları sayaçsız verdiği için) |
Süresi dolmuş, silinmiş veya limiti dolmuş bağlantı 404 döner. Yanlış parola 401 invalid_password. Bir paylaşımda 15 dakika içinde 10 hatalı parola denenirse o paylaşım geçici olarak kilitlenir (429) — bu sayaç IP'ye değil paylaşıma bağlıdır.
6Planlar ve ödeme
GET/api/orders/plans
{
"plans": [{ "id": "standart", "name": "Standart", "storageGb": 500, "monthlyPrice": 89, "featured": true }],
"periods": [{ "months": 1, "label": "Aylık", "discount": 0 }, { "months": 12, "label": "Yıllık", "discount": 0.2 }]
}Güncel katalog (fiyatlar aylık, ₺):
| id | Ad | Depolama | Aylık |
|---|---|---|---|
free | Ücretsiz | 5 GB | 0 |
baslangic | Başlangıç | 100 GB | 39 |
standart | Standart | 500 GB | 89 |
plus | Plus | 1 TB | 149 |
pro | Pro | 2 TB | 249 |
discount kesirdir (0.2 = %20). Toplam: round(monthlyPrice × months × (1 − discount))
Fiyatı istemcide hesaplayıp göndermeyin — sunucu kendi kataloğundan faturalandırır, gönderilen tutar dikkate alınmaz. Katalog burası üzerinden okunmalı; sabit kodlanan fiyat, gösterilen ile tahsil edilen tutarın ayrılması demektir.
POST/api/orders/checkout
{ "planId": "standart", "months": 12 } → { "action": "https://...", "fields": { ... } }
403 account_frozen — dondurulmuş hesap ödeme başlatamaz.
Yanıt imzalı form alanlarıdır (JSON), sayfa değil. İstemci bu alanlarla bir POST isteği kurup tarayıcıyı/WebView'i action adresine göndermelidir — alanların hiçbiri değiştirilmemeli, aksi halde imza doğrulanmaz ve ödeme reddedilir. Uçtaki değerleri kaçışlamaya (HTML escape) çalışmayın; fields içindeki metin ne ise imza onun üzerinden hesaplandı.
Ödeme tamamlandığında sunucu, sağlayıcıdan gelen imzalı bildirimle siparişi etkinleştirir; uygulamanın bir şey yapması gerekmez, GET /api/auth/me ile yeni kotayı okumak yeterlidir.
Bildirimi karşılayan uç POST /api/orders/callback. Oturum istemez ama çağırmayın: gövdedeki HMAC imzası doğrulanmadan hiçbir sipariş etkinleştirilmez, imzasız istek 400 invalid_signature döner. Tarayıcı ödeme sonrası buraya düştüğünde uç, işini bitirip 303 ile /orders sayfasına yönlendirir. Tekrarlanan bildirim güvenlidir: zaten paid olan sipariş ikinci kez işlenmez, yani planın süresi iki katına çıkmaz.
Sipariş sorgulama
| Uç | Açıklama |
|---|---|
GET /api/orders | kullanıcının son 100 siparişi |
GET /api/orders/:orderNumber | tek sipariş — başkasınınki 404 |
7Destek talepleri
| Uç | Açıklama |
|---|---|
GET /api/tickets | liste (son 100) |
POST /api/tickets | { subject, message, priority } — low | normal | high → 201 |
GET /api/tickets/:id | { ticket, replies } |
POST /api/tickets/:id/replies | { message } → 201 { reply } |
POST /api/tickets/:id/close | kapatır |
subject 3–200, message 10–5000 karakter (yanıtta 1–5000). Kapatılmış talebe yanıt yazmak 403 ticket_closed döner. Başkasının talebine erişim reddedilir.
8Genel uçlar (oturum gerekmez)
| Uç | Açıklama |
|---|---|
GET /api/public/settings | { settings: { maintenance, duyuru } } — bakım modu ve duyuru |
GET /api/public/stats | { totalUsers, totalRatings, averageRating, allocatedStorageBytes } |
GET /api/public/testimonials | onaylanmış son 24 yorum |
POST /api/public/contact | { name, email, subject, message } |
POST /api/public/basvuru | bayilik/yetkili başvurusu — ayırıcı alan type: bayi | yetkili |
GET /health | { status: "ok", time } — veritabanı erişimini de sınar |
POST /api/public/basvuru içindeki website alanı http veya https ile başlamalıdır. javascript: ve data: adresleri reddedilir: değer yönetim panelinde tıklanabilir bir bağlantı olarak çıkıyor ve uç kimlik doğrulaması istemiyor.
POST /api/public/testimonials (oturum gerektirir) — { content, rating }, content 10–1000 karakter, rating 1–5. Yorum pending durumunda kaydedilir; moderasyondan geçmeden yayınlanmaz.
Yönetim uçları /api/admin/* altındadır ve admin/moderator rolü ister; bu dokümanın kapsamı dışında. İki not: rol her istekte veritabanından okunur (belirtecin içindekine güvenilmez) ve dondurulmuş bir personel hesabı 403 account_frozen alır. PUT /api/admin/settings/:key gövdesinde value alanı zorunludur — alan gönderilmezse 400; null geçerli bir değerdir.
9Hız sınırları
Genel sınır IP başına dakikada 300 istek. Aşağıdaki uçlarda ek sınır var.
Anahtar sütunu önemli. IP dışındaki anahtarlar, paylaşılan bir çıkış IP'sinin (ev NAT'i, kurum ağı, mobil operatör havuzu) arkasındaki kullanıcıların birbirinin kotasını tüketmesini engeller:
hesap— kullanıcı kimliği. Token yenilemek temiz bir kova açmaz.e-posta— gövdedeki adresin özeti. Dağıtık bir ağdan (vekil havuzu) tek bir hesaba yönelen denemeyi keser; IP başına sınırın tek başına göremediği şey bu.belirteç sahibi— adresteki imzalı belirtecin içindeki kullanıcı.
Bir uçta iki sınır varsa ikisi de işler: hangisi önce dolarsa 429 o verir.
| Uç | Sınır | Anahtar |
|---|---|---|
register | 15 dakikada 5 | IP |
login | 15 dakikada 10 | IP |
login | 15 dakikada 20 | e-posta |
login/2fa | 15 dakikada 10 | hesap |
2fa/* (kurulum, açma, kapatma, kodlar) | 15 dakikada 5 | hesap |
forgot-password | 15 dakikada 5 | IP |
forgot-password | saatte 5 | e-posta |
reset-password · verify-email | genel sınır | IP |
resend-verification | 15 dakikada 3 | IP |
change-password | 15 dakikada 5 | hesap |
logout-all | 15 dakikada 5 | hesap |
hesabi-sil | 15 dakikada 5 | hesap |
POST /api/orders/checkout | 5 dakikada 10 | hesap |
/api/files/* (tümü) | dakikada 240 | hesap |
/api/files/ara | dakikada 60 | IP |
/api/files/degisenler | dakikada 60 | IP |
| yükleme tamamlama, sürüm geri yükleme, silme, çöp boşaltma | dakikada 60 | hesap |
GET /api/onizleme/:token | dakikada 300 | belirteç sahibi |
klasör zip indirme (?indir=1) | 5 dakikada 20 | belirteç sahibi |
GET /api/kucukresim/:token | dakikada 600 | belirteç sahibi |
/api/tickets/* (tümü) | dakikada 60 | hesap |
POST /api/tickets | saatte 10 | IP |
POST /api/tickets/:id/replies | 10 dakikada 20 | hesap |
POST /api/s/:token/anahtar | saatte 60 | IP |
POST /api/s/:token/liste | saatte 120 | IP |
POST /api/s/:token/indirme-anahtari | saatte 30 | IP |
GET /api/s/indir/:anahtar | saatte 60 | IP |
POST /api/public/basvuru | saatte 3 | IP |
POST /api/public/contact | saatte 5 | IP |
POST /api/public/testimonials | 24 saatte 3 | IP |
Parolalı paylaşımlarda tablodaki IP sınırlarının üstüne bir de paylaşım başına başarısız deneme kilidi biner (ayrıntı bölüm 5). Dağıtık bir ağdan gelen parola denemesini IP sınırı tek başına göremediği için var.
Aşıldığında 429. Kullanıcıya bekleme mesajı gösterin, sessizce yeniden denemeyin.
Tek istisna parçalı yükleme: orada 429 ve 408, 409 ile aynı kutuda — geçici sayılıp artan beklemeyle (1s, 2s, 4s… en fazla 15s, 5 deneme) yeniden gönderilir. Gerekçe, saatlerdir süren bir yüklemenin tek bir geçici yanıt yüzünden ölmemesi; sayaç bütün /api/files/* uçlarıyla paylaşıldığı için yükleme sırasında başka bir sekmede gezinmek bu sınıra değebilir.
Uygulama sınırlarının önünde ayrıca ters vekilde (nginx) bir sınır var: /api/ için saniyede 20 istek (200'lük ani yığına izin verir), şifre kabul eden uçlarda saniyede 1, IP başına 50 eşzamanlı bağlantı. Buraya çarpan istek Node sürecine hiç ulaşmaz ve gövdesiz bir 429 döner.
10Boyut sınırları
| Ne | Sınır |
|---|---|
| JSON gövde | 1 MB |
| Tek istekte dosya yükleme | ~100 MB (nginx 128 MB, Cloudflare ~100 MB) |
Tek parça (PUT .../:chunkIndex) | etkin ~100 MB (uygulama 512 MB kabul eder, ters vekil 128 MB'da keser) |
| Parçalı yüklemede toplam boyut | sınırsız — yalnızca kota |
| Toplu silmede yol sayısı | 200 |
| Dosya/klasör adı | 255 karakter |
| Yol | 1024 karakter |
11İstemci tarafında dikkat edilecekler
- Access token'ı bellekte tutun, kalıcı depolamaya yazmayın. Refresh token güvenli alanda saklanmalı (Android Keystore / iOS Keychain).
- 401 alındığında bir kez yenileyip isteği tekrarlayın; yenileme de başarısızsa oturumu kapatın.
- Eşzamanlı yenileme çağrılarını tek isteğe toplayın (token tek kullanımlık).
- Büyük dosyalarda parçalı yüklemeyi kullanın; dosyayı belleğe almayın. Durum sorgusunda
parcavetoplamgöndermeyi atlamayın ve parça özetini (X-Parca-Ozeti) gönderin — ikisi de sessiz dosya bozulmasını önlüyor. - İndirmede
Rangeile devam ettirin. - Izgara/galeri görünümünde tam dosya değil küçük resim ucunu kullanın.
email_not_verified,accountFrozenvescanner_unavailabledurumlarını ayrı ele alın; üçünde de kullanıcıya ne yapması gerektiğini söyleyin.quota_exceeded(413) alındığında plan yükseltme ekranına yönlendirin.
12Hata kodları
| Kod | HTTP | Anlamı |
|---|---|---|
no_session | 401 | refresh çerezi yok |
invalid_credentials | 401 | e-posta/şifre hatalı |
invalid_token | 401 | önizleme/doğrulama belirteci geçersiz veya süresi dolmuş |
invalid_password | 401 | paylaşım parolası hatalı |
preview_disabled | 404 | indirme sınırlı paylaşımda çizilemeyen türün önizlemesi kapalı |
wrong_password | 400 | mevcut şifre hatalı (şifre değiştirme, 2FA) |
invalid_totp | 401/400 | doğrulama kodu hatalı |
totp_expired | 401 | 2. adım belirteci süresi doldu — baştan giriş |
totp_not_started | 400 | etkinleştirmeden önce kurulum çağrılmadı |
totp_already_enabled | 409 | iki adımlı doğrulama zaten açık |
totp_not_enabled | 400 | iki adımlı doğrulama kapalı |
current_session | 400 | kendi oturumunuzu bu uçtan kapatamazsınız |
email_not_verified | 400 | yazma işlemi için e-posta doğrulanmalı (bölüm 2) |
email_taken | 409 | bu e-posta kayıtlı |
account_frozen | 403 | hesap donduruldu — giriş, yenileme, depolama, ödeme ve yönetim uçları kapalı |
forbidden | 403 | bu kayda erişim yok |
ticket_closed | 403 | kapatılmış talebe yanıt |
invalid_path | 400 | geçersiz yol (.., kök, ters eğik çizgi) |
invalid_name | 400 | ad yasak karakter içeriyor |
already_exists | 400 | aynı isimde dosya var (overwrite gönderin) |
invalid_move / invalid_copy | 400 | klasörü kendi içine taşıma/kopyalama |
not_a_folder | 400 | klasör bekleyen bir alan dosya paylaşımına gönderildi (altYol, zip, uploadAllowed) |
upload_not_allowed | 400 | bu paylaşıma dosya bırakma izni yok |
too_many_duplicates | 400 | aynı adın 20 kopyası zaten var — dosyayı yeniden adlandırın |
plan_required | 400 | ücretli plan özelliği |
invalid_api_key | 401 | uygulama belirteci tanınmıyor |
api_key_expired | 401 | uygulama belirtecinin süresi dolmuş |
api_key_not_allowed | 403 | bu uç uygulama belirtecine kapalı (bölüm 1) |
insufficient_scope | 403 | belirtecin bu işlem için yetkisi yok |
no_scopes / invalid_scope | 400 | belirteç oluştururken yetki verilmedi / bilinmeyen yetki |
too_many_keys | 400 | hesap başına 20 belirteç sınırı |
invalid_url / invalid_url_scheme | 400 | webhook adresi geçersiz / https değil |
private_address | 400 | webhook adresi iç ağa bakıyor |
no_events / invalid_event | 400 | webhook için olay seçilmedi / bilinmeyen olay |
too_many_webhooks | 400 | hesap başına 10 abonelik sınırı |
push_disabled | 503 | bildirim özelliği bu sunucuda kapalı (VAPID anahtarı yok) |
no_file | 400 | multipart gövdede file alanı yok |
file_too_large | 400 | sunucu yükleme sınırı aşıldı |
chunk_corrupt | 409 | parça özeti tutmadı — yeniden gönderin |
quota_exceeded | 413 | depolama kotası doldu |
rate_limited | 429 | hız sınırı |
scanner_unavailable | 503 | virüs tarayıcı hazır değil — biraz sonra tekrar deneyin |
storage_unreachable | 502 | depolama sunucusuna ulaşılamıyor |
Listede olmayan bir kod gelirse message alanını gösterin; kod adına göre dal kurmayın.