Yazı API'si

Siteye yazıyı başka bir yazılımdan eklemek, okumak, düzenlemek, yayına almak ve silmek için tek kapı. Her istek kurallara göre denetlenir; hatalar tek seferde, alan alan ve anlaşılır bir dille döner.

  1. GET
  2. POST
  3. PUT
  4. PATCH
  5. DELETE
01

Başlarken

Üç şey yeter: adres, anahtar ve JSON gövde.

Adreshttps://www.birseyleryapiyoruz.com/api/articles
BiçimJSON — istekte Content-Type: application/json, en çok 256 KB
KimlikAuthorization: Bearer bsy_… (okuma ya da yazma yetkili anahtar)
Yeni yazıHer zaman taslak girer, sitede görünmez. PATCH {"taslak": false} ile yayına çıkar.
SiteHer yazma isteği site önbelleğini hemen tazeler; değişiklik anında görünür.
İlk istek: son üç yazı
curl "https://www.birseyleryapiyoruz.com/api/articles?limit=3" \
  -H "Authorization: Bearer $API_KEY"
02

Kimlik doğrulama

Anahtarı platform üretir. Anahtar yalnız üretildiği anda bir kez gösterilir; veritabanında kendisi değil, özeti tutulur.

Her istekte
Authorization: Bearer bsy_TCteCi…
Yetkiİzin verdiği
readListe, tek yazı ve /validate.
writeOkumanın hepsi + ekleme, değiştirme, düzenleme, yayına alma, silme.
Anahtar yönetimi (proje klasöründe)
"gelistiriciler-module__GHkoHq__tCom"># Yeni anahtar — yalnız bu sefer gösterilir
npm run api-anahtar -- olustur uretici-1 write "Otomatik yazı üretici"

"gelistiriciler-module__GHkoHq__tCom"># Anahtarlar: ad, yetki, son kullanım
npm run api-anahtar -- liste

"gelistiriciler-module__GHkoHq__tCom"># Anında kapat (bu anahtarla gelen istekler 403 alır)
npm run api-anahtar -- iptal uretici-1

Anahtar yoksa 401 UNAUTHORIZED, geçersiz ya da iptal edilmişse 403 FORBIDDEN. Anahtar adreste (?key=) kabul edilmez; adresler kayıtlara düşer.

03

Yanıt biçimi

Bütün yanıtlar aynı zarfta gelir. Önce ok alanına bakman yeter.

Başarı
{
  "ok": true,
  "data": { … },
  "meta": { … },
  "corrections": [ … ]
}
Hata
{
  "ok": false,
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "…",
    "fields": [ … ]
  }
}
AlanAnlamı
dataYazı nesnesi; listede yazı dizisi.
metaYalnız listede: page, limit, total, pages.
correctionsAPI'nin senin yerine düzelttikleri (ör. kategori yazımı). Varsa gelir.
error.codeMakinenin okuyacağı kod — §09.
error.fieldsHer neden ayrı: field, code, message; gerekiyorsa expected, received, allowed.

Yanıtlar önbelleğe alınmaz (Cache-Control: no-store). Yazı dönen her yanıtta X-Version başlığı vardır — §08.

04

Yazı nesnesi

Gönderdiğin gövde. Yıldızlı alanlar zorunlu; bilmediğimiz her alan ek alan olarak saklanır.

AlanTürKural
slug *stringAdres: /yazilar/<slug>. Yalnız a-z 0-9 - (Türkçe harf yok), en çok 60 karakter, benzersiz, değiştirilemez.
baslik *string25–60 karakter. Sondaki nokta kendiliğinden kalkar.
ozet *string120–200 karakter, tek paragraf. Kartta 3 satır görünür.
tarih *stringYYYY-AA-GG, gerçek bir gün. Liste yeniden eskiye bu alana göre sıralanır.
kategori *stringBeş kategoriden biri — §05. Büyük/küçük harf fark etmez.
giris *stringBölümlerden önceki giriş, 1–2 paragraf Markdown.
bolumler *dizi3–6 öğe, her biri yalnız { baslik, icerik }.
ikonstringYazının kendi kategorisinden bir ikon — §05. Boşsa kategorinin varsayılanı.
yazarstringEn çok 60 karakter.
ek alanlarherhangiAd harfle başlar (harf, rakam, _), en çok 20 alan, toplam 8 KB, en çok 3 kat iç içe. Yanıtta ekAlanlar içinde döner.

