Etkileşimler
Biri botunun butonuna bastığında ya da komutunu çalıştırdığında bot INTERACTION_CREATE alır ve ona yanıt verir. Bu sayfa yanıtın dört türünü, süreleri ve sonradan gelen mesajları anlatır. Basmanın kendisi ve bileşenlerin nasıl yazıldığı Bileşenler sayfasında.
Zaman çizelgesi
| Ne zaman | Ne olur |
|---|---|
| 0 sn | Kişi basar, bot INTERACTION_CREATE alır. Olayda id ve token vardır. |
| 3 sn | İlk yanıtın son anı. Sonrası 400 interaction_timeout döner, kişi "Bot yanıt vermedi" görür. |
| 15 dk | Token'ın ömrü. @original düzenlemesi ve takip mesajları buraya kadar çalışır, sonrası 400 interaction_expired döner. |
Her etkileşim tek bir ilk yanıt alır. İkincisi 400 interaction_already_acknowledged döner. Reddedilen bir yanıt hakkını harcamaz: hatayı düzeltip süre içinde yeniden gönderebilirsin.
Gateway mı HTTP mi
Etkileşim botuna iki yoldan gelebilir. Uygulamanın etkileşim adresi yoksa gateway'den, varsa yalnızca o adrese. İçerik ikisinde aynıdır; değişen, yanıtı nasıl verdiğindir:
| Gateway | HTTP adresi | |
|---|---|---|
| Etkileşim nasıl gelir | INTERACTION_CREATE olayı | Adresine imzalı POST |
| İlk yanıt | callback rotası, bot token'ıyla | Aynı isteğin 200 gövdesi; ya da 202 dönüp callback rotası |
| 3 saniye | Etkileşimin kimliğinden sayılır | Adresine bağlanma ve yanıtın tamamı dahil |
| Reddedilen yanıt | Hata kodunu sen alırsın, süre içinde düzeltip yeniden gönderebilirsin | Kişi "Bot zamanında yanıt vermedi." görür, kod teslim günlüğüne yazılır |
| Bot kapalıysa | Etkileşim kaybolur, kişi 3 saniye sonra hatayı görür | Kişi hatayı hemen görür |
Takip, @original | Aynı rotalar | Aynı rotalar, bot token'ıyla |
| Sınırlar | interaction sınıfı ve ortak tavanlar | Aynısı |
Kişi hangi yolu kullandığını görmez.
Sunucuda mı DM'de mi
Her etkileşim context alanını taşır: 0 sunucu kanalı, 1 kişinin botunla açtığı DM. Basma, komut, otomatik tamamlama ve form DM'de de aynı çalışır; fark yalnızca kimin nerede olduğundadır:
| Alan | Sunucuda | DM'de |
|---|---|---|
context | 0 | 1 |
guild_id | Sunucunun kimliği | Yok |
member | Kişi, permissions dolu | Yok |
user | Yok | Kişi |
app_permissions | Botun bu kanaldaki izinleri | DM'nin sabit izinleri |
// Aynı kod sunucuda ve DM'de çalışır.
const guildId = interaction.guild_id ?? null; // DM'de null
const person = interaction.member?.user ?? interaction.user;
const inDM = interaction.context === 1;
if (inDM) {
// Rol yok, izin yok: yetki isteyen işi burada yapma.
}
Yanıt rotaları DM'de de aynıdır. Kişi DM'yi kapatır ya da botu engellerse yanıt 403 dm_closed alır (Özel mesajlar).
Hangi yanıtı seçmeliyim?
| İşin 3 saniyeden uzun sürer mi? | Neyi değiştiriyorsun? | Seç |
|---|---|---|
| Hayır | Kanala yeni bir mesaj yazıyorsun | type: 4 |
| Hayır | Butonun durduğu mesajı değiştiriyorsun | type: 7 |
| Evet | Sonuç yeni bir mesaj olacak | type: 5, sonra PATCH @original |
| Evet | Butonun durduğu mesajı değiştireceksin | type: 6, sonra kanal mesajını düzenle |
| Evet ya da hayır | Görünen hiçbir şey değişmiyor | type: 6 |
| Hayır | Bir komuta yanıt veriyorsun | type: 4 |
| Evet | Bir komuta yanıt veriyorsun | type: 5, sonra PATCH @original |
Her yanıt her etkileşime uymaz. Uymayanı göndermek 400 interaction_response_invalid döner:
| Etkileşim | type: 4 | type: 5 | type: 6 | type: 7 | type: 8 | type: 9 |
|---|---|---|---|---|---|---|
Butona basma, menüden seçme (type: 3) | Evet | Evet | Evet | Evet | Hayır | Evet |
Komut çalıştırma (type: 2) | Evet | Evet | Hayır | Hayır | Hayır | Evet |
Otomatik tamamlama (type: 4) | Hayır | Hayır | Hayır | Hayır | Evet | Hayır |
Gönderilen form (type: 5) | Evet | Evet | Butondan açıldıysa | Butondan açıldıysa | Hayır | Hayır |
Komut çalıştırmanın üzerinde durduğu bir mesaj yoktur; değiştirilecek bir şey olmadığı için 6 ve 7 almaz. type: 8 kişi yazarken önerdiğin seçeneklerdir (data.choices) ve yalnızca otomatik tamamlamaya uyar. type: 9 kişiye bir form açar; ilk yanıt olmalıdır ve gönderilen form sana yeni bir etkileşim olarak gelir.
Yanıtı yalnızca basan kişi görsün istiyorsan data içine flags: 64 ekle: Yalnızca basan kişi görsün.
Yanıt rotası
Dört tür de aynı rotaya gider:
curl -X POST "https://noluyo.net/api/v1/interactions/$INTERACTION_ID/$INTERACTION_TOKEN/callback" \
-H "Authorization: Bot $BOT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"type":4,"data":{"content":"Kaydın alındı."}}'
type 4: yeni mesajla yanıt
Kanala yeni bir mesaj yazar. data bir mesaj gibidir: content, embeds, components, allowed_mentions. Metin ya da embed zorunludur.
{ "type": 4, "data": { "content": "Kaydın alındı." } }
Yanıt 200 ve mesajdır. Mesajın interaction alanı kimin bastığını söyler:
{
"message": {
"id": "111600000000000500",
"type": 0,
"channel_id": "111500000000000100",
"content": "Kaydın alındı.",
"application_id": "111540000000000000",
"interaction": {
"id": "111600000000000400",
"type": 3,
"user": { "id": "111540000000000009", "username": "ayse" }
}
}
}
type 5: önce "düşünüyor", sonra sonuç
İşin uzun sürecekse hemen bunu gönder. Kanala boş bir mesaj düşer ve flags: 128 taşır; kişi onu "düşünüyor" olarak görür. data içinden yalnızca flags okunur: content, embeds ve components gönderirsen yok sayılır, onları PATCH @original ile gönder.
{ "type": 5 }
Yanıt 200 ve mesajdır:
{
"message": {
"id": "111600000000000500",
"type": 0,
"content": "",
"flags": 128,
"interaction": {
"id": "111600000000000400",
"type": 3,
"user": { "id": "111540000000000009", "username": "ayse" }
}
}
}
İş bitince mesajı doldur. flags'teki 128 kendiliğinden silinir, mesaj "(düzenlendi)" olarak işaretlenmez:
curl -X PATCH "https://noluyo.net/api/v1/interactions/$INTERACTION_ID/$INTERACTION_TOKEN/messages/@original" \
-H "Authorization: Bot $BOT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"content":"Rapor hazır."}'
type 6: sessiz onay
Bastığını aldığını söyler, ekranda hiçbir şey değişmez. Mesaj oluşmaz, SendMessages da gerekmez. data gönderirsen yok sayılır.
{ "type": 6 }
Yanıt 204, gövdesizdir. Sonra kanala bir şey yazmak istersen takip mesajı kullan. Butonun durduğu mesajı değiştirmek istersen mesaj düzenleme rotası çalışır; @original burada işe yaramaz, çünkü bu yanıtın mesajı yoktur: istek 200 döner ama ekranda bir şey değişmez.
type 7: basılan mesajı güncelle
Butonun durduğu mesajı değiştirir. Göndermediğin alan olduğu gibi kalır, boş components listesi butonları kaldırır. Yalnızca components değişirse mesaj "(düzenlendi)" olarak işaretlenmez.
{ "type": 7, "data": { "content": "Oylama bitti.", "components": [] } }
Yanıt 200 ve güncellenen mesajdır:
{
"message": {
"id": "111600000000000000",
"content": "Oylama bitti.",
"edited_timestamp": "2026-11-07T20:00:00.000Z"
}
}
Bu rotalarda yeni dosya gönderilemez. Görsel göndermek istiyorsan takip mesajı kullan.
@original ve takip mesajları
İlk yanıtı verdikten sonra token 15 dakika boyunca çalışır:
| İstek | Ne yapar | Yanıt |
|---|---|---|
POST /interactions/{id}/{token}/messages | Yeni takip mesajı yazar, dosya da alır | 200 ve mesaj |
PATCH /interactions/{id}/{token}/messages/@original | type: 4 ya da type: 5 mesajını düzenler | 200 ve mesaj |
PATCH /interactions/{id}/{token}/messages/{message_id} | Bu etkileşimin bir mesajını düzenler | 200 ve mesaj |
DELETE /interactions/{id}/{token}/messages/{message_id} | Bu etkileşimin bir mesajını siler, @original da olur | 204 |
Token yalnızca kendi etkileşiminin mesajlarına ulaşır. Aynı kanaldaki başka bir mesaj 404 unknown_message döner. Bir etkileşim en çok 5 takip mesajı atabilir, altıncısı 429 döner. Takip mesajı dosya almak için multipart/form-data kullanır; biçimi mesaj gönderme ile aynıdır.
curl -X POST "https://noluyo.net/api/v1/interactions/$INTERACTION_ID/$INTERACTION_TOKEN/messages" \
-H "Authorization: Bot $BOT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"content":"Bir şey daha: rapor e-postana da gitti."}'
Ephemeral takip mesajı dosya almaz ama beşe aynı sayılır. Bir etkileşimin ephemeral mesajları 5 saniyede en çok 5 kez düzenlenebilir, fazlası 429 döner. Ayrıca tüm botlar birlikte bir kişiye 5 saniyede en çok 262144 bayt ephemeral mesaj gönderebilir (metin, embed'ler ve bileşenlerin üç katı sayılır); fazlası 429 rate_limited döner ve kişiye bir şey gitmez. Yanıtlara yavaş mod ve mesaj sınırı işlemez, çünkü onları bir kişinin basması tetikler. SendMessages izni, otomatik moderasyon ve interaction sınıfı ile ortak tavanlar yine geçerlidir.
Yalnızca basan kişi görsün
data içine flags: 64 eklersen yanıtı yalnızca basan kişi görür. Buna ephemeral mesaj denir. type: 4, type: 5 ve takip mesajında çalışır:
{ "type": 4, "data": { "content": "Kaydın alındı. Bunu yalnızca sen görüyorsun.", "flags": 64 } }
Yanıt 200 ve {"message": ...}, takip mesajında yalnızca mesajdır. flags 64 gelir, mentions her zaman boştur. İlk yanıtın kimliği etkileşimin kimliğidir, takip mesajı yeni kimlik alır.
type: 5 ile flags: 64 gönderirsen kişi "düşünüyor" görür ve flags 192 gelir. PATCH @original ile doldurduğunda 64 olur. Bu PATCH ve diğerleri yalnızca basan kişiye gider. Kişi artık kanalı görmüyorsa 404 unknown_channel döner, ona bir şey gitmez.
Ne zaman kaybolur
N'oluyo bu mesajı saklamaz. Kişi sayfayı yenilerse ya da uygulamayı yeniden açarsa mesaj gider. O anda açık olan başka cihazında da görünür, sonradan açtığı cihazda görünmez. Kişi mesajdaki "Kapat" düğmesiyle onu kendi ekranından kaldırabilir, bu sana haber vermez. Mesaj geçmişte çıkmaz, okunmadı sayacını ve last_message_id'yi oynatmaz, bildirim göndermez. Diğer üyeler ve botlar, senin botun da, MESSAGE_CREATE almaz.
Kalıcı olması gereken bir şeyi burada söyleme. Kişi mesajı kaybetse de sonucu bulabilmeli.
Ne yapamaz
| Yapılamayan | Olan | Yerine |
|---|---|---|
| Görsel ya da dosya | 400 ephemeral_files, hem attachment:// hem multipart/form-data | Dosya bir mesaj satırına bağlıdır, burada satır yok. Görseli herkese açık mesajla gönder. |
| Tepki, sabitleme | Satırı olmayan mesajda çalışmaz | Bileşen kullan. |
| Kanala doğrudan atma | POST /channels/{id}/messages 400 ephemeral_forbidden döner | Bir etkileşime yanıt ver: kime gösterileceğini basma söyler. |
| Kanal mesajı rotalarıyla okuma, düzenleme | 404 unknown_message | Etkileşim rotalarını kullan. |
| 15 dakika sonra basma | Kişi 400 interaction_expired alır, sana bir şey gelmez | Mesajı değiştirirsen süre yeniden başlar. |
Butonlu ephemeral
Bileşen eklersen kişi basabilir. Mesaj saklanmadığı için botuna gelen message kısadır: id, channel_id, flags, author ve components. Metni gelmez, gerekiyorsa bilgiyi custom_id'ye koy ya da kendi veritabanında tut.
{
"type": 4,
"data": {
"content": "Silinsin mi?",
"flags": 64,
"components": [{ "type": 1, "components": [
{ "type": 2, "style": 4, "label": "Sil", "custom_id": "sil:42" }
] }]
}
}
Kişi bastığında:
{
"id": "111600000000000700",
"type": 3,
"token": "...",
"channel_id": "111500000000000100",
"data": { "custom_id": "sil:42", "component_type": 2 },
"message": {
"id": "111600000000000400",
"channel_id": "111500000000000100",
"flags": 64,
"author": { "id": "111540000000000001", "username": "botun" },
"components": [{ "type": 1, "components": [
{ "type": 2, "style": 4, "label": "Sil", "custom_id": "sil:42" }
] }]
}
}
type: 7 basılan mesajı değiştirir. type: 4 ile flags: 64 yeni bir ephemeral açar, flags olmadan herkese açık yanıt verir. type: 7 sonrası düzenleme için @original değil, message.id kullan: PATCH /interactions/{id}/{token}/messages/{message.id}.
{ "type": 7, "data": { "content": "Silindi.", "components": [] } }
Satırı olmayan kimlik ephemeral sayıldığı için type: 6 ya da type: 7 sonrası @original 200 döner ama ekranda bir şey değişmez: o kimlikte mesaj yoktur. İstemci ephemeral MESSAGE_UPDATE ve MESSAGE_DELETE olayını yalnızca elinde flags: 64 ile tuttuğu ve application_id'si aynı olan mesaja uygular. Böylece bir bot başka botun mesajını değiştiremez.
Kişi ne görür
Etkileşime yanıt olan mesajın üstünde, yanıt satırı gibi, "ad kullandı" yazar. Herkese açık yanıtta bunu kanaldaki herkes görür. Böyle bir mesaj botunun bir önceki mesajıyla tek blokta birleşmez, adı ve avatarıyla ayrı başlar.
type: 5 sonrası mesajda üç nokta oynar ve "Botun adı düşünüyor…" yazar. PATCH @original gelince yerini yanıt alır. Bot 15 dakika içinde doldurmazsa yazı "Bot yanıt vermedi." olur; kişi sonsuza dek bekleyen bir mesaj görmez.
Ephemeral mesaj hafif renkli bir zeminde, solunda temanın renginde bir çizgiyle durur, altında "Yalnızca sen görüyorsun · Kapat" yazar. Üzerinde mesaj araç çubuğu ve sağ tık menüsü yoktur: yanıtlanamaz, iletilemez, sabitlenemez, tepki eklenemez ve bildirilemez. "Kapat" mesajı yalnızca o ekrandan kaldırır. Sayfa yenilenince ephemeral mesajlar gider; okunmadı sayacı ve kanalın son mesajı yerinde kalır.
Ephemeral mesajın butonları ve menüleri herkese açık mesajdakiler gibi çizilir ve basılır. Basınca uygulama mesajla gelen ephemeral_state'i geri gönderir, sunucu bileşenleri onunla doğrular. type: 7 ile yanıt verirsen ephemeral mesaj yerinde değişir. Mesaj gelişinden ya da son güncellenişinden 15 dakika sonra basan kişi "Bu etkileşimin süresi doldu." görür.
Token'ı koru
Token tek başına yetmez: dört rota da Authorization: Bot başlığı ister ve token'ı yalnızca etkileşimin gittiği bot kullanabilir. Başka bir botun göndermesi 400 interaction_token_invalid döner. Sunucu bu rotaların adresindeki token'ı kendi log'larına yazmaz.
Hatalar
| Kod | Ne oldu | Ne yap |
|---|---|---|
interaction_timeout | İlk yanıt 3 saniyeyi geçti | İşi yanıttan önce yapma. Önce type: 5 ya da type: 6 gönder, sonra işe başla. |
interaction_already_acknowledged | Bu etkileşime zaten yanıt verdin | Sonrası için takip mesajı ya da @original kullan. |
interaction_not_acknowledged | Takip ya da düzenleme ilk yanıttan önce geldi | Önce callback gönder ve yanıtını bekle. |
interaction_response_invalid | Bu etkileşime uymayan bir type gönderdin, type: 7'de data yok, choices type: 8 dışında geldi, ya da type: 9 otomatik tamamlamaya veya gönderilen forma gitti | Basmaya 4, 5, 6, 7 ya da 9, komuta 4, 5 ya da 9, otomatik tamamlamaya 8 gönder. |
interaction_token_invalid | Token bozuk, adresteki kimlikle uyuşmuyor ya da başka bir botun | id ve token'ı aynı olaydan al, kendi bot token'ınla gönder. |
interaction_expired | Token'ın 15 dakikası doldu | Kanala normal mesaj gönder. |
ephemeral_files | Ephemeral mesajda dosya ya da attachment:// var | Görseli herkese açık mesajla gönder. |
validation_failed | data bir mesaj olarak geçersiz, örneğin metin yok | errors alanına bak. Hakkın gitmedi, düzeltip yeniden gönder. |
missing_permissions | Botun bu kanalda SendMessages izni yok | type: 6 izin istemez. Diğerleri için izni ver. |
rate_limited | Sınır doldu; X-RateLimit-Scope: shared ise tüm botların ortak tavanı | retry_after kadar bekle. 3 saniye geçtiyse ilk yanıt artık kabul edilmez. |
Her tür için hangisi gelebilir:
| Kod | type: 4 | type: 5 | type: 6 | type: 7 |
|---|---|---|---|---|
interaction_timeout | Evet | Evet | Evet | Evet |
interaction_already_acknowledged | Evet | Evet | Evet | Evet |
validation_failed | Evet | Yalnızca flags | Hayır | Evet |
missing_permissions | Evet | Evet | Hayır | Evet |
automod_blocked | Evet | Hayır | Hayır | Evet |
Tam örnek: sayaç botu
Node.js 22 veya üstü yeter. Gateway sayfasındaki gateway.mjs ile Örnekler sayfasındaki api.mjs aynı klasörde olmalı. Bot açılınca kanala bir buton atar. Her basmada sayıyı bir artırıp aynı mesajı type: 7 ile günceller. Sayı custom_id'nin içinde durur, bot yeniden başlasa da kaybolmaz:
import { connect } from "./gateway.mjs";
import { call } from "./api.mjs";
const { CHANNEL_ID } = process.env;
if (!CHANNEL_ID) throw new Error("CHANNEL_ID tanımlı olmalı");
// Mesajın gövdesi: hem ilk gönderimde hem güncellemede aynı biçim.
const view = (count) => ({
content: `Sayaç: ${count}`,
components: [{ type: 1, components: [
{ type: 2, style: 1, label: "Artır", custom_id: `sayac:${count}` },
] }],
});
async function onPress(d) {
const [kind, count] = d.data.custom_id.split(":");
if (kind !== "sayac") return;
await call("POST", `/interactions/${d.id}/${d.token}/callback`, {
type: 7,
data: view(Number(count) + 1),
});
}
let posted = false;
await connect({
intents: 0,
onEvent(t, d) {
if (t === "READY" && !posted) {
posted = true;
call("POST", `/channels/${CHANNEL_ID}/messages`, view(0)).catch(console.error);
}
if (t === "INTERACTION_CREATE") onPress(d).catch(console.error);
},
});
Çalıştırmak için:
BOT_TOKEN='kopyaladigin_token' CHANNEL_ID='kanal id degeri' node sayac-botu.mjs
İki kişi aynı anda basarsa ikisi de aynı sayıyı görüp aynı sonucu yazar. Sayım önemliyse sayıyı kendi veritabanında tut.
Bu sayfayı yapay zekaya verirsen
Sırada ne var
- Komutlar:
/menüsü, kullanıcı ve mesaj komutlarının tanımı - Formlar:
type: 9ile çok satırlı form penceresi açmak - HTTP ile teslim: etkileşimleri gateway yerine kendi HTTPS adresine almak