İçeriğe geç
codebiy
← Yazı masasına dön

TikTok onayladı, herkese açık gönderi gitmedi: Direct Post audit'i

TikTok, uygulamamızı onayladı ama herkese açık her gönderi unaudited_client hatasıyla döndü. İkinci bir onay gerekiyordu: Direct Post audit'i. Bu denetim yalnızca isteklere değil, kullanıcının gördüğü ekrana da bakıyor.

Spoolt bir web sitesinden kısa videolar üretiyor ve bunları TikTok'ta yayımlanmak üzere planlıyor. TikTok'un v2 API'sini SDK kullanmadan, kendi yazdığımız küçük bir istemciyle çağırıyoruz: hesap bağlamak için Login Kit, yayımlamak için Content Posting API'deki Direct Post. 24 Ağustos 2026'da uygulamamız TikTok'un incelemesinden geçip yayına girdi. Herkese açık gönderilerin hepsi yine de unaudited_client_can_only_post_to_private_accounts hatasıyla döndü.

Sebep, hiç başvurmadığımız ikinci bir onaydı: Direct Post audit'i. O günün bir kısmını, bir not yüzünden bekleyerek kaybettik. Aynı akşam başvurduk, dokuz gün sonra onay aldık. O zamana kadar Spoolt yalnızca gizli hesaplarda paylaşım yapabildi. Bu denetim entegrasyondan çok ürünü değiştirdi: planlama ekranında dört değişiklik, sunucuda da uyguladığımız bir kural ve bitmişken geri çektiğimiz bir özellik.

Yanlış teşhis: yansıma gecikmesi

Hata bizi şaşırtmadı, çünkü elimizde hazır bir açıklama vardı. Önceki bir çalışma oturumunun notunda, geriye kalan hipotez olarak yansıma gecikmesi yazıyordu: birkaç saat sonra tekrar denenecekti. Birlikte çalıştığımız yapay zekâ agent'ı bu notu devraldı ve üç tur boyunca bulguymuş gibi taşıdı.

Döngüyü, işi yöneten insan kırdı: TikTok onayladığına göre hata bizde olabilirdi. Ondan sonra doğru teşhis on dakikada çıktı. Bu API için TikTok'tan iki ayrı onay almamız gerekiyordu ve bizde yalnızca biri vardı.

İkisi de TikTok'un kendi sayfalarında yazıyor (Ekim 2026'daki hâlleriyle). TikTok'un Direct Post başlangıç rehberinde, ön koşullar arasında uygulamanın video.publish scope'u için onaylanmış olması var. Aynı yerde, denetlenmemiş bir istemcinin paylaştığı içeriğin, istemci denetimden geçene kadar gizli kalacağı da yazıyor.

Direct Post referansında ise bizim hata kodumuz video/init çağrısının 403 yanıtları arasında geçiyor: denetlenmemiş istemciler yalnızca gizli bir hesapta paylaşım yapabilir (“Unaudited clients can only post to a private account.”).

Not bize günlere değil, saatlere mal oldu: onay, başarısız gönderiler, doğru teşhis, düzeltme ve denetim başvurusu, hepsi 24 Ağustos 2026'da. O saatlerin ne kadarını notun götürdüğünü kaydetmedik.

Bu işten iki kural çıktı:

  • Nota yazılmış bir hipotezi, biri doğrulayana kadar doğrulanmamış sayın. En çok da “bekle, kendi kendine düzelir” türünde olanı: onu hiçbir şey yanlışlamaz, o yüzden günlerce yaşar.
  • Sağlayıcı “onaylandı” dediği hâlde yetki hatası sürüyorsa önce sağlayıcının izin modelini okuyun: kaç ayrı onay var, hangisi neyi açıyor? Destek talebi en son çare.

TikTok'un iki onayı: uygulama incelemesi ve Direct Post audit'i

İlki uygulama incelemesi. Scope'ları o veriyor, bize de video.publish scope'unu verdi. Bu incelemeye daha önce de başvurmuş, reddedilmiştik: kurum sitesi olarak girdiğimiz adres tanıtım sitesini değil, uygulamanın oturum açma sayfasını açıyordu.

İkincisi Direct Post audit'i, yani Content Posting API altında ayrı bir başvuru. Biz “onaylandı” sözünün ikisini de kapsadığını sanmıştık.

İllüstrasyon: yolda art arda iki bariyer var, ilki açık, kırmızı kollu ikincisi kapalı, aralarında küçük, yuvarlak bir kutu bekliyor. Uygulama incelemesinden geçtik ama herkese açık gönderiler Direct Post audit'ine takıldı.

Denetim başka türden bir inceleme. Başvuru formunda destekleyici belge isteniyor. Biz bütün akışın ekran kaydını hazırladık: bağlı hesaptan, profilde yayımlanmış videoya kadar. TikTok'un içerik paylaşım yönergelerinde “Required UX Implementation in Your App” (uygulamanızda zorunlu arayüz) başlıklı bir bölüm var. Başvuruda, sunucunun gönderdiği istekler kadar kullanıcının gördüğü arayüze de bakılıyor.