API'nin eklediği alanlar

AlanAnlamı
taslaktrue: sitede görünmez. Yalnız PATCH ile değişir.
urlYazının sitedeki adresi.
kelime · okumaDkKelime sayısı ve okuma süresi (dakikada 200 kelime).
surumHer değişiklikte 1 artar — §08.
olusturuldu · guncellendiISO tarih.

Gönderilemez: taslak (yalnız PATCH), _id, olusturuldu, guncellendi, kaynak, surum ve eski alanlar arama, bolum, alan, icerik, tur → RESERVED_FIELD.

Senin yerine düzelttiklerimiz

Gereksiz hata çıkmasın diye gövde denetimden önce temizlenir ve yapılan her düzeltme corrections ile bildirilir: kenar boşlukları ve görünmez karakterler silinir, satır sonları birleşir, art arda boş satırlar teke iner; slug ve ikon küçük harfe, kategori doğru yazımına çevrilir ("değişim" → "Değişim", eski ad "Değişmek" → "Değişim"); bölüm başlığının başındaki numara (1. ) kalkar.

05

Kategoriler ve ikonlar

Tek kategori seçilir: yazının ana sorusu hangisine aitse. İkon yalnız anahtar olarak yazılır ve kendi kategorisinden seçilir; ilk ikon varsayılandır.

[CSR]Cesaret
  • bayrakvarsayılan
  • merdiven
  • roket
  • kivilcim
  • kapi
  • ampul
  • mikrofon
[DYN]Dayanıklılık
  • nabizvarsayılan
  • kalkan
  • capa
  • pil
  • fidan
  • dag
[FRK]Farkındalık
  • gozvarsayılan
  • geri-al
  • buyutec
  • soru
  • terazi
  • kalem
[DGS]Değişim
  • pusulavarsayılan
  • dongu
  • yol-ayrimi
  • cip
  • parilti
[VZN]Vizyon
  • durbunvarsayılan
  • hedef
  • kup
  • grafik
  • harita
06

İçerik kuralları

Toplam 600–1200 kelime (3–6 dk okuma). Bölüm başlığı 2–6 kelime; numara eklenmez, site numaralar.

Kullanılır

BiçimYazımı
Paragrafboş satırla ayrılır
Vurgu**kalın** · *italik*
Alıntı> Tek cümle. — en çok 2
Liste- madde · 1. adım
Ara başlık### Başlık
Bağlantı[metin](https://…)

Kullanılmaz

  • # / ## başlık — bölüm başlığı ayrı alanda
  • #### ve daha derin başlık
  • HTML etiketleri
  • Görsel ![…](…)
  • Tablo ve kod bloğu
  • http(s):// ile başlamayan bağlantı

Hata, ilgili alan ve satır numarasıyla döner.

Dil ve ton: Türkçe, sade ve samimi; okura "sen" diye seslenir. Kısa cümleler, somut örnek, net bir ana fikir. Reklam dili ve doldurma cümle yok. Konular: girişimcilik, teknoloji, yapay zekâ, yatırım ve sektörden notlar.

07

Uç noktalar

Yedi uç nokta; renkler Branding Kit'in beş alan rengi.

YöntemAdresNe yapar
GET/api/articlesListe (sayfalı, filtreli)
POST/api/articlesYeni yazı (taslak)
POST/api/articles/validateYalnız denetle, kaydetme
GET/api/articles/{slug}Tek yazı
PUT/api/articles/{slug}Tümüyle değiştir
PATCH/api/articles/{slug}Kısmi düzenle · yayına al · taslağa çek
DELETE/api/articles/{slug}Sil (arşive taşı)
GET/api/articlesokuma yetkisi

Yazıları listele

En yeniden eskiye sıralı. Varsayılan olarak yalnız künye gelir; içerik için include=content.

ParametreDeğerlerVarsayılan
statusall · draft · publishedall
categoryAd ya da adres biçimi: Değişim, degisim (eski adlar da)—
qBaşlıkta arama—
page1 ve üzeri1
limit1–10020
includecontent—
İstek
curl "https://www.birseyleryapiyoruz.com/api/articles?status=draft&category=degisim&limit=10" \
  -H "Authorization: Bearer $API_KEY"
200 OK
{
  "ok": true,
  "data": [ { "slug": "…", "baslik": "…", "taslak": true, "kategori": "Değişim", "kelime": 617, … } ],
  "meta": { "page": 1, "limit": 10, "total": 1, "pages": 1 }
}

Olası hatalar: 400 INVALID_QUERY · 401 · 403

POST/api/articlesyazma yetkisi

Yazı ekle

Yazı taslak olarak girer. Aynı slug’da yazı varsa üzerine yazılmaz.

Gövde (metinler kısaltıldı; gerçek yazı 600–1200 kelime)
{
  "slug": "yapay-zekayla-ilk-urunu-cikarmak",
  "baslik": "Yapay zekâyla ilk ürünü çıkarmak",
  "ozet": "Model seçmek işin en kolay kısmı. Asıl soru hangi sorunu, kimin için, ne kadar iyi çözdüğün…",
  "tarih": "2026-10-15",
  "kategori": "Değişim",
  "ikon": "parilti",
  "yazar": "Bir Şeyler Yapıyoruz",
  "giris": "Yapay zekâ araçları ürün çıkarmayı hiç olmadığı kadar ucuzlattı. Ama ucuzlayan şey **denemek**…",
  "bolumler": [
    { "baslik": "Önce sorun, sonra model", "icerik": "En sık yapılan hata…\n\n> Model değişir; çözdüğün sorun kalır." },
    { "baslik": "İlk sürüm tek iş yapsın", "icerik": "İlk sürümün tek bir işi iyi yapması yeter…\n\n- Birinci soru\n- İkinci soru" },
    { "baslik": "Ölç, sonra büyüt", "icerik": "Kaç kişinin ikinci kez geldiğine bak…" }
  ],
  "kaynakUrl": "https://example.com/kaynak",
  "etiketler": ["yapay zekâ", "ürün"]
}
İstek
curl -X POST "https://www.birseyleryapiyoruz.com/api/articles" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d @yazi.json
201 Created · X-Version: 1
{
  "ok": true,
  "data": {
    "slug": "yapay-zekayla-ilk-urunu-cikarmak",
    "url": "https://www.birseyleryapiyoruz.com/yazilar/yapay-zekayla-ilk-urunu-cikarmak",
    "taslak": true,
    "baslik": "Yapay zekâyla ilk ürünü çıkarmak",
    "ozet": "Model seçmek işin en kolay kısmı…",
    "tarih": "2026-10-15",
    "kategori": "Değişim",
    "ikon": "parilti",
    "yazar": "Bir Şeyler Yapıyoruz",
    "giris": "Yapay zekâ araçları…",
    "bolumler": [{ "baslik": "Önce sorun, sonra model", "icerik": "…" }],
    "kelime": 617,
    "okumaDk": 4,
    "surum": 1,
    "olusturuldu": "2026-10-15T09:00:00.000Z",
    "guncellendi": "2026-10-15T09:00:00.000Z",
    "ekAlanlar": { "kaynakUrl": "https://example.com/kaynak", "etiketler": ["yapay zekâ", "ürün"] }
  },
  "corrections": ["kategori \"değişim\" → \"Değişim\""]
}

Olası hatalar: 409 SLUG_TAKEN · 422 VALIDATION_FAILED · 400 · 413 · 415 · 401 · 403

POST/api/articles/validateokuma yetkisi

Kaydetmeden denetle

Gövde POST ile aynıdır. Hiçbir şey kaydedilmez; üretici yazılım göndermeden önce kendini sınar.

200 OK
{
  "ok": true,
  "data": {
    "gecerli": true,
    "kelime": 617,
    "okumaDk": 4,
    "yazi": { "slug": "…", "baslik": "…", "kategori": "Değişim", "…": "temizlenmiş hali", "ekAlanlar": { } }
  },
  "corrections": [ "…" ]
}

Geçmezse: 422 VALIDATION_FAILED — POST ile aynı hata listesi.

GET/api/articles/{slug}okuma yetkisi

Tek yazıyı oku

Taslak da olsa döner; içerik dahil. X-Version başlığı güncel sürümü verir.

İstek
curl "https://www.birseyleryapiyoruz.com/api/articles/yapay-zekayla-ilk-urunu-cikarmak" -H "Authorization: Bearer $API_KEY"

Olası hatalar: 404 NOT_FOUND · 401 · 403

PUT/api/articles/{slug}yazma yetkisi

Tümüyle değiştir

Yazının tamamı yeniden gönderilir; gönderilmeyen isteğe bağlı ve ek alanlar silinir. Gövdede slug yazılmayabilir (adresteki kullanılır). Yayındaki yazı yeniden taslağa döner; yayın kararı yeniden verilir. Oluşturulma tarihi korunur, sürüm artar.

İstek
curl -X PUT "https://www.birseyleryapiyoruz.com/api/articles/yapay-zekayla-ilk-urunu-cikarmak" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -H "X-Expected-Version: 3" \
  -d @yazi.json

Olası hatalar: 404 · 412 VERSION_CONFLICT · 422 SLUG_IMMUTABLE · 422 VALIDATION_FAILED

PATCH/api/articles/{slug}yazma yetkisi

Kısmi düzenle, yayına al, taslağa çek

Yalnız gönderdiğin alanlar değişir. İçerik değişirse yazının son hali baştan denetlenir.

GövdeSonuç
{ "yazar": "Ad Soyad" }Yalnız yazar değişir.
{ "ikon": null, "kaynakUrl": null }İsteğe bağlı alan ve ek alan silinir (ikon varsayılana döner).
{ "taslak": false }Yayına alır; içerik yeniden denetlenmez.
{ "taslak": true }Taslağa çeker; yazı siteden hemen kalkar.
{ "kategori": "Vizyon", "ikon": "grafik" }Kategori ve ikon birlikte değişir.
Yayına al
curl -X PATCH "https://www.birseyleryapiyoruz.com/api/articles/yapay-zekayla-ilk-urunu-cikarmak" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"taslak": false}'

Olası hatalar: 404 · 412 · 422 SLUG_IMMUTABLE · 422 MISSING_FIELD (zorunlu alana null) · 422 VALIDATION_FAILED

DELETE/api/articles/{slug}yazma yetkisi

Sil

Yazı siteden hemen kalkar. Bir kopyası arşivde saklanır; API ile geri getirilmez, gerekirse arşivden elle geri alınır.

İstek
curl -X DELETE "https://www.birseyleryapiyoruz.com/api/articles/yapay-zekayla-ilk-urunu-cikarmak" -H "Authorization: Bearer $API_KEY"
200 OK
{ "ok": true, "data": { "slug": "yapay-zekayla-ilk-urunu-cikarmak", "silindi": true } }

Olası hatalar: 404 · 412

08

Sürüm kontrolü

İki yazılımın birbirinin değişikliğini ezmemesi için. İsteğe bağlı ama önerilir.

  1. Yazıyı okurken yanıttaki X-Version başlığını (ya da gövdedeki surum) sakla.
  2. PUT, PATCH ya da DELETE’te X-Expected-Version olarak geri gönder.
  3. Yazı bu arada değiştiyse işlem yapılmaz: 412 VERSION_CONFLICT. Güncel hali okuyup yeniden dene.
PATCH /api/articles/yapay-zekayla-ilk-urunu-cikarmak
X-Expected-Version: 3

Standart If-Match başlığını gönderme: barındırma altyapısı onu kendisi yorumlayıp başarılı yanıtı bozuyor.

09

Hata kodları

Doğrulama hataları tek seferde, alan alan gelir; ilk hatada durulmaz.

422 Unprocessable Entity
{
  "ok": false,
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "Yazı 3 nedenle kaydedilmedi.",
    "fields": [
      { "field": "ozet", "code": "SUMMARY_LENGTH", "message": "Özet 120–200 karakter olmalı (şu an 96).", "expected": "120–200", "received": 96 },
      { "field": "ikon", "code": "ICON_INVALID", "message": "\"roket\" Değişim ikonu değil.", "received": "roket", "allowed": ["pusula", "dongu", "yol-ayrimi", "cip", "parilti"] },
      { "field": "bolumler[1].icerik", "code": "MARKDOWN_FORBIDDEN", "message": "# ve ## başlık kullanılamaz… (satır 3)" }
    ]
  }
}

HTTP durumları

HTTPerror.codeNe zaman
400INVALID_JSONGövde geçerli bir JSON değil.
400INVALID_QUERYListe parametresi hatalı; ayrıntı fields içinde.
401UNAUTHORIZEDAuthorization: Bearer … başlığı yok.
403FORBIDDENAnahtar geçersiz, iptal edilmiş ya da yalnız okuma yetkili.
404NOT_FOUNDBu slug'da yazı yok.
409SLUG_TAKENPOST: aynı slug'da yazı zaten var.
412VERSION_CONFLICTX-Expected-Version, yazının güncel sürümüyle eşleşmiyor.
413PAYLOAD_TOO_LARGEGövde 256 KB'tan büyük.
415UNSUPPORTED_MEDIA_TYPEContent-Type: application/json değil.
422VALIDATION_FAILEDYazı kurallara uymuyor; her neden fields içinde.
422SLUG_IMMUTABLESlug değiştirilmeye çalışıldı.
500INTERNAL_ERRORBizim hatamız; yanıttaki requestId ile bildir.

Alan hataları · fields[].code

KodNe zaman
MISSING_FIELDZorunlu alan yok ya da boş.
INVALID_TYPEAlan beklenen türde değil (expected).
UNKNOWN_FIELDBölümde baslik ve icerik dışında alan var.
SLUG_INVALIDSlug yalnız a-z, 0-9 ve tire içerebilir; en çok 60 karakter; ayrılmış adres olamaz.
TITLE_LENGTHBaşlık 25–60 karakter değil.
SUMMARY_LENGTHÖzet 120–200 karakter değil.
AUTHOR_LENGTHYazar 60 karakterden uzun.
DATE_INVALIDTarih YYYY-AA-GG değil ya da gerçek bir gün değil (2026-02-30).
CATEGORY_INVALIDBeş kategoriden biri değil (allowed).
ICON_INVALIDİkon yazının kategorisine ait değil (allowed).
SECTION_COUNTBölüm sayısı 3–6 değil.
SECTION_TITLE_LENGTHBölüm başlığı 2–6 kelime / en çok 60 karakter değil.
CONTENT_EMPTYBölüm metni boş.
WORD_COUNTYazı 600–1200 kelime değil (Markdown işaretleri sayılmaz).
MARKDOWN_FORBIDDENYasak biçim: # / ## / #### başlık, HTML, görsel, tablo, kod bloğu ya da http(s) olmayan bağlantı. Satır numarasıyla.
QUOTE_LIMIT2'den fazla alıntı (>).
RESERVED_FIELDGönderilemeyen alan: taslak, _id, olusturuldu, guncellendi, kaynak, surum, arama, bolum, alan, icerik, tur.
EXTRA_FIELD_INVALIDEk alanın adı, sayısı, boyutu ya da iç içeliği kurala uymuyor.
SLUG_IMMUTABLEPATCH / PUT ile slug değiştirilemez.

field boşsa hata yazının bütünüyle ilgilidir (kelime sayısı, alıntı sayısı). Konum bolumler[1].icerik biçimindedir.

10

Örnek akış

Üretici yazılımın bir yazıyı yayına kadar götürmesi.

  1. POST /validate — kurallardan geçiyor mu? Geçmiyorsa fields’a göre yeniden üret.
  2. POST /api/articles — taslak olarak ekle.
  3. GET /api/articles?status=draft — editör taslakları görür, okur.
  4. PATCH { "taslak": false } — onaylanan yazı yayına çıkar, sitede hemen görünür.
  5. PUT Yeniden üretilen sürüm — yazı yeniden taslağa döner.
  6. DELETE Gerekmeyen yazı kalkar; kopyası arşivde durur.
Uçtan uca test (bütün uç noktalar, 127 kontrol)
API_KEY=bsy_… npm run api:test