Skip to content
Micup API

Etkileşimler: slash komut, buton, menü, modal

Micup’taki her bot slash komut kaydedebilir, gizli yanıt verebilir, mesajına buton ve seçim menüsü koyabilir ve modal açabilir. Onay ya da başvuru gerekmez. Alan adları, tip numaraları ve rotalar Discord ile aynıdır; discord.js ya da discord.py ile yazdığın bot birkaç ayarla çalışır. Bot oluşturmayı bilmiyorsan önce Hızlı başlangıç sayfasını oku.

Ayrıntılı başvuru: Uygulama komutları, Etkileşimler, Mesaj bileşenleri.

  1. Botun komutlarını kaydeder: tüm sunucular için global ya da tek sunucu için.
  2. Kullanıcı / yazıp komutu seçer, butona basar ya da menüden seçim yapar.
  3. Micup bunu botun tek bir gateway oturumuna INTERACTION_CREATE olarak gönderir. Olayın içinde bir token vardır.
  4. Bot 3 saniye içinde ilk yanıtı verir. Uzun sürecek işte önce “düşünüyor” (defer) yanıtı ver.
  5. Aynı token ile 15 dakika boyunca ilk yanıtı düzenleyebilir ve en çok 20 takip mesajı gönderebilirsin.

Gizli yanıt (flags: 64) yalnız komutu kullanan kişiye görünür; kanala mesaj olarak hiç yazılmaz, aramada, bildirimde ve okunmamış sayısında yer almaz.

Micup REST’te /v1, gateway’de v=1 kullanır. API adresini sabitleme; Micup’ın keşif yanıtındaki endpoints.api_public değerini oku.

KütüphaneAyar
discord.js 14new Client({rest: {api, version: '1'}, ws: {version: 1}}); gateway adresini kendisi GET /v1/gateway/bot ile alır
discord.py 2discord.http.Route.BASE, discord.http.INTERNAL_API_VERSION = 1 ve DiscordWebSocket.DEFAULT_GATEWAY

Kütüphanelerin gönderdiği name_localizations, description_localizations ve false değerli nsfw kabul edilir ama saklanmaz (her dilde varsayılan ad görünür); nsfw: true 400 döner. contexts Discord’daki gibi uygulanır: 0 yoksa komut sunucularda görünmez, 1 varsa genel komut botla birebir DM’de çalışır. integration_types yok sayılır.

/yardım komutu gizli bir yanıtla kategori menüsü, bir buton ve bir bağlantı butonu gösterir. Menüden seçim mesajı günceller, buton bir modal açar, modal gönderilince bot önce “düşünüyor” yanıtı verip sonra cevabı yazar. npm install discord.js ile kur, MICUP_TOKEN ve SUNUCU_ID ortam değişkenlerini ver, node bot.mjs ile çalıştır.

import {
ActionRowBuilder,
ButtonBuilder,
ButtonStyle,
Client,
Events,
GatewayIntentBits,
MessageFlags,
ModalBuilder,
Routes,
SlashCommandBuilder,
StringSelectMenuBuilder,
TextInputBuilder,
TextInputStyle,
} from 'discord.js';
const {MICUP_TOKEN, SUNUCU_ID} = process.env;
const kesif = await (await fetch('https://micup.gg/.well-known/fluxer')).json();
const api = kesif.endpoints.api_public.replace(/\/$/, '');
const KATEGORILER = {
mod: 'Moderasyon: /uyar, /sustur, /at',
seviye: 'Seviye: /seviye, /top',
};
const client = new Client({
intents: [GatewayIntentBits.Guilds],
rest: {api, version: '1'},
ws: {version: 1},
});
client.once(Events.ClientReady, async (c) => {
const komutlar = [new SlashCommandBuilder().setName('yardım').setDescription('Komut kategorilerini gösterir').toJSON()];
await c.rest.put(Routes.applicationGuildCommands(c.application.id, SUNUCU_ID), {body: komutlar});
console.log(`${c.user.username} hazır`);
});
client.on(Events.InteractionCreate, async (etkilesim) => {
try {
if (etkilesim.isChatInputCommand() && etkilesim.commandName === 'yardım') {
const menu = new StringSelectMenuBuilder()
.setCustomId('yardim:kategori')
.setPlaceholder('Bir kategori seçin...')
.addOptions({label: 'Moderasyon', value: 'mod'}, {label: 'Seviye', value: 'seviye'});
const butonlar = new ActionRowBuilder().addComponents(
new ButtonBuilder().setCustomId('yardim:oneri').setLabel('Öneri gönder').setStyle(ButtonStyle.Primary),
new ButtonBuilder().setURL('https://micup.gg/docs/').setLabel('Belgeler').setStyle(ButtonStyle.Link),
);
await etkilesim.reply({
content: 'Bir kategori seç:',
components: [new ActionRowBuilder().addComponents(menu), butonlar],
flags: MessageFlags.Ephemeral,
});
} else if (etkilesim.isStringSelectMenu() && etkilesim.customId === 'yardim:kategori') {
const metin = KATEGORILER[etkilesim.values[0]];
if (metin === undefined) return;
await etkilesim.update({content: metin});
} else if (etkilesim.isButton() && etkilesim.customId === 'yardim:oneri') {
const alan = new TextInputBuilder()
.setCustomId('metin')
.setLabel('Önerin')
.setStyle(TextInputStyle.Paragraph)
.setMaxLength(500);
const modal = new ModalBuilder()
.setCustomId('yardim:oneri-formu')
.setTitle('Öneri')
.addComponents(new ActionRowBuilder().addComponents(alan));
await etkilesim.showModal(modal);
} else if (etkilesim.isModalSubmit() && etkilesim.customId === 'yardim:oneri-formu') {
await etkilesim.deferReply({flags: MessageFlags.Ephemeral});
const oneri = etkilesim.fields.getTextInputValue('metin');
console.log('Yeni öneri, uzunluk:', oneri.length);
await etkilesim.editReply({content: 'Teşekkürler, önerin alındı.'});
}
} catch (hata) {
console.error('Etkileşim yanıtlanamadı:', hata.code ?? hata.message);
}
});
client.login(MICUP_TOKEN);