TikTok yönergelerinin planlama ekranından istedikleri

Planlama ekranının (kodumuzdaki adıyla composer) bir kısmı yönergelere zaten uyuyordu. Seçenek paneli canlı creator_info yanıtına göre kuruluyordu. Aynı sorguyu her yayından önce yeniden yapıyoruz. Görünürlük menüsünde önceden seçili bir değer yoktu. Yorum, düet ve stitch işaretsiz başlıyor, içerik üreticisinin kendi ayarları izin vermiyorsa devre dışı kalıyordu. Ticari içerik beyanı da varsayılan olarak kapalıydı.

Dört gereklilikte ise eksiğimiz vardı. Başvurmadan önce hepsini tek değişiklikte kapattık:

  1. Markalı içerik gizli olamaz. Markalı içerik açıkken “gizli” seçeneği devre dışı kalıyor ve nedeni gösteriliyor. Kullanıcı daha önce gizliyi seçmişse seçimi temizliyoruz. Fark ettirmeden herkese açığa çevirmek yerine yeniden seçtiriyoruz.
  2. “Kendi markan” seçeneğinin ayrı etiketi var. Artık “Tanıtım içeriği” ifadesini gösteriyor. Markalı içerikte “Ücretli iş birliği” kalıyor.
  3. Beyan açıksa tür seçilmiş olmalı. İki türden biri seçilene kadar “Planla” düğmesi devre dışı kalıyor.
  4. Son kontrol adımı videoyu gösteriyor. Eskiden bu adımda yalnızca taslağın başlığı vardı. Şimdi videonun kendi küçük resmi var, böylece kullanıcı onay vermeden önce içeriği görüyor.

İlk kuralı sunucuda da uyguluyoruz, her planlama isteğinin geçtiği şemada:

  // Branded content may not be private. The composer already disables the
  // option, but the client isn't the trust boundary — and TikTok rejects the
  // combination at publish time, which would surface as a failed post hours
  // after the user walked away.
  .refine(
    (v) => !(v.brandContentToggle && v.privacyLevel === "SELF_ONLY"),
    "Branded content visibility cannot be set to private",
  );

Model çıktısına da aynı gözle bakıyoruz: prompt rica eder, kod uygular. Bunu kodda uyguladığımız üç LLM kuralı yazısında anlattık.

Denetim başvurusunu 24 Ağustos 2026'da yaptık. Portalda iki ila dört hafta yazıyordu. Onay 2 Eylül'de, dokuz gün sonra geldi.

Diğer TikTok API ayrıntıları: PKCE, scope'lar, sınırlar, dosya çekme

TikTok hex kodlanmış code_challenge bekliyor. 12 Ağustos 2026'da TikTok, içinde code_challenge olmayan yetkilendirme isteğimizi reddetti. TikTok'un web için Login Kit sayfasında PKCE parametresi yok (Ekim 2026). Masaüstü için Login Kit sayfasında var: verifier'ın SHA-256'sı hex kodlanmış olarak isteniyor. RFC 7636'nın 4.2. bölümü ise S256 challenge'ını base64url olarak tanımlıyor, standart bir PKCE kütüphanesi de onu üretir. Değeri bu yüzden elle kuruyoruz:

    code_challenge: createHash("sha256").update(codeVerifier).digest("hex"),
    code_challenge_method: "S256",

Onaylanmamış tek bir scope yüzünden kimse hesabını bağlayamadı. Yayındaki uygulama sürümüne tanınmamış bir scope istediğimizde TikTok, yetkilendirme sayfasının tamamını reddetti. video.list'i 24 Ağustos'ta istekten çıkardık, 2 Eylül'deki onaydan sonra geri koyduk.

Sınırlar, planlayıcının ve yayımlayıcının ortak kullandığı sabitlerde duruyor. Onaydan sonra TikTok'un sınırlarını, kendi bıraktığımız payların yanına yazdık:

Kural TikTok'un sınırı Bizimki
Bir hesapta, 24 saatlik herhangi bir aralıktaki gönderi sayısı İçerik üreticisine göre değişiyor, genelde 15 civarı, bütün API istemcileri arasında ortak 15
Aynı hesapta iki gönderi arasındaki süre Bağlantısını verdiğimiz sayfalarda yok 5 dakika
Bir hesap için video/init isteği sayısı Kullanıcı access token'ı başına dakikada 6 Dakikada bir çalışan yayın işinde, her seferinde 3 yayın

İlk iki kuraldan birini çiğneyecek bir yayın saati, vakti gelince değil, kullanıcı planlarken reddediliyor.

Dosyayı TikTok kendisi çekiyor. PULL_FROM_URL ile yayımlıyoruz, yani TikTok videoyu bizim medya adresimizden indiriyor. O adresin alan adını geliştirici portalında doğrulamamız gerekti. Herkese açık medya izin listemizde tek bir yol ön eki eksik kalınca, içe aktarılan klipler için gelen istekler 404 döndü ve TikTok onları video_pull_failed ile reddetti.

Doğrulanmayan gönderiler: “yayında olabilir” için ayrı bir durum

En çok önlemek istediğimiz hata, aynı videoyu iki kez paylaşmaktı. 2 Eylül 2026'dan beri TikTok'un init çağrısından döndürdüğü publish_id'yi veritabanına hemen ve ayrı bir sorguyla yazıyoruz. Ondan önce, aynı adımda sonradan fırlatılan bir hata taslağın geri alınmasına yol açabiliyordu. Geri alınmış bir taslağı da kullanıcı yeniden planlamaya kalkar.

Başarısız bir init her zaman ret demek değil:

/**
 * Only a 4xx answer (429 included) proves TikTok did NOT create the post. A
 * network error, timeout, 5xx/gateway error, or a 200 whose body we couldn't
 * read may all arrive after TikTok accepted the init.
 */
export function initRejected(err: unknown): boolean {
  return err instanceof TikTokError && err.status >= 400 && err.status < 500;
}

Bu yüzden init çağrısını yalnızca 429'da yeniden deniyoruz, çünkü 429'u videonun kabul edilmediğinin kanıtı sayıyoruz. TikTok'un referansında 5xx için sonra tekrar denenmesi söyleniyor (“Try again later”). Biz bu çağrıda denemiyoruz, çünkü isteği yeniden göndermek ikinci bir gönderi oluşturabilir.

Açık bir ret olmayan her sonuç için 22 Eylül 2026'dan beri ayrı bir durum var. Gönderi “doğrulanmadı” işaretiyle başarısız olarak kaydediliyor, taslak planlı kalıyor ve kullanıcıya olağan hata e-postasından farklı bir e-posta gidiyor. Takvimde iki seçenek çıkıyor: “TikTok’u kontrol et” ve “Takvimden kaldır”. Yeniden planlama yok. Gönderi kaldırılınca taslak geri geliyor ama gönderi, kullanıcının planındaki aylık haktan düşülmüş kalıyor, çünkü TikTok'un onu yayımlayıp yayımlamadığını bilemiyoruz.

Bir çökmeden on beş dakika sonra hâlâ posting durumunda bulduğumuz gönderi de aynı işlemi görüyor.

Onaylanan akışın dışında kalan: otomatik yayın

TikTok tek bir akışı onayladı: kullanıcı planlama ekranını açar, bu gönderi için görünürlüğü, etkileşimi ve beyanı seçer, videoyu görür ve onaylar. Yönergelerde ilke tek cümleyle yazıyor: API istemcilerinin kullanıcıları, TikTok hesaplarında ne paylaşıldığını tam olarak bilmeli, kontrol de onlarda olmalı (“The users of API Clients must have full awareness and control of what is being posted to their TikTok accounts.”).

En belirgin kayıp otomasyon. Ağustos 2026'da seriler (belirli aralıklarla taslak üreten tekrarlı işler) kendi videosunu render edip planlayabilir hâle gelmişti. Eylülde planlama kısmını geri çektik: bunu isteyen bir seri reddediliyor. Seri hâlâ taslak ve video üretiyor. Sonra her biri, bir insanın onu inceleyip ayarlarını takvimde seçmesini bekliyor.

Kural agent'lar için de geçerli. Bir agent, Spoolt'un takvimini MCP üzerinden yönetebiliyor ve planlama aracı TikTok ayarlarını zorunlu tutuyor. Aracın açıklamasında agent'a ayarları kendisinin doldurmaması, kullanıcıya sorması söyleniyor. Bu kodda çalışan her agent oturumunun başta okuduğu talimatlara da bir satır yazdık: otomatik yayın kapalı kalır ve kimse bunu “düzeltmemeli”.

Bir dahaki sefere baştan yapacaklarımız

  • Entegrasyonu yazmadan önce platformun istediği onayları ve her birinin neyi açtığını listeleyin. Hata kodunu belirti saymadan önce, içindeki adı olduğu gibi okuyun.
  • Planlama ekranını ilk sürümden itibaren platformun canlı ayarlarına göre kurun. Denetime gönderilen ekran kaydında görünen şey arayüzdür.
  • Her platform kuralını formun yanı sıra sunucunun şemasına da koyun.
  • “Sonucu bilinmiyor” için ayrı bir durum tanımlayın. Bu durumdayken otomatik iade ya da yeniden planlama yapmayın.
  • Onayın üründe bir kısıt olarak kalacağını hesaba katın. Biz bu yüzden, bitirdiğimiz bir özelliği geri çektik.
OKUMAYA DEVAM ETMac'te çevrimdışı Pro lisansı: hesap yok, lisans sunucusu yok ↗App Store Connect salesReports, rapor saati gelmeden “satış yok” dedi ↗