Makroskop'un API merkezi. Bu sayfa hem doküman hem test arayüzü: her servisi buradan, gerçek sunucuya karşı deneyebilirsin. Mesajlar WebSocket (Phoenix Channels) üzerinden akar; geri kalan her şey REST.
Postman'a aktar
Postman > Import ile dosyayı içe aktar; access_token değişkenini doldurman yeterli.
Base URL
https://mskop-api.gurerlabs.com
Sistem durumu
Kontrol ediliyor…
60 dk
Access token imzalı · opak
90 gün
Refresh token tek kullanımlık
UUID
Kimlikler oda: slug
Hızlı başlangıç
# 1) Uygulama GlobalTrustID'den (OIDC + PKCE) aldığı kodu token'a çevirir
curl -X POST https://mskop-api.gurerlabs.com/api/auth/globaltrustid \
-H "Content-Type: application/json" \
-d '{"code": "GTID_KODU", "code_verifier": "PKCE_VERIFIER", "redirect_uri": "REDIRECT_URI"}'
# 2) Dönen access_token ile istek at
curl https://mskop-api.gurerlabs.com/api/me -H "Authorization: Bearer $ACCESS_TOKEN"
# 3) 401 token_expired gelince yenile (eski refresh token o an biter)
curl -X POST https://mskop-api.gurerlabs.com/api/auth/refresh \
-H "Content-Type: application/json" \
-d '{"refresh_token": "REFRESH_TOKEN"}'
Kimlik doğrulama
Korunan servisler Authorization: Bearer <access_token> başlığı ister. Giriş yalnızca GlobalTrustID ile yapılır; parola yoktur. Access token 1 saat yaşar, süresi dolunca refresh token ile yeni bir çift alınır.
1Giriş
Uygulama GlobalTrustID'ye karşı OIDC authorization code + PKCE akışını yürütür, dönen kodu POST /api/auth/globaltrustid'ye yollar; access + refresh token döner.
2Rumuz
İlk girişte account.username boştur. PUT /api/me/username ile seçilene kadar odalar ve socket 403 username_required döner.
3Yenileme
401 token_expired gelince POST /api/auth/refresh ile yeni çift alınır; eski refresh token o an biter.
4Çıkış
POST /api/auth/logout oturumu kapatır ve o cihaza push gönderimini durdurur.
🔐 Kimlik
Backend GlobalTrustID'den gelen kimliği saklamaz; hesabı yalnızca tek yönlü bir parmak iziyle bulur. Aynı kişi her cihazda aynı hesaba düşer: ilk giriş 201, sonrakiler 200 döner.
📱 Token saklama
Refresh token yanıt gövdesinde döner ve 90 gün geçerlidir; Keychain / Keystore gibi güvenli depoda saklanmalı. Her kullanımda yenisiyle değişir, eskisi tekrar kullanılamaz.
Hatalar
Tüm hatalar aynı biçimde döner. İstemci mantığı her zaman code alanına bakmalı; message insan için yazılmıştır ve değişebilir. fields yalnızca 422 validation_failed yanıtında bulunur. Her yanıtta x-request-id başlığı vardır; destek isterken bunu ilet.
{"error":{"code":"validation_failed","fields":{"slug":["lowercase letters, digits and '-' only"]},"message":"Some fields are invalid."}}
code
HTTP
Anlamı
invalid_request
400
Eksik ya da geçersiz parametre
unauthorized
401
Authorization başlığı yok ya da geçersiz
token_expired
401
Access token'ın süresi dolmuş: /api/auth/refresh çağır
invalid_refresh_token
401
Refresh token geçersiz ya da kullanılmış; tekrar giriş gerekir
star_required
402
Oda yıldızla açılıyor
insufficient_stars
402
Yıldız bakiyesi yetmiyor
username_required
403
Önce rumuz seçilmeli (PUT /api/me/username)
not_member
403
Odanın üyesi değilsin
not_admin
403
Bu işlem odanın yöneticisine ait
not_allowed
403
Gereken oda yetkisi yok
banned
403
Bu odadan engellendin
dm_closed
403
Kişi birebir mesaja kapalı
not_found
404
Kayıt ya da yol yok
room_not_found
404
Oda yok
founder_protected
409
Kurucuya bu işlem uygulanamaz
validation_failed
422
Alanlar geçersiz; ayrıntı fields içinde
rate_limited
429
Hız sınırı aşıldı; biraz bekleyip tekrar dene
gtid_unavailable
502
GlobalTrustID'ye ulaşılamadı
internal_error
500
Beklenmeyen hata; x-request-id ile bildir
Rate limit
Limitler sabit pencereyle uygulanır ve aşılınca 429 rate_limited döner. Yanıtlarda X-RateLimit-* ya da Retry-After başlığı yoktur; 429 alan istemci birkaç saniye bekleyip tekrar denemelidir.
/api/auth/*
IP başına dakikada 20 istek
GET /api/link-preview
Hesap başına dakikada 60 istek (önbellekten dönenler de sayılır)
POST /api/analytics/events
Hesap başına dakikada 30 paket
socket · message:new
Hesap başına 10 saniyede 20 mesaj; gövde en fazla 16 KB
socket · komutlar
Hesap + oda + komut başına dakikada 5 (/mute, /ban…)
PATCH /api/panel/organization
Slug değişikliği: organizasyon başına günde 10
Sağlık ve genel
GET/api/health
Servis durumu
Veritabanı (Postgres), Redis ve dosya deposunun (MinIO) durumunu döner. Postgres ya da Redis cevap vermezse 503 ve status: "degraded" döner; MinIO raporlanır ama tek başına hataya yol açmaz (sohbet medyasız da çalışır). Rate limit uygulanmaz; izleme ve yük dengeleyiciler için uygundur.
Yanıtlar
200Postgres ve Redis çalışıyor
503Postgres ya da Redis çalışmıyor (status: "degraded")
curl https://mskop-api.gurerlabs.com/api/health
const res = await fetch("https://mskop-api.gurerlabs.com/api/health", {
method: "GET",
});
const data = await res.json();
const res = await fetch("https://mskop-api.gurerlabs.com/api/usernames/available?username=osman", {
method: "GET",
});
const data = await res.json();
{"available":true,"username":"osman"}
Dene
Kimlik doğrulama
Bu gruptaki tüm servisler IP başına dakikada 20 istekle sınırlıdır ve token istemez.
POST/api/auth/globaltrustid
⏱ IP başına 20/dk
GlobalTrustID ile giriş
Uygulama GlobalTrustID'ye karşı OIDC authorization code + PKCE akışını kendisi yürütür (scope=openid profile) ve dönen kodu buraya yollar. Backend kodu kendi client secret'ı ile token'a çevirir, id_token'ı GlobalTrustID'nin JWKS'i ile doğrular (imza, iss, aud, exp). Hesap yoksa açılır (201), varsa aynı hesaba girilir (200).
›Kimlikten yalnızca birthdate ve gender saklanır; başka hiçbir claim tutulmaz.
›İlk girişte account.usernamenull gelir: uygulama rumuz seçme ekranına gitmeli.
Parametreler
codestringbodyzorunlu
GlobalTrustID'nin döndürdüğü authorization code
redirect_uristringbodyzorunlu
Akışta kullanılan redirect URI; GlobalTrustID'de kayıtlı olanla aynı olmalı
code_verifierstringbodyzorunlu
PKCE doğrulayıcısı
noncestringbodyisteğe bağlı
Akışta nonce gönderildiyse aynısı
Yanıtlar
201Yeni hesap açıldı; token çifti + account
200Var olan hesaba girildi; token çifti + account
400code ya da redirect_uri yok (invalid_request)
401Kod reddedildi (gtid_rejected) ya da id_token doğrulanamadı (invalid_id_token)
Refresh token ile yeni bir access + refresh çifti alır. Refresh token tek kullanımlıktır: bu çağrıdan sonra eskisi çalışmaz, yanıttaki yenisi saklanmalı. Yanıtta account yoktur.
Parametreler
refresh_tokenstringbodyzorunlu
Girişte ya da son yenilemede dönen refresh token
Yanıtlar
200Yeni token çifti
400refresh_token yok (invalid_request)
401Geçersiz, süresi dolmuş ya da kullanılmış (invalid_refresh_token): tekrar giriş gerekir
Refresh token'ın ait olduğu oturumu kapatır ve o cihaza push gönderimini durdurur. Bilinmeyen ya da zaten kapanmış bir token için de 204 döner; yanıt token'ın varlığını sızdırmaz.
Giriş yapmış kişinin kendi hesabı. Bu gruptaki servisler yalnız geçerli bir access token ister; rumuz seçilmemiş hesap da çağırabilir, çünkü rumuz seçme ekranı (onboarding) bunlarla çalışır. Hesap döndüren her uç (GET /api/me, rumuz ve profil güncellemesi) aynı tam nesneyi verir; istemcinin kısa bir yanıtı elindekiyle birleştirmesi gerekmez.
GET/api/me
🔒 Bearer token
Kendi hesabım
Token sahibinin hesabını; birincil profil fotoğrafı (avatar), takip sayıları (follows) ve yıldız bakiyesi (stars) ile birlikte döner. Uygulama açılışta ve girişten sonra çağırır; usernamenull ise rumuz seçme ekranına gidilmelidir.
›birth_date (YYYY-MM-DD) ve gender GlobalTrustID'nin doğruladığı değerlerdir ve yalnız burada döner; başkasının profil kartında hiçbir zaman yer almaz.
›created_at ve avatar.created_at ISO-8601 metindir. avatar.url ve avatar.thumb_url 1 saat geçerli presigned linklerdir.
Yanıtlar
200{account}
401Token yok ya da geçersiz (unauthorized) veya süresi dolmuş (token_expired)
{"account":{"account_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","avatar":{"byte_size":118432,"content_type":"image/jpeg","created_at":"2026-09-24T11:05:43.201544Z","id":"3f2a9c1e-7b44-4e0a-9d61-5c8e2b7a1f03","is_primary":true,"size_px":1024,"thumb_url":"https://mskop-api.gurerlabs.com/makroskop-media/avatars/f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21/a81c5e27-0f93-4b6d-8e2a-7c4f1b9d3e60-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026X-Amz-Date=20261014T091500Z\u0026X-Amz-Expires=3600\u0026X-Amz-SignedHeaders=host\u0026X-Amz-Signature=5d0c8e2a91b47f3c6e1d0a9b8c7f6e5d4c3b2a1908f7e6d5c4b3a29180f7e6d5","url":"https://mskop-api.gurerlabs.com/makroskop-media/avatars/f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21/a81c5e27-0f93-4b6d-8e2a-7c4f1b9d3e60.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026X-Amz-Date=20261014T091500Z\u0026X-Amz-Expires=3600\u0026X-Amz-SignedHeaders=host\u0026X-Amz-Signature=5d0c8e2a91b47f3c6e1d0a9b8c7f6e5d4c3b2a1908f7e6d5c4b3a29180f7e6d5"},"bio":"Fenerbahçe, kahve ve uzun yürüyüşler.","birth_date":"1990-04-12","created_at":"2026-09-22T09:02:35.300000Z","dm_policy":"open","dm_star_cost":0,"follows":{"followers":12,"following":8},"gender":"male","hidden_profile":false,"personalized_ads":true,"photo_visibility":"everyone","premium":false,"stars":40,"username":"osman"}}
DeneÖnce token gir: otomatik eklenir
PUT/api/me/username
🔒 Bearer token
Rumuz seç ya da değiştir
Onboarding'in son adımı; rumuz sonradan da değiştirilebilir. Değer kırpılır (trim), büyük/küçük harf duyarsız olarak tekil olmalıdır. Rumuz seçilene kadar odalar, kişiler, yüklemeler ve socket bağlantısı 403 username_required döner; seçildiği an aynı token ile hepsi açılır.
›Yazarken anlık kontrol için GET /api/usernames/available kullanın; kesin karar bu çağrının yanıtıdır (iki kişi aynı anda aynı rumuzu deneyebilir).
›makroskop ayrılmış bir addır ve her yazımı is taken hatası verir.
Parametreler
usernamestringbodyzorunlu
3–24 karakter: harf (Türkçe dahil), rakam, _ ya da . (^[\p{L}\p{N}_.]{3,24}$)
Yanıtlar
200Rumuz kaydedildi; GET /api/me ile aynı {account}
400username yok ya da metin değil (invalid_request)
401Token yok ya da geçersiz (unauthorized) veya süresi dolmuş (token_expired)
422validation_failed: fields.username biçim hatası için "3-24 characters: letters, digits, '_' or '.'", alınmış ya da ayrılmış ad için "is taken"
{"account":{"account_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","avatar":{"byte_size":118432,"content_type":"image/jpeg","created_at":"2026-09-24T11:05:43.201544Z","id":"3f2a9c1e-7b44-4e0a-9d61-5c8e2b7a1f03","is_primary":true,"size_px":1024,"thumb_url":"https://mskop-api.gurerlabs.com/makroskop-media/avatars/f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21/a81c5e27-0f93-4b6d-8e2a-7c4f1b9d3e60-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026X-Amz-Date=20261014T091500Z\u0026X-Amz-Expires=3600\u0026X-Amz-SignedHeaders=host\u0026X-Amz-Signature=5d0c8e2a91b47f3c6e1d0a9b8c7f6e5d4c3b2a1908f7e6d5c4b3a29180f7e6d5","url":"https://mskop-api.gurerlabs.com/makroskop-media/avatars/f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21/a81c5e27-0f93-4b6d-8e2a-7c4f1b9d3e60.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026X-Amz-Date=20261014T091500Z\u0026X-Amz-Expires=3600\u0026X-Amz-SignedHeaders=host\u0026X-Amz-Signature=5d0c8e2a91b47f3c6e1d0a9b8c7f6e5d4c3b2a1908f7e6d5c4b3a29180f7e6d5"},"bio":"Fenerbahçe, kahve ve uzun yürüyüşler.","birth_date":"1990-04-12","created_at":"2026-09-22T09:02:35.300000Z","dm_policy":"open","dm_star_cost":0,"follows":{"followers":12,"following":8},"gender":"male","hidden_profile":false,"personalized_ads":true,"photo_visibility":"everyone","premium":false,"stars":40,"username":"osman"}}
DeneÖnce token gir: otomatik eklenir
PUT/api/me/profile
🔒 Bearer token
Profil ve gizlilik ayarları
Profilin kişiye ait kısmını günceller: biyografi, kimin birebir yazabileceği, fotoğrafı kimin göreceği ve ilgi alanına göre sponsorlu içerik. Bütün alanlar isteğe bağlıdır; gönderilmeyen alan olduğu gibi kalır. Yanıt GET /api/me ile aynı tam hesaptır.
›personalized_adsfalse yapıldığı anda ilgi profili silinir, davranış olayları artık saklanmaz ve yalnız hedefsiz sponsorlu içerik gösterilir.
›dm_policy ve dm_star_cost yalnız yeni açılacak birebir sohbetleri etkiler; var olan sohbete dönmek her zaman serbest ve ücretsizdir.
›hidden_profile saklanır ama bugün hiçbir şeyi gizlemez (kullanıcı araması ucu henüz yok); arama geldiğinde ilk kuralı bu olacak.
Parametreler
biostringbodyisteğe bağlı
Profil yazısı; kırpıldıktan sonra en çok 200 karakter. null siler
dm_policystringbodyisteğe bağlı
Kim birebir sohbet açabilir: open (herkes) · closed (kimse) · paid (dm_star_cost yıldız karşılığında)
dm_star_costintegerbodyisteğe bağlı
Birebir sohbet açmanın yıldız bedeli, 0–100000. dm_policypaid ise 0'dan büyük olmalı
photo_visibilitystringbodyisteğe bağlı
Fotoğrafı kim görür: everyone (herkes) · followers (taraflardan biri diğerini takip ediyorsa) · nobody (yalnız kendisi)
hidden_profilebooleanbodyisteğe bağlı
Aramalarda görünmeme tercihi (henüz etkisi yok)
personalized_adsbooleanbodyisteğe bağlı
İlgi alanlarına göre sponsorlu içerik. null gönderilemez
Yanıtlar
200Kaydedildi; GET /api/me ile aynı {account}
401Token yok ya da geçersiz (unauthorized) veya süresi dolmuş (token_expired)
422validation_failed: geçersiz değer, 200 karakteri aşan bio, paid iken 0 olan dm_star_cost ("must be more than 0 stars") ya da nullpersonalized_ads
curl -X PUT https://mskop-api.gurerlabs.com/api/me/profile \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"bio":"Fenerbahçe, kahve ve uzun yürüyüşler.","dm_policy":"paid","dm_star_cost":5,"photo_visibility":"followers"}'
const res = await fetch("https://mskop-api.gurerlabs.com/api/me/profile", {
method: "PUT",
headers: {
"Authorization": "Bearer " + accessToken,
"Content-Type": "application/json",
},
body: JSON.stringify({"bio":"Fenerbahçe, kahve ve uzun yürüyüşler.","dm_policy":"paid","dm_star_cost":5,"photo_visibility":"followers"}),
});
const data = await res.json();
{"account":{"account_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","avatar":{"byte_size":118432,"content_type":"image/jpeg","created_at":"2026-09-24T11:05:43.201544Z","id":"3f2a9c1e-7b44-4e0a-9d61-5c8e2b7a1f03","is_primary":true,"size_px":1024,"thumb_url":"https://mskop-api.gurerlabs.com/makroskop-media/avatars/f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21/a81c5e27-0f93-4b6d-8e2a-7c4f1b9d3e60-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026X-Amz-Date=20261014T091500Z\u0026X-Amz-Expires=3600\u0026X-Amz-SignedHeaders=host\u0026X-Amz-Signature=5d0c8e2a91b47f3c6e1d0a9b8c7f6e5d4c3b2a1908f7e6d5c4b3a29180f7e6d5","url":"https://mskop-api.gurerlabs.com/makroskop-media/avatars/f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21/a81c5e27-0f93-4b6d-8e2a-7c4f1b9d3e60.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026X-Amz-Date=20261014T091500Z\u0026X-Amz-Expires=3600\u0026X-Amz-SignedHeaders=host\u0026X-Amz-Signature=5d0c8e2a91b47f3c6e1d0a9b8c7f6e5d4c3b2a1908f7e6d5c4b3a29180f7e6d5"},"bio":"Fenerbahçe, kahve ve uzun yürüyüşler.","birth_date":"1990-04-12","created_at":"2026-09-22T09:02:35.300000Z","dm_policy":"paid","dm_star_cost":5,"follows":{"followers":12,"following":8},"gender":"male","hidden_profile":false,"personalized_ads":true,"photo_visibility":"followers","premium":false,"stars":40,"username":"osman"}}
DeneÖnce token gir: otomatik eklenir
GET/api/me/stars
🔒 Bearer token
Yıldız bakiyesi ve hareketleri
Yıldız bakiyesini ve son 50 hareketi (yeniden eskiye) döner. Bakiye, hareketlerin toplamıdır; delta pozitifse kazanç, negatifse harcamadır.
›Bugün üretilen reason değerleri: dm_open (ücretli birebir sohbet açmak: açandan düşer, karşı tarafa yazılır) ve room_vanity_link (odaya kısa link almak; related_room o odadır). İstemci bilmediği bir reason'ı genel bir satır olarak göstermelidir.
›created_at ISO-8601 metindir.
Yanıtlar
200{balance, entries}
401Token yok ya da geçersiz (unauthorized) veya süresi dolmuş (token_expired)
Profil sayfasındaki sekmeler için: kişinin kurduğu gruplar (founded) ve kurmadan yönettiği gruplar (administered). Her iki liste de ada göre sıralıdır ve yalnız grup odalarını içerir; birebir sohbetler burada yer almaz.
›Her oda standart oda nesnesidir ve birincil fotoğrafı avatar alanında gelir (yoksa null). my_role, member_count gibi bağlama bağlı alanlar bu yanıtta yoktur.
Yanıtlar
200{founded, administered}
401Token yok ya da geçersiz (unauthorized) veya süresi dolmuş (token_expired)
{"administered":[{"avatar":null,"created_at":"2026-09-23T20:02:51.090317Z","discussions_enabled":false,"events_visibility":"all","founder_id":"2b9e6f13-7a48-4c51-8e02-d3f6a1b7c9e4","gifts":0,"history_for_new_members":true,"id":"4c18f0a7-93be-4d25-8f61-2a7b9c0e5d34","join_approval":false,"kind":"group","level":0,"member_denied":[],"members_can_pin":false,"members_can_video":false,"message_ttl_hours":null,"name":"Fenerbahçe Taraftar","peer":null,"pinned":null,"pins":[],"short_link":"mskp.io/fenerbahce-taraftar","show_gifts":true,"show_members":true,"show_welcome":true,"slug":"fenerbahce-taraftar","star_gated":false,"stars":0,"vanity_code":null,"visibility":"open","wallpaper":"okyanus","welcome_message":"Hoş geldin {username}, maç günü burası kalabalık olur."}],"founded":[{"avatar":{"byte_size":97310,"content_type":"image/jpeg","created_at":"2026-09-25T18:42:30.118544Z","id":"d5a7e3c1-9b02-4f68-a4e1-6c3b8f2d0e97","is_primary":true,"size_px":1024,"thumb_url":"https://mskop-api.gurerlabs.com/makroskop-media/room-avatars/9b7e2c41-6d3a-4f8e-a1b5-7c0d9e2f4a63/2f8c4d61-7e3a-4b95-b0d2-9a1e6c5f8b34-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026X-Amz-Date=20261014T091500Z\u0026X-Amz-Expires=3600\u0026X-Amz-SignedHeaders=host\u0026X-Amz-Signature=5d0c8e2a91b47f3c6e1d0a9b8c7f6e5d4c3b2a1908f7e6d5c4b3a29180f7e6d5","url":"https://mskop-api.gurerlabs.com/makroskop-media/room-avatars/9b7e2c41-6d3a-4f8e-a1b5-7c0d9e2f4a63/2f8c4d61-7e3a-4b95-b0d2-9a1e6c5f8b34.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026X-Amz-Date=20261014T091500Z\u0026X-Amz-Expires=3600\u0026X-Amz-SignedHeaders=host\u0026X-Amz-Signature=5d0c8e2a91b47f3c6e1d0a9b8c7f6e5d4c3b2a1908f7e6d5c4b3a29180f7e6d5"},"created_at":"2026-09-25T18:40:12.512004Z","discussions_enabled":true,"events_visibility":"all","founder_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","gifts":0,"history_for_new_members":true,"id":"9b7e2c41-6d3a-4f8e-a1b5-7c0d9e2f4a63","join_approval":false,"kind":"group","level":1,"member_denied":[],"members_can_pin":false,"members_can_video":false,"message_ttl_hours":24,"name":"Gece Kulübü","peer":null,"pinned":null,"pins":[],"short_link":"mskp.io/gece","show_gifts":true,"show_members":true,"show_welcome":true,"slug":"gece-kulubu","star_gated":false,"stars":10,"vanity_code":"gece","visibility":"closed","wallpaper":"lavanta","welcome_message":"Hoş geldin {username}!"}]}
DeneÖnce token gir: otomatik eklenir
GET/api/me/followers
🔒 Bearer token
Takipçilerim
Beni takip edenler, en yeni takip başta. En çok 200 kişi döner; sayfalama yoktur. Toplam sayı için GET /api/me içindeki follows.followers kullanılır.
›followed_at ISO-8601 metindir.
Yanıtlar
200{people}
401Token yok ya da geçersiz (unauthorized) veya süresi dolmuş (token_expired)
Benim takip ettiklerim, en yeni takip başta. En çok 200 kişi döner; sayfalama yoktur. Toplam sayı için GET /api/me içindeki follows.following kullanılır.
Yanıtlar
200{people}
401Token yok ya da geçersiz (unauthorized) veya süresi dolmuş (token_expired)
Hesabı geri alınamaz biçimde kapatır. GlobalTrustID ile açılmış hesap, hâlâ kendisi olduğunu kanıtlamak için gövdede aynı kimlikten alınmış taze bir GlobalTrustID kodu göndermelidir (giriş akışı yeniden yürütülür). Silindiği an hesabın bütün cihazlarındaki socket bağlantıları düşürülür.
›Gidenler: hesap, oturumları, fotoğrafları (dosyalarıyla), takip ilişkileri, oda üyelikleri ve yöneticilikleri, ifadeleri, görüldü kayıtları ve yıldız defteri.
›Kurucusu olduğu gruplar devredilmez, üyeleriyle birlikte silinir: üyelere room:gone, odaya room:deleted gider.
›Birebir sohbetler karşı tarafa devredilir ve onun listesinde kalır; karşıda kimse kalmamışsa sohbet silinir.
›Başkalarının odalarında yazdığı mesajlar silinmez; yalnız sender.account_idnull olur.
Aynı kimlik için yeniden yürütülen giriş akışından gelen authorization code
redirect_uristringbodyzorunlu
Akışta kullanılan redirect URI
code_verifierstringbodyzorunlu
PKCE doğrulayıcısı
noncestringbodyisteğe bağlı
Akışta nonce gönderildiyse aynısı
Yanıtlar
204Hesap silindi; gövde boş
400code ya da redirect_uri yok (invalid_request)
401Kod reddedildi (gtid_rejected), id_token doğrulanamadı ya da kod başka bir kimliğe ait (invalid_id_token), veya access token geçersiz (unauthorized / token_expired)
Bu çağrı taze bir GlobalTrustID kodu ister ve hesabı geri dönüşü olmayan biçimde siler; sayfadan denenmez.
Profil fotoğrafları
Hesabın kare (1:1) fotoğrafları. Bir hesabın birden çok fotoğrafı olabilir, biri "yüz"dür (is_primary): GET /api/me ve başkalarının gördüğü profil kartı avatar alanında onu verir. Backend dosya baytı taşımaz; yükleme üç adımdır: (1) POST /api/me/avatars/presign iki presigned PUT linki verir: full (1:1 orijinal) ve thumb (cihazın önbelleğe alacağı küçük kopya); (2) uygulama kareyi kırpar, küçük kopyayı kendisi üretir ve iki dosyayı bu linklere doğrudan PUT eder (MinIO, 10 dakika geçerli, Authorization başlığı gönderilmez); (3) POST /api/me/avatars dönen iki key ile fotoğrafı kaydeder. Bu gruptaki servisler yalnız geçerli token ister; rumuz seçilmemiş hesap da fotoğraf yükleyebilir.
GET/api/me/avatars
🔒 Bearer token
Fotoğraflarım
Hesabın bütün fotoğraflarını döner: yüz olan başta, ardından yeniden eskiye. Fotoğraf yoksa liste boştur.
›url ve thumb_url 1 saat geçerli presigned GET linkleridir. Uygulama küçük kopyanın baytını yerelde saklayıp önce onu çizmeli; süresi dolmuş link boş avatar değil, bir tazeleme demektir.
›created_at ISO-8601 metindir.
Yanıtlar
200{avatars}
401Token yok ya da geçersiz (unauthorized) veya süresi dolmuş (token_expired)
Yüklemenin 1. adımı: aynı fotoğrafın orijinali ve küçük kopyası için iki presigned PUT linki üretir. Linkler 600 saniye geçerlidir; iki dosya da avatars/{account_id}/ altına, content_type'a uygun uzantıyla yazılır. Bu çağrı kayıt oluşturmaz: dosyalar yüklendikten sonra POST /api/me/avatars ile kaydedilmelidir.
›Dosyayı PUT ederken Content-Type başlığını burada seçilen türle gönderin; MinIO isteğine Authorization başlığı eklenmez, imza URL'nin içindedir.
Parametreler
content_typestringbodyisteğe bağlı
image/jpeg (varsayılan) · image/webp · image/png
Yanıtlar
200{content_type, full, thumb}
400Desteklenmeyen content_type (invalid_request)
401Token yok ya da geçersiz (unauthorized) veya süresi dolmuş (token_expired)
Yüklemenin 3. adımı: presign yanıtındaki full.key ve thumb.key ile fotoğrafı hesaba kaydeder. Hesabın ilk fotoğrafı ve primary: false denmeden eklenen her fotoğraf yüz olur; eski yüz aynı işlemde yüz olmaktan çıkar. Yeni fotoğraf yüz olduysa bağlı olan herkese socket üzerinden account:avatar duyurulur.
›Anahtarlar bu hesabın kendi önekiyle (avatars/{account_id}/) başlamalıdır; başkasının dosyası kaydedilemez.
›Sunucu dosyanın gerçekten yüklendiğini denetlemez: önce iki PUT tamamlanmalı, sonra bu çağrı yapılmalıdır.
Parametreler
keystringbodyzorunlu
Presign yanıtındaki full.key
thumb_keystringbodyzorunlu
Presign yanıtındaki thumb.key
content_typestringbodyisteğe bağlı
image/jpeg (varsayılan) · image/webp · image/png
byte_sizeintegerbodyisteğe bağlı
Orijinal dosyanın boyutu (bayt); 1 ile 8388608 (8 MiB) arası
size_pxintegerbodyisteğe bağlı
Karenin kenar uzunluğu (piksel); 1 ile 4096 arası
primarybooleanbodyisteğe bağlı
Yüz yapılsın mı; varsayılan true. false ise mevcut yüz korunur (hesabın ilk fotoğrafı yine de yüz olur)
Yanıtlar
201Kaydedildi; {avatar}
401Token yok ya da geçersiz (unauthorized) veya süresi dolmuş (token_expired)
422validation_failed: key/thumb_key eksik ya da bu hesabın değil ("must be this account's own upload"), desteklenmeyen content_type, sınır dışı byte_size/size_px
Hesabın fotoğraflarından birini yüz yapar; önceki yüz aynı işlemde yüz olmaktan çıkar. Değişiklik bağlı olan herkese socket üzerinden account:avatar ile duyurulur, böylece sohbet listeleri ve mesaj satırları yeni fotoğrafı hemen çizer.
Parametreler
iduuidpathzorunlu
Fotoğrafın id'si (GET /api/me/avatars)
Yanıtlar
200{avatar} (artık is_primary: true)
401Token yok ya da geçersiz (unauthorized) veya süresi dolmuş (token_expired)
404Fotoğraf yok, başka hesaba ait ya da id UUID değil (not_found)
curl -X PUT https://mskop-api.gurerlabs.com/api/me/avatars/e04b7d92-1a6c-4f58-b3e7-9d2c8a5f1b46/primary \
-H "Authorization: Bearer $ACCESS_TOKEN"
Fotoğrafı ve depodaki iki dosyasını (orijinal ve küçük kopya) siler. Silinen yüzse en yeni fotoğraf yüz olur; son fotoğraf silindiyse hesabın yüzü kalmaz. Ardından güncel yüz (ya da null) bağlı olan herkese account:avatar ile duyurulur.
Parametreler
iduuidpathzorunlu
Silinecek fotoğrafın id'si
Yanıtlar
204Silindi; gövde boş
401Token yok ya da geçersiz (unauthorized) veya süresi dolmuş (token_expired)
404Fotoğraf yok, başka hesaba ait ya da id UUID değil (not_found)
Her oturum bir cihazdır: cihazın ne olduğu ve push adresi access token'ın taşıdığı oturuma yazılır, hesaba değil. Aynı kişinin iki telefonu iki ayrı kayıttır. Bu gruptaki servisler yalnız geçerli token ister; rumuz seçilmemiş hesap da çağırabilir.
PUT/api/me/device
🔒 Bearer token
Cihazı ve push token'ı kaydet
Cihaz kendini tanıtır ve (varsa) push adresini bildirir. Uygulama her açılışta, push token yenilendiğinde ve dil değiştiğinde gönderir; çağrı idempotenttir. Yalnız platform zorunludur: token alamayan cihaz (iOS simülatörü, bildirime izin vermeyen kullanıcı) da kendini tanıtabilir. Gönderilmeyen alan olduğu gibi kalır; push_token göndermemek "token'a dokunma" demektir, silmek DELETE /api/me/device'ın işidir.
›Aynı push_token başka bir oturumda kayıtlıysa (yeniden kurulum, ağsız çıkış, aynı telefonda başka hesap) oradan alınıp bu oturuma taşınır; bir cihaz başka hesabın bildirimini almaz.
›push_env gönderilmeden yeni bir push_token gelirse token production sayılır; önceki token'ın değeri taşınmaz.
›Push içeriği gizlidir: FCM'e ve APNs'e yalnız {type, room_slug, message_id} gider (type: message ya da mention). Mesaj metni, oda adı ve gönderen Google'a ya da Apple'a gönderilmez; görünen metni uygulama kendi önbelleğinden üretir. Sessize alınmış odalar push üretmez.
›Oturum kimliği taşımayan eski bir access token ile gelinirse 401 token_expired döner: token yenilenip çağrı tekrarlanmalıdır.
Parametreler
platformstringbodyzorunlu
android · ios · web_app · web_integration. Push'un hangi servise gideceğini belirler: ios → APNs, diğerleri → FCM. Son ikisini bugün hiçbir istemci göndermez
Bu oturumun push token'ını siler; cihaz bildirim almayı bırakır, platform ve model bilgisi kalır. Kullanıcı bildirimleri kapattığında çağrılır. Çıkış (POST /api/auth/logout) bunu zaten yapar.
Yanıtlar
204Her zaman (token zaten yoksa da); gövde boş
401Token yok ya da geçersiz (unauthorized), süresi dolmuş ya da oturum kimliği taşımıyor (token_expired)
Başka hesaplar: profil kartı, takip ilişkisi ve birebir sohbet (DM). Kişiler rumuzla adreslenir ve rumuz büyük/küçük harf duyarsızdır. Bu gruptaki servisler rumuz seçilmiş olmayı ister: rumuzu olmayan hesap 403 username_required alır.
GET/api/contacts
🔒 Bearer token
Kişi kartı listesi
Ataçtaki "kişi" ekinin seçim listesi: takip ettiklerim ve birebir sohbetim olan kişiler, rumuza göre sıralı, en çok 500 kişi. Bir kişi iki kaynakta da varsa bir kez, source: "following" ile gelir.
›Cihazın telefon rehberi hiçbir zaman okunmaz ya da yüklenmez; kişi kartı yalnız bir Makroskop hesabını gösterir.
›Henüz kimsenin yazmadığı, yalnız açılmış birebir sohbetin karşı tarafı da listede yer alır.
Yanıtlar
200{people}; source: following ya da dm
401Token yok ya da geçersiz (unauthorized) veya süresi dolmuş (token_expired)
Bir kişinin profil kartını, birlikte üye olduğumuz grupları (common_rooms, ada göre) ve aramızdaki birebir sohbeti (dm) döner. dm yalnız benim üyesi olduğum bir sohbet varsa doludur (biçimi POST /api/dm/{username} yanıtıyla aynı), yoksa null. Kişinin kendi ayarları (fotoğraf görünürlüğü, gizli profil, doğum tarihi, cinsiyet) burada dönmez.
›avatar karşı tarafın photo_visibility ayarı izin veriyorsa doludur, yoksa null.
›following: ben onu takip ediyor muyum; follows_me: o beni takip ediyor mu. follows onun takipçi/takip sayılarıdır.
›dm_policy ve dm_star_cost "mesaj gönder" düğmesini gizlemek ya da fiyatını göstermek içindir.
Parametreler
usernamestringpathzorunlu
Kişinin rumuzu; büyük/küçük harf duyarsız
Yanıtlar
200{user, common_rooms, dm}
401Token yok ya da geçersiz (unauthorized) veya süresi dolmuş (token_expired)
{"common_rooms":[{"avatar":null,"created_at":"2026-09-23T20:02:51.090317Z","discussions_enabled":false,"events_visibility":"all","founder_id":"2b9e6f13-7a48-4c51-8e02-d3f6a1b7c9e4","gifts":0,"history_for_new_members":true,"id":"4c18f0a7-93be-4d25-8f61-2a7b9c0e5d34","join_approval":false,"kind":"group","level":0,"member_count":148,"member_denied":[],"members_can_pin":false,"members_can_video":false,"message_ttl_hours":null,"name":"Fenerbahçe Taraftar","peer":null,"pinned":null,"pins":[],"short_link":"mskp.io/fenerbahce-taraftar","show_gifts":true,"show_members":true,"show_welcome":true,"slug":"fenerbahce-taraftar","star_gated":false,"stars":0,"vanity_code":null,"visibility":"open","wallpaper":"okyanus","welcome_message":"Hoş geldin {username}, maç günü burası kalabalık olur."}],"dm":null,"user":{"account_id":"8d41b7e2-5c09-4f3a-b6d8-1e7a2c94f05b","avatar":{"byte_size":102877,"content_type":"image/jpeg","created_at":"2026-09-23T16:21:09.418902Z","id":"71d9c3b5-8e2f-4a60-b4d7-c1e5f09a2b38","is_primary":true,"size_px":960,"thumb_url":"https://mskop-api.gurerlabs.com/makroskop-media/avatars/8d41b7e2-5c09-4f3a-b6d8-1e7a2c94f05b/0d6f3a8c-52b1-4e97-a3c4-8f1e7b2d9c50-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026X-Amz-Date=20261014T091500Z\u0026X-Amz-Expires=3600\u0026X-Amz-SignedHeaders=host\u0026X-Amz-Signature=5d0c8e2a91b47f3c6e1d0a9b8c7f6e5d4c3b2a1908f7e6d5c4b3a29180f7e6d5","url":"https://mskop-api.gurerlabs.com/makroskop-media/avatars/8d41b7e2-5c09-4f3a-b6d8-1e7a2c94f05b/0d6f3a8c-52b1-4e97-a3c4-8f1e7b2d9c50.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026X-Amz-Date=20261014T091500Z\u0026X-Amz-Expires=3600\u0026X-Amz-SignedHeaders=host\u0026X-Amz-Signature=5d0c8e2a91b47f3c6e1d0a9b8c7f6e5d4c3b2a1908f7e6d5c4b3a29180f7e6d5"},"bio":"Kitap, kahve, deniz.","created_at":"2026-09-23T14:11:07.902000Z","dm_policy":"open","dm_star_cost":0,"following":true,"follows":{"followers":31,"following":17},"follows_me":true,"premium":false,"username":"ozum"}}
DeneÖnce token gir: otomatik eklenir
POST/api/users/{username}/follow
🔒 Bearer token
Takip et
Kişiyi takip etmeye başlar. İdempotenttir: zaten takip ediliyorsa yine 200 döner. Yanıttaki follows takip edilen kişinin güncel sayılarıdır.
Parametreler
usernamestringpathzorunlu
Kişinin rumuzu; büyük/küçük harf duyarsız
Yanıtlar
200{following: true, follows}
400Kendini takip etmeye çalıştın (invalid_request)
401Token yok ya da geçersiz (unauthorized) veya süresi dolmuş (token_expired)
403Rumuz henüz seçilmemiş (username_required)
404Bu rumuzla hesap yok (not_found)
curl -X POST https://mskop-api.gurerlabs.com/api/users/ozum/follow \
-H "Authorization: Bearer $ACCESS_TOKEN"
Kişiyle birebir sohbet odasını döner; yoksa açar. Oda yalnız açanın listesine girer: karşı taraf ilk mesaj saklandığında odaya eklenir ve room:new olayını o zaman alır, o ana kadar onun profil kartında dm: null görünür. Karşı tarafın dm_policy değeri paid ise dm_star_cost yıldız açandan düşer ve karşı tarafa yazılır; ücret yalnız oda ilk açılırken bir kez alınır, var olan sohbete dönmek ücretsizdir.
›Birebir sohbet bir sistem odasıdır: kind: "dm", yönetici yok, herkese kapalı (visibility: "closed"), aramada çıkmaz. name karşı tarafın rumuzudur ve peer onu (online ile) verir.
›Slug iki hesap kimliğinden türer (dm- + her UUID'nin tiresiz ilk 12 karakteri, sıralı); aynı çift hep aynı odaya düşer.
›Bu yanıtta member_count her zaman 2'dir; karşı taraf henüz eklenmemiş olsa bile.
›Odada değiştirilebilen tek ayar duvar kağıdıdır (PATCH /api/rooms/{slug}, iki taraf da). Var olan sohbete karşı tarafın dm_policy ayarı sonradan closed olsa da dönülebilir.
Parametreler
usernamestringpathzorunlu
Sohbet açılacak kişinin rumuzu; büyük/küçük harf duyarsız
Oda döndüren her uç aynı oda nesnesini verir; bağlama göre üstüne my_role, member_count, is_member, my_permissions, avatar gibi alanlar eklenir. kindgroup (olağan grup) ya da dm (birebir sohbetin sistem odası: peer dolu, name karşı tarafın rumuzu) olur. Odalar slug ile anılır: 3–48 karakter, küçük harf, rakam ve tek tire (^[a-z0-9]+(-[a-z0-9]+)*$), birebir sohbette dm-<id>-<id>; visibilityopen ise bağlantı katılmaya yeter, closed ise kişiyi bir yönetici ekler.
GET/api/rooms
🔒 Bearer token
Odalarım
Üyesi olduğun bütün odalar (arşivdekiler dahil), sohbet listesinin çizdiği satır bilgileriyle: my_role, joined_at, archived, muted, pinned_to_top, last_message, unread, unread_mentions. Sıra: önce başa sabitlenenler (en yeni sabit üstte), sonra en son konuşulan oda; hiç konuşulmamış oda joined_at'e düşer, eşitliği oda kimliği bozar. Birebir sohbet karşı tarafın rumuzuyla gelir ve peer.online o anki çevrimiçi durumunu taşır.
›last_message.body gövdenin ilk 120 karakteridir; tartışma yanıtları ve silinmiş mesajlar last_message sayılmaz. Oda hiç konuşmadıysa null.
›unread okuma imlecinden (message:read) sonraki mesaj sayısıdır; kendi mesajların ve göremediğin admins satırları sayılmaz.
›Birebir sohbette yönetici yoktur: iki tarafın my_role değeri de member gelir.
›Listenin canlı hâli user:<account_id> hattındaki room:activity, room:new ve room:gone olaylarıdır; her mesajda bu ucu yeniden çağırmak gerekmez.
{"rooms":[{"archived":false,"avatar":{"byte_size":118432,"content_type":"image/jpeg","created_at":"2026-09-28T18:44:51.207913Z","id":"3f2a8d17-b6c4-4e09-9d25-71a0c3e5f8b2","is_primary":true,"size_px":1024,"thumb_url":"https://mskop-api.gurerlabs.com/makroskop-media/room-avatars/9b7e2c51-4d0a-4f6e-8a13-6e2d7c90b4f5/3f2a8d17-b6c4-4e09-9d25-71a0c3e5f8b2-thumb.jpg?X-Amz-Signature=...","url":"https://mskop-api.gurerlabs.com/makroskop-media/room-avatars/9b7e2c51-4d0a-4f6e-8a13-6e2d7c90b4f5/3f2a8d17-b6c4-4e09-9d25-71a0c3e5f8b2.jpg?X-Amz-Signature=..."},"created_at":"2026-09-28T18:42:07.512338Z","discussions_enabled":true,"events_visibility":"all","founder_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","gifts":0,"history_for_new_members":true,"id":"9b7e2c51-4d0a-4f6e-8a13-6e2d7c90b4f5","join_approval":false,"joined_at":"2026-09-28T18:42:07.530114Z","kind":"group","last_message":{"audience":"all","body":"Maç kaçta başlıyor? #mac","event":null,"id":"e7d4a210-3c6f-4b85-9a1e-2f08c5b7d964","inserted_at":1792004113482,"kind":"text","sender":{"account_id":"2b9d71c4-8e05-4a3f-b6d2-5c19e7a04f83","username":"ozum"},"seq":421},"level":0,"member_denied":["group.can_pin_message"],"members_can_pin":false,"members_can_video":false,"message_ttl_hours":null,"muted":false,"my_role":"founder","name":"Fenerbahçe Taraftar","peer":null,"pinned":{"at":"2026-10-12T19:05:33.841220Z","by":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","message_id":"b0127e4c-5a93-4d1f-8c26-9e4a0f7b3d18"},"pinned_to_top":true,"pins":[{"account_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","at":"2026-10-12T19:05:33.841220Z","message_id":"b0127e4c-5a93-4d1f-8c26-9e4a0f7b3d18"}],"short_link":"mskp.io/fenerbahce-taraftar","show_gifts":true,"show_members":true,"show_welcome":true,"slug":"fenerbahce-taraftar","star_gated":false,"stars":0,"unread":3,"unread_mentions":1,"vanity_code":null,"visibility":"open","wallpaper":"lavanta","welcome_message":"Hoş geldin {username}! Maç günleri #mac etiketini kullan."},{"archived":false,"avatar":null,"created_at":"2026-10-03T08:17:45.009412Z","discussions_enabled":false,"events_visibility":"all","founder_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","gifts":0,"history_for_new_members":true,"id":"4e18c0a7-6b2d-4f93-a5e1-0c7d9b28f361","join_approval":false,"joined_at":"2026-10-03T08:17:45.021877Z","kind":"dm","last_message":{"audience":"all","body":"Akşam görüşürüz","event":null,"id":"51c8e9a3-7f20-4d6b-b3e4-a0d92f6c1b75","inserted_at":1791998402117,"kind":"text","sender":{"account_id":"2b9d71c4-8e05-4a3f-b6d2-5c19e7a04f83","username":"ozum"},"seq":58},"level":0,"member_denied":[],"members_can_pin":false,"members_can_video":false,"message_ttl_hours":null,"muted":false,"my_role":"member","name":"ozum","peer":{"account_id":"2b9d71c4-8e05-4a3f-b6d2-5c19e7a04f83","official":false,"online":true,"username":"ozum"},"pinned":null,"pinned_to_top":false,"pins":[],"short_link":"mskp.io/dm-2b9d71c48e05-f6cad4623b1e","show_gifts":true,"show_members":true,"show_welcome":true,"slug":"dm-2b9d71c48e05-f6cad4623b1e","star_gated":false,"stars":0,"unread":0,"unread_mentions":0,"vanity_code":null,"visibility":"closed","wallpaper":"okyanus","welcome_message":null}]}
DeneÖnce token gir: otomatik eklenir
GET/api/rooms/search
🔒 Bearer token
Oda ara
Katılmadan önce bir grubu adının ya da slug'ının bir parçasıyla bulur (büyük/küçük harf duyarsız). Üyesi olduğun odalar başta, gerisi ada göre sıralanır; en çok 20 sonuç döner ve her satırda is_member, archived, member_count, avatar vardır. Kapalı gruplar ve başka bir organizasyonun odaları yalnız kendi üyelerinin aramasında çıkar; birebir sohbetler hiç çıkmaz.
›Kapalı bir gruba davet bağlantısıyla gelen kişi aramada bulamaz ama GET /api/rooms/{slug} ile odanın kapı sayfasını açabilir.
Parametreler
qstringqueryzorunlu
Aranan metin. % ve _ karakterleri yok sayılır; yalnız boşluksa sonuç boş liste olur
{"rooms":[{"archived":false,"avatar":{"byte_size":118432,"content_type":"image/jpeg","created_at":"2026-09-28T18:44:51.207913Z","id":"3f2a8d17-b6c4-4e09-9d25-71a0c3e5f8b2","is_primary":true,"size_px":1024,"thumb_url":"https://mskop-api.gurerlabs.com/makroskop-media/room-avatars/9b7e2c51-4d0a-4f6e-8a13-6e2d7c90b4f5/3f2a8d17-b6c4-4e09-9d25-71a0c3e5f8b2-thumb.jpg?X-Amz-Signature=...","url":"https://mskop-api.gurerlabs.com/makroskop-media/room-avatars/9b7e2c51-4d0a-4f6e-8a13-6e2d7c90b4f5/3f2a8d17-b6c4-4e09-9d25-71a0c3e5f8b2.jpg?X-Amz-Signature=..."},"created_at":"2026-09-28T18:42:07.512338Z","discussions_enabled":true,"events_visibility":"all","founder_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","gifts":0,"history_for_new_members":true,"id":"9b7e2c51-4d0a-4f6e-8a13-6e2d7c90b4f5","is_member":true,"join_approval":false,"kind":"group","level":0,"member_count":214,"member_denied":["group.can_pin_message"],"members_can_pin":false,"members_can_video":false,"message_ttl_hours":null,"name":"Fenerbahçe Taraftar","peer":null,"pinned":{"at":"2026-10-12T19:05:33.841220Z","by":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","message_id":"b0127e4c-5a93-4d1f-8c26-9e4a0f7b3d18"},"pins":[{"account_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","at":"2026-10-12T19:05:33.841220Z","message_id":"b0127e4c-5a93-4d1f-8c26-9e4a0f7b3d18"}],"short_link":"mskp.io/fenerbahce-taraftar","show_gifts":true,"show_members":true,"show_welcome":true,"slug":"fenerbahce-taraftar","star_gated":false,"stars":0,"vanity_code":null,"visibility":"open","wallpaper":"lavanta","welcome_message":"Hoş geldin {username}! Maç günleri #mac etiketini kullan."},{"archived":false,"avatar":null,"created_at":"2026-10-01T11:20:14.774051Z","discussions_enabled":false,"events_visibility":"all","founder_id":"7c41e0b2-93d5-4f18-a2c6-0e8b5d3f9a17","gifts":0,"history_for_new_members":true,"id":"e19b4d73-5c2a-4f80-b6e7-3a8d0c51f2e9","is_member":false,"join_approval":true,"kind":"group","level":0,"member_count":57,"member_denied":[],"members_can_pin":false,"members_can_video":false,"message_ttl_hours":null,"name":"Fenerbahçe Basketbol","peer":null,"pinned":null,"pins":[],"short_link":"mskp.io/fenerbahce-basketbol","show_gifts":true,"show_members":true,"show_welcome":true,"slug":"fenerbahce-basketbol","star_gated":false,"stars":0,"vanity_code":null,"visibility":"open","wallpaper":"okyanus","welcome_message":null}]}
DeneÖnce token gir: otomatik eklenir
POST/api/rooms
🔒 Bearer token
Oda kur
Yeni bir grup kurar; kuran kişi aynı işlemde kurucu (founder) ve ilk üye olur. slug verilmezse addan türetilir (Kadıköy Koşu Kulübü → kadikoy-kosu-kulubu, Türkçe harfler sadeleşir, en çok 40 karakter); türetilen slug doluysa sonuna -a1b2c3 gibi rastgele bir ek gelir. Fotoğraf ayrı yüklenir (*Oda fotoğrafları*): oda baytlardan önce var olur.
›Kendi verdiğin slug doluysa ek eklenmez, 422 döner (fields.slug: has already been taken).
›star_gated: true olan odaya katılma şimdilik 402 star_required döner; yıldızla katılma henüz açık değil.
›Diğer ayarlar (wallpaper, join_approval, show_members...) kurulumdan sonra PATCH /api/rooms/{slug} ile değişir.
Parametreler
namestringbodyzorunlu
Oda adı; baştaki/sondaki boşluk kırpılır, 1–80 karakter
slugstringbodyisteğe bağlı
3–48 karakter, küçük harf, rakam ve tek tire; küçük harfe çevrilir. Sonradan değiştirilemez
visibilitystringbodyisteğe bağlı
open (varsayılan; bağlantı yeter) ya da closed (yönetici ekler)
message_ttl_hoursintegerbodyisteğe bağlı
Mesajlar bu kadar saat sonra silinir; 1–8760, null = silinmez (varsayılan)
welcome_messagestringbodyisteğe bağlı
Yeni üyeye odanın yazdığı karşılama; en çok 500 karakter, {username} yerine katılanın rumuzu konur
422Alan hatası (validation_failed): name boş ya da 80'den uzun, slug biçimi bozuk ya da dolu, visibility bilinmiyor, message_ttl_hours aralık dışında, welcome_message 500'den uzun
Tek odanın tam nesnesi. Üye olmayan herkes de çağırabilir (davet bağlantısının açtığı kapı sayfası); kapalı gruplar dahil. is_member senin üye olup olmadığını, my_permissions bu odada yapabileceğin her şeyi söyler: istemci ataşı ve menüleri bu listeden çizmeli, kuralları kendisi türetmemelidir.
›Üye değilsen my_permissions boş liste gelir.
›pinned en yeni sabitlenen mesajdır (eski uygulamalar bunu okur), pins bütün sabitlerin listesidir (yeniden eskiye). Yalnız mesaj kimliği gelir; metni cihaz kendi kopyasından çizer.
›member_denied odanın üyelerden geri aldığı yetkilerdir; members_can_pin aynı kuralın eski adıdır (group.can_pin_message).
›Bu uçta my_role yoktur; rolü GET /api/rooms listesi ya da GET /api/rooms/{slug}/members verir.
{"room":{"avatar":{"byte_size":118432,"content_type":"image/jpeg","created_at":"2026-09-28T18:44:51.207913Z","id":"3f2a8d17-b6c4-4e09-9d25-71a0c3e5f8b2","is_primary":true,"size_px":1024,"thumb_url":"https://mskop-api.gurerlabs.com/makroskop-media/room-avatars/9b7e2c51-4d0a-4f6e-8a13-6e2d7c90b4f5/3f2a8d17-b6c4-4e09-9d25-71a0c3e5f8b2-thumb.jpg?X-Amz-Signature=...","url":"https://mskop-api.gurerlabs.com/makroskop-media/room-avatars/9b7e2c51-4d0a-4f6e-8a13-6e2d7c90b4f5/3f2a8d17-b6c4-4e09-9d25-71a0c3e5f8b2.jpg?X-Amz-Signature=..."},"created_at":"2026-09-28T18:42:07.512338Z","discussions_enabled":true,"events_visibility":"all","founder_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","gifts":0,"history_for_new_members":true,"id":"9b7e2c51-4d0a-4f6e-8a13-6e2d7c90b4f5","is_member":true,"join_approval":false,"kind":"group","level":0,"member_count":214,"member_denied":["group.can_pin_message"],"members_can_pin":false,"members_can_video":false,"message_ttl_hours":null,"muted":false,"my_permissions":["send_message","edit_message","delete_message","update_tag","sub_chat.send_message","sub_chat.close_subject","group.can_open_discussion","group.can_take_screen_shot","send_message.photos","send_message.videos","send_message.files","send_message.musics","send_message.voice_messages","send_message.video_messages","send_message.gifs","send_message.surveys","send_message.links","send_message.reactions","send_message.locations","send_message.share_contact_cards","send_message.events","send_message.entries","sub_chat.send_message.photos","sub_chat.send_message.videos","sub_chat.send_message.files","sub_chat.send_message.musics","sub_chat.send_message.voice_messages","sub_chat.send_message.video_messages","sub_chat.send_message.gifs","sub_chat.send_message.surveys","sub_chat.send_message.links","sub_chat.send_message.reactions","sub_chat.send_message.locations","sub_chat.send_message.share_contact_cards","sub_chat.send_message.events","sub_chat.send_message.entries"],"name":"Fenerbahçe Taraftar","peer":null,"pinned":{"at":"2026-10-12T19:05:33.841220Z","by":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","message_id":"b0127e4c-5a93-4d1f-8c26-9e4a0f7b3d18"},"pins":[{"account_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","at":"2026-10-12T19:05:33.841220Z","message_id":"b0127e4c-5a93-4d1f-8c26-9e4a0f7b3d18"}],"short_link":"mskp.io/fenerbahce-taraftar","show_gifts":true,"show_members":true,"show_welcome":true,"slug":"fenerbahce-taraftar","star_gated":false,"stars":0,"vanity_code":null,"visibility":"open","wallpaper":"lavanta","welcome_message":"Hoş geldin {username}! Maç günleri #mac etiketini kullan."}}
DeneÖnce token gir: otomatik eklenir
PATCH/api/rooms/{slug}
🔑 oda yöneticisi
Oda ayarları
Odanın ayarlarını değiştirir; göndermediğin alan olduğu gibi kalır, bilinmeyen alanlar yok sayılır, slug hiç değişmez. Gönderilen her ayar adı odaya yalnız yöneticilerin gördüğü bir room_settings_changed satırı olarak yazılır (event.data.settings; değerler saklanmaz). Birebir sohbette iki taraf da çağırabilir ama yalnız wallpaper değişir ve orada wallpaper zorunludur.
›Kurucu ve bütün yöneticiler çağırabilir; verilen anahtarlara (granted) bakılmaz.
›members_can_pin gönderilirse member_denied içindeki group.can_pin_message de aynı yönde güncellenir.
›visibility, wallpaper ve name için null gönderilemez (422); "message_ttl_hours": null otomatik silmeyi kapatır.
Parametreler
slugstringpathzorunlu
Oda slug'ı (büyük/küçük harf fark etmez)
namestringbodyisteğe bağlı
Oda adı, 1–80 karakter
visibilitystringbodyisteğe bağlı
open ya da closed
welcome_messagestringbodyisteğe bağlı
Karşılama metni, en çok 500 karakter; {username} kullanılabilir
{"room":{"avatar":{"byte_size":118432,"content_type":"image/jpeg","created_at":"2026-09-28T18:44:51.207913Z","id":"3f2a8d17-b6c4-4e09-9d25-71a0c3e5f8b2","is_primary":true,"size_px":1024,"thumb_url":"https://mskop-api.gurerlabs.com/makroskop-media/room-avatars/9b7e2c51-4d0a-4f6e-8a13-6e2d7c90b4f5/3f2a8d17-b6c4-4e09-9d25-71a0c3e5f8b2-thumb.jpg?X-Amz-Signature=...","url":"https://mskop-api.gurerlabs.com/makroskop-media/room-avatars/9b7e2c51-4d0a-4f6e-8a13-6e2d7c90b4f5/3f2a8d17-b6c4-4e09-9d25-71a0c3e5f8b2.jpg?X-Amz-Signature=..."},"created_at":"2026-09-28T18:42:07.512338Z","discussions_enabled":true,"events_visibility":"all","founder_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","gifts":0,"history_for_new_members":true,"id":"9b7e2c51-4d0a-4f6e-8a13-6e2d7c90b4f5","is_member":true,"join_approval":false,"kind":"group","level":0,"member_count":214,"member_denied":["group.can_pin_message"],"members_can_pin":false,"members_can_video":false,"message_ttl_hours":72,"muted":false,"my_permissions":["send_message","edit_message","delete_message","update_tag","sub_chat.send_message","sub_chat.close_subject","group.can_open_discussion","group.can_pin_message","group.can_take_screen_shot","send_message.photos","send_message.videos","send_message.files","send_message.musics","send_message.voice_messages","send_message.video_messages","send_message.gifs","send_message.surveys","send_message.links","send_message.reactions","send_message.locations","send_message.share_contact_cards","send_message.events","send_message.entries","sub_chat.send_message.photos","sub_chat.send_message.videos","sub_chat.send_message.files","sub_chat.send_message.musics","sub_chat.send_message.voice_messages","sub_chat.send_message.video_messages","sub_chat.send_message.gifs","sub_chat.send_message.surveys","sub_chat.send_message.links","sub_chat.send_message.reactions","sub_chat.send_message.locations","sub_chat.send_message.share_contact_cards","sub_chat.send_message.events","sub_chat.send_message.entries","group.edit_informations","group.can_remove_message","group.can_ban_members","group.can_ban_administrators","group.can_invite_members","group.can_create_invite_link","group.can_cancel_invite_link","group.can_edit_member_tags","group.can_open_voice_calls","group_can_give_permissions","group.can_edit_permissions","group.can_be_anonymous"],"name":"Fenerbahçe Taraftar Grubu","peer":null,"pinned":{"at":"2026-10-12T19:05:33.841220Z","by":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","message_id":"b0127e4c-5a93-4d1f-8c26-9e4a0f7b3d18"},"pins":[{"account_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","at":"2026-10-12T19:05:33.841220Z","message_id":"b0127e4c-5a93-4d1f-8c26-9e4a0f7b3d18"}],"short_link":"mskp.io/fenerbahce-taraftar","show_gifts":true,"show_members":false,"show_welcome":true,"slug":"fenerbahce-taraftar","star_gated":false,"stars":0,"vanity_code":null,"visibility":"open","wallpaper":"grafit","welcome_message":"Hoş geldin {username}! Maç günleri #mac etiketini kullan."}}
DeneÖnce token gir: otomatik eklenir
DELETE/api/rooms/{slug}
🔑 kurucu (for=everyone, grup)
Sohbeti sil / listemden kaldır
for=me sohbeti yalnız senin listenden düşürür: POST /api/rooms/{slug}/leave ile birebir aynıdır ve onun yanıtını döner (kurucuysan oda devredilir). for=everyone odayı temelli siler: üyeler, mesajlar, konular, banlar, fotoğraflar ve medya dosyaları gider; diğer üyelerin user: hattına room:gone, odanın kanalına room:deleted yayılır. Grupta bunu yalnız kurucu yapabilir, birebir sohbette iki taraftan biri; geri alınamaz.
›for verilmezse (ya da tanınmayan bir değerse) birebir sohbette me, grupta everyone sayılır.
Parametreler
slugstringpathzorunlu
Oda slug'ı (büyük/küçük harf fark etmez)
forstringqueryisteğe bağlı
everyone (odayı herkes için sil) ya da me (yalnız listemden kaldır)
Yanıtlar
200for=me: ayrılma yanıtı (left, handed_over ya da room_gone)
204for=everyone: oda silindi; gövde boş
403for=everyone ve kurucu değilsin / birebir sohbetin üyesi değilsin (not_admin); for=me ve üye değilsin (not_member)
Odaya girer ve sonucu status ile, odanın güncel hâlini room ile döner. joined: üye oldun; odaya member:joined yayılır, member_joined satırı ve (açıksa) karşılama satırı yazılır. already_member: zaten üyesin, hiçbir şey değişmez. requested: oda onay istiyor (join_approval), isteğin yöneticilerin requests listesine düştü ve onaylanınca user: hattına room:new gelir.
›Denetim sırası: üyelik → ban (403 banned) → yıldız (402 star_required) → onay kuyruğu (requested) → kapalı oda (403 room_closed). Kapalı ama kuyruklu oda istek alır.
›Oda geçmişi yeni üyelerden gizliyorsa (history_for_new_members: false) akışın katıldığın andan başlar.
Parametreler
slugstringpathzorunlu
Oda slug'ı (büyük/küçük harf fark etmez)
Yanıtlar
200status: joined, already_member ya da requested; yanında room
402Oda yıldızla giriliyor; henüz açık değil (star_required)
403Bu odadan engellendin (banned) ya da oda kapalı ve onay kuyruğu yok (room_closed)
404Böyle bir oda yok (room_not_found)
curl -X POST https://mskop-api.gurerlabs.com/api/rooms/fenerbahce-taraftar/join \
-H "Authorization: Bearer $ACCESS_TOKEN"
{"room":{"avatar":{"byte_size":118432,"content_type":"image/jpeg","created_at":"2026-09-28T18:44:51.207913Z","id":"3f2a8d17-b6c4-4e09-9d25-71a0c3e5f8b2","is_primary":true,"size_px":1024,"thumb_url":"https://mskop-api.gurerlabs.com/makroskop-media/room-avatars/9b7e2c51-4d0a-4f6e-8a13-6e2d7c90b4f5/3f2a8d17-b6c4-4e09-9d25-71a0c3e5f8b2-thumb.jpg?X-Amz-Signature=...","url":"https://mskop-api.gurerlabs.com/makroskop-media/room-avatars/9b7e2c51-4d0a-4f6e-8a13-6e2d7c90b4f5/3f2a8d17-b6c4-4e09-9d25-71a0c3e5f8b2.jpg?X-Amz-Signature=..."},"created_at":"2026-09-28T18:42:07.512338Z","discussions_enabled":true,"events_visibility":"all","founder_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","gifts":0,"history_for_new_members":true,"id":"9b7e2c51-4d0a-4f6e-8a13-6e2d7c90b4f5","is_member":true,"join_approval":false,"kind":"group","level":0,"member_count":215,"member_denied":["group.can_pin_message"],"members_can_pin":false,"members_can_video":false,"message_ttl_hours":null,"muted":false,"my_permissions":["send_message","edit_message","delete_message","update_tag","sub_chat.send_message","sub_chat.close_subject","group.can_open_discussion","group.can_take_screen_shot","send_message.photos","send_message.videos","send_message.files","send_message.musics","send_message.voice_messages","send_message.video_messages","send_message.gifs","send_message.surveys","send_message.links","send_message.reactions","send_message.locations","send_message.share_contact_cards","send_message.events","send_message.entries","sub_chat.send_message.photos","sub_chat.send_message.videos","sub_chat.send_message.files","sub_chat.send_message.musics","sub_chat.send_message.voice_messages","sub_chat.send_message.video_messages","sub_chat.send_message.gifs","sub_chat.send_message.surveys","sub_chat.send_message.links","sub_chat.send_message.reactions","sub_chat.send_message.locations","sub_chat.send_message.share_contact_cards","sub_chat.send_message.events","sub_chat.send_message.entries"],"name":"Fenerbahçe Taraftar","peer":null,"pinned":{"at":"2026-10-12T19:05:33.841220Z","by":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","message_id":"b0127e4c-5a93-4d1f-8c26-9e4a0f7b3d18"},"pins":[{"account_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","at":"2026-10-12T19:05:33.841220Z","message_id":"b0127e4c-5a93-4d1f-8c26-9e4a0f7b3d18"}],"short_link":"mskp.io/fenerbahce-taraftar","show_gifts":true,"show_members":true,"show_welcome":true,"slug":"fenerbahce-taraftar","star_gated":false,"stars":0,"vanity_code":null,"visibility":"open","wallpaper":"lavanta","welcome_message":"Hoş geldin {username}! Maç günleri #mac etiketini kullan."},"status":"joined"}
DeneÖnce token gir: otomatik eklenir
POST/api/rooms/{slug}/leave
🔒 Bearer token
Odadan ayrıl
Odadan çıkarsın; odaya member:left yayılır ve member_left satırı yazılır. Kurucu da ayrılabilir: oda önce yöneticilerden, yoksa üyelerden odada en uzun süredir bulunana geçer, yanıt handed_over + founder_id olur, odaya founder_changed satırı yazılır ve yeni kurucunun user: hattına my_role: "founder" taşıyan room:new gider. Odada senden başka kimse kalmadıysa oda dosyalarıyla birlikte silinir (room_gone, odaya room:deleted).
›Birebir sohbette kurucu yoktur: ayrılan çıkar, ikinci taraf da çıkınca oda silinir.
Parametreler
slugstringpathzorunlu
Oda slug'ı (büyük/küçük harf fark etmez)
Yanıtlar
200status: left, handed_over (+ founder_id) ya da room_gone
403Odanın üyesi değilsin (not_member)
404Böyle bir oda yok (room_not_found)
curl -X POST https://mskop-api.gurerlabs.com/api/rooms/fenerbahce-taraftar/leave \
-H "Authorization: Bearer $ACCESS_TOKEN"
Odayı yalnız kendi arşivine taşır; başka kimsenin listesi değişmez. Arşivdeki oda GET /api/rooms içinde archived: true ile gelmeye devam eder ve sıradan mesajlar için push göndermez; seni @rumuz ile anan mesajın push'u yine gelir. Zaten arşivdeyse de 204 döner.
Parametreler
slugstringpathzorunlu
Oda slug'ı (büyük/küçük harf fark etmez)
Yanıtlar
204Arşivlendi; gövde boş
403Odanın üyesi değilsin (not_member)
404Böyle bir oda yok (room_not_found)
curl -X PUT https://mskop-api.gurerlabs.com/api/rooms/fenerbahce-taraftar/archive \
-H "Authorization: Bearer $ACCESS_TOKEN"
Odayı yalnız senin sohbet listenin tepesine sabitler; odadaki başka kimsenin listesi kıpırdamaz. Sabitlenen odalar listede en yeni sabit üstte olacak şekilde önce gelir, pinned_to_top: true taşır. Odanın mesaj sabitlemesiyle (pinned, pins) ilgisi yoktur.
Parametreler
slugstringpathzorunlu
Oda slug'ı (büyük/küçük harf fark etmez)
Yanıtlar
204Sabitlendi; gövde boş
403Odanın üyesi değilsin (not_member)
404Böyle bir oda yok (room_not_found)
curl -X PUT https://mskop-api.gurerlabs.com/api/rooms/fenerbahce-taraftar/pin \
-H "Authorization: Bearer $ACCESS_TOKEN"
Bu odadan sana push gelmez; başka hiçbir şey değişmez (mesajlar, rozet, liste aynen sürer). Arşivden farklı olarak @rumuz bahsetmeleri de sessize alınır. Oda nesnesinde muted: true görünür.
Parametreler
slugstringpathzorunlu
Oda slug'ı (büyük/küçük harf fark etmez)
Yanıtlar
204Sessize alındı; gövde boş
403Odanın üyesi değilsin (not_member)
404Böyle bir oda yok (room_not_found)
curl -X PUT https://mskop-api.gurerlabs.com/api/rooms/fenerbahce-taraftar/mute \
-H "Authorization: Bearer $ACCESS_TOKEN"
Sessize almayı kaldırır; push'lar yeniden gelir. Sessizde değilse de 204 döner. Bir yöneticinin seni susturmasıyla (members/{account_id}/mute) karıştırılmamalı.
Grup sayfasının üst şeridi: ne zamandan beri var, kaç üye, kaç mesaj, ne kadar yıldız ve hediye almış. Yanıt stats nesnesine sarılıdır. message_count oda satırlarını (kind: "event") ve silinmiş mesajları saymaz.
Odanın kendi yazdığı son satırlar (katılma, ayrılma, atma, ban, susturma, ayar değişikliği...), yeniden eskiye. Her biri kind: "event" olan normal bir mesaj nesnesidir; event.type ne olduğunu, event.username kimin hakkında olduğunu, event.actor kimin yaptığını söyler. Yöneticiler audience: "admins" satırlarını da görür, üyeler görmez.
›Arama odanın son 500 mesajı içinde yapılır; daha eski olaylar bu uçtan gelmez.
Odada kullanılan hashtag'ler, en son aktif olan başta, en çok 100 tane. Her mesaj taşıdığı her hashtag'in sayacını artırır; hashtag'siz mesajlar unknown konusunda sayılır (unknown: true). last_active ISO-8601 zamandır.
Odaya yıldızla bir kısa link alır: short_link artık mskp.io/<code> olur, slug değişmez. Ücret (varsayılan 10 yıldız, app_settings.vanity_link_star_cost) çağıranın bakiyesinden düşer, yıldızlar odaya yazılır ve level yeniden hesaplanır; harcama yıldız defterine room_vanity_link sebebiyle işlenir. Yeniden çağırmak kodu değiştirir ve ücreti yeniden keser.
›Bakiye, kodun biçiminden önce denetlenir: yetersiz bakiyede kod hatalı olsa da 402 döner.
›Birebir sohbette yönetici olmadığı için bu uç 403 not_admin döner.
Parametreler
slugstringpathzorunlu
Oda slug'ı (büyük/küçük harf fark etmez)
codestringbodyzorunlu
İstenen kod; kırpılıp küçük harfe çevrilir. 3–48 karakter, slug biçiminde, başka odada olmamalı
{"room":{"avatar":{"byte_size":118432,"content_type":"image/jpeg","created_at":"2026-09-28T18:44:51.207913Z","id":"3f2a8d17-b6c4-4e09-9d25-71a0c3e5f8b2","is_primary":true,"size_px":1024,"thumb_url":"https://mskop-api.gurerlabs.com/makroskop-media/room-avatars/9b7e2c51-4d0a-4f6e-8a13-6e2d7c90b4f5/3f2a8d17-b6c4-4e09-9d25-71a0c3e5f8b2-thumb.jpg?X-Amz-Signature=...","url":"https://mskop-api.gurerlabs.com/makroskop-media/room-avatars/9b7e2c51-4d0a-4f6e-8a13-6e2d7c90b4f5/3f2a8d17-b6c4-4e09-9d25-71a0c3e5f8b2.jpg?X-Amz-Signature=..."},"created_at":"2026-09-28T18:42:07.512338Z","discussions_enabled":true,"events_visibility":"all","founder_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","gifts":0,"history_for_new_members":true,"id":"9b7e2c51-4d0a-4f6e-8a13-6e2d7c90b4f5","is_member":true,"join_approval":false,"kind":"group","level":1,"member_count":214,"member_denied":["group.can_pin_message"],"members_can_pin":false,"members_can_video":false,"message_ttl_hours":null,"muted":false,"my_permissions":["send_message","edit_message","delete_message","update_tag","sub_chat.send_message","sub_chat.close_subject","group.can_open_discussion","group.can_pin_message","group.can_take_screen_shot","send_message.photos","send_message.videos","send_message.files","send_message.musics","send_message.voice_messages","send_message.video_messages","send_message.gifs","send_message.surveys","send_message.links","send_message.reactions","send_message.locations","send_message.share_contact_cards","send_message.events","send_message.entries","sub_chat.send_message.photos","sub_chat.send_message.videos","sub_chat.send_message.files","sub_chat.send_message.musics","sub_chat.send_message.voice_messages","sub_chat.send_message.video_messages","sub_chat.send_message.gifs","sub_chat.send_message.surveys","sub_chat.send_message.links","sub_chat.send_message.reactions","sub_chat.send_message.locations","sub_chat.send_message.share_contact_cards","sub_chat.send_message.events","sub_chat.send_message.entries","group.edit_informations","group.can_remove_message","group.can_ban_members","group.can_ban_administrators","group.can_invite_members","group.can_create_invite_link","group.can_cancel_invite_link","group.can_edit_member_tags","group.can_open_voice_calls","group_can_give_permissions","group.can_edit_permissions","group.can_be_anonymous"],"name":"Fenerbahçe Taraftar","peer":null,"pinned":{"at":"2026-10-12T19:05:33.841220Z","by":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","message_id":"b0127e4c-5a93-4d1f-8c26-9e4a0f7b3d18"},"pins":[{"account_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","at":"2026-10-12T19:05:33.841220Z","message_id":"b0127e4c-5a93-4d1f-8c26-9e4a0f7b3d18"}],"short_link":"mskp.io/fb","show_gifts":true,"show_members":true,"show_welcome":true,"slug":"fenerbahce-taraftar","star_gated":false,"stars":10,"vanity_code":"fb","visibility":"open","wallpaper":"lavanta","welcome_message":"Hoş geldin {username}! Maç günleri #mac etiketini kullan."}}
DeneÖnce token gir: otomatik eklenir
Oda yönetimi ve üyeler
Odada üç rol vardır: founder (kurucu; her yetkiyi her zaman taşır, kısıtlanamaz, atılamaz ve engellenemez), admin (yönetici; yalnız kendisine verilen anahtarları, granted, taşır) ve member (üye; odanın member_denied ile geri aldıkları ve yöneticiye özgü anahtarlar dışında her şeyi yapabilir). Üye anahtarları: send_message, edit_message, delete_message, update_tag, sub_chat.send_message, sub_chat.close_subject, group.can_open_discussion, group.can_pin_message, group.can_take_screen_shot, ayrıca her ek türü için send_message.<tür> ve sub_chat.send_message.<tür> (tür: photos, videos, files, musics, voice_messages, video_messages, gifs, surveys, links, reactions, locations, share_contact_cards, events, entries; musics ve video_messages henüz kullanılmıyor). Yönetici anahtarları: group.edit_informations, group.can_remove_message, group.can_ban_members, group.can_ban_administrators (yalnız kurucu verebilir), group.can_invite_members, group.can_create_invite_link, group.can_cancel_invite_link, group.can_pin_message, group.can_edit_member_tags, group.can_open_voice_calls, group_can_give_permissions (noktasız yazılır), group.can_edit_permissions, group.can_be_anonymous, group.can_take_screen_shot. Bazı uçlar anahtara değil yalnız yönetici olmaya bakar; her kartın rozeti neyin gerektiğini söyler, kişinin odadaki sonucu ise her zaman oda nesnesindeki my_permissions listesidir.
PUT/api/rooms/{slug}/admins/{account_id}
🔑 kurucu
Yönetici yap
Bir üyeyi yönetici yapar. Yeni yönetici hiçbir anahtarla başlamaz (granted: []); ne yapabileceğini ayrıca PUT …/admins/{account_id}/permissions ile verirsin. Kimin atadığı saklanır ve üye listesinde granted_by olarak döner. Zaten yöneticiyse hiçbir şey değişmez ve yine admin döner.
Parametreler
slugstringpathzorunlu
Oda slug'ı (büyük/küçük harf fark etmez)
account_iduuidpathzorunlu
Yönetici yapılacak üyenin hesap kimliği
Yanıtlar
200{status: "admin"}
403Kurucu değilsin (not_admin) ya da hedef odanın üyesi değil (not_member)
404Böyle bir oda yok (room_not_found)
409Hedef kurucunun kendisi (founder_protected)
curl -X PUT https://mskop-api.gurerlabs.com/api/rooms/fenerbahce-taraftar/admins/2b9d71c4-8e05-4a3f-b6d2-5c19e7a04f83 \
-H "Authorization: Bearer $ACCESS_TOKEN"
Bir yöneticinin taşıdığı anahtarların tamamını yazar: liste her seferinde bütün gerçektir, içinde olmayan geri alınır. Bilinmeyen anahtarlar reddedilmez, sessizce düşer; liste tekilleştirilip sıralanır. Odaya yalnız yöneticilerin gördüğü bir admin_permissions_changed satırı yazılır (event.data.granted).
›Kimse kendi anahtarlarını değiştiremez (403 cannot_grant_to_self).
›group.can_ban_administrators yalnız kurucu verebilir; başka bir yönetici gönderirse çağrı reddedilmez, o anahtar listeden düşer. Yanıttaki granted gerçekte yazılandır.
›Üyelerden geri alınmış bir anahtar (ör. send_message.links) yöneticiye ayrıca verilirse o yönetici için yasak kalkar.
Parametreler
slugstringpathzorunlu
Oda slug'ı (büyük/küçük harf fark etmez)
account_iduuidpathzorunlu
Anahtarları yazılacak yöneticinin hesap kimliği
grantedstring[]bodyzorunlu
Verilecek anahtarların tam listesi; boş liste hepsini geri alır
Yanıtlar
200{granted: [...]}: yazılan liste
403Bu yetkin yok ya da hedef bir yönetici değil (not_admin); hedef kendinsin (cannot_grant_to_self)
Odanın üyelerden geri aldığı yetkileri (member_denied) yazar. Liste her seferinde bütün gerçektir: içinde olmayan her şey serbesttir; bilinmeyen anahtarlar sessizce düşer. Yasak yöneticileri de bağlar, onlara aynı anahtar ayrıca verilmediyse. Odaya yalnız yöneticilerin gördüğü bir member_permissions_changed satırı yazılır.
›denied gönderilmezse ya da liste değilse boş liste sayılır ve bütün kısıtlar kalkar.
›Bu uç members_can_pin alanını güncellemez; sabitleme kuralı için member_denied ve my_permissions esas alınmalı.
Parametreler
slugstringpathzorunlu
Oda slug'ı (büyük/küçük harf fark etmez)
deniedstring[]bodyzorunlu
Üyelerden alınacak anahtarların tam listesi; [] hepsini geri verir
Yanıtlar
200Güncel oda (GET /api/rooms/{slug} ile aynı biçim)
{"room":{"avatar":{"byte_size":118432,"content_type":"image/jpeg","created_at":"2026-09-28T18:44:51.207913Z","id":"3f2a8d17-b6c4-4e09-9d25-71a0c3e5f8b2","is_primary":true,"size_px":1024,"thumb_url":"https://mskop-api.gurerlabs.com/makroskop-media/room-avatars/9b7e2c51-4d0a-4f6e-8a13-6e2d7c90b4f5/3f2a8d17-b6c4-4e09-9d25-71a0c3e5f8b2-thumb.jpg?X-Amz-Signature=...","url":"https://mskop-api.gurerlabs.com/makroskop-media/room-avatars/9b7e2c51-4d0a-4f6e-8a13-6e2d7c90b4f5/3f2a8d17-b6c4-4e09-9d25-71a0c3e5f8b2.jpg?X-Amz-Signature=..."},"created_at":"2026-09-28T18:42:07.512338Z","discussions_enabled":true,"events_visibility":"all","founder_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","gifts":0,"history_for_new_members":true,"id":"9b7e2c51-4d0a-4f6e-8a13-6e2d7c90b4f5","is_member":true,"join_approval":false,"kind":"group","level":0,"member_count":214,"member_denied":["group.can_pin_message","send_message.links","send_message.locations"],"members_can_pin":false,"members_can_video":false,"message_ttl_hours":null,"muted":false,"my_permissions":["send_message","edit_message","delete_message","update_tag","sub_chat.send_message","sub_chat.close_subject","group.can_open_discussion","group.can_pin_message","group.can_take_screen_shot","send_message.photos","send_message.videos","send_message.files","send_message.musics","send_message.voice_messages","send_message.video_messages","send_message.gifs","send_message.surveys","send_message.links","send_message.reactions","send_message.locations","send_message.share_contact_cards","send_message.events","send_message.entries","sub_chat.send_message.photos","sub_chat.send_message.videos","sub_chat.send_message.files","sub_chat.send_message.musics","sub_chat.send_message.voice_messages","sub_chat.send_message.video_messages","sub_chat.send_message.gifs","sub_chat.send_message.surveys","sub_chat.send_message.links","sub_chat.send_message.reactions","sub_chat.send_message.locations","sub_chat.send_message.share_contact_cards","sub_chat.send_message.events","sub_chat.send_message.entries","group.edit_informations","group.can_remove_message","group.can_ban_members","group.can_ban_administrators","group.can_invite_members","group.can_create_invite_link","group.can_cancel_invite_link","group.can_edit_member_tags","group.can_open_voice_calls","group_can_give_permissions","group.can_edit_permissions","group.can_be_anonymous"],"name":"Fenerbahçe Taraftar","peer":null,"pinned":{"at":"2026-10-12T19:05:33.841220Z","by":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","message_id":"b0127e4c-5a93-4d1f-8c26-9e4a0f7b3d18"},"pins":[{"account_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","at":"2026-10-12T19:05:33.841220Z","message_id":"b0127e4c-5a93-4d1f-8c26-9e4a0f7b3d18"}],"short_link":"mskp.io/fenerbahce-taraftar","show_gifts":true,"show_members":true,"show_welcome":true,"slug":"fenerbahce-taraftar","star_gated":false,"stars":0,"vanity_code":null,"visibility":"open","wallpaper":"lavanta","welcome_message":"Hoş geldin {username}! Maç günleri #mac etiketini kullan."}}
DeneÖnce token gir: otomatik eklenir
GET/api/rooms/{slug}/members
🔒 Bearer token
Üyeler
Odanın üyeleri, katılma sırasına göre (en eski başta). Her satırda rol (founder, admin, member), odanın taktığı etiket (tag), yöneticinin anahtarları (granted), onu kimin atadığı (granted_by, rumuz) ve ne zamandan beri yönetici olduğu (admin_since) vardır. muted_until bir yöneticinin susturması sürerken ms epoch, bitince null; joined_at ve admin_since ISO-8601'dir.
›Oda üyeleri gizliyorsa (show_members: false) kurucu ya da yönetici olmayan biri yalnız kurucuyu ve yöneticileri görür.
›granted yalnız kurucuya ve yöneticilere dolu gelir; sıradan üye herkeste [] görür.
Kişiyi engellemeden odadan çıkarır (/kick komutunun REST ikizi); bağlantıyla yeniden katılabilir. Yöneticiyse yöneticiliği de gider. Odaya member_kicked satırı yazılır ve member:left yayılır, kişinin user: hattına room:gone gider. Hedef bir yöneticiyse ayrıca group.can_ban_administrators gerekir.
Parametreler
slugstringpathzorunlu
Oda slug'ı (büyük/küçük harf fark etmez)
account_iduuidpathzorunlu
Çıkarılacak hesabın kimliği
Yanıtlar
204Çıkarıldı; gövde boş
403Bu yetkin yok: yönetici değilsen not_admin, yöneticisin ama group.can_ban_members verilmediyse ya da hedef bir yöneticiyse ve group.can_ban_administrators yoksa not_allowed
403Hedef odanın üyesi değil (not_member)
404Oda yok (room_not_found) ya da hesap yok (not_found)
Odanın bir üyesine taktığı kısa kelime (ör. Kaptan); o kişinin bu odadaki her mesajında adının yanında çizilir, başka odada görünmez. Metin kırpılır ve 32 karakterden uzunsa kesilir; boş metin ya da null etiketi kaldırır. Odaya member:tagged {account_id, tag} yayılır, açık cihazlar listeyi yeniden istemeden çizer.
Parametreler
slugstringpathzorunlu
Oda slug'ı (büyük/küçük harf fark etmez)
account_iduuidpathzorunlu
Etiketlenecek üyenin hesap kimliği
tagstringbodyisteğe bağlı
Etiket, en çok 32 karakter; boş ya da null kaldırır
Yanıtlar
200{account_id, tag}; kaldırıldıysa tag: null
403Bu yetkin yok (not_admin) ya da hedef üye değil (not_member)
Kişi odada kalır ama süre bitene kadar mesaj gönderemez; denerse socket muted hatası ve until döner (/mute komutunun REST ikizi, yönetim ekranı için). Odaya member_muted satırı yazılır (data.until ms, data.seconds verilen süre). Yeniden çağırmak süreyi baştan kurar.
Parametreler
slugstringpathzorunlu
Oda slug'ı (büyük/küçük harf fark etmez)
account_iduuidpathzorunlu
Susturulacak üyenin hesap kimliği
minutesintegerbodyisteğe bağlı
Süre (dakika); 1–525600 arasına sıkıştırılır, verilmezse ya da sayı değilse 60
Yanıtlar
200{muted_until}: bitiş anı, ms epoch
403Bu yetkin yok: yönetici değilsen not_admin, yöneticisin ama group.can_ban_members verilmediyse ya da hedef bir yöneticiyse ve group.can_ban_administrators yoksa not_allowed
403Hedef odanın üyesi değil (not_member)
404Oda yok (room_not_found) ya da hesap yok (not_found)
Kişinin sesini hemen geri verir ve odaya member_unmuted satırı yazar. Susturulmamış bir üye için de 204 döner (satır yine yazılır).
Parametreler
slugstringpathzorunlu
Oda slug'ı (büyük/küçük harf fark etmez)
account_iduuidpathzorunlu
Sesi açılacak üyenin hesap kimliği
Yanıtlar
204Susturma kalktı; gövde boş
403Bu yetkin yok: yönetici değilsen not_admin, yöneticisin ama group.can_ban_members verilmediyse ya da hedef bir yöneticiyse ve group.can_ban_administrators yoksa not_allowed
403Hedef odanın üyesi değil (not_member)
404Oda yok (room_not_found) ya da hesap yok (not_found)
{"bans":[{"account_id":"d03f6a95-1c7b-4e28-b4f0-89a2e6c13d54","banned_at":"2026-10-11T22:14:05.338172Z","reason":"Reklam ve spam","username":"emre"}]}
DeneÖnce token gir: otomatik eklenir
PUT/api/rooms/{slug}/bans/{account_id}
🔑 group.can_ban_members
Engelle
Kişiyi odadan çıkarır ve bir daha katılamaz (join → 403 banned); /ban komutunun REST ikizidir. Odaya member_banned satırı yazılır (data.reason), member:left yayılır ve kişinin user: hattına room:gone gider. Hedefin o anda üye olması gerekmez: odaya hiç girmemiş bir hesap da önceden engellenebilir.
›Zaten engelliyse çağrı yine 204 döner; ilk sebep değişmez.
Parametreler
slugstringpathzorunlu
Oda slug'ı (büyük/küçük harf fark etmez)
account_iduuidpathzorunlu
Engellenecek hesabın kimliği
reasonstringbodyisteğe bağlı
Sebep; engellenenler listesinde görünür
Yanıtlar
204Engellendi; gövde boş
403Bu yetkin yok: yönetici değilsen not_admin, yöneticisin ama group.can_ban_members verilmediyse ya da hedef bir yöneticiyse ve group.can_ban_administrators yoksa not_allowed
404Oda yok (room_not_found) ya da hesap yok (not_found)
409Hedef kurucu (founder_protected)
curl -X PUT https://mskop-api.gurerlabs.com/api/rooms/fenerbahce-taraftar/bans/2b9d71c4-8e05-4a3f-b6d2-5c19e7a04f83 \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"reason":"Reklam ve spam"}'
const res = await fetch("https://mskop-api.gurerlabs.com/api/rooms/fenerbahce-taraftar/bans/2b9d71c4-8e05-4a3f-b6d2-5c19e7a04f83", {
method: "PUT",
headers: {
"Authorization": "Bearer " + accessToken,
"Content-Type": "application/json",
},
body: JSON.stringify({"reason":"Reklam ve spam"}),
});
const data = await res.json();
DeneÖnce token gir: otomatik eklenir
DELETE/api/rooms/{slug}/bans/{account_id}
🔑 group.can_ban_members
Engeli kaldır
Engeli kaldırır ve odaya member_unbanned satırı yazar (/unban komutunun REST ikizi). Kişi üye olarak geri eklenmez; isterse bağlantıyla yeniden katılır.
Parametreler
slugstringpathzorunlu
Oda slug'ı (büyük/küçük harf fark etmez)
account_iduuidpathzorunlu
Engeli kaldırılacak hesabın kimliği
Yanıtlar
204Engel kalktı; gövde boş
403Bu yetkin yok: yönetici değilsen not_admin, yöneticisin ama group.can_ban_members verilmediyse ya da hedef bir yöneticiyse ve group.can_ban_administrators yoksa not_allowed
404Oda ya da hesap yok (room_not_found, not_found) veya kişi engelli değil (not_found)
Bekleyen kişiyi üye yapar. Odaya member:joined yayılır, member_joined ve (açıksa) karşılama satırı yazılır; kişinin user: hattına room:new gider, odayı açık olmasa da listesinde görür.
Parametreler
slugstringpathzorunlu
Oda slug'ı (büyük/küçük harf fark etmez)
account_iduuidpathzorunlu
Onaylanacak isteğin sahibi
Yanıtlar
200{status: "joined"}
403Odanın yöneticisi değilsin (not_admin)
404Oda yok (room_not_found) ya da bu hesabın bekleyen isteği yok (not_found)
curl -X POST https://mskop-api.gurerlabs.com/api/rooms/fenerbahce-taraftar/requests/2b9d71c4-8e05-4a3f-b6d2-5c19e7a04f83 \
-H "Authorization: Bearer $ACCESS_TOKEN"
Oda fotoğrafları karedir (1:1); bir odanın birkaç fotoğrafı olabilir ama biri birincildir ve listelerde, başlıkta o görünür. Backend bayt taşımaz: önce presign ile iki yükleme adresi alınır, istemci asıl görüntüyü ve kendi ürettiği küçük kopyayı doğrudan depoya PUT eder, sonra anahtarları POST /api/rooms/{slug}/avatars ile kaydeder. url ve thumb_url 1 saatlik imzalı adreslerdir; küçük kopyanın baytını cihazda saklayıp önce onu çizmek, bayat adresi boş avatar yerine bir tazelemeye çevirir.
GET/api/rooms/{slug}/avatars
🔒 Bearer token
Oda fotoğrafları
Odanın bütün fotoğrafları: birincil başta, gerisi yeniden eskiye. Oda detayı gibi üye olmayanlar da çağırabilir. created_at ISO-8601'dir; adresler her çağrıda yeniden imzalanır.
Bir fotoğraf için iki imzalı PUT adresi verir: full (1:1 asıl görüntü) ve thumb (küçük kopya). İkisi aynı kimliği paylaşır ve 600 saniye geçerlidir. İstemci kareyi kırpar, küçük kopyayı kendisi üretir ve iki nesneyi de Content-Type başlığıyla bu adreslere yükler. Birebir sohbette iki taraf da çağırabilir.
Parametreler
slugstringpathzorunlu
Oda slug'ı (büyük/küçük harf fark etmez)
content_typestringbodyisteğe bağlı
image/jpeg (varsayılan), image/webp ya da image/png
presign ile yüklenen iki nesneyi odanın fotoğrafı olarak kaydeder. Odanın ilk fotoğrafı ve primary: false denmeden eklenen her fotoğraf birincil olur; eski birincil aynı işlemde düşer. Sunucu nesnelerin gerçekten yüklendiğini denetlemez: iki PUT bitmeden bu uç çağrılmamalı.
›key ve thumb_key bu odanın kendi önekiyle (room-avatars/<oda id>/) başlamalı; başka odanın ya da hesabın anahtarı 422 alır.
›Birincil fotoğrafı yalnız JSON false değeri engeller; başka her değer (ya da alanın olmaması) birincil yapar.
Parametreler
slugstringpathzorunlu
Oda slug'ı (büyük/küçük harf fark etmez)
keystringbodyzorunlu
presign yanıtındaki full.key
thumb_keystringbodyzorunlu
presign yanıtındaki thumb.key
content_typestringbodyisteğe bağlı
image/jpeg (varsayılan), image/webp ya da image/png
byte_sizeintegerbodyisteğe bağlı
Asıl görüntünün boyutu (bayt); 1–8000000
size_pxintegerbodyisteğe bağlı
Karenin kenarı (piksel); 1–4096
primarybooleanbodyisteğe bağlı
Birincil yap (varsayılan true)
Yanıtlar
201Fotoğraf kaydedildi; {avatar}
403Odanın yöneticisi değilsin (not_admin)
404Böyle bir oda yok (room_not_found)
422Alan hatası (validation_failed): key/thumb_key yok ya da odanın öneki değil, bilinmeyen content_type, byte_size ya da size_px aralık dışında
Fotoğraf kaydını ve depodaki iki nesnesini (asıl ve küçük kopya) siler. Silinen birincilse en yeni fotoğraf birincil olur; başka fotoğraf yoksa odanın avatar alanı null kalır.
Parametreler
slugstringpathzorunlu
Oda slug'ı (büyük/küçük harf fark etmez)
iduuidpathzorunlu
Silinecek fotoğrafın kimliği
Yanıtlar
204Silindi; gövde boş
403Odanın yöneticisi değilsin (not_admin)
404Oda yok (room_not_found) ya da fotoğraf yok (not_found)
Mesajların kendisi REST'ten değil WebSocket'ten gider (message:new). Bu gruptaki çağrılar dosyanın yolculuğunu yönetir: önce presign ile MinIO'ya doğrudan yüklenecek bir PUT linki alınır, dosya o linke yüklenir, sonra socket'te message:new içindeki attachment ile yalnızca dönen key'ler gönderilir. Yükleme linkleri 600 sn (10 dk), mesajlardaki indirme linkleri (url, thumb_url) 3600 sn (1 saat) geçerlidir; bayatlayan link buradaki uçlardan tazelenir. Hepsi yalnız oda üyelerine açıktır: oda yoksa 404 room_not_found, üye değilsen 403 not_member.
GET/api/rooms/{slug}/media
🔑 oda üyesi
Medya galerisi
Odanın fotoğraf ve video mesajlarını yeniden eskiye döner: grup sayfasındaki ve profildeki Medya sekmesi. GIF, çıkartma, tek gösterimlik ve silinmiş mesajlar listede yoktur; yöneticilere ayrılmış (audience: "admins") satırları yalnız yöneticiler, oda geçmişi kapalıysa (history_for_new_members: false) yeni üye yalnız katıldıktan sonrakileri görür. Her mesaj taze presigned linklerle (url, thumb_url, 1 saat) gelir.
›Sayfalama zaman imleciyle yapılır: bir sonraki sayfa için son mesajın inserted_at değerini before olarak gönder. Karşılaştırma kesin (<) olduğundan aynı milisaniyede gönderilmiş iki medyadan biri sayfa sınırında atlanabilir.
›Geçersiz from (UUID değil) ve sayı olmayan before / limit hata vermez, yok sayılır.
Parametreler
slugstringpathzorunlu
Oda slug'ı
fromuuidqueryisteğe bağlı
Yalnız bu hesabın gönderdikleri (profildeki Medya sekmesi)
beforemsqueryisteğe bağlı
Bu andan (ms epoch) önce gönderilenler; ilk sayfada verilmez
limitintegerqueryisteğe bağlı
Sayfa boyu; varsayılan 60, 1–100 arasına çekilir
Yanıtlar
200{media: [mesaj], has_more} — has_more: true ise daha eskisi var
{"has_more":true,"media":[{"attachment":{"byte_size":412876,"content_type":"image/jpeg","height":1200,"key":"room-media/9b7e3c1a-52d4-4e8f-a1c6-3f0d2b8e7a14/c41d7a90-1e5b-4f3c-8d26-7a9b0c1d2e3f.jpg","thumb_key":"room-media/9b7e3c1a-52d4-4e8f-a1c6-3f0d2b8e7a14/c41d7a90-1e5b-4f3c-8d26-7a9b0c1d2e3f-thumb.jpg","thumb_url":"https://mskop-api.gurerlabs.com/makroskop-media/room-media/9b7e3c1a-52d4-4e8f-a1c6-3f0d2b8e7a14/c41d7a90-1e5b-4f3c-8d26-7a9b0c1d2e3f-thumb.jpg?X-Amz-Signature=91d4e2f0…","type":"image","url":"https://mskop-api.gurerlabs.com/makroskop-media/room-media/9b7e3c1a-52d4-4e8f-a1c6-3f0d2b8e7a14/c41d7a90-1e5b-4f3c-8d26-7a9b0c1d2e3f.jpg?X-Amz-Signature=5e0c9b7a…","width":1600},"audience":"all","body":"İkinci yarının ilk golü, tribün yıkıldı #derbi","deleted":false,"delivered":true,"edited_at":null,"event":null,"forwarded_from":null,"hashtags":["#derbi"],"id":"a9ea4f12-7c3b-4d1e-9f80-2b6c5d7e8f90","inserted_at":1791967272345,"kind":"image","mentions":[],"parent_id":null,"reactions":[{"account_id":"fdea8b31-6c2f-4a9e-b7d4-1e3f5a6c8b02","emoji":"🔥","username":"mehmet"}],"reply_to":null,"rsvps":null,"sender":{"account_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","role":"admin","tag":"kaptan","username":"ayse"},"seq":1842,"thread_closed":false,"thread_count":2,"thread_participants":[{"account_id":"fdea8b31-6c2f-4a9e-b7d4-1e3f5a6c8b02","avatar":null,"username":"mehmet"}],"thread_senders":[{"account_id":"fdea8b31-6c2f-4a9e-b7d4-1e3f5a6c8b02","username":"mehmet"}],"views":14}]}
DeneÖnce token gir: otomatik eklenir
GET/api/rooms/{slug}/media/{id}
🔑 oda üyesi
Medya için taze link
Tek bir fotoğraf, video, GIF ya da çıkartma mesajını yeni presigned linklerle döner. Mesajdaki linkler 1 saatte bayatlar; küçük kopyayı yerelde saklayan cihaz büyük dosyayı isterken buraya sorar. Metin, belge gibi başka türden bir mesaj ya da silinmiş mesaj 404 döner.
›Tek gösterimlik (view_once: true) mesajda link ve anahtar hiç gelmez; o dosya yalnız socket'teki message:open_once ile, bir kez açılır.
Parametreler
slugstringpathzorunlu
Oda slug'ı
iduuidpathzorunlu
Mesajın kimliği
Yanıtlar
200{message} — taze url ve thumb_url ile
403Odanın üyesi değilsin (not_member)
404Oda yok (room_not_found), ya da mesaj yok, silinmiş ya da medya değil (not_found)
Fotoğraf, video, GIF ya da çıkartma mesajı için iki presigned PUT linki verir: dosyanın kendisi (full) ve küçük kopyası (thumb). İstemci ikisini de dönen url'lere doğrudan PUT eder (10 dk içinde), sonra socket'te message:new ile attachment: {type, key, thumb_key, content_type, width, height, byte_size} gönderir. Anahtarlar bu odanın room-media/<oda kimliği>/ önekindedir; başka bir odada kullanılamaz.
›thumb_content_type kabul edilenler: image/jpeg, image/png, image/webp. Verilmezse video ve GIF için image/jpeg, diğerlerinde dosyanın kendi türü. Saydamlığı korunması gereken çıkartmada image/png gönder.
›Sınırlar message:new anında denetlenir (yükleme sırasında değil), aşılırsa socket invalid_attachment döner. Fotoğraf: image/jpeg, image/png, image/webp; en çok 8 MiB (8.388.608 bayt) ve kenar başına 1–8192 px.
›Video: yalnız video/mp4; en çok 16 MiB (16.777.216 bayt), duration_ms 1–10.500. GIF: image/gif ya da image/webp; en çok 8 MiB. Çıkartma: image/webp, image/png ya da image/gif; en çok 2 MiB (2.097.152 bayt), isteğe bağlı pack_id ([A-Za-z0-9_.:-]{1,64}) ve emoji (1–8 karakter).
›Tek gösterimlik (view_once: true, yalnız birebir sohbette, fotoğraf ya da video) mesajda thumb_key gönderilmez; thumb linki kullanılmadan bırakılır.
Bir belge için tek bir presigned PUT linki verir. İstemci dosyayı put.url'e yükler (10 dk içinde), sonra socket'te message:new ile attachment: {type: "document", key, name, content_type, byte_size} gönderir. Belge bir ödünçtür: dosya gönderildikten expires_in saniye (1 saat) sonra sunucudan silinir, mesaj satırı kalır.
›En çok 10 MiB (10.485.760 bayt, yanıttaki max_bytes). Boyut message:new anında byte_size ile denetlenir; name orada boş olmamalı ve en çok 200 karakter olmalı, yoksa socket invalid_attachment döner.
›İki süre karıştırılmamalı: put.expires_in (600) yükleme linkinin ömrü, üst düzeydeki expires_in (3600) belgenin gönderildikten sonra sunucuda kalacağı süre.
Parametreler
slugstringpathzorunlu
Oda slug'ı
content_typestringbodyzorunlu
Belgenin MIME türü; yukarıdaki listeden biri
namestringbodyzorunlu
Dosyanın görünen adı; burada yalnız varlığı denetlenir, anahtara girmez
Belge mesajını, dosya hâlâ sunucudayken yeni bir indirme linkiyle döner. Link belgenin kalan ömrüyle (ttl_left saniye) sınırlıdır, belgeden uzun yaşayamaz. Belgenin saati dolduysa 410 document_expired döner: belge buradaydı, uygulama bunu "süresi doldu" diye göstermeli.
›Socket'ten gelen ya da senkronlanan belge mesajında da expired ve ttl_left bulunur; süresi geçmiş kartta expired: true ve url: null olur, ad ve boyut kalır.
Parametreler
slugstringpathzorunlu
Oda slug'ı
iduuidpathzorunlu
Belge mesajının kimliği
Yanıtlar
200{message} — attachment.url taze
403Odanın üyesi değilsin (not_member)
404Oda yok (room_not_found), ya da mesaj yok, silinmiş ya da belge değil (not_found)
{"message":{"attachment":{"byte_size":845213,"content_type":"application/pdf","expired":false,"expires_in":3600,"extension":"pdf","key":"room-docs/9b7e3c1a-52d4-4e8f-a1c6-3f0d2b8e7a14/5d2e8f1a-9c3b-4e7d-b0a1-6c4f2e8d9a3b.pdf","name":"Sezon Bütçesi 2026.pdf","ttl_left":2741,"type":"document","url":"https://mskop-api.gurerlabs.com/makroskop-media/room-docs/9b7e3c1a-52d4-4e8f-a1c6-3f0d2b8e7a14/5d2e8f1a-9c3b-4e7d-b0a1-6c4f2e8d9a3b.pdf?X-Amz-Signature=a17c4e0d…"},"audience":"all","body":"Bütçe taslağı, toplantıdan önce bakın","deleted":false,"delivered":true,"edited_at":null,"event":null,"forwarded_from":null,"hashtags":[],"id":"6b1d9e4f-2a7c-4c3e-8f5b-9d0e1a2b3c4d","inserted_at":1791968740512,"kind":"document","mentions":[],"parent_id":null,"reactions":[],"reply_to":null,"rsvps":null,"sender":{"account_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","role":"admin","tag":"kaptan","username":"ayse"},"seq":1846,"thread_closed":false,"thread_count":0,"thread_participants":[],"thread_senders":[],"views":3}}
DeneÖnce token gir: otomatik eklenir
POST/api/rooms/{slug}/messages/{id}/share
🔑 oda üyesi · makalenin yazarı
Makaleyi sözlüğe gönder
Yazar kendi makale mesajını (kind: "article") sözlüğün moderasyon kuyruğuna gönderir; gövde yoktur. Topic'i makalenin etiketi belirler: önce kartın kendi hashtag'i, yoksa mesajın ilk hashtag'i (# atılır, küçük harfe çevrilir). 201 yayımlandı değil kuyruğa alındı demektir: kararı bir moderatör verir, uygulama yazara bunu söylemeli.
›Sözlük kendi kopyasını saklar (başlık + blokların düz metni): mesaj sonradan düzenlense ya da odanın otomatik silmesiyle gitse de kayıt kalır.
›Etiketin henüz topic'i yoksa güncel konsol makaleyi reddetmez, bekleyen bir topic önerisi açar; bu durumda yanıttaki topic.statuspending olur. topic konsol bilgi vermezse null gelebilir.
›Yalnız Makroskop'un kendi odalarında çalışır; bir organizasyonun odasındaki makale 403 not_available_in_organization alır.
›503 sozluk_unavailable ret değil arızadır: yazara "tekrar dene" denmeli, "makalen reddedildi" değil.
403Üye değilsin (not_member), makale senin değil (not_author), oda bir organizasyonun (not_available_in_organization) ya da yayın yasağın var (sozluk_author_banned; message moderatörün gerekçesidir)
404Sunucuda sözlük ayarlı değil ya da mesaj yok / silinmiş (not_found); oda yok (room_not_found)
409Bu makale kuyrukta zaten var (sozluk_already_shared)
422Mesaj makale değil (not_an_article), makalenin etiketi yok (sozluk_tag_required) ya da eski konsollarda etiketin topic'i yok (sozluk_topic_not_found)
503Sözlüğe ulaşılamadı ya da tanınmayan yanıt verdi (sozluk_unavailable)
curl -X POST https://mskop-api.gurerlabs.com/api/rooms/fenerbahce-taraftar/messages/d4a8c2e6-1b3f-4d5a-9e7c-8f0b2d4e6a1c/share \
-H "Authorization: Bearer $ACCESS_TOKEN"
{"share":{"entry_id":7342,"message":"Yazın sözlük kuyruğuna alındı; bir moderatör onaylayınca yayımlanacak.","status":"pending","topic":{"status":"published","tag":"derbi","title":"Derbi"}}}
DeneÖnce token gir: otomatik eklenir
Bağlantı önizleme ve analitik
Mesajdaki bir linkin altındaki kartı sunucu hazırlar: sayfayı telefon değil backend çeker, böylece linkteki site odada kimin okuduğunu görmez. Analitik ucu ise uygulamanın Keşfet'te yaptıklarını (topic, makale, kategori açılışları) yerel kuyruğundan toplu olarak yükler; olaylar yalnız sayılır, mesaj içeriği hiçbir zaman okunmaz. İkisi de rumuzu seçilmiş bir hesabın token'ını ister.
GET/api/link-preview
🔒 Bearer token⏱ hesap başına 60/dk
Bağlantı önizleme kartı
Verilen adresin başlığını, kısa açıklamasını, site adını ve ikonunu döner. Sonuçlar normalleştirilmiş adrese göre (şema ve host küçük harf, #fragment atılır) önbelleğe alınır: başarılı önizleme 24 saat, başarısızlık 1 saat saklanır; aynı adres için aynı anda gelen istekler tek çekişi bekler. 404 preview_unavailable gelirse uygulama kart çizmeden yalnız linki gösterir.
›SSRF koruması: yalnız http/https, yalnız port 80 ve 443, adreste kullanıcı/şifre olmamalı, en çok 2048 karakter. Ad sunucuda çözülür ve çözüldüğü her adres denetlenir; biri bile yasaklıysa reddedilir: loopback, özel ağlar (10/8, 172.16/12, 192.168/16), link-local (169.254/16, bulut metadata adresi dahil), CGNAT (100.64/10), 0.0.0.0/8, multicast, ayrılmış ve belgeleme aralıkları, IPv6 ::1, fc00::/7, fe80::/10, fec0::/10, ff00::/8 ve içinde bunları taşıyan her IPv6 biçimi. 2130706433, 127.1 gibi sayısal yazımlar da reddedilir.
›Bağlantı denetlenen adrese açılır (DNS rebinding'e yer kalmaz). En çok 3 yönlendirme, her adım baştan denetlenir; sayfa + ikon için toplam 5 sn; sayfanın en çok 512 KB'ı okunur ve yalnız text/html işlenir. İstekler User-Agent: MakroskopBot/1.0 (+https://makroskop.gurerlabs.com) ile, çerezsiz gider.
›Başlık og:title, twitter:title, title sırasıyla, en çok 200 karakter; açıklama og:description, twitter:description, meta description sırasıyla, en çok 300 karakter; site adı og:site_name. İkon en çok 64 KB'lık PNG, ICO, JPEG, GIF ya da WebP olur (SVG hiç kullanılmaz) ve data: URI olarak döner; bulunamazsa null.
›ASCII dışı karakterli adresler olduğu gibi gönderilebilir (çiçek.com.tr): alan adı punycode'a, geri kalanı yüzde kodlamasına çevrilir.
›Rate limit önbellekten dönen ve reddedilen istekleri de sayar.
Parametreler
urlstringqueryzorunlu
Önizlenecek adres, yüzde kodlanmış; en çok 2048 karakter
Yanıtlar
200{url, final_url, title, description, site_name, icon}; url sorulduğu gibi, final_url yönlendirmelerden sonraki adres
404Sayfa çekilemedi, HTML değil, 2xx dönmedi, başlığı yok ya da bir yönlendirme yasaklı bir yere gidiyor (preview_unavailable)
422url yok, http/https değil, port 80/443 değil, kullanıcı/şifre içeriyor, çok uzun ya da hedef adres yasaklı (invalid_url)
429Hesap başına dakikada 60 istek aşıldı (rate_limited)
{"description":"Maçın ardından basın toplantısına çıkan teknik direktör, ikinci yarıdaki oyun değişikliğini anlattı.","final_url":"https://www.ornek.com/haber/derbi-sonrasi","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAA…","site_name":"Örnek Haber","title":"Derbi sonrası teknik direktörden açıklama","url":"https://ornek.com/haber/derbi-sonrasi"}
DeneÖnce token gir: otomatik eklenir
POST/api/analytics/events
🔒 Bearer token⏱ hesap başına 30 paket/dk
Keşfet davranış olayları (toplu)
Uygulamanın yerel kuyruğundaki Keşfet olaylarını tek pakette yükler; olaylar yalnız eklenir ve saatlik bir iş onları kişi başına bir ilgi profiline çevirir (istek anında hiçbir şey puanlanmaz). Geçersiz olaylar hata vermez, sessizce düşer ve ignored içinde sayılır; aynı id ikinci kez gelirse saklanmaz, duplicates olarak sayılır. Hesapta personalized_ads: false ise paket kabul edilir ama hiçbir şey saklanmaz: 200 {accepted: 0, duplicates: 0, ignored: n}.
›id: istemcinin ürettiği kimlik (ör. UUID v4), 1–64 karakter, yalnız [A-Za-z0-9_-]. Tekilleştirme hesap + id üzerinden yapılır; paket içindeki tekrar da duplicates sayılır.
›type ve zorunlu alanı: topic_open için topic; entry_open için entry_id; entry_read için entry_id ve duration_ms; category_open için category.
›at: olayın anı, ms epoch; son 30 gün ile 5 dk ileri arasında olmalı, yoksa olay düşer.
›topic küçük harfe çevrilir ve baştaki # atılır (en çok 120 karakter); category en çok 64 karakter; entry_id pozitif tam sayı; author_id UUID; source en çok 32 karakter (ör. topic_list, chat_card, my_entries, link); duration_ms 6 saatle sınırlanır. topic, category ve author_id ipucudur: iş kategoriyi sözlükten kendisi çözer.
›Paket en çok 100 olay taşır (fazlası 413, rate limit'e sayılmaz). Dakikada 30 paket sınırı personalized_ads kapalıyken de işler.
›Önerilen istemci davranışı: her 2xx'te paketi gönderildi say; 413 ve 429 dışındaki 4xx'te paketi at (asla geçmeyecek); 5xx, ağ hatası ve 429'da geri çekilerek tekrar dene.
Parametreler
eventsobject[]bodyzorunlu
En çok 100 olay; şekil ve kurallar aşağıda
Yanıtlar
200{accepted, duplicates, ignored} — yeni saklanan, zaten var olan ve düşen olay sayıları
400Gövdede events listesi yok (invalid_request)
413Pakette 100'den fazla olay var (too_many_events)
429Hesap başına dakikada 30 paket aşıldı (rate_limited)
Keşfet, sözlüğün uygulamadaki yüzüdür. Kategoriler, topic'ler ve makaleler (entry) yönetim konsolunun sözlüğünden okunur; backend bunlara yalnız kendisinin bildiklerini ekler: yazarın güncel rumuzu ve fotoğrafı, tepki sayıları, kaynak grubun tartışması, görüntülenme ve paylaşım sayaçları. Yalnız moderatörün yayımladığı topic ve makaleler görünür. Sunucuda sözlük ayarlı değilse bu gruptaki her uç 404 not_found döner; sözlüğe ulaşılamazsa ya da beklenmedik bir yanıt gelirse 503 sozluk_unavailable (ret değil arıza, tekrar denenebilir). Topic listesi ve etiket önerileri oturumun diliyle (PUT /api/me/device ile bildirilen language) süzülür; dili boş topic'ler her dilde, dil hiç bildirilmediyse tüm topic'ler görünür. Sayfalama limit/offset iledir: topic'ler ve Makalelerim varsayılan 30 (en çok 100), bir topic'in makaleleri varsayılan 20 (en çok 50); geçersiz değerler reddedilmez, sınıra çekilir. Makale kimlikleri tam sayıdır; tüm zamanlar ms epoch'tur.
GET/api/discover/categories
🔒 Bearer token
Kategoriler
Keşfet'in kategori çiplerini konsoldaki sırasıyla döner; arşivlenmiş kategoriler gelmez. Topic listesini süzmek için slug kullanılır.
Yayımlanmış topic'leri makale sayısına göre çoktan aza döner. Her topic'in yanında share (bu süzgeçteki tüm yayımlanmış makalelerin yüzdesi, 2 hane) ve listedeki sırası rank (offset'ten devam eder) gelir. Oturumun diliyle süzülür.
Parametreler
categorystringqueryisteğe bağlı
Yalnız bu kategorinin topic'leri (kategori slug'ı)
Makale yazarken hashtag alanının önerileri: etiketi ya da başlığının bir kelimesi q ile başlayan en çok 5 yayımlanmış topic, makale sayısına göre çoktan aza. q'nun başındaki # atılır; q boşsa en popüler 5 topic gelir. Oturumun diliyle süzülür.
Parametreler
qstringqueryisteğe bağlı
Yazılan etiketin başı
Yanıtlar
200{topics: [{tag, title, entry_count}]}, en çok 5
Tek bir yayımlanmış topic'i döner. Liste dışında sorulduğu için share her zaman 0.0, rank her zaman null'dır. Yayımlanmamış ya da bilinmeyen etiket 404 döner; bu uç dil süzgeci uygulamaz.
Parametreler
tagstringpathzorunlu
Topic'in etiketi (küçük harf, # olmadan)
Yanıtlar
200{topic}
404Topic yok ya da yayımlanmamış, veya sunucuda sözlük ayarlı değil (not_found)
Bir topic'in yayımlanmış makalelerini tam makale nesnesiyle döner. new (varsayılan) yayın tarihine göre yeniden eskiye, old tersi, top toplam tepki sayısına göre (eşitlikte yeni olan önce) sıralar; tanınmayan sortnew sayılır. Yanıtta total yoktur, devamı has_more ile anlaşılır.
Parametreler
tagstringpathzorunlu
Topic'in etiketi
sortstringqueryisteğe bağlı
new | old | top
limitintegerqueryisteğe bağlı
Sayfa boyu; varsayılan 20, en çok 50
offsetintegerqueryisteğe bağlı
Atlanacak kayıt sayısı; varsayılan 0
Yanıtlar
200{entries: [entry], has_more}
404Topic yok ya da yayımlanmamış, veya sunucuda sözlük ayarlı değil (not_found)
{"entries":[{"author":{"account_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","avatar":null,"username":"ayse"},"blocks":[{"text":"İlk yarı dengeli geçti; iki takım da orta sahayı kapatmayı seçti.","type":"p"},{"text":"Değişiklikler","type":"h"},{"text":"İkinci yarıda yapılan iki değişiklik oyunun dengesini tamamen bozdu.","type":"p"}],"body":"İlk yarı dengeli geçti; iki takım da orta sahayı kapatmayı seçti.\n\nİkinci yarıda yapılan iki değişiklik oyunun dengesini tamamen bozdu.","discussion":{"available":true,"is_member":true,"message_id":"d4a8c2e6-1b3f-4d5a-9e7c-8f0b2d4e6a1c","reply_count":0,"room":{"member_count":48,"name":"Fenerbahçe Taraftar","slug":"fenerbahce-taraftar","visibility":"open"},"thread_participants":[]},"excerpt":"İlk yarı dengeli geçti; iki takım da orta sahayı kapatmayı seçti.","id":7341,"link":"https://sozluk.gurerlabs.com/e/7341","media":[],"mine":false,"published_at":1791919800000,"reaction_total":41,"reactions":[{"count":41,"emoji":"🔥"}],"reshare_count":1,"stats_visible":true,"title":"Derbide ikinci yarı neden koptu?","topic":{"tag":"derbi","title":"Derbi"}}],"has_more":true}
DeneÖnce token gir: otomatik eklenir
GET/api/discover/entries/{id}
🔒 Bearer token
Makale
Tek bir yayımlanmış makaleyi döner; sohbetteki makale kartı ve sözlük linki buraya açılır. blocks makalenin grupta yazıldığı hâlidir; kaynak mesaj silinmişse null ve media: [] olur, uygulama o zaman body'yi çizer. discussion.available kaynak mesaj hâlâ odadaysa ve grup açıksa ya da okuyan üyeyse true olur.
›reactions yalnız emoji başına sayıdır; kimin tepki verdiği hiçbir zaman dönmez.
›author.avatar yazarın fotoğraf görünürlük ayarına uyar; gizliyse null. media ve avatar linkleri 1 saatlik presigned GET'lerdir.
›reshare_count: kökü bu makalenin mesajı olan iletiler ile bu makalenin sohbet kartlarının toplamı (silinenler hariç).
›stats_visible: okuyan yazarsa ya da kaynak grup açıksa true; GET /api/discover/entries/{id}/stats için.
Parametreler
idintegerpathzorunlu
Makalenin (entry) kimliği
Yanıtlar
200{entry}
404Makale yok ya da yayımlanmamış, veya sunucuda sözlük ayarlı değil (not_found)
{"entry":{"author":{"account_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","avatar":{"thumb_url":"https://mskop-api.gurerlabs.com/makroskop-media/avatars/f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21/1a3c5e7b-9d2f-4b6a-8c0e-2f4a6c8e0b1d-thumb.jpg?X-Amz-Signature=f1b3d5e7…","url":"https://mskop-api.gurerlabs.com/makroskop-media/avatars/f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21/1a3c5e7b-9d2f-4b6a-8c0e-2f4a6c8e0b1d.jpg?X-Amz-Signature=2e4a6c8d…"},"username":"ayse"},"blocks":[{"text":"İlk yarı dengeli geçti; iki takım da orta sahayı kapatmayı seçti.","type":"p"},{"text":"Değişiklikler","type":"h"},{"text":"İkinci yarıda yapılan iki değişiklik oyunun dengesini tamamen bozdu.","type":"p"},{"text":"Son yirmi dakikada tribünün baskısı da sahaya yansıdı.","type":"quote"}],"body":"İlk yarı dengeli geçti; iki takım da orta sahayı kapatmayı seçti.\n\nİkinci yarıda yapılan iki değişiklik oyunun dengesini tamamen bozdu.\n\nSon yirmi dakikada tribünün baskısı da sahaya yansıdı.","discussion":{"available":true,"is_member":false,"message_id":"d4a8c2e6-1b3f-4d5a-9e7c-8f0b2d4e6a1c","reply_count":12,"room":{"member_count":48,"name":"Fenerbahçe Taraftar","slug":"fenerbahce-taraftar","visibility":"open"},"thread_participants":[{"account_id":"fdea8b31-6c2f-4a9e-b7d4-1e3f5a6c8b02","avatar":null,"username":"mehmet"}]},"excerpt":"İlk yarı dengeli geçti; iki takım da orta sahayı kapatmayı seçti.","id":7341,"link":"https://sozluk.gurerlabs.com/e/7341","media":[{"height":900,"thumb_url":"https://mskop-api.gurerlabs.com/makroskop-media/room-media/9b7e3c1a-52d4-4e8f-a1c6-3f0d2b8e7a14/e2c4a6b8-0d1f-4a3c-9e5b-7d9f1b3d5f7a-thumb.jpg?X-Amz-Signature=b5d7f9a1…","url":"https://mskop-api.gurerlabs.com/makroskop-media/room-media/9b7e3c1a-52d4-4e8f-a1c6-3f0d2b8e7a14/e2c4a6b8-0d1f-4a3c-9e5b-7d9f1b3d5f7a.jpg?X-Amz-Signature=6c0e2a4f…","width":1600}],"mine":false,"published_at":1791919800000,"reaction_total":209,"reactions":[{"count":125,"emoji":"❤️"},{"count":84,"emoji":"😂"}],"reshare_count":3,"stats_visible":true,"title":"Derbide ikinci yarı neden koptu?","topic":{"tag":"derbi","title":"Derbi"}}}
DeneÖnce token gir: otomatik eklenir
GET/api/discover/entries/{id}/discussion
🔒 Bearer token
Makalenin tartışması (salt okunur)
Kaynak gruptaki makale mesajının altındaki tartışmayı, gruba katılmadan okumak için döner: root makale mesajı, messages yanıtlar (eskiden yeniye), şekil socket'teki mesajla aynı. Grup açıksa herkes, kapalıysa yalnız üyeler okuyabilir. Üye olan uygulama tartışmaya her zamanki gibi socket'ten yazar; bu uç yalnız okumak içindir.
{"is_member":false,"messages":[{"attachment":null,"audience":"all","body":"Bence asıl kırılma 70. dakikadaki oyuncu değişikliği.","deleted":false,"delivered":true,"edited_at":null,"event":null,"forwarded_from":null,"hashtags":[],"id":"e7b9d1f3-5a2c-4e8b-a0d6-3c5e7a9b1d2f","inserted_at":1791919800000,"kind":"text","mentions":[],"parent_id":"d4a8c2e6-1b3f-4d5a-9e7c-8f0b2d4e6a1c","reactions":[],"reply_to":null,"rsvps":null,"sender":{"account_id":"fdea8b31-6c2f-4a9e-b7d4-1e3f5a6c8b02","role":"member","tag":null,"username":"mehmet"},"seq":1795,"thread_closed":false,"thread_count":0,"thread_participants":[],"thread_senders":[],"views":0}],"room":{"name":"Fenerbahçe Taraftar","slug":"fenerbahce-taraftar","visibility":"open"},"root":{"attachment":{"blocks":[{"text":"İlk yarı dengeli geçti; iki takım da orta sahayı kapatmayı seçti.","type":"p"},{"text":"Değişiklikler","type":"h"}],"hashtag":"derbi","media":[],"title":"Derbide ikinci yarı neden koptu?","type":"article"},"audience":"all","body":"","deleted":false,"delivered":true,"edited_at":null,"event":null,"forwarded_from":null,"hashtags":[],"id":"d4a8c2e6-1b3f-4d5a-9e7c-8f0b2d4e6a1c","inserted_at":1791827110000,"kind":"article","mentions":[],"parent_id":null,"reactions":[],"reply_to":null,"rsvps":null,"sender":{"account_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","role":"admin","tag":"kaptan","username":"ayse"},"seq":1790,"thread_closed":false,"thread_count":12,"thread_participants":[{"account_id":"fdea8b31-6c2f-4a9e-b7d4-1e3f5a6c8b02","avatar":null,"username":"mehmet"}],"thread_senders":[{"account_id":"fdea8b31-6c2f-4a9e-b7d4-1e3f5a6c8b02","username":"mehmet"}],"views":0}}
DeneÖnce token gir: otomatik eklenir
POST/api/discover/entries/{id}/view
🔒 Bearer token
Görüntülendi sayacı
Makale kartı ekranda yaklaşık 1 sn kalınca çağrılır. Kişi + makale + gün (UTC) başına bir kez sayılır; aynı gün tekrar çağırmak zararsızdır. Gövde yoktur; sözlüğe gidilmez ve makalenin varlığı denetlenmez, yalnız id'nin pozitif tam sayı olması istenir.
Parametreler
idintegerpathzorunlu
Makalenin (entry) kimliği
Yanıtlar
204Sayıldı (ya da bugün zaten sayılmıştı); gövde boş
404id pozitif tam sayı değil, ya da sunucuda sözlük ayarlı değil (not_found)
curl -X POST https://mskop-api.gurerlabs.com/api/discover/entries/7341/view \
-H "Authorization: Bearer $ACCESS_TOKEN"
Makale bir sohbete iletildiğinde (forward) ya da linki kopyalandığında (link) çağrılır; her çağrı ayrı bir paylaşım olarak sayılır ve istatistikteki shares alanına yansır. Makalenin varlığı denetlenmez. İletinin kendisi socket'ten attachment: {type: "entry", entry_id} ile gider; bu uç yalnız sayaçtır.
Parametreler
idintegerpathzorunlu
Makalenin (entry) kimliği
viastringbodyzorunlu
forward (sohbete iletme) | link (link kopyalama)
Yanıtlar
204Sayıldı; gövde boş
400via yok ya da forward / link değil (invalid_request)
404id pozitif tam sayı değil, ya da sunucuda sözlük ayarlı değil (not_found)
Makalenin sayılarını döner: görüntülenme (views toplam, viewers tekil kişi), tepkiler, tartışmadaki yanıtlar, yeniden paylaşımlar ve paylaşım sayaçları. Yazar her zaman görebilir; başkaları yalnız kaynak grup açıksa (makaledeki stats_visible). Kapalı grubun makalesi herkese açık okunur ama üyelerinin tepkisi grubun kendisinindir.
Ben → Makalelerim: kişinin sözlüğe gönderdiği her makale, durumu ne olursa olsun (pending, published, rejected). Reddedilenlerde review_note moderatörün notudur. Yalnız published olanlar ayrıca excerpt, blocks, media ve reshare_count taşır; bekleyen ve reddedilende bu alanlar hiç yoktur.
{"entries":[{"created_at":1791969600000,"id":7342,"published_at":null,"review_note":null,"status":"pending","title":"Hakem kararları maçı nasıl etkiledi?","topic":{"status":"published","tag":"derbi","title":"Derbi"}},{"blocks":[{"text":"İlk yarı dengeli geçti; iki takım da orta sahayı kapatmayı seçti.","type":"p"},{"text":"Değişiklikler","type":"h"}],"created_at":1791828000000,"excerpt":"İlk yarı dengeli geçti; iki takım da orta sahayı kapatmayı seçti.","id":7341,"media":[],"published_at":1791919800000,"reshare_count":3,"review_note":null,"status":"published","title":"Derbide ikinci yarı neden koptu?","topic":{"status":"published","tag":"derbi","title":"Derbi"}},{"created_at":1791642125000,"id":7120,"published_at":null,"review_note":"Kaynak belirtilmemiş; düzenleyip tekrar gönderebilirsin.","status":"rejected","title":"Stadyum bileti fiyatları","topic":{"status":"pending","tag":"bilet-fiyatlari","title":"Bilet Fiyatları"}}],"total":3}
DeneÖnce token gir: otomatik eklenir
Sponsorlu içerik
Sohbet listesindeki ve Keşfet'teki sponsorlu satırlar. Satırları organizasyonlar işletme panelinde yazar, konsolda onaylanınca yayına girer; uygulama gösterilebilecekleri buradan ister, nereye koyacağına kendisi karar verir ve olanı (gösterim, dokunma, gizleme) geri bildirir. Üç yerleşim vardır: chats (sohbet listesi), discover_topics (Keşfet topic listesi) ve discover_entries (topic'in makale listesi). Makroskop Premium hesaplarına hiçbir zaman satır gelmez. Hedefleme cihazın dili ve platformu (PUT /api/me/device) ile isteğe bağlı anonim bir kitledir; kitle bilgisi uygulamaya hiç dönmez.
GET/api/sponsored
🔒 Bearer token
Sponsorlu satırlar
Bu kişiye bu cihazda, bu yerleşimde şu an gösterilebilecek yayındaki satırları döner. Kitlesi olan (hedefli) satır yalnız ilgi profili eşleşen kişiye gelir ve önde sıralanır, sonra hedefsizler; her grupta bu yerleşimde bugün görülmemiş olanlar önce, gerisi rastgele. Profili olmayan ya da personalized_ads: false kişi yalnız hedefsiz satırları görür; gizlenen (hide) satırlar hiç gelmez.
›Diğer listelerin aksine geçersiz değer sınıra çekilmez: tanınmayan placement ya da sayı olmayan / 1'den küçük limit400 döner. 5'ten büyük limit 5'e indirilir.
›Cihaz dil ya da platform bildirmediyse tr ve android varsayılır.
›image_url ve thumb_url 1 saatlik presigned GET'lerdir; resim yoksa null. thumb_url küçük kopya yoksa tam boy resme düşer.
›target_kind: url (https adresi), room (bir grubun slug'ı) ya da deeplink. Hedef click yanıtında da döner.
{"items":[{"advertiser":{"name":"Örnek Spor Mağazası","verified":true},"body":"Yeni sezon formaları ve atkılar bu hafta yüzde 25 indirimli.","id":"2f9c4e1a-8b3d-4a6f-9c2e-5d7a1b3c9e4f","image_url":"https://mskop-api.gurerlabs.com/makroskop-media/sponsored/8c1e3a5b-7d9f-4b2c-a4e6-0f2b4d6a8c1e/4b6d8f0a-2c4e-4a6c-8e0b-1d3f5b7d9f2a.jpg?X-Amz-Signature=7f1a3c5e…","target":"https://ornek.com/kampanya/forma","target_kind":"url","thumb_url":"https://mskop-api.gurerlabs.com/makroskop-media/sponsored/8c1e3a5b-7d9f-4b2c-a4e6-0f2b4d6a8c1e/9a1c3e5f-7b2d-4f6a-8c0e-3d5f7b9d1e4c.jpg?X-Amz-Signature=0d2f4b6a…","title":"Deplasman formalarında sezon indirimi"},{"advertiser":{"name":"Örnek Taraftar Derneği","verified":false},"body":"Maç günleri canlı yorum ve anket burada.","id":"6a8c0e2b-4d6f-4b1a-9c3e-7f9b1d3a5c8e","image_url":null,"target":"ornek-taraftar-kulubu","target_kind":"room","thumb_url":null,"title":"Taraftar sohbet grubuna katıl"}]}
DeneÖnce token gir: otomatik eklenir
POST/api/sponsored/{id}/impression
🔒 Bearer token
Gösterim bildir
Satır ya da kart yarısı ekranda 1 sn kalınca çağrılır. Kişi + satır + gün + yerleşim başına yalnız ilk çağrı sayılır ve organizasyonun gösterim kredisinden bir düşer; tekrarlar da 204 döner, uygulamanın kontrol etmesine gerek yoktur. Satır bütçesine ulaşınca yayından kalkar; organizasyonun kredisi biterse tüm satırları duraklatılır.
Satıra dokunulduğunda çağrılır ve gidilecek hedefi döner; uygulama target_kind'e göre linki, grubu ya da deeplink'i açar. Tıklama yalnız o gün o satır için bir gösterim sayılmışsa ve kişi + gün + yerleşim başına bir kez sayılır; placement verilmezse bugün görüldüğü herhangi bir yerleşim kullanılır. Az önce duraklatılan ya da biten satırda da hedef döner, böylece dokunuş boşa gitmez.
Satırın ⋮ menüsündeki "Bunu gösterme": bu satır bu kişiye bir daha hiçbir yerleşimde gelmez. Gövde yoktur; aynı satırı ikinci kez gizlemek zararsızdır. Uygulama satırı yanıtı beklemeden listeden kaldırabilir.
Parametreler
iduuidpathzorunlu
Sponsorlu satırın kimliği
Yanıtlar
204Gizlendi; gövde boş
404Satır yok ya da id UUID değil (not_found)
curl -X POST https://mskop-api.gurerlabs.com/api/sponsored/2f9c4e1a-8b3d-4a6f-9c2e-5d7a1b3c9e4f/hide \
-H "Authorization: Bearer $ACCESS_TOKEN"
İşletme paneli (mk-panel), uygulamadaki hesabın bir cihazı gibi çalışır. Kişi panele GlobalTrustID ile girer; bu giriş henüz bir hesaba bağlı değilse panel bir QR gösterir (app.gurerlabs.makroskop://panel-link?code=KOD). Uygulama QR'ı okutur, bu gruptaki uçlarla kimin bağlanmak istediğini gösterir ve kişiden onay alır. Ardından panel kendi oturumunu alır: telefondakiyle aynı türden bir token çifti (platform: "web_app"). Kod 180 saniye geçerlidir ve tek kullanımlıktır. Aynı GlobalTrustID girişi daha sonra QR istemeden doğrudan hesaba bağlanır. Bu uçları uygulama, kişinin kendi token'ıyla çağırır. Rumuz seçilmiş olmalıdır (403 username_required).
GET/api/panel-links/{code}
🔒 Bearer token
QR kodunu önizle
Uygulama QR'ı okuttuktan sonra, onay ekranını çizmek için bu ucu çağırır. Ekranda panelin hangi tarayıcıdan açıldığı (label) ve GlobalTrustID girişindeki maskeli ad (name_hint) gösterilir. Bu çağrı kodu harcamaz; kod ancak onaylanınca kullanılmış sayılır.
›label ve name_hint paneli çalıştıran sunucudan gelir ve null olabilir. Uygulama bu durumda genel bir metin göstermelidir.
›expires_in, kodun kaç saniye daha geçerli olduğunu söyler. Onay ekranında geri sayım göstermek için kullanılabilir.
Kişi onay ekranında "Evet" dediğinde çağrılır. Panelin GlobalTrustID girişini, token'ın sahibi olan hesaba bağlar. Gövde yoktur. Panel bir sonraki yoklamasında kendi oturumunu alır; bu oturum yalnız bir kez teslim edilir ve ardından kod harcanmış olur.
›Panel girişi hesapla anahtarlı bir özet (HMAC) üzerinden bağlanır. GlobalTrustID'nin sub değeri ve kodun kendisi saklanmaz; koddan yalnız SHA-256 özeti tutulur.
›Aynı panel girişi başka bir hesaba zaten bağlıysa yeni bağ kurulmaz ve 409 already_used döner.
Parametreler
codestringpathzorunlu
QR'daki code değeri
Yanıtlar
204Bağlandı; gövde boş
401Token geçersiz (unauthorized) ya da süresi dolmuş (token_expired)
403Rumuz henüz seçilmemiş (username_required)
404Böyle bir kod yok (not_found)
409Kod zaten onaylanmış, ya da bu panel girişi zaten bir hesaba bağlı (already_used)
410Kodun süresi dolmuş (expired)
curl -X POST https://mskop-api.gurerlabs.com/api/panel-links/517A05VtAO4pdsc4O3HsRSaz6LVNmoM8/confirm \
-H "Authorization: Bearer $ACCESS_TOKEN"
Hesaba bağlı web panellerini en yenisi başta olacak şekilde listeler. Uygulamadaki "Bağlı cihazlar" ekranı bu listeyle çizilir. Kişi buradan bir paneli seçip bağını koparabilir.
›linked_at ve last_used_at ms epoch değerleridir. last_used_at, panelin bu bağla en son oturum açtığı anı gösterir; panel henüz oturum almadıysa null olabilir.
›label, bağlanırken bildirilen tarayıcıdır (en çok 64 karakter) ve null olabilir.
Yanıtlar
200Liste döndü (bağlı panel yoksa boş dizi)
401Token geçersiz (unauthorized) ya da süresi dolmuş (token_expired)
Paneli hesaptan ayırır. O panelin bütün oturumları aynı anda silinir. Panelin elindeki access token'ın süresi dolmamış olsa bile, /api/panel/* uçlarına yapacağı bir sonraki istek 401 alır; refresh token'ı da artık çalışmaz. Aynı GlobalTrustID girişiyle yeniden bağlanmak için QR adımı baştan yapılmalıdır.
Parametreler
iduuidpathzorunlu
GET /api/me/panels listesindeki id
Yanıtlar
204Bağ koparıldı; gövde boş
401Token geçersiz (unauthorized) ya da süresi dolmuş (token_expired)
403Rumuz henüz seçilmemiş (username_required)
404Böyle bir panel yok, bu hesaba ait değil ya da id UUID değil (not_found)
Bu uçlar işletme panelinin (mk-panel) kendi API'sidir. Her istek, panel bağlamayla alınmış oturumun access token'ını taşır (Authorization: Bearer ACCESS_TOKEN); token'ın süresi dolunca POST /api/auth/refresh ile yenilenir. Sunucu her istekte oturumun hâlâ var olup olmadığına bakar. Kişi uygulamadan panelin bağını koparırsa, token'ın süresi dolmamış olsa bile bir sonraki istek hemen 401 unauthorized alır. Rumuz seçilmiş olmalıdır (403 username_required). Organizasyon gerektiren uçlar, kişinin organizasyonu yoksa 404 no_organization döner. Organizasyonu owner ve admin rolleri yönetir; sponsorlu içeriği owner, admin ve ads rolleri yapar. Bu rollerin dışında kalanlar 403 not_allowed alır. Bu gruptaki bütün zamanlar ms epoch'tur.
GET/api/panel/me
🔒 Bearer token
Panel başlangıç verisi
Panelin bütün sayfaları bu tek yanıttan beslenir. Yanıtta kimin oturum açtığı, organizasyonu ve oradaki rolü, organizasyonun paketi ve kalan kredileri bulunur. Formların seçim listeleri (catalog) ve satın alınabilecek paketler (products) de lang diliyle adlandırılmış olarak gelir.
›Kişinin organizasyonu yoksa organization ve role alanları null gelir. Panel bu durumda organizasyon kurma formunu göstermelidir.
›billing yalnız şirket organizasyonlarında ve yalnız owner ya da admin rolüne gelir; diğer durumlarda null olur.
›slug_editable, organizasyonun hiç odası yokken true olur. İlk oda kurulunca önek (slug) kilitlenir.
›subscription yürürlükteki pakettir, yoksa null olur. pending_request, konsolun onayını bekleyen paket isteğidir, yoksa null olur. balances alanında her sayaç (message, ai, impression, verification) her zaman bulunur.
›Paket fiyatı KDV ayarına göre bölünür: price_cents girilen fiyattır; net_cents ve vat_cents faturada yazacak tutarlardır. Bir çeviri eksikse önce İngilizcesi, o da yoksa Türkçesi gösterilir.
Parametreler
langstringqueryisteğe bağlı
tr ya da en. Verilmezse ya da başka bir değerse tr kullanılır
Yanıtlar
200Başlangıç verisi döndü
401Token geçersiz ya da panel bağı koparılmış (unauthorized), ya da token'ın süresi dolmuş (token_expired)
{"account":{"account_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","premium":false,"username":"osmangurer"},"catalog":{"group_types":[{"description":null,"id":"ddc21e4d-7f33-4241-ab80-d91c76eb079f","name":"İşletme","slug":"business"},{"description":null,"id":"3b9f6c0e-5d21-4a8e-9c47-1e2f8a6b7d30","name":"Müşteri Hizmetleri","slug":"customer-service"}],"organization_types":[{"description":null,"id":"870ce7d4-33be-4603-b23c-c5aa9d6e123d","name":"E-ticaret firması","slug":"e-commerce"},{"description":null,"id":"ed28856f-375b-4b59-95b6-7015efed5625","name":"Yazılım firması","slug":"software"}],"positions":[{"description":null,"id":"a6082456-0c3e-4ece-9c17-faa434bdb657","name":"IT / Bilişim","slug":"it"},{"description":null,"id":"e585a71d-987b-470a-906b-35f66438f38d","name":"Reklamcı / Grafiker","slug":"advertising"}]},"organization":{"balances":{"ai":500,"impression":8730,"message":9412,"verification":0},"billing":{"address":"Caferağa Mah. Moda Cad. No: 12","city":"İstanbul","contact_phone":"+902165550101","country":"TR","district":"Kadıköy","legal_name":"Kargo Lojistik Anonim Şirketi","postal_code":"34710","region":"Marmara","tax_id":"4829157365","tax_office":"Kadıköy"},"created_at":1790928845000,"display_name":"Kargo A.Ş.","id":"e5b8ec80-e426-4e4f-b6e4-dea3da782ba5","kind":"company","pending_request":null,"position_id":null,"purpose":"Müşterilerimize gönderilerinin durumunu anında bildirmek ve kampanyalarımızı duyurmak.","slug":"kargo-a-s","slug_editable":false,"status":"active","subscription":{"ends_at":1793521241000,"id":"a8100fcf-bd6e-40c4-9de1-3236eabfd7a3","product":{"ai_credits":500,"bullets":["Ayda 10.000 işletme mesajı","Web sitesi entegrasyonu","Panelden cevap","AI ile otomatik cevap (500 kredi)","Sponsorlu içerik (10.000 gösterim)"],"currency":"USD","description":null,"features":["web_chat","panel_reply","ai","sponsored"],"id":"44b16db2-bbff-46d1-903f-c5682075a8a6","impression_quota":10000,"message_quota":10000,"name":"Pro","net_cents":1666,"price_cents":1999,"seats":5,"slug":"pro","vat_cents":333,"vat_included":true},"starts_at":1790929241000,"status":"active"},"team_size":5,"type_id":"870ce7d4-33be-4603-b23c-c5aa9d6e123d","verified":true},"products":[{"ai_credits":0,"bullets":["Ayda 100 işletme mesajı","Web chat denemesi"],"currency":"USD","description":null,"features":["web_chat_trial"],"id":"de473219-5a5a-49b6-ad6c-1e2b11518546","impression_quota":0,"message_quota":100,"name":"Ücretsiz","net_cents":0,"price_cents":0,"seats":1,"slug":"free","vat_cents":0,"vat_included":true},{"ai_credits":500,"bullets":["Ayda 10.000 işletme mesajı","Web sitesi entegrasyonu","Panelden cevap","AI ile otomatik cevap (500 kredi)","Sponsorlu içerik (10.000 gösterim)"],"currency":"USD","description":null,"features":["web_chat","panel_reply","ai","sponsored"],"id":"44b16db2-bbff-46d1-903f-c5682075a8a6","impression_quota":10000,"message_quota":10000,"name":"Pro","net_cents":1666,"price_cents":1999,"seats":5,"slug":"pro","vat_cents":333,"vat_included":true}],"role":"owner"}
DeneÖnce token gir: otomatik eklenir
POST/api/panel/organization
🔒 Bearer token
Organizasyon kur
Kişinin organizasyonunu kurar ve kişiyi organizasyonun sahibi (owner) yapar. Bir kişinin en fazla bir organizasyonu olabilir. Organizasyon iki türlü kurulur: individual (bireysel) ya da company (şirket). Örnek gövde bir şirket içindir; bireysel kurulumun gövdesi aşağıdaki notlardadır.
›Bireysel kurulum: {"kind": "individual", "display_name": "Ayşe Yılmaz Tasarım", "purpose": "Müşterilerime iş takibi ve duyuru", "position_id": "POSITION_ID"}. Bireysel organizasyonda type_id, team_size ve billing alanlarına bakılmaz.
›Şirket kurulumunda type_id ve billing zorunludur. billing alanlarından legal_name, tax_office, tax_id, address, city ve country (ISO-2, ör. TR) zorunludur; district, region, postal_code ve contact_phone isteğe bağlıdır. Her alan kırpılır ve en çok 200 karaktere kısaltılır.
›Türkiye'de tax_id ya kontrol basamağı tutan 10 haneli bir VKN ya da şahıs şirketi için 11 haneli bir TCKN olmalıdır; aksi hâlde 422 invalid_tax_id döner. Başka ülkelerde 2–32 harf ve rakamdan oluşmalıdır. contact_phone içindeki boşluk, parantez, nokta ve tire atılır; kalan kısım 7–20 rakam olmalıdır (başta + olabilir).
›slug (organizasyon öneki) Makroskop genelinde tekildir. Önce kırpılır ve küçük harfe çevrilir, sonra ^[a-z0-9]+(-[a-z0-9]+)*$ biçimine uyan 3–48 karakter olmalıdır. Ayrılmış kelimeler (admin api app console destek help konsol official panel resmi root sozluk support system www) ve makroskop ile başlayan önekler 422 invalid_slug alır. Önek boş bırakılırsa görünen addan üretilir; o önek alınmışsa sonuna -2, -3 eklenir.
›Yeni organizasyonun paketi yoktur ve bütün kredileri 0'dır. Paket POST /api/panel/organization/package ile istenir.
Parametreler
langstringqueryisteğe bağlı
Yanıttaki paket adlarının dili: tr (varsayılan) ya da en
kindstringbodyzorunlu
individual ya da company. Sonradan değiştirilemez
display_namestringbodyzorunlu
Görünen ad, 2–80 karakter (kırpılır)
purposestringbodyzorunlu
Organizasyonun ne için kullanılacağı, en çok 1000 karakter
position_iduuidbodyisteğe bağlı
Yalnız individual için: catalog.positions listesindeki bir id
type_iduuidbodyisteğe bağlı
company için zorunlu: catalog.organization_types listesindeki bir id
team_sizeintegerbodyisteğe bağlı
Yalnız company için: ekip büyüklüğü, 1–20
billingobjectbodyisteğe bağlı
company için zorunlu: fatura bilgileri (alanlar notlarda)
201Kuruldu; organization ve role: "owner" döner (GET /api/panel/me ile aynı şekil)
400Zorunlu bir alan eksik ya da geçersiz: bilinmeyen kind, katalogda olmayan type_id/position_id, aralık dışında team_size, bozuk country ya da contact_phone (invalid_request)
401Token geçersiz ya da panel bağı koparılmış (unauthorized), ya da token'ın süresi dolmuş (token_expired)
403Rumuz henüz seçilmemiş (username_required)
409Kişinin zaten bir organizasyonu var (already_in_organization) ya da önek başkasında (slug_taken)
422Vergi numarası geçersiz (invalid_tax_id) ya da önek kurallara uymuyor (invalid_slug)
🔑 owner · admin⏱ organizasyon başına günde 10 önek değişikliği
Organizasyonu düzenle
Organizasyonun kendisi hakkında söylediklerini değiştirir. Alanlar kuruluştakilerle aynıdır ve hepsi isteğe bağlıdır; gönderilmeyen alan olduğu gibi kalır. kind hiçbir zaman değişmez. Şirket organizasyonunda billing içinde gönderilen alanlar eskilerinin yerine yazılır; diğer fatura alanları korunur.
›Önek (slug) yalnız slug_editable iken, yani organizasyonun hiç odası yokken değiştirilebilir. Odası varken farklı bir önek göndermek 409 slug_locked döner. Organizasyonun zaten sahip olduğu öneki göndermek değişiklik sayılmaz.
›Yeni bir önek denemek organizasyon başına günde en çok 10 kez yapılabilir; sınır aşılınca 429 rate_limited döner. Böylece başkalarının hangi önekleri aldığı tek tek denenerek bulunamaz.
›position_id ya da type_id için boş metin ya da null göndermek o alanı temizler.
Parametreler
langstringqueryisteğe bağlı
Yanıttaki paket adlarının dili: tr (varsayılan) ya da en
display_namestringbodyisteğe bağlı
Görünen ad, 2–80 karakter
purposestringbodyisteğe bağlı
En çok 1000 karakter
position_iduuidbodyisteğe bağlı
Yalnız individual için; catalog.positions listesinden
type_iduuidbodyisteğe bağlı
Yalnız company için; catalog.organization_types listesinden
team_sizeintegerbodyisteğe bağlı
Yalnız company için; 1–20
billingobjectbodyisteğe bağlı
Yalnız company için; değişecek fatura alanları
slugstringbodyisteğe bağlı
Yeni önek; kurallar kuruluştakiyle aynı
Yanıtlar
200Güncellendi; organization ve role döner
400Bir alan geçersiz (invalid_request)
401Token geçersiz ya da panel bağı koparılmış (unauthorized), ya da token'ın süresi dolmuş (token_expired)
403Rol owner ya da admin değil (not_allowed), ya da rumuz seçilmemiş (username_required)
404Kişinin organizasyonu yok (no_organization)
409Organizasyonun odası var, önek kilitli (slug_locked), ya da önek başkasında (slug_taken)
422Önek kurallara uymuyor (invalid_slug) ya da vergi numarası geçersiz (invalid_tax_id)
429Günlük önek denemesi hakkı doldu (rate_limited)
Organizasyon için bir paket ister. Ücretsiz paket hemen açılır: yürürlükteki paket biter ve sayaçlar yeni paketin kotalarına ayarlanır (üstüne eklenmez). Ücretli paket ödeme altyapısı olmadığı için konsolun onayını bekler; bu sürede pending_request alanında görünür. Yeniden paket istemek önceki bekleyen isteğin yerine geçer.
Parametreler
langstringqueryisteğe bağlı
Yanıttaki paket adlarının dili: tr (varsayılan) ya da en
product_iduuidbodyzorunlu
products listesindeki bir paketin id'si
Yanıtlar
200İstek alındı (ya da ücretsiz paket açıldı); organization ve role döner
400product_id gönderilmedi (invalid_request)
401Token geçersiz ya da panel bağı koparılmış (unauthorized), ya da token'ın süresi dolmuş (token_expired)
403Rol owner ya da admin değil (not_allowed), ya da rumuz seçilmemiş (username_required)
404Kişinin organizasyonu yok (no_organization), ya da paket bilinmiyor veya satışta değil (not_found)
Organizasyonun her sayaçta kalan kredisini ve kredi hareketlerinin en yeni 50 kaydını döner. Paketten ya da konsoldan gelen krediler pozitif, harcamalar negatif quantity ile yazılır. Bakiye hızlı cevaptır; asıl kayıt hareketlerdir.
›source değerleri: grant:package (paket açıldı; note paketin slug'ı), grant:manual (konsoldan ek kredi), impression (bir sponsorlu gösterim için harcanan kredi).
›Sayaçlar: message, ai, impression, verification.
Yanıtlar
200Bakiyeler ve hareketler döndü
401Token geçersiz ya da panel bağı koparılmış (unauthorized), ya da token'ın süresi dolmuş (token_expired)
Kişinin kurduğu (founded) ve yönettiği (administered) grupları döner. Her grup, uygulamadaki oda nesnesiyle aynı şekildedir; ek olarak panelde seçilen grup türünü taşıyan group_type_id alanı vardır. Uygulamadan kurulmuş gruplarda bu alan null gelir. Bu uç organizasyon istemez.
Yanıtlar
200Gruplar döndü
401Token geçersiz ya da panel bağı koparılmış (unauthorized), ya da token'ın süresi dolmuş (token_expired)
{"administered":[],"founded":[{"created_at":"2026-10-02T08:31:17.512903Z","discussions_enabled":false,"events_visibility":"all","founder_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","gifts":0,"group_type_id":"3b9f6c0e-5d21-4a8e-9c47-1e2f8a6b7d30","history_for_new_members":true,"id":"9b7e2c41-6f0a-4d8e-b3a5-2c7d9e1f4a60","join_approval":false,"kind":"group","level":0,"member_denied":[],"members_can_pin":false,"members_can_video":false,"message_ttl_hours":null,"name":"Kargo Destek","peer":null,"pinned":null,"pins":[],"short_link":"mskp.io/kargo-destek","show_gifts":true,"show_members":true,"show_welcome":true,"slug":"kargo-destek","star_gated":false,"stars":0,"vanity_code":null,"visibility":"open","wallpaper":"okyanus","welcome_message":"Hoş geldin {username}! Gönderi numaranı yaz, hemen bakalım."}]}
DeneÖnce token gir: otomatik eklenir
POST/api/panel/groups
🔒 Bearer token
Grup kur
Panelden yeni bir grup kurar; kurucusu oturumu açan kişidir. Uygulamadaki oda kurmanın aynısıdır, ancak burada grup türü (group_type_id) zorunludur. Grup kurulunca uygulamada da kişinin oda listesinde görünür.
›slug verilmezse addan üretilir; üretilen slug alınmışsa sonuna rastgele bir ek konur. Açıkça verilen bir slug alınmışsa 422 validation_failed döner (fields.slug).
Parametreler
namestringbodyzorunlu
Grup adı, 1–80 karakter
group_type_iduuidbodyzorunlu
catalog.group_types listesindeki bir id
slugstringbodyisteğe bağlı
3–48 karakter, ^[a-z0-9]+(-[a-z0-9]+)*$
visibilitystringbodyisteğe bağlı
open (varsayılan: bağlantıyı bilen katılır) ya da closed (kişiyi bir yönetici ekler)
welcome_messagestringbodyisteğe bağlı
Yeni üyeye odanın yazacağı karşılama metni, en çok 500 karakter; {username} rumuzla değiştirilir
{"room":{"created_at":"2026-10-02T08:31:17.512903Z","discussions_enabled":false,"events_visibility":"all","founder_id":"f6cad462-3b1e-4d6a-9a77-2c1e0b8f4d21","gifts":0,"group_type_id":"3b9f6c0e-5d21-4a8e-9c47-1e2f8a6b7d30","history_for_new_members":true,"id":"9b7e2c41-6f0a-4d8e-b3a5-2c7d9e1f4a60","join_approval":false,"kind":"group","level":0,"member_count":1,"member_denied":[],"members_can_pin":false,"members_can_video":false,"message_ttl_hours":null,"my_role":"founder","name":"Kargo Destek","peer":null,"pinned":null,"pins":[],"short_link":"mskp.io/kargo-destek","show_gifts":true,"show_members":true,"show_welcome":true,"slug":"kargo-destek","star_gated":false,"stars":0,"vanity_code":null,"visibility":"open","wallpaper":"okyanus","welcome_message":"Hoş geldin {username}! Gönderi numaranı yaz, hemen bakalım."}}
DeneÖnce token gir: otomatik eklenir
GET/api/panel/sponsored
🔒 Bearer token
Sponsorlu içeriklerim
Organizasyonun bütün sponsorlu satırlarını, en yenisi başta olacak şekilde döner. Her satırın durumu, bütçesi, gösterim ve tıklama sayıları ve hedef kitlesi yanıtta bulunur. Görsel linkleri kısa ömürlü, imzalı GET adresleridir.
›Durumlar: draft (taslak), review (konsolun onayını bekliyor), live (yayında), paused (duraklatıldı), rejected (reddedildi; sebep reject_reason alanında), ended (bütçe doldu).
›budget satırın en çok kaç gösterim alacağıdır. Gösterim sayısı bütçeye ulaşınca satır ended olur. Organizasyonun impression kredisi biterse yayındaki bütün satırları paused olur.
›audience her zaman bir nesnedir. Hedefsiz bir satırda {"interests": [], "activity": "any", "segments": []} gelir.
Yanıtlar
200Liste döndü
401Token geçersiz ya da panel bağı koparılmış (unauthorized), ya da token'ın süresi dolmuş (token_expired)
{"items":[{"audience":{"activity":"medium","interests":["teknoloji","ekonomi"],"segments":["group_active"]},"body":"Gönderi numaranı Kargo Destek grubuna yaz, durumunu saniyeler içinde söyleyelim.","budget":5000,"clicks":84,"created_at":1791548100000,"ends_at":1795132800000,"id":"42aff321-6614-4a11-921c-eb401d18eb46","image_key":"sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/5705db63-17b2-4109-88fa-c367bb9c3111.webp","image_url":"https://mskop-api.gurerlabs.com/makroskop-media/sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/5705db63-17b2-4109-88fa-c367bb9c3111.webp?X-Amz-Signature=…","impressions":1270,"languages":["tr"],"platforms":[],"reject_reason":null,"reviewed_at":1791637200000,"reviewed_by":"editor@gurerlabs.com","starts_at":1791637500000,"status":"live","target":"kargo-destek","target_kind":"room","thumb_key":"sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/961cb17c-f383-413b-9a36-bc720cf19a2d.webp","thumb_url":"https://mskop-api.gurerlabs.com/makroskop-media/sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/961cb17c-f383-413b-9a36-bc720cf19a2d.webp?X-Amz-Signature=…","title":"Kargon nerede, anında öğren","updated_at":1791637200000}]}
DeneÖnce token gir: otomatik eklenir
POST/api/panel/sponsored
🔑 owner · admin · ads
Sponsorlu taslak oluştur
Yeni bir sponsorlu satırı taslak (draft) olarak oluşturur. Taslak yayına kendiliğinden çıkmaz: önce submit ile incelemeye gönderilir, konsol onaylayınca yayına girer. Organizasyonun paketinde sponsored özelliği bulunmalı ve organizasyon askıya alınmamış olmalıdır.
›Hedef türleri: url yalnız https:// adresi olabilir (kullanıcı bilgisi içermemeli, alan adında nokta olmalı). room var olan bir grubun slug'ı olmalıdır. deeplinkşema://… biçiminde olmalıdır; javascript, data, file, content, intent, about, blob ve vbscript şemaları yasaktır. target en çok 500 karakterdir.
›Görsel önce POST /api/panel/sponsored/media ile yüklenir; dönen key burada image_key, küçük kopyanınki thumb_key olarak verilir. Anahtar organizasyonun kendi sponsored/ORG_ID/ önekinde olmalıdır.
›audience: interests sözlüğün kategori slug'larıdır (en çok 20); kişinin ilgi alanlarından herhangi biri eşleşmelidir. activity en düşük etkinlik seviyesidir (any, low, medium, high). segments listesindeki bütün segmentler kişide bulunmalıdır. Hepsi boşsa hedefleme yapılmaz ve satır herkese gösterilir. Seçenekler GET /api/panel/sponsored/audience-options ile alınır.
›languages ve platforms boş bırakılırsa satır bütün dillerde ve platformlarda gösterilir. starts_at ve ends_at ms epoch'tur; ends_at, starts_at'ten sonra olmalıdır.
›Metinlerdeki fazla boşluklar teke indirilir. Satırın budget değeri gönderilmezse 0 kalır; bu durumda submit reddedilir.
Parametreler
titlestringbodyzorunlu
Başlık, 2–60 karakter
bodystringbodyzorunlu
Metin, 2–140 karakter
target_kindstringbodyzorunlu
url, room ya da deeplink
targetstringbodyzorunlu
Hedef: https adresi, grup slug'ı ya da derin bağlantı; en çok 500 karakter
image_keystringbodyisteğe bağlı
sponsored/media yanıtındaki key
thumb_keystringbodyisteğe bağlı
Küçük kopyanın key değeri
languagesstring[]bodyisteğe bağlı
tr, en; boş liste bütün diller demektir
platformsstring[]bodyisteğe bağlı
android, ios; boş liste bütün platformlar demektir
budgetintegerbodyisteğe bağlı
En çok gösterim sayısı, 100–10.000.000
starts_atmsbodyisteğe bağlı
Yayın başlangıcı (ms epoch) ya da null
ends_atmsbodyisteğe bağlı
Yayın bitişi (ms epoch) ya da null; başlangıçtan sonra olmalı
audienceobjectbodyisteğe bağlı
Hedef kitle {interests, activity, segments}; null herkes demektir
Yanıtlar
201Taslak oluştu; item döner
400Bir alan eksik, aralık dışında ya da hedef geçersiz; görsel anahtarı başka bir organizasyonun ya da bitiş başlangıçtan önce (invalid_request)
401Token geçersiz ya da panel bağı koparılmış (unauthorized), ya da token'ın süresi dolmuş (token_expired)
403Rol yetmiyor (not_allowed), pakette sponsored özelliği yok (feature_unavailable), organizasyon askıda (organization_suspended), ya da rumuz seçilmemiş (username_required)
404Kişinin organizasyonu yok (no_organization)
422Bilinmeyen kategori, segment ya da etkinlik seviyesi, veya 20'den fazla ilgi alanı (invalid_audience)
503Kategorileri doğrulamak için sözlüğe ulaşılamadı (sozluk_unavailable)
curl -X POST https://mskop-api.gurerlabs.com/api/panel/sponsored \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"audience":{"activity":"medium","interests":["teknoloji","ekonomi"],"segments":["group_active"]},"body":"Gönderi numaranı Kargo Destek grubuna yaz, durumunu saniyeler içinde söyleyelim.","budget":5000,"ends_at":1795132800000,"image_key":"sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/5705db63-17b2-4109-88fa-c367bb9c3111.webp","languages":["tr"],"starts_at":1792454400000,"target":"kargo-destek","target_kind":"room","thumb_key":"sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/961cb17c-f383-413b-9a36-bc720cf19a2d.webp","title":"Kargon nerede, anında öğren"}'
const res = await fetch("https://mskop-api.gurerlabs.com/api/panel/sponsored", {
method: "POST",
headers: {
"Authorization": "Bearer " + accessToken,
"Content-Type": "application/json",
},
body: JSON.stringify({"audience":{"activity":"medium","interests":["teknoloji","ekonomi"],"segments":["group_active"]},"body":"Gönderi numaranı Kargo Destek grubuna yaz, durumunu saniyeler içinde söyleyelim.","budget":5000,"ends_at":1795132800000,"image_key":"sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/5705db63-17b2-4109-88fa-c367bb9c3111.webp","languages":["tr"],"starts_at":1792454400000,"target":"kargo-destek","target_kind":"room","thumb_key":"sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/961cb17c-f383-413b-9a36-bc720cf19a2d.webp","title":"Kargon nerede, anında öğren"}),
});
const data = await res.json();
{"item":{"audience":{"activity":"medium","interests":["teknoloji","ekonomi"],"segments":["group_active"]},"body":"Gönderi numaranı Kargo Destek grubuna yaz, durumunu saniyeler içinde söyleyelim.","budget":5000,"clicks":0,"created_at":1791969153000,"ends_at":1795132800000,"id":"42aff321-6614-4a11-921c-eb401d18eb46","image_key":"sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/5705db63-17b2-4109-88fa-c367bb9c3111.webp","image_url":"https://mskop-api.gurerlabs.com/makroskop-media/sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/5705db63-17b2-4109-88fa-c367bb9c3111.webp?X-Amz-Signature=…","impressions":0,"languages":["tr"],"platforms":[],"reject_reason":null,"reviewed_at":null,"reviewed_by":null,"starts_at":1792454400000,"status":"draft","target":"kargo-destek","target_kind":"room","thumb_key":"sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/961cb17c-f383-413b-9a36-bc720cf19a2d.webp","thumb_url":"https://mskop-api.gurerlabs.com/makroskop-media/sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/961cb17c-f383-413b-9a36-bc720cf19a2d.webp?X-Amz-Signature=…","title":"Kargon nerede, anında öğren","updated_at":1791969153000}}
DeneÖnce token gir: otomatik eklenir
POST/api/panel/sponsored/media
🔑 owner · admin · ads
Sponsorlu görsel yükle
Sponsorlu satırın görselini sunucuya yükler. İstek gövdesi JSON değildir; doğrudan resmin baytlarıdır ve türü Content-Type başlığında bildirilir. Her satır için iki kez çağrılır: biri asıl görsel, diğeri küçük kopya (yaklaşık 160 px, kare). Dönen key değerleri taslağın image_key ve thumb_key alanlarına yazılır.
›Kabul edilen türler image/jpeg, image/png ve image/webp'tir; boyut en çok 2 MB olabilir. Sunucu baytların gerçekten bildirilen türde olup olmadığını kontrol eder. Uyuşmazsa, dosya boşsa ya da 2 MB'ı aşıyorsa 422 invalid_media döner.
›Dosya organizasyonun sponsored/ORG_ID/ önekine rastgele bir adla kaydedilir. Hiçbir taslağa bağlanmayan dosya kendiliğinden silinmez.
›Pakette sponsored özelliği bulunmalı ve organizasyon askıda olmamalıdır.
400Gövde alınırken bağlantı koptu ya da zaman aşımı oldu (invalid_request)
401Token geçersiz ya da panel bağı koparılmış (unauthorized), ya da token'ın süresi dolmuş (token_expired)
403Rol yetmiyor (not_allowed), pakette sponsored özelliği yok (feature_unavailable), organizasyon askıda (organization_suspended), ya da rumuz seçilmemiş (username_required)
404Kişinin organizasyonu yok (no_organization)
422Desteklenmeyen tür, boş ya da 2 MB'tan büyük dosya, veya bildirilen türle uyuşmayan baytlar (invalid_media)
Bu uç gövde olarak resmin ham baytlarını bekler. Sayfadaki form yalnız JSON gönderebildiği için buradan denenemez; örnekteki curl --data-binary komutunu kullan.
GET/api/panel/sponsored/audience-options
🔑 owner · admin · ads
Hedef kitle seçenekleri
Sponsorlu formundaki hedef kitle seçeneklerini döner. İlgi alanları sözlüğün kategorileridir. Segmentler ve etkinlik seviyeleri hem Türkçe hem İngilizce etiketle gelir. Reklamveren tek bir kişiyi değil, yalnız anonim bir kitleyi hedefleyebilir.
Yanıtlar
200Seçenekler döndü
401Token geçersiz ya da panel bağı koparılmış (unauthorized), ya da token'ın süresi dolmuş (token_expired)
403Rol yetmiyor (not_allowed) ya da rumuz seçilmemiş (username_required)
404Kişinin organizasyonu yok (no_organization)
503Kategoriler için sözlüğe ulaşılamadı (sozluk_unavailable)
{"activity":[{"key":"any","label_en":"Everyone","label_tr":"Herkes"},{"key":"low","label_en":"Low and above","label_tr":"Düşük ve üstü"},{"key":"medium","label_en":"Medium and above","label_tr":"Orta ve üstü"},{"key":"high","label_en":"High","label_tr":"Yüksek"}],"categories":[{"name":"Teknoloji","slug":"teknoloji"},{"name":"Ekonomi","slug":"ekonomi"},{"name":"Spor","slug":"spor"}],"segments":[{"key":"group_active","label_en":"Active in groups","label_tr":"Gruplarda aktif"},{"key":"discussion_active","label_en":"Active in discussions","label_tr":"Tartışmalarda aktif"},{"key":"dm_active","label_en":"Active in direct messages","label_tr":"Birebir mesajlaşmada aktif"},{"key":"article_reader","label_en":"Reads articles","label_tr":"Makale okuyan"},{"key":"article_sharer","label_en":"Shares articles","label_tr":"Makale paylaşan"},{"key":"writer","label_en":"Writer (has published articles)","label_tr":"Yazar (yayında makalesi var)"}]}
DeneÖnce token gir: otomatik eklenir
POST/api/panel/sponsored/audience-estimate
🔑 owner · admin · ads
Kitle tahmini
Bir hedef kitlenin yaklaşık kaç kişiye ulaşacağını tahmin eder. Hedefli kitle, kişiselleştirilmiş reklamı kapatmamış hesapların ilgi profillerinden sayılır. Hedefsiz kitle ise sponsorlu satır görebilen herkesten sayılır; Premium hesaplar ve sistem hesabı bu sayıya girmez. languages ya da platforms verilirse yalnız o dilde ya da platformda oturumu olan kişiler sayılır.
›50 kişinin altındaki kitle için hiçbir zaman sayı verilmez: {"estimate": null, "label": "50'den az"} döner.
›50 ve üstü yuvarlanır: 1.000'e kadar 10'a, 10.000'e kadar 100'e, daha büyük sayılar 1.000'e yuvarlanır. Örnek: {"estimate": 1200, "label": "≈ 1.200"}.
Parametreler
audienceobjectbodyisteğe bağlı
{interests, activity, segments}; null ya da boş bırakılırsa herkes
languagesstring[]bodyisteğe bağlı
tr, en
platformsstring[]bodyisteğe bağlı
android, ios
Yanıtlar
200Tahmin döndü
400languages ya da platforms liste değil ya da bilinmeyen değer içeriyor (invalid_request)
401Token geçersiz ya da panel bağı koparılmış (unauthorized), ya da token'ın süresi dolmuş (token_expired)
403Rol yetmiyor (not_allowed) ya da rumuz seçilmemiş (username_required)
404Kişinin organizasyonu yok (no_organization)
422Hedef kitle geçersiz (invalid_audience)
503Kategorileri doğrulamak için sözlüğe ulaşılamadı (sozluk_unavailable)
Bir sponsorlu satırın alanlarını değiştirir. Alanlar oluşturmadakilerle aynıdır ve hepsi isteğe bağlıdır. Yayındaki, duraklatılmış ya da reddedilmiş bir satırda herhangi bir alan değişirse (hedef kitle dahil) satır taslağa (draft) döner, çünkü onaylanan içerik artık aynı değildir. Bu durumda yeniden submit gerekir.
›review ve ended durumundaki satırlar düzenlenemez (409 not_editable).
›audience: null hedeflemeyi kaldırır ve satır herkese gösterilir. image_key, thumb_key, starts_at ya da ends_at için null göndermek o alanı temizler.
›Bu çağrı satırdaki eski reject_reason değerini siler.
Parametreler
iduuidpathzorunlu
Sponsorlu satırın id'si
titlestringbodyisteğe bağlı
2–60 karakter
bodystringbodyisteğe bağlı
2–140 karakter
target_kindstringbodyisteğe bağlı
url, room ya da deeplink; target ile birlikte gönderilir
targetstringbodyisteğe bağlı
Yeni hedef; target_kind ile birlikte gönderilir
budgetintegerbodyisteğe bağlı
100–10.000.000 gösterim
ends_atmsbodyisteğe bağlı
Yayın bitişi (ms epoch) ya da null
audienceobjectbodyisteğe bağlı
Yeni hedef kitle ya da null
Yanıtlar
200Güncellendi; item döner
400Bir alan geçersiz (invalid_request)
401Token geçersiz ya da panel bağı koparılmış (unauthorized), ya da token'ın süresi dolmuş (token_expired)
403Rol yetmiyor (not_allowed) ya da rumuz seçilmemiş (username_required)
404Kişinin organizasyonu yok (no_organization), ya da satır yok veya bu organizasyonun değil (not_found)
409Satır review ya da ended durumunda (not_editable)
422Hedef kitle geçersiz (invalid_audience)
503Kategorileri doğrulamak için sözlüğe ulaşılamadı (sozluk_unavailable)
{"item":{"audience":{"activity":"any","interests":["teknoloji"],"segments":[]},"body":"Gönderi numaranı Kargo Destek grubuna yaz, durumunu saniyeler içinde söyleyelim.","budget":8000,"clicks":84,"created_at":1791548100000,"ends_at":1795132800000,"id":"42aff321-6614-4a11-921c-eb401d18eb46","image_key":"sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/5705db63-17b2-4109-88fa-c367bb9c3111.webp","image_url":"https://mskop-api.gurerlabs.com/makroskop-media/sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/5705db63-17b2-4109-88fa-c367bb9c3111.webp?X-Amz-Signature=…","impressions":1270,"languages":["tr"],"platforms":[],"reject_reason":null,"reviewed_at":1791637200000,"reviewed_by":"editor@gurerlabs.com","starts_at":1791637500000,"status":"draft","target":"kargo-destek","target_kind":"room","thumb_key":"sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/961cb17c-f383-413b-9a36-bc720cf19a2d.webp","thumb_url":"https://mskop-api.gurerlabs.com/makroskop-media/sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/961cb17c-f383-413b-9a36-bc720cf19a2d.webp?X-Amz-Signature=…","title":"Kargon nerede, anında öğren","updated_at":1791969302000}}
DeneÖnce token gir: otomatik eklenir
DELETE/api/panel/sponsored/{id}
🔑 owner · admin · ads
Sponsorlu satırı sil
Taslak (draft) ya da reddedilmiş (rejected) bir satırı ve görsellerini siler. Yayında olan, duraklatılmış, incelemedeki ya da bitmiş bir satır silinemez. Böyle bir satırı yayından kaldırmak için pause kullanılır.
Parametreler
iduuidpathzorunlu
Sponsorlu satırın id'si
Yanıtlar
204Silindi; gövde boş
401Token geçersiz ya da panel bağı koparılmış (unauthorized), ya da token'ın süresi dolmuş (token_expired)
403Rol yetmiyor (not_allowed) ya da rumuz seçilmemiş (username_required)
404Kişinin organizasyonu yok (no_organization), ya da satır yok (not_found)
409Satır taslak ya da reddedilmiş değil (not_editable)
Taslak ya da reddedilmiş bir satırı konsolun incelemesine (review) gönderir. Konsoldaki editör onaylarsa satır yayına (live) girer; reddederse rejected olur ve sebebi reject_reason alanına yazılır. Satırın bütçesi 0'dan büyük olmalı ve organizasyonun gösterim (impression) kredisi bulunmalıdır.
403Rol yetmiyor (not_allowed), pakette sponsored yok (feature_unavailable), organizasyon askıda (organization_suspended), ya da rumuz seçilmemiş (username_required)
404Kişinin organizasyonu yok (no_organization), ya da satır yok (not_found)
409Satır taslak ya da reddedilmiş değil (not_editable)
curl -X POST https://mskop-api.gurerlabs.com/api/panel/sponsored/42aff321-6614-4a11-921c-eb401d18eb46/submit \
-H "Authorization: Bearer $ACCESS_TOKEN"
{"item":{"audience":{"activity":"medium","interests":["teknoloji","ekonomi"],"segments":["group_active"]},"body":"Gönderi numaranı Kargo Destek grubuna yaz, durumunu saniyeler içinde söyleyelim.","budget":5000,"clicks":84,"created_at":1791548100000,"ends_at":1795132800000,"id":"42aff321-6614-4a11-921c-eb401d18eb46","image_key":"sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/5705db63-17b2-4109-88fa-c367bb9c3111.webp","image_url":"https://mskop-api.gurerlabs.com/makroskop-media/sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/5705db63-17b2-4109-88fa-c367bb9c3111.webp?X-Amz-Signature=…","impressions":1270,"languages":["tr"],"platforms":[],"reject_reason":null,"reviewed_at":1791637200000,"reviewed_by":"editor@gurerlabs.com","starts_at":1791637500000,"status":"paused","target":"kargo-destek","target_kind":"room","thumb_key":"sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/961cb17c-f383-413b-9a36-bc720cf19a2d.webp","thumb_url":"https://mskop-api.gurerlabs.com/makroskop-media/sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/961cb17c-f383-413b-9a36-bc720cf19a2d.webp?X-Amz-Signature=…","title":"Kargon nerede, anında öğren","updated_at":1791969302000}}
DeneÖnce token gir: otomatik eklenir
POST/api/panel/sponsored/{id}/resume
🔑 owner · admin · ads
Yayına devam et
Duraklatılmış (paused) ve daha önce konsolca onaylanmış bir satırı yeniden yayına (live) alır. Organizasyonun gösterim kredisi bulunmalı ve satır bütçesini doldurmamış olmalıdır. Kredi bittiği için sunucunun kendiliğinden duraklattığı satırlar, konsol kredi ekledikten sonra bu çağrıyla yeniden başlatılır.
Parametreler
iduuidpathzorunlu
Sponsorlu satırın id'si
Yanıtlar
200Yeniden yayında; item (status: "live") döner
401Token geçersiz ya da panel bağı koparılmış (unauthorized), ya da token'ın süresi dolmuş (token_expired)
402Gösterim kredisi kalmamış ya da satır bütçesini doldurmuş (insufficient_credits)
403Rol yetmiyor (not_allowed) ya da rumuz seçilmemiş (username_required)
404Kişinin organizasyonu yok (no_organization), ya da satır yok (not_found)
409Satır duraklatılmış değil ya da hiç onaylanmamış (not_editable)
curl -X POST https://mskop-api.gurerlabs.com/api/panel/sponsored/42aff321-6614-4a11-921c-eb401d18eb46/resume \
-H "Authorization: Bearer $ACCESS_TOKEN"
{"item":{"audience":{"activity":"medium","interests":["teknoloji","ekonomi"],"segments":["group_active"]},"body":"Gönderi numaranı Kargo Destek grubuna yaz, durumunu saniyeler içinde söyleyelim.","budget":5000,"clicks":84,"created_at":1791548100000,"ends_at":1795132800000,"id":"42aff321-6614-4a11-921c-eb401d18eb46","image_key":"sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/5705db63-17b2-4109-88fa-c367bb9c3111.webp","image_url":"https://mskop-api.gurerlabs.com/makroskop-media/sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/5705db63-17b2-4109-88fa-c367bb9c3111.webp?X-Amz-Signature=…","impressions":1270,"languages":["tr"],"platforms":[],"reject_reason":null,"reviewed_at":1791637200000,"reviewed_by":"editor@gurerlabs.com","starts_at":1791637500000,"status":"live","target":"kargo-destek","target_kind":"room","thumb_key":"sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/961cb17c-f383-413b-9a36-bc720cf19a2d.webp","thumb_url":"https://mskop-api.gurerlabs.com/makroskop-media/sponsored/e5b8ec80-e426-4e4f-b6e4-dea3da782ba5/961cb17c-f383-413b-9a36-bc720cf19a2d.webp?X-Amz-Signature=…","title":"Kargon nerede, anında öğren","updated_at":1791969302000}}
DeneÖnce token gir: otomatik eklenir
Gerçek zamanlı (WebSocket)
Mesajlar, okundu bilgileri, tepkiler, yazıyor göstergesi ve çevrimiçi durumu Phoenix Channels üzerinden akar. Adres wss://mskop-api.gurerlabs.com/socket/websocket?token=ACCESS_TOKEN&vsn=2.0.0 şeklindedir. Token başlıkta değil, sorgu dizesinde gönderilir. Long-polling kapalıdır; yalnız WebSocket kullanılır. Her frame bir JSON dizisidir: [join_ref, ref, topic, event, payload]. İstemcinin gönderdiği bir olayın yanıtı aynı ref ile phx_reply olarak gelir: {"status": "ok" | "error", "response": {...}}. Hata yanıtında response.reason bulunur; olaya özgü sebepler kartların notlarındadır. Kimlik her zaman token'dan alınır; payload'daki account_id yok sayılır. Sınırlar: message:new hesap başına 10 saniyede 20 mesajdır, gövde en çok 16 KB olabilir. Tepkiler aynı sınırla ayrı bir kovadan sayılır. Eğik çizgili komutlar hesap, oda ve komut başına dakikada 5 kez çalıştırılabilir. Bilinmeyen bir olay ya da biçimi tutmayan bir payload genellikle unknown_event alır. Hazır istemciler: web için phoenix (npm), Android için JavaPhoenixClient, iOS için SwiftPhoenixClient.
WS/socket/websocket?token={token}&vsn=2.0.0
🔒 Bearer token
Bağlantı aç
Uygulama açıkken tek bir WebSocket bağlantısı tutulur; oda ve kişi kanallarına bu bağlantı üzerinden katılınır. Token yalnız bağlanırken doğrulanır. Açık bağlantı, token'ın süresi dolsa da sürer. Bağlantı koparsa istemci, gerekirse önce token'ı yeniler, sonra taze token'la yeniden bağlanır.
›Token geçersizse, süresi dolmuşsa ya da hesabın rumuzu henüz seçilmemişse bağlantı HTTP 403 ile reddedilir. Bu durumda gövdede hata kodu gelmez; istemci önce POST /api/auth/refresh ile yeni token almayı denemelidir.
›Heartbeat: istemci 30 saniyede bir [null, "hb", "phoenix", "heartbeat", {}] gönderir. Sunucu 60 saniye boyunca hiç frame almazsa bağlantıyı kapatır.
›Tarayıcıdan bağlanan istemciler API'nin kendi alan adından gelmelidir (Origin kontrolü). Mobil uygulamalar Origin göndermez ve her zaman kabul edilir.
›Sunucu bir hesabın bütün bağlantılarını tek seferde kapatabilir. Bu, örneğin hesap silindiğinde olur.
Parametreler
tokenstringqueryzorunlu
Geçerli access token (Bearer öneki olmadan)
vsnstringqueryzorunlu
Frame biçimi; dizi biçimi için 2.0.0 olmalıdır
Yanıtlar
101Bağlantı kuruldu (Switching Protocols)
403Token geçersiz ya da süresi dolmuş, rumuz seçilmemiş, veya tarayıcının Origin değeri kabul edilmedi
websocat "wss://mskop-api.gurerlabs.com/socket/websocket?token=$ACCESS_TOKEN&vsn=2.0.0"
# 30 saniyede bir heartbeat:
→ [null,"hb","phoenix","heartbeat",{}]
← [null,"hb","phoenix","phx_reply",{"status":"ok","response":{}}]
# Phoenix JS istemcisi (vsn'yi kendisi ekler):
const socket = new Socket("wss://mskop-api.gurerlabs.com/socket", {params: {token: accessToken}})
socket.connect()
DeneÖnce token gir: otomatik eklenir
WebSocket bağlantısı bu sayfadan denenemez; örnekteki websocat komutunu ya da Phoenix istemcisini kullan.
WSroom:{slug} → phx_join
🔒 Bearer token
Odaya katıl
Bir odanın kanalına katılır. Yalnız odanın üyeleri katılabilir. Katılma yanıtında oda nesnesi gelir (REST'teki oda yüküyle aynı şekil, ek olarak member_count, is_member, avatar, peer ve muted). Ardından sunucu yalnız bu bağlantıya önce presence_state, sonra message:sync gönderir.
›Hata sebepleri: room_not_found (böyle bir oda yok), not_member (oda var ama kişi üyesi değil).
›Senkron modeli: odadaki her mesajın tek yönde artan bir seq imleci vardır. Düzenleme, silme, tepki, etkinlik yanıtı ve tartışma sayacı da imleci ileri taşır. Cihaz elindeki son latest_seq değerini since olarak gönderir ve o imleçten sonra değişen her satırı en eskisi önce, 100'erli paketler hâlinde alır. has_more true ise message:sync {since: latest_seq} ile devam eder.
›since verilmezse ya da 0 ise cihaz yeni sayılır ve en yeni 100 mesaj gelir. Daha eskileri message:history ile istenir.
›Paket seq sırasıyla gelir ama akış inserted_at sırasıyla çizilir. Cihaz mesajı id ile günceller, seq = max(eski, yeni) olarak saklar ve listeyi yeniden sıralamaz.
›Birebir sohbette room.peer alanı {account_id, username, online} taşır. Karşı tarafın durumu değişince peer:presence gelir.
›show_members: false olan bir odada sıradan üyeler, kurucu ve yöneticiler dışındaki kişileri presence içinde hidden-… takma kimlikleriyle ve rumuzsuz görür.
Parametreler
slugstringpathzorunlu
Odanın slug'ı; topic room:SLUG olur
sinceintegerpayloadisteğe bağlı
Cihazın sakladığı son latest_seq; 0 ya da yoksa yeni cihaz
{"response":{"room":{"avatar":null,"created_at":"2026-09-24T18:02:11.734512Z","discussions_enabled":true,"events_visibility":"all","founder_id":"0c4e8a92-51d7-4b3f-a6e2-9d18f7c3b456","gifts":0,"history_for_new_members":true,"id":"3c8f1a2e-7b64-4d09-a5e1-6f2b9c0d4e17","is_member":true,"join_approval":false,"kind":"group","level":1,"member_count":214,"member_denied":[],"members_can_pin":false,"members_can_video":false,"message_ttl_hours":null,"muted":false,"name":"Fenerbahçe Taraftar","peer":null,"pinned":null,"pins":[],"short_link":"mskp.io/fenerbahce-taraftar","show_gifts":true,"show_members":true,"show_welcome":true,"slug":"fenerbahce-taraftar","star_gated":false,"stars":12,"vanity_code":null,"visibility":"open","wallpaper":"okyanus","welcome_message":"Hoş geldin {username}! Maç günü burada buluşuyoruz."}},"status":"ok"}
DeneÖnce token gir: otomatik eklenir
WebSocket bağlantısı bu sayfadan denenemez; örnekteki websocat komutunu ya da Phoenix istemcisini kullan.
WSroom:{slug} → message:new
🔑 send_message (tartışmada sub_chat.send_message)⏱ hesap başına 10 sn'de 20
Mesaj gönder
Odaya mesaj gönderir. Mesaj sunucuda oda anahtarıyla şifreli saklanır. Gönderen mesajı yalnız yanıt olarak alır; odadaki diğer herkese message:new olarak yayılır. Gövde / ile başlıyor ve ek yoksa mesaj yazılmaz, komut çalıştırılır.
›Hata sebepleri: invalid_payload (body metin değil), read_only (Makroskop'un resmi duyuru sohbeti), empty_body (ek yok ve gövde boş), not_allowed (konuşma yetkisi yok; ek türü yasaksa permission alanıyla, ör. send_message.photos), body_too_large (16 384 bayttan uzun), rate_limited, invalid_parent (birebir sohbet, tartışmalar kapalı, kök bu odada değil ya da tartışma sonlandırılmış), muted (until ms ile), invalid_forward, not_available_in_organization (Keşfet kartı Makroskop dışı bir odaya), invalid_attachment.
›Ek türleri (attachment.type; yoksa image): image{key, thumb_key, content_type, width, height, byte_size?}. Türü jpeg, png ya da webp olmalı; en çok 8 MB ve 8192 px; anahtar odanın room-media/ROOM_ID/ önekinde olmalı. video mp4, en çok 16 MB, duration_ms en çok 10 500. gif image/gif ya da image/webp. sticker webp, png ya da gif, en çok 2 MB; pack_id? ve emoji? alabilir.
›Diğer ek türleri: contact{account_id} (rumuzu sunucu doldurur). location{lat, lng, label?}. article{title (≤200), hashtag?, blocks (≤200; p, h, li, quote; her biri ≤4000 karakter), media (≤20 fotoğraf)}. document{key, name, content_type, byte_size (≤10 MB)}; dosya 1 saat sonra silinir. happening{title, starts_at, ends_at?, location?, description?, media?}. entry{entry_id}; yalnız Makroskop odalarında kullanılabilir.
›Tek gösterimlik ek: view_once: true. Yalnız birebir sohbette, image ya da video ile ve thumb_key olmadan gönderilir.
›hashtags gönderilmezse gövdeden çıkarılır. Yanıttaki topics alanında mesajın düştüğü konular bulunur; hashtag yoksa ["unknown"] olur. reply_to.sender en çok 40, snippet en çok 120 karakter olarak saklanır.
›parent_id verilirse mesaj o tartışmanın içine düşer. Bu durumda yanıttaki parent_thread_count, parent_seq ve parent_thread_participants kök mesajın yeni hâlini taşır; tartışma dışındaki mesajlarda bu alanlar null olur.
›Komutlar: /mute @rumuz [5m|2h|1d], /unmute @rumuz, /ban @rumuz [sebep], /unban @rumuz, /kick @rumuz, /score [daily|weekly|monthly|all]. Yanıtı {command, target: {account_id, username}, …} biçimindedir (/mute için until ms). Komutlar hesap, oda ve komut başına dakikada 5 kez çalıştırılabilir. Komut hataları: not_admin, user_not_found, unknown_command, bad_duration, bad_window, founder_protected, not_member, rate_limited.
›Birebir sohbette ilk mesaj karşı tarafı odaya ekler; karşı tarafın user: kanalına room:new gider.
Parametreler
bodystringpayloadzorunlu
Mesaj metni, en çok 16 KB; ek varsa boş olabilir
client_refstringpayloadisteğe bağlı
İstemcinin kendi kimliği; yanıtta ve yayında aynen döner
hashtagsstring[]payloadisteğe bağlı
Ayrıca gönderilen etiketler; yoksa gövdeden çıkarılır
WebSocket bağlantısı bu sayfadan denenemez; örnekteki websocat komutunu ya da Phoenix istemcisini kullan.
WSroom:{slug} → message:ack
🔒 Bearer token
Aldım bildirimi
Cihaz mesajları aldığını ve yerel veritabanına yazdığını bildirir. Gönderen dışındaki birinden gelen ilk ack, odaya message:delivered {id} olarak yayılır; gönderen bunu çift tik olarak gösterir. Yanıt gelmez.
›Tek seferde en çok 200 kimlik işlenir; fazlası atılır.
›Biçimi tutmayan payload (id metin değil, ids liste değil) unknown_event alır.
WebSocket bağlantısı bu sayfadan denenemez; örnekteki websocat komutunu ya da Phoenix istemcisini kullan.
WSroom:{slug} → message:sync
🔒 Bearer token
Senkronu sürdür
Katılma sırasında gelen senkron paketinin devamını ister. since imlecinden sonra değişen satırlar en eskisi önce, en çok 100'er gelir. Yanıttaki has_more true ise yanıttaki latest_seq değeriyle yeniden istenir.
›Silinmiş mesajlar deleted: true ve boş gövdeyle, düzenlenmişler dolu edited_at ve yeni gövdeyle gelir. Tepki alan mesajlar reactions alanının yeni hâliyle satırın tamamı olarak gelir.
›audience: "admins" olan oda satırları (yönetici kaydı) sıradan üyelerin senkronuna girmez.
›since negatif ya da tam sayı değilse unknown_event döner.
{"response":{"has_more":false,"latest_seq":422,"messages":[{"attachment":null,"audience":"all","body":"Maç ne oldu? #fb-maçı","deleted":false,"delivered":true,"edited_at":null,"event":null,"forwarded_from":null,"hashtags":["#fb-maçı"],"id":"a9ea1c52-7d3b-4e0f-9b18-5c2e6f4d8a71","inserted_at":1791969153000,"kind":"text","mentions":[],"parent_id":null,"reactions":[{"account_id":"fdea3b17-2c9e-4a61-8d40-7b5e1c9a2f08","emoji":"🔥","username":"mehmet"}],"reply_to":null,"rsvps":null,"sender":{"account_id":"0c4e8a92-51d7-4b3f-a6e2-9d18f7c3b456","role":"founder","tag":null,"username":"ayse"},"seq":422,"thread_closed":false,"thread_count":0,"thread_participants":[],"thread_senders":[],"views":2}],"since":421},"status":"ok"}
DeneÖnce token gir: otomatik eklenir
WebSocket bağlantısı bu sayfadan denenemez; örnekteki websocat komutunu ya da Phoenix istemcisini kullan.
WSroom:{slug} → message:history
🔒 Bearer token
Eski mesajlar
Yukarı kaydırırken cihazda bulunmayan eski mesajları getirir. before anından eski en yeni limit mesaj, eskiden yeniye sıralı gelir. before_id ekrandaki en eski mesajın kimliğidir; aynı milisaniyede yazılmış mesajların atlanmamasını sağlar.
›before tam sayı değilse unknown_event döner. limit geçersizse 50 kullanılır.
›Yeni üyelere geçmiş kapalı olan odalarda (history_for_new_members: false) kişinin katıldığı andan öncesi verilmez.
{"response":{"has_more":true,"messages":["…mesaj nesneleri (message:sync ile aynı şekil)…"]},"status":"ok"}
DeneÖnce token gir: otomatik eklenir
WebSocket bağlantısı bu sayfadan denenemez; örnekteki websocat komutunu ya da Phoenix istemcisini kullan.
WSroom:{slug} → message:thread
🔒 Bearer token
Tartışmayı aç
Bir mesajın altındaki tartışmanın tamamını getirir: üstte kök mesaj (root), altında yanıtlar (messages, eskiden yeniye, en çok 200). Tartışma yanıtları odanın kendi akışında görünmez; bu yüzden onları okumanın tek yolu bu olaydır.
›Hata sebebi: not_found (bu odada böyle bir kök mesaj yok). id metin değilse unknown_event döner.
{"response":{"messages":[{"body":"2-1 bitti, son dakika golü!","id":"5f1d7c3a-9e24-4b86-a0f2-1c7b8d3e6a95","parent_id":"a9ea1c52-7d3b-4e0f-9b18-5c2e6f4d8a71","…":"…"}],"root":{"id":"a9ea1c52-7d3b-4e0f-9b18-5c2e6f4d8a71","seq":430,"thread_count":3,"…":"…"}},"status":"ok"}
DeneÖnce token gir: otomatik eklenir
WebSocket bağlantısı bu sayfadan denenemez; örnekteki websocat komutunu ya da Phoenix istemcisini kullan.
WSroom:{slug} → message:thread:close
🔑 kök mesajın yazarı ya da oda yöneticisi
Tartışmayı sonlandır / yeniden aç
Bir tartışmayı bitmiş olarak işaretler (closed: true) ya da yeniden açar. Kapalı tartışma okunabilir ama yeni yanıt almaz. Durum değişirse odaya message:thread:closed {id, closed, seq} yayılır ve odaya discussion_closed ya da discussion_reopened satırı yazılır.
›Tartışma zaten istenen durumdaysa hiçbir şey yayılmaz ve yanıtta seq bulunmaz.
WebSocket bağlantısı bu sayfadan denenemez; örnekteki websocat komutunu ya da Phoenix istemcisini kullan.
WSroom:{slug} → message:rsvp
🔒 Bearer token
Etkinliğe yanıt ver
Bir etkinlik kartına (kind: "happening") katılım yanıtı verir. Her kişinin tek bir yanıtı vardır; fikir değişince yeni yanıt eskisinin yerine geçer. Yeni sayılar odadaki herkese message:rsvp {id, rsvps, seq} olarak yayılır.
WebSocket bağlantısı bu sayfadan denenemez; örnekteki websocat komutunu ya da Phoenix istemcisini kullan.
WSroom:{slug} → message:read
🔒 Bearer token
Okundu imleci
"Buraya kadar okudum" bildirimidir. Oda listesindeki okunmamış rozeti bu imleçten sonraki mesajları sayar; böylece rozet hesabın bütün cihazlarında aynı olur. İmleç hiçbir zaman geri gitmez: daha küçük bir seq göndermek bir şey değiştirmez.
›seq negatif ya da tam sayı değilse unknown_event döner.
WebSocket bağlantısı bu sayfadan denenemez; örnekteki websocat komutunu ya da Phoenix istemcisini kullan.
WSroom:{slug} → message:react
🔒 Bearer token⏱ hesap başına 10 sn'de 20 (ayrı kova)
Tepki bırak / geri al
Bir mesaja tepki ekler ya da (on: false) geri alır. Yalnız iki uygulamada da bulunan yedi emoji kabul edilir: ❤️ 👍 😂 😮 😢 🙏 🔥. Tepki mesajın imlecini ilerletir; odadaki diğer kişilere message:reaction olarak yayılır, tepkiyi bırakan cihaz yeni seq değerini yanıtta alır.
›Mesaj başına tepki sınırı ücretsiz hesapta 1, Premium hesapta 3'tür. Sınır aşılınca reaction_limit ve limit alanı döner.
›Hiçbir şey değişmediyse (aynı tepki ikinci kez ya da olmayan bir tepkiyi geri alma) seqnull döner.
›Hata sebepleri: invalid_payload (id UUID değil), unknown_emoji, rate_limited, reaction_limit.
Parametreler
iduuidpayloadzorunlu
Mesajın id'si
emojistringpayloadzorunlu
❤️ 👍 😂 😮 😢 🙏 🔥 emojilerinden biri
onbooleanpayloadisteğe bağlı
false tepkiyi geri alır; varsayılan true
→ ["1","10","room:fenerbahce-taraftar","message:react",{"id":"a9ea1c52-7d3b-4e0f-9b18-5c2e6f4d8a71","emoji":"🔥"}]
← ["1","10","room:fenerbahce-taraftar","phx_reply",{"status":"ok","response":{"seq":434}}]
# Sınır doluysa:
← ["1","10","room:fenerbahce-taraftar","phx_reply",{"status":"error","response":{"reason":"reaction_limit","limit":1}}]
{"response":{"seq":434},"status":"ok"}
DeneÖnce token gir: otomatik eklenir
WebSocket bağlantısı bu sayfadan denenemez; örnekteki websocat komutunu ya da Phoenix istemcisini kullan.
WSroom:{slug} → message:seen
🔒 Bearer token
Görüldü bildirimi
"Bu mesajlar ekranımda" bildirimidir. Sunucu kimin neyi gördüğünü kaydeder; bu kayıt mesajın "Görüntüleyenler" listesini ve views sayacını besler. Odadaki diğer kişilere message:seen {ids, account_id, username} yayılır. Yanıt gelmez.
›UUID olmayan kimlikler atılır; tek seferde en çok 200 kimlik işlenir.
›Üyelerini gizleyen bir odada, sıradan üyelere giden yayında görenin account_id ve username alanları null olur.
WebSocket bağlantısı bu sayfadan denenemez; örnekteki websocat komutunu ya da Phoenix istemcisini kullan.
WSroom:{slug} → message:open_once
🔒 Bearer token
Tek gösterimlik dosyayı aç
Birebir sohbette tek gösterimlik bir fotoğrafı ya da videoyu açar. Yanıttaki url 60 saniye geçerli, tek bir imzalı GET adresidir ve yalnız bir kez verilir. Açılış odaya message:opened {id, seq, opened_at} olarak yayılır; iki taraf da baloncuğu "Açıldı" yapar. Dosya açıldıktan yaklaşık 90 saniye sonra silinir.
›Hata sebepleri: not_allowed (gönderen kendi dosyasını açamaz), already_opened (dosya başka bir cihazdan da olsa zaten açılmış), gone (dosya silinmiş), not_view_once (mesaj tek gösterimlik değil ya da oda birebir sohbet değil), not_found.
WebSocket bağlantısı bu sayfadan denenemez; örnekteki websocat komutunu ya da Phoenix istemcisini kullan.
WSroom:{slug} → message:state
🔒 Bearer token
Tepki ve görüntülenme durumu
Cihazda zaten bulunan mesajların güncel tepkilerini ve görüntülenme sayılarını toplu olarak getirir. Mesajın tamamını yeniden indirmeden bu iki bilgiyi tazelemek için kullanılır. UUID olmayan kimlikler atılır; en çok 200 kimlik işlenir.
WebSocket bağlantısı bu sayfadan denenemez; örnekteki websocat komutunu ya da Phoenix istemcisini kullan.
WSroom:{slug} → message:viewers
🔒 Bearer token
Görüntüleyenler
Mesaj menüsündeki "Görüntüleyenler" listesini getirir: mesajı kimin, ne zaman gördüğü ve varsa bıraktığı tepki. Liste görülme sırasına göre, en eskisi başta gelir. seen_at ISO-8601 biçimindedir.
›Üyelerini gizleyen bir odada sıradan üyeler yalnız kurucuyu ve yöneticileri adıyla görür; diğerleri yalnız hidden sayısına eklenir.
›id UUID değilse liste boş döner; id metin değilse unknown_event döner.
WebSocket bağlantısı bu sayfadan denenemez; örnekteki websocat komutunu ya da Phoenix istemcisini kullan.
WSroom:{slug} → message:edit
🔑 yalnız yazarı (edit_message)
Mesajı düzenle
Kişi kendi mesajının gövdesini değiştirir; sunucudaki şifreli kopya da güncellenir. Hashtag'ler ve bahsetmeler yeni gövdeden yeniden çıkarılır. Odaya message:edited {id, body, account_id, hashtags, mentions, edited_at, seq} yayılır; edited_at ms epoch'tur. Yanıt boş bir ok'tur.
›Hata sebepleri: not_allowed (permission: "edit_message"; oda bu yetkiyi üyelerden almış), empty_body, body_too_large, not_author, not_found. id ya da body metin değilse unknown_event döner.
WebSocket bağlantısı bu sayfadan denenemez; örnekteki websocat komutunu ya da Phoenix istemcisini kullan.
WSroom:{slug} → message:delete
🔑 yazarı (delete_message) ya da group.can_remove_message
Mesajı sil
Kişi kendi mesajını geri alır ya da yetkili biri başkasının mesajını kaldırır. Gövde sunucudan silinir, yerinde bir iz kalır; böylece o sırada bağlı olmayan cihazlar da silindiğini öğrenir. Ekli dosyalar hemen silinir. Odaya message:deleted yayılır ve yöneticilere görünen bir message_deleted satırı yazılır.
›Silinen mesaj bir tartışma yanıtıysa yayında parent_id, parent_thread_count, parent_seq ve parent_thread_participants alanları kökün yeni hâliyle gelir.
›Hata sebepleri: not_allowed, not_author, not_found. id metin değilse unknown_event döner.
WebSocket bağlantısı bu sayfadan denenemez; örnekteki websocat komutunu ya da Phoenix istemcisini kullan.
WSroom:{slug} → room:pin
🔑 group.can_pin_message
Mesaj sabitle
Bir mesajı odanın sabitlenenler listesinin başına ekler. Mesaj zaten sabitliyse başa taşınır. id: null göndermek bütün sabitleri bir kerede kaldırır. Odaya room:pinned {message_id, account_id, at, pins} yayılır ve odaya message_pinned ya da message_unpinned satırı yazılır.
›message_id, account_id ve at en yeni sabiti anlatır; pins listenin tamamıdır ve en yenisi başta gelir. Son sabit de kalkınca message_idnull olur ve pins boş gelir. at ISO-8601 biçimindedir.
›members_can_pin açık olan odalarda sıradan üyeler de sabitleyebilir.
›Hata sebepleri: not_admin, not_found (mesaj bu odada yok), invalid_payload.
WebSocket bağlantısı bu sayfadan denenemez; örnekteki websocat komutunu ya da Phoenix istemcisini kullan.
WSroom:{slug} → room:unpin
🔑 group.can_pin_message
Sabiti kaldır
Sabitlenenler listesinden tek bir mesajı kaldırır; diğerleri yerinde kalır. Birden fazla sabit varken "bunu kaldır" ile "hepsini kaldır" farklı isteklerdir; hepsini kaldırmak için room:pin {id: null} kullanılır. Odaya güncel listeyle room:pinned yayılır.
›Sabit olmayan bir mesajın kimliğini göndermek hata vermez; liste değişmeden yeniden yayılır.
›Hata sebepleri: not_admin, invalid_payload (id yok ya da metin değil).
WebSocket bağlantısı bu sayfadan denenemez; örnekteki websocat komutunu ya da Phoenix istemcisini kullan.
WSroom:{slug} → typing
🔒 Bearer token⏱ hesap ve oda başına 2 sn'de 1 yayın
Yazıyor
Kişinin yazmakta olduğunu odaya bildirir. Sunucu aynı hesap ve oda için 2 saniyede en çok bir kez typing {account_id, username} yayar; aradaki istekler sessizce düşer. Yayın gönderene gelmez. Yanıt gelmez.
WebSocket bağlantısı bu sayfadan denenemez; örnekteki websocat komutunu ya da Phoenix istemcisini kullan.
WSroom:{slug} → presence:set
🔒 Bearer token
Çevrimiçi durumu
Uygulamanın ön planda (online) ya da arka planda (background) olduğunu bildirir. Değişiklik odaya presence_diff olarak gider: aynı anahtar leaves içinde eski durumuyla, joins içinde yeni durumuyla görünür. Bağlantının kapanması, kişinin listeden düşmesi demektir.
›Uygulamalardaki renkler: listede ve online ise yeşil, listede ve background ise sarı, listede yoksa gri.
›online durumundaki kişilere o odanın push bildirimi gönderilmez; mesajı canlı olarak alırlar.
WebSocket bağlantısı bu sayfadan denenemez; örnekteki websocat komutunu ya da Phoenix istemcisini kullan.
WSroom:{slug} ← sunucu olayları
🔒 Bearer token
Odadan gelen olaylar
Sunucunun oda kanalına kendiliğinden gönderdiği olaylardır. Cihaz her olayı kendi yerel kopyasına uygular. seq taşıyan olaylarda satırın ve senkron imlecinin seq değerini de ilerletir; aksi hâlde aynı satır bir sonraki senkronda yeniden gelir.
›message:new — mesaj nesnesi (senkrondakiyle aynı şekil) ve ek olarak topics, client_ref, parent_thread_count, parent_seq, parent_thread_participants. Gönderen kendi mesajını yayın olarak almaz. parent_id doluysa mesaj bir tartışma yanıtıdır ve akışa değil, tartışma penceresine girer. Odanın kendi satırları (kind: "event", gönderen null) da bu olayla gelir. event.type şunlardan biridir: member_joined, member_left, member_kicked, member_banned, member_unbanned, member_muted, member_unmuted, score, welcome, founder_changed, room_settings_changed, member_permissions_changed, admin_permissions_changed, message_deleted, message_pinned, message_unpinned, discussion_closed, discussion_reopened.
›message:sync{since, messages, latest_seq, has_more} — katılınca yalnız bu bağlantıya. message:delivered{id} — gönderen dışından biri mesajı aldı (çift tik).
›room:pinned{message_id, account_id, at, pins} — at ISO-8601. typing{account_id, username}.
›presence_state{ACCOUNT_ID: {metas: [{state, username, online_at, phx_ref}]}} — katılınca tam liste; online_at saniye cinsinden epoch. presence_diff{joins, leaves} — değişiklikler. Üyelerini gizleyen odada sıradan üyeler hidden-… kimlikleri görür.
›member:joined{account_id, username} (biri REST ile katıldı), member:left{account_id}, member:tagged{account_id, tag}. Gizli üyelerin giriş ve çıkışları sıradan üyelere gönderilmez.
›room:removed{} — kişi odadan ayrıldı ya da çıkarıldı (başka bir cihazdan da olabilir); ardından kanal phx_close ile kapanır. room:deleted{slug} — oda silindi.
›peer:presence{account_id, online} — yalnız birebir sohbette: karşı taraf bağlandı ya da bağlantısı koptu.
WebSocket bağlantısı bu sayfadan denenemez; örnekteki websocat komutunu ya da Phoenix istemcisini kullan.
WSuser:{account_id} → phx_join
🔒 Bearer token
Kişinin kendi kanalı
Uygulama açılışta odaların yanı sıra kendi kanalına da katılır. Bu kanal sunucunun bir odaya değil kişiye ulaştığı yoldur: oda listesi açık kanal olmadan da güncel kalır. Katılmak hesabı genel çevrimiçi listesine de yazar; bu liste yalnız birebir sohbetin karşı tarafına durum göstermek için kullanılır.
›Yalnız kendi account_id'nle katılabilirsin; başka bir kimlik forbidden alır. Bu kanala gönderilen her istemci olayı unknown_event alır.
›room:new{room} — biri seninle birebir sohbete ilk mesajı yazdı ya da bir yönetici katılma isteğini onayladı; uygulama odayı listeye hemen ekler.
›room:gone{slug} — odadan çıkarıldın, engellendin, ayrıldın (başka cihazdan da olabilir) ya da oda silindi.
›room:activity{slug, seq, last_message, mentioned} — üyesi olduğun bir odaya mesaj düştü (gönderene gelmez). last_message, GET /api/rooms listesindeki nesneyle aynıdır: {id, seq, kind, audience, sender, body (ilk 120 karakter), event, inserted_at}. mentioned, mesajın seni @rumuz ile anıp anmadığını söyler. Okunmamış sayısı gönderilmez; cihaz rozeti kendisi bir artırır. Tartışma yanıtları ve odanın kendi satırları bu olayı tetiklemez.
›peer:presence{account_id, online} — birebir sohbet ettiğin biri bağlandı ya da bağlantısı koptu; o sohbetin açık olması gerekmez.
›account:avatar{account_id, avatar} — biri profil fotoğrafını değiştirdi. Son fotoğraf silindiyse avatar: null gelir. Bağlı olan herkese, kişinin kendisine de gider.