etkilesim.reply, update, showModal ve deferReply ilk yanıttır ve 3 saniye içinde gitmelidir; editReply ve followUp 15 dakika boyunca çalışır.

Aynı akış discord.py 2 ile, kütüphanenin kendi CommandTree, View ve Modal sınıflarıyla. discord.py 2.5 ve sonrası her ilk yanıtta yanıt gövdesini ister (with_response=1); Micup bu gövdeyi Discord’daki gibi döndürür, gizli mesajdaki buton ve menü de View geri çağrısına ulaşır. pip install discord.py ile kur, python bot.py ile çalıştır.

import json
import os
import urllib.request
import discord
import discord.gateway
import discord.http
import yarl
from discord import app_commands
TOKEN = os.environ["MICUP_TOKEN"]
SUNUCU = discord.Object(id=int(os.environ["SUNUCU_ID"]))
with urllib.request.urlopen("https://micup.gg/.well-known/fluxer", timeout=15) as yanit:
API = json.load(yanit)["endpoints"]["api_public"].rstrip("/")
discord.http.INTERNAL_API_VERSION = 1
discord.http.Route.BASE = f"{API}/v1"
istek = urllib.request.Request(f"{API}/v1/gateway/bot", headers={"Authorization": f"Bot {TOKEN}"})
with urllib.request.urlopen(istek, timeout=15) as yanit:
discord.gateway.DiscordWebSocket.DEFAULT_GATEWAY = yarl.URL(json.load(yanit)["url"])
KATEGORILER = {"mod": "Moderasyon: /uyar, /sustur, /at", "seviye": "Seviye: /seviye, /top"}
class OneriFormu(discord.ui.Modal, title="Öneri"):
metin = discord.ui.TextInput(label="Önerin", style=discord.TextStyle.paragraph, max_length=500)
async def on_submit(self, etkilesim):
await etkilesim.response.defer(ephemeral=True, thinking=True)
print("Yeni öneri, uzunluk:", len(self.metin.value))
await etkilesim.edit_original_response(content="Teşekkürler, önerin alındı.")
class YardimMenusu(discord.ui.View):
@discord.ui.select(
custom_id="yardim:kategori",
placeholder="Bir kategori seçin...",
options=[
discord.SelectOption(label="Moderasyon", value="mod"),
discord.SelectOption(label="Seviye", value="seviye"),
],
)
async def kategori(self, etkilesim, secim):
await etkilesim.response.edit_message(content=KATEGORILER[secim.values[0]])
@discord.ui.button(label="Öneri gönder", custom_id="yardim:oneri", style=discord.ButtonStyle.primary)
async def oneri(self, etkilesim, buton):
await etkilesim.response.send_modal(OneriFormu())
client = discord.Client(intents=discord.Intents.default())
agac = app_commands.CommandTree(client)
@agac.command(name="yardım", description="Komut kategorilerini gösterir", guild=SUNUCU)
async def yardim(etkilesim):
gorunum = YardimMenusu(timeout=None)
gorunum.add_item(discord.ui.Button(label="Belgeler", url="https://micup.gg/docs/"))
await etkilesim.response.send_message("Bir kategori seç:", view=gorunum, ephemeral=True)
@client.event
async def on_ready():
await agac.sync(guild=SUNUCU)
print(f"{client.user} hazır")
client.run(TOKEN)

timeout=None menüyü bot çalıştığı sürece açık tutar; discord.py’nin varsayılanı 180 saniyedir. agac.sync sunucu komutlarını yazar ve dakikada 2 yazımla sınırlıdır; komutlar değişmediyse her açılışta çağırmak gerekmez.

Yanıt tipleri: 4 mesajla yanıt, 5 “düşünüyor”, 6 bileşeni sessizce onayla, 7 bileşenin olduğu mesajı güncelle, 8 otomatik tamamlama önerileri, 9 modal aç. Tam liste.

Bir STRING, INTEGER ya da NUMBER seçeneğine autocomplete: true verirsen kullanıcı yazarken tip 4 etkileşim gelir. Odaktaki seçeneğin value alanı yazılan ham metindir. 3 saniye içinde tip 8 ile en çok 25 öneri döndür; bu yanıt ertelenemez. Aynı seçenekte choices ile autocomplete birlikte kullanılamaz.

KonuMicup
SürümREST /v1, gateway v=1
HTTP uç noktasıYok; her etkileşim gateway’den gelir
Bot üyeliğiBot sunucuda üye olmalı; herkese açık yanıt için kanalda SEND_MESSAGES gerekir
dm_permission alanıVarsayılanı false; DM’de yalnız kullanıcı ile bot arasındaki birebir sohbette çalışır
Ertelenmiş herkese açık yanıtKanalda yer tutucu mesaj yok; ilk @original düzenlemesi mesajı oluşturur
Gizli yanıtKanala mesaj olarak yazılmaz, yalnız kullanıcının oturumuna gider
Components v2Sunucu content alanına yedek metin koyar; bot bunu yok sayar. Bugün kapalı
Ek takip yoluPOST /v1/interactions/{id}/followups, bot tokenı ve Idempotency-Key ile
Komut yazımıIf-Match isteğe bağlı
Yerelleştirmename_localizations ve description_localizations saklanmaz, her dilde varsayılan ad görünür; nsfw: true reddedilir
Henüz yokSağ tık komutları, premium buton, yanıtta dosya, modal içinde menü ve dosya
  • custom_id ve menü değerleri güvenilmez girdidir. Micup yalnız bileşenin mesajda olduğunu ve değerin seçenekler arasında olduğunu denetler. Botun bunları her kullanıcı girdisi gibi doğrulamalı; içine gizli bilgi ya da yetki koyma.
  • Yetkiyi botta denetle. default_member_permissions yalnız komutu gizler.
  • Bağlantı butonu yalnız http ve https adresi alır, en çok 512 karakter, kullanıcı adı ve parola içeremez, engel listesindeki alan adları reddedilir. Kullanıcı açmadan önce dış bağlantı uyarısını görür.
  • Etkileşim tokenı bir kimlik bilgisidir: 15 dakika boyunca o etkileşimin yanıtlarını yazar. Loglara ve hata raporlarına yazma.
  • Botlar butona tıklayamaz: tıklama rotası bot tokenıyla 403 ACCESS_DENIED döner. Bu, botların bileşen yazamadığı anlamına gelmez; bileşenler botun kendi mesajına yazılır.
Ne zamanKod
İlk yanıt 3 saniyeyi ya da token 15 dakikayı geçti410 INTERACTION_EXPIRED
Etkileşime zaten ilk yanıt verildi409 INTERACTION_TOKEN_CONSUMED
Token ya da uygulama kimliği tutmuyor404 UNKNOWN_WEBHOOK
Bot ya da kullanıcı için ilgili özellik kapalı403 APPLICATION_COMMAND_FEATURE_DISABLED
If-Match ile yazarken komut seti değişmiş412 APPLICATION_COMMAND_VERSION_CONFLICT
Desteklenmeyen bileşen türü400 UNSUPPORTED_COMPONENT
Seçim değeri bileşende yok400 INVALID_COMPONENT_VALUE
Açık modal olmadan gönderim409 MODAL_NOT_OPEN

Hız sınırı aşılınca 429 gelir; Retry-After kadar bekle. Hız sınırları.

Başvuru şartları ayrıca duyurulacak.