Media API

/api/v1/media, medya kütüphanesinin üstünde ince bir REST katmanı. Onu kullanmaya değer kılan şey yüklemenin sırasında olup bitenler: görsel yeniden boyutlanır, AVIF ve WebP'ye çevrilir, küçük boyutları üretilir ve yanıt dönmeden veritabanına işlenir. Yoklanacak bir kuyruk, beklenecek bir işçi süreç yok.

Medya kütüphanesi
API ile yüklenen dosya da bu kütüphaneye düşer ve elle yüklenenle aynı varyantları alır.

Her çağrı API anahtarı ister; her yazma işlemi upload_files yetkisi ister - yönetici, editör ve yazar rollerinin üçünde de bu yetki var.

Dosyaları listeleme

GET /api/v1/media üç parametre alır, üçünden fazlasını değil: page (1'den başlar, varsayılan 1), per_page (varsayılan 20) ve type.

type, kayıtlı MIME türüne göre süzer; image, video, audio ya da file değerini alır. file burada "görsel, video ve ses dışındaki her şey" demektir; PDF'ler, tablolar ve arşivler oraya düşer. type göndermezseniz kütüphanenin tamamı gelir. Bu uçta kelime araması, yükleyen süzgeci ve sıralama parametresi yok; sonuçlar her zaman en yeniden başlar.

curl -H "X-API-Key: ANAHTARINIZ" \
  "https://siteniz.com/api/v1/media?type=image&per_page=20"
{
    "success": true,
    "data": {
        "items": [
            {
                "id": 45,
                "filename": "kapak-8f3a12c4.avif",
                "original_filename": "kapak.jpg",
                "path": "images/2026/04/kapak-8f3a12c4.avif",
                "url": "https://siteniz.com/uploads/images/2026/04/kapak-8f3a12c4.avif",
                "type": "image",
                "mime_type": "image/avif",
                "size": 61204,
                "width": 1600,
                "height": 900,
                "alt_text": "Tabakta menemen",
                "title": "kapak",
                "caption": "",
                "user_id": 1,
                "created_at": "2026-04-10 08:55:00",
                "formats": {
                    "avif": { "path": "images/2026/04/kapak-8f3a12c4.avif", "size": 61204 },
                    "webp": { "path": "images/2026/04/kapak-8f3a12c4.webp", "size": 88431 }
                },
                "thumbnails": { "thumbnail": { "…": "…" }, "medium": { "…": "…" }, "large": { "…": "…" } }
            }
        ],
        "total": 412,
        "pages": 21,
        "current_page": 1
    }
}

formats, thumbnails ve srcset satırın JSON meta sütununda durur ve yanıt üretilirken nesneye karıştırılır; bu yüzden sıradan üst düzey anahtarlar gibi görünürler. GET /api/v1/media/{id} aynı şekli tek öğe için döner, kimlik yoksa 404.

Dosya yükleme

Çok parçalı (multipart) form gönderin; ikili veri file adlı alanda olsun. Yanında iki isteğe bağlı metin alanı gider: alt alternatif metin olur, title kütüphanedeki başlık. alt boş bırakılırsa jekcms dosya adından okunabilir bir varsayılan türetir - sayfalarınıza boş alt="" göndermek yerine.

curl -X POST https://siteniz.com/api/v1/media \
  -H "X-API-Key: ANAHTARINIZ" \
  -F "file=@/yol/kapak.jpg" \
  -F "alt=Tabakta menemen"

Yanıt, yükleme sonucudur: success, kaydedilen id, nihai path ve url, size, mime_type, üretilen formats ve thumbnails. Görsellerde path artık dönüştürülmüş dosyayı gösterir, gönderdiğinizi değil.

Adresten yükleme

Aynı uç, çok parçalı dosya yerine içinde url bulunan bir JSON gövdesi de kabul eder; böylece otomasyonun görseli önce kendi diskine indirmesi gerekmez:

curl -X POST https://siteniz.com/api/v1/media \
  -H "X-API-Key: ANAHTARINIZ" -H "Content-Type: application/json" \
  -d '{"url": "https://gorseller.example.com/yemek/menemen.jpg", "alt": "Tabakta menemen"}'

İndirme kasıtlı olarak dar tutulmuştur. Yalnız http ve https izlenir, yönlendirmeler hiç izlenmez ve istek yapılmadan önce alan adı çözülür: özel ağ, loopback, link-local ya da bulut meta veri adresine işaret eden her şey reddedilir. İndirme 25 MB'ta kesilir, 60 saniyede zaman aşımına uğrar. Ret, HTTP hatası olarak değil, 200 içinde success: false ve hata metninde bir sebep koduyla döner - private-or-reserved-ip, scheme-not-allowed, internal-host, metadata-or-linklocal, dns-failed ya da invalid-url. Yani yalnız durum koduna değil, bayrağa bakın.

Base64 yükleme bu ucun parçası değil. Otomasyon yüzeyinde POST /api/v1/webhook/media-base64 olarak yaşıyor; data ve filename alır ve yalnız görsel kabul eder.

Dönüşüm gerçekte ne yapıyor

Dönüşüm istek sırasında, yerinde çalışır. Görsel okunur, kenarlarından biri ayarlanan azami değeri (varsayılan 2560 piksel) aşıyorsa küçültülür, sonra hem AVIF hem WebP olarak yazılır. AVIF birincil dosyadır ve veritabanı satırının gösterdiği dosya odur; WebP yedektir. İkisi de oluştuktan sonra özgün JPEG, PNG ya da GIF silinir - modern biçimler kütüphanenin kendisidir, ona eklenen bir katman değil. WebP veya AVIF olarak yüklenen dosyaya dokunulmaz.

Yanında dört küçük boyut üretilir: kırpılmış 400×400 kare, bu sınırların içine sığdırılmış 800×800 ve 1600×1600, bir de Pinterest için kırpılmış 1000×1500.

Kalite ve boyut tercihleri Ayarlar → Medya altında: azami kenar (800–4096), JPEG kalitesi, WebP kalitesi (55–95, varsayılan 82) ve AVIF kalitesi (40–80, varsayılan 60). Varsayılanlar, dosyanın ağırlığını büyük ölçüde düşürürken gözle fark edilmeyecek kalite hedefiyle seçilmiştir.

Sunucuda GD eklentisi yoksa dönüşüm ölümcül hata vermez, atlanır: dosya özgün biçiminde saklanır ve yanıt bunu söyler. AVIF beklerken JPEG aldığınız tek durum budur.

Üst veriyi güncelleme

/api/v1/media/{id} üzerinde PUT ya da PATCH, alt_text, title, caption ve description alanlarını değiştirir. Satırın başka hiçbir alanı API üzerinden yazılabilir değildir; yanıt yalnızca {"success": true} olur.

Silme

DELETE /api/v1/media/{id} veritabanı satırını, birincil dosyayı, WebP ve AVIF kardeşlerini ve üretilmiş tüm küçük boyutları siler.

Dosyaya hâlâ bir şeyin işaret edip etmediğine bakmaz. Bir yazının kapak görseli ya da gövdesinde kullanılan bir görseli silerseniz geriye kırık bir referans kalır - özellikle betikten silmeden önce kullanımı kontrol edin.

Sınırlar

MAX_UPLOAD_SIZE yüklemeleri 50 MB ile sınırlar; PHP'nin kendi upload_max_filesize ve post_max_size değerleri bir kez daha sınırlar. Paylaşımlı barındırmada fiilî tavan genellikle PHP tarafındadır; büyük bir dosya reddedildiğinde önce oraya bakın. Adresten indirmenin kendi ve daha alçak bir tavanı var: 25 MB.

Uzantılar beyaz listeyle denetlenir, istemcinin bildirdiği MIME türüne güvenilmez. Görsellerde jpg, jpeg, png, gif, webp ve avif. Belge ve arşivlerde pdf, doc, docx, xls, xlsx, zip ve txt. Bunların dışındaki her şey, yanıt gövdesinde açıklamasıyla birlikte reddedilir.

SVG bilerek dışarıda bırakıldı. SVG, image/svg+xml olarak satır içinde sunulur ve betik taşıyabilir; yükleme formu bu yüzden kendi alan adınızda kalıcı XSS yüzeyine dönüşürdü. Site logosu ve arayüz ikonları bunun yerine tema varlığı olarak gelir.

Durum kodları

| Kod | Ne zaman | |---|---| | 200 | Listeleme, okuma, güncelleme, silme ya da yükleme işlendi | | 400 | Ne file alanı ne de url gönderildi, ya da medya kimliği eksik | | 401 | Anahtar yok, tanınmıyor, pasif ya da süresi dolmuş | | 403 | Rolde upload_files yetkisi yok | | 404 | O kimlikte medya yok | | 405 | Bu yolda bu yöntem desteklenmiyor | | 429 | IP başına saatlik hız sınırı aşıldı |

Yüklemenin içindeki doğrulama hataları HTTP 200 ile döner; gövdede success: false ve bir mesaj olur. Yanlış uzantı, fazla büyük dosya, bozuk görsel, reddedilen adres bu gruba girer. Sebebi şu: bunlar isteğin kusuru değil, yüklemenin sonucu. Bayrağı okuyun.

Yeniliklerden ilk sen haberdar ol

Yeni özellikler, sürüm notları ve CMS rehberleri. Ayda birkaç e-posta gönderiyoruz.