N'oluyo · Geliştirici Dokümanları · Son güncelleme: · https://noluyo.net/gelistirici

Formlar

Form, botunun bir komuta ya da butona yanıt olarak kişiye açtığı pencere: kişi en çok beş alanı doldurur, gönderir ve doldurduğu her şey sana yeni bir etkileşim olarak gelir.

Formlar

Form, botunun bir komuta ya da butona yanıt olarak kişiye açtığı pencere: kişi en çok beş alanı doldurur, gönderir ve doldurduğu her şey sana yeni bir etkileşim olarak gelir.

Form mu, komut seçeneği mi?

DurumSeç
Kısa, tek satırlık birkaç değer: bir sayı, bir kişi, listeden bir şeyKomut seçeneği
Uzun ya da çok satırlı metin: şikayet, başvuru, açıklamaForm
Değeri bir butona basınca sormakForm (butonun seçeneği yoktur)
Kişinin yazdığını önceden doldurup düzelttirmekForm, value ile
Yazarken öneri göstermekOtomatik tamamlama; formda öneri yok

Akış

AdımNe olur
1Kişi komutunu çalıştırır ya da butonuna basar. Sana INTERACTION_CREATE gelir, type: 2 ya da type: 3.
23 saniye içinde callback ile type: 9 ve formu gönderirsin. Yanıt 204'tür. Bu, etkileşimin tek yanıtıdır.
3Form kişinin ekranında açılır; altında sabit uyarı satırı durur. Kişi istediği kadar uzun yazabilir.
4Kişi gönderir. Sana yeni bir INTERACTION_CREATE gelir, type: 5: kendi id'si ve 15 dakikalık yeni token'ı vardır.
53 saniye içinde bu yeni etkileşime yanıt verirsin: 4, 5, form bir butondan açıldıysa 6 ya da 7 de olur.

DM'de de aynıdır: komut ya da buton botla açılmış DM'deyse gönderim context: 1 ile ve member yerine user ile gelir; kişi gönderim arasında botu engellerse gönderim reddedilir.

Form açıldıktan sonra 1 saat gönderilebilir. Açan etkileşimin 15 dakikalık token'ı bunu kısaltmaz: kişi 40 dakika yazsa da gönderim çalışır.

Kişi ne görür

Form yalnızca komutu çalıştıran ya da butona basan cihazda açılır; kişinin öbür oturumları aynı olayı alır ama yok sayar. Pencerenin başlığı senin title'ındır. Altında botunun avatarı, adı, BOT etiketi ve uygulaman doğrulanmışsa "Doğrulanmış" etiketi durur. Alanlar senin sıranla gelir; zorunlu olanların adının yanında kırmızı bir yıldız vardır.

AlanKişi ne görür
Metin girişi, style: 1Tek satırlık yazı kutusu, placeholder ve value ile. Altında kalan karakter sayısı yazar; sınırı geçince sayı kırmızıya döner. max_length göndermezsen sınır 4000'dir.
Metin girişi, style: 2Çok satırlı, boyu uzatılabilen yazı kutusu; sayaç aynı.
Metin menüsüTek seçimliyse uygulamanın açılır listesi, çok seçimliyse işaretlenen bir liste penceresi. default seçenekler seçili gelir.
Kullanıcı, rol, kanal, karma menüBir düğme; basınca aramalı bir liste penceresi açılır, kişi işaretleyip "Onayla"ya basar. Kanal listesinde yalnızca kişinin gördüğü ve channel_types'a uyan kanallar çıkar. required: false menü boş bırakılabilir.

Pencerenin altında, alanların dışında, kişinin her zaman gördüğü satır durur: "Bu form {bot} botuna gider. Şifreni ya da doğrulama kodunu asla yazma." Alanlar uzunsa yalnızca alanlar kayar; bu satır ve düğmeler yerinde kalır.

Kişi "Gönder"e basınca uygulama önce zorunlu alanları ve uzunlukları sunucunun kurallarıyla denetler: yalnızca boşluk yazılmış zorunlu alan boş sayılır. Hata alanın altında kırmızı yazar ve form gitmez. Her şey tamsa "Gönder" dönen bir simgeye döner ve botun yanıtlayana kadar bekler; yanıt gelince form kapanır.

Gönderim başarısız olursa form açık kalır ve kişinin yazdığı her şey yerinde durur:

Ne olduKişi ne görür
Botun 3 saniyede yanıt vermediFormun altında "Bot yanıt vermedi." Kişi yeniden gönderebilir.
Sunucu bir alanı reddetti (validation_failed)Hata o alanın altında.
Form süresi doldu ya da üç kez gönderildi (modal_expired)"Süre doldu, metni kopyalayıp komutu yeniden çalıştır." "Gönder" kapanır, yanında bir "Kopyala" düğmesi çıkar; yazılan metin alan adlarıyla birlikte panoya kopyalanır.
Başka bir hataHatanın metni formun altında.

Kişi bir şey yazmışsa kapatma düğmesi, Esc, dışarı tıklama ya da "Vazgeç" önce "Yazdıkların silinsin mi?" diye sorar. Yalnızca senin value ile doldurduğun metin duruyorsa form sormadan kapanır.

En küçük örnek

Komuta form ile yanıt ver:

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":9,"data":{"custom_id":"sikayet","title":"Şikayet","components":[{"type":1,"components":[{"type":4,"custom_id":"konu","style":1,"label":"Konu","max_length":100}]},{"type":1,"components":[{"type":4,"custom_id":"detay","style":2,"label":"Ne oldu?","required":false}]}]}}'

Aynı form JSON olarak:

{
  "type": 9,
  "data": {
    "custom_id": "sikayet",
    "title": "Şikayet",
    "components": [
      { "type": 1, "components": [
        { "type": 4, "custom_id": "konu", "style": 1, "label": "Konu", "max_length": 100 }
      ] },
      { "type": 1, "components": [
        { "type": 4, "custom_id": "detay", "style": 2, "label": "Ne oldu?", "required": false }
      ] }
    ]
  }
}

Formun alanları

AlanKural
custom_idZorunlu, en çok 100 karakter. Gönderimde data.custom_id olarak geri gelir.
titleZorunlu, en çok 45 karakter
components1-5 eylem satırı (type: 1); her satırda tek bir metin girişi ya da tek bir menü

Formun JSON'u en çok 16 KiB olabilir. Alanların custom_id'leri form içinde tekil olmalı. Otomatik moderasyon başlığı, etiketleri, yer tutucuları ve ön doldurduğun değerleri okur; kuralı tutan form automod_blocked ile reddedilir.

Metin girişi

AlanKural
type4
custom_idZorunlu, en çok 100 karakter
style1 tek satır, 2 paragraf
labelZorunlu, en çok 45 karakter
placeholderBoşken görünen yazı, en çok 100 karakter
min_length0-4000, varsayılan 0
max_length1-4000, varsayılan 4000
requiredVarsayılan true
valueForm açılırken alanda dolu görünen metin, en çok max_length; kişi değiştirebilir

Zorunlu alana yalnız boşluk yazılırsa gönderim reddedilir ve kişi alanı doldurması gerektiğini görür. Bunun dışında metin yazıldığı gibi gelir: baştaki ve sondaki boşluk silinmez, satır sonları korunur. İsteğe bağlı alan boş bırakıldıysa value boş dizedir.

Formda menü

Bir satır metin girişi yerine bir menü de taşıyabilir: metin (3), kullanıcı (5), rol (6), kullanıcı ya da rol (7), kanal (8). Bileşenler sayfasındaki kurallar geçerlidir; formda iki fark vardır:

AlanFormda
labelZorunlu, en çok 45 karakter
requiredVarsayılan true; false ise kişi menüyü boş bırakabilir, o zaman values boş liste gelir
disabledKullanılmaz

Sunucu seçilenleri kişinin erişebildiğine göre denetler: kullanıcı sunucunun üyesi, rol bu sunucunun, kanal kişinin görebildiği olmalı. Seçilen kullanıcılar, üyeler, roller ve kanallar data.resolved içinde gelir.

Ön doldurma

value ile kişinin daha önce yazdığını ya da senin bildiğin bir değeri alana koyarsın; kişi onaylar ya da düzeltir. Örneğin bir butondan "düzenle" formu açarken eski metni geri ver:

{ "type": 4, "custom_id": "aciklama", "style": 2, "label": "Açıklama", "value": "Eski açıklama burada." }

Kullanıcı, rol ve kanal menüsünde default_values aynı işi görür.

Gönderim sana nasıl gelir

{
  "id": "111804206284800777",
  "application_id": "14631410073600008",
  "type": 5,
  "token": "eyJpZCI6IjExMTgwNDIwNjI4NDgwMDc3NyJ9.bWFj",
  "version": 1,
  "guild_id": "21531879014400001",
  "channel_id": "21531887403008007",
  "member": {
    "user": { "id": "14631410073600003", "username": "ayse", "display_name": "Ayşe", "avatar": null, "cosmetics": null },
    "nick": null, "roles": [], "joined_at": "2026-10-01T12:00:00Z", "permissions": "2147483648"
  },
  "app_permissions": "2048",
  "locale": "tr",
  "data": {
    "custom_id": "sikayet",
    "components": [
      { "type": 1, "components": [{ "type": 4, "custom_id": "konu", "value": "Spam yapan biri" }] },
      { "type": 1, "components": [{ "type": 4, "custom_id": "detay", "value": "Genel kanalda\nreklam atıyor." }] },
      { "type": 1, "components": [{ "type": 5, "custom_id": "kim", "values": ["14631410073600005"] }] }
    ],
    "resolved": {
      "users": { "14631410073600005": { "id": "14631410073600005", "username": "spamci", "display_name": null, "avatar": null, "cosmetics": null } }
    }
  }
}
AlanAnlamı
type5: gönderilen form
tokenBu gönderimin kendi token'ı, 15 dakika geçerli; yanıt ve takip mesajları bununla
data.custom_idAçtığın formun custom_id'si
data.componentsFormun her alanı kendi sırasıyla, doldurulmuş ya da boş; metin girişi value, menü values taşır
data.resolvedMenülerde seçilen kullanıcı, üye, rol ve kanal; menü yoksa yer almaz
member ya da user, localeGönderen kişi ve dili

Formu bir komut açtıysa yanıtın mesajı "X, /komut kullandı" diye gösterilir.

Yanıt seçenekleri

Etkileşimtype: 4type: 5type: 6type: 7type: 9
Komut çalıştırma (type: 2)EvetEvetHayırHayırEvet
Butona basma, menüden seçme (type: 3)EvetEvetEvetEvetEvet
Otomatik tamamlama (type: 4)HayırHayırHayırHayırHayır
Komuttan açılmış formun gönderimi (type: 5)EvetEvetHayırHayırHayır
Butondan açılmış formun gönderimi (type: 5)EvetEvetEvetEvetHayır

type: 7 butondan açılmış formda butonun durduğu mesajı günceller; o mesaj ephemeral ise ephemeral mesaj bütünüyle değişir. flags: 64 ile 4 ya da 5 yanıtı yalnızca gönderen görür. Ayrıntılar Etkileşimler sayfasında.

Kurallar

  • Formu açan bir form açamaz. Gönderilen forma type: 9 ile yanıt veremezsin. Başka soruların varsa ilk formu en çok beş alanla tasarla ya da yanıtına bir buton koy; buton yeni bir form açabilir.
  • Formu açmak ilk yanıttır. Önce type: 5 ya da type: 6 verip sonra form açamazsın: 3 saniye içinde doğrudan type: 9 gönder. Formu hazırlamak için dışarıya gitme; tanımı kodunda hazır tut.
  • Form yazmaz. type: 9 kanala mesaj yazmaz ve tüm botların ortak yazma tavanına sayılmaz.
  • Bir form üç kez gönderilebilir. Botun yanıt vermezse kişi yazdığını kaybetmeden yeniden gönderebilir. Her gönderim sana ayrı bir etkileşim olarak gelir; aynı içerik ikinci kez gelirse işini iki kez yapma. Üçüncüden sonra kişi modal_expired alır ve formu yeniden açması gerekir.
  • Gönderimde her şey yeniden denetlenir. Kişi kanala hâlâ erişebilmeli, zaman aşımında olmamalı, botun sunucuda olmalı ve form bir komuttan açıldıysa komutun izin kuralları kişiye hâlâ izin vermeli. Form sen açtığından beri değişmemiştir: kişi alan ekleyemez, custom_id değiştiremez.
  • Yazılan saklanmaz. N'oluyo formun içeriğini saklamaz; yalnızca kişinin bir form gönderdiğini erişim kaydına yazar. İçerik sana gelir; yalnızca işin için kullan.

Tam örnek: şikayet formu botu

Node.js 22 veya üstü yeter. Gateway sayfasındaki gateway.mjs ile Örnekler sayfasındaki api.mjs aynı klasörde olmalı. Bot /sikayet komutunu kaydeder, form açar, gönderilen şikayeti moderatör kanalına yazar ve kişiye yalnızca onun göreceği bir teşekkür gönderir:

import { connect } from "./gateway.mjs";
import { call } from "./api.mjs";

// Moderatörlerin gördüğü kanalın kimliği.
const modChannel = process.env.MOD_CHANNEL_ID;

const commands = [{
  name: "sikayet",
  name_localizations: { en: "report" },
  description: "Moderatörlere şikayet gönder",
  description_localizations: { en: "Send a report to the moderators" },
}];

const form = (en) => ({
  custom_id: "sikayet",
  title: en ? "Report" : "Şikayet",
  components: [
    { type: 1, components: [{ type: 5, custom_id: "kim", label: en ? "Who?" : "Kim?" }] },
    { type: 1, components: [{ type: 4, custom_id: "konu", style: 1, label: en ? "Subject" : "Konu", max_length: 100 }] },
    { type: 1, components: [{ type: 4, custom_id: "detay", style: 2, label: en ? "What happened?" : "Ne oldu?",
      required: false, max_length: 1500 }] },
  ],
});

// Gönderilen formun alanları: custom_id -> value ya da values.
function fields(data) {
  const out = {};
  for (const row of data.components) for (const f of row.components) out[f.custom_id] = f.value ?? f.values;
  return out;
}

async function onInteraction(d) {
  const path = `/interactions/${d.id}/${d.token}/callback`;
  const en = d.locale === "en";
  if (d.type === 2 && d.data.name === "sikayet") {
    // Formu açmak ilk yanıttır: önce 5 verilmez.
    await call("POST", path, { type: 9, data: form(en) });
    return;
  }
  if (d.type !== 5 || d.data.custom_id !== "sikayet") return;
  const f = fields(d.data);
  const who = d.data.resolved?.users?.[f.kim[0]];
  const from = d.member?.user ?? d.user;
  await call("POST", path, { type: 5, data: { flags: 64 } });
  try {
    await call("POST", `/channels/${modChannel}/messages`, {
      embeds: [{
        title: f.konu,
        description: f.detay || "-",
        fields: [
          { name: "Şikayet edilen", value: `<@${who.id}>`, inline: true },
          { name: "Gönderen", value: `<@${from.id}>`, inline: true },
        ],
      }],
      allowed_mentions: { parse: [] },
    });
    await call("PATCH", `/interactions/${d.id}/${d.token}/messages/@original`, {
      content: en ? "Thanks, the moderators got your report." : "Teşekkürler, şikayetin moderatörlere ulaştı.",
    });
  } catch (err) {
    console.error(err.message);
    await call("PATCH", `/interactions/${d.id}/${d.token}/messages/@original`, {
      content: en ? "Your report could not be delivered. Try again later." : "Şikayetin iletilemedi. Biraz sonra yeniden dene.",
    });
  }
}

let registered = false;

await connect({
  intents: 0,
  onEvent(t, d) {
    if (t === "READY" && !registered) {
      registered = true;
      call("PUT", `/applications/${d.application.id}/commands`, commands)
        .then(() => console.log("/sikayet kaydedildi"))
        .catch(console.error);
    }
    if (t === "INTERACTION_CREATE") onInteraction(d).catch((err) => console.error(err.message));
  },
});

Çalıştırmak için botunun moderatör kanalında SendMessages ve EmbedLinks izni olsun:

BOT_TOKEN='kopyaladigin_token' MOD_CHANNEL_ID='kanal_kimligi' node sikayet-botu.mjs

Örnek şikayetin içeriğini konsola yazmaz. Moderatör kanalına yazma 3 saniyeyi aşabilir; bu yüzden önce type: 5 ile yanıt verip sonucu @original ile doldurur.

Limitler

AnahtarDeğerSaniyeAnlamı
title45Başlık, karakter
rows5Formdaki alan sayısı
label45Alan etiketi, karakter
placeholder100Metin girişinin yer tutucusu, karakter
value4000Metin girişine yazılabilen, karakter
bytes16384Formun JSON'u
sends33600Bir formun gönderilebileceği sayı ve formun ömrü
user55Kişi başına kanalda basma, komut ve form gönderimi birlikte

Kişinin gönderimleri basma ve komutlarla aynı sınırları paylaşır; aşılırsa sana bir şey gelmez, kişi 429 alır ve form açık kalır.

Hatalar

Formu açarken sana dönenler:

KodNe olduNe yap
interaction_response_invalidtype: 9'u otomatik tamamlamaya ya da gönderilen forma verdin, data yok, ya da yanında content, embeds, flags gibi mesaj alanı varFormu yalnızca komuta ya da basmaya, yalnızca custom_id, title ve components ile gönder.
validation_failedForm geçersiz: örneğin başlık yok, beşten çok satır, bir satırda iki alan, etiket 45 karakteri aşıyorerrors alanına bak. Hakkın gitmedi, düzeltip yeniden gönder.
automod_blockedBaşlık, etiket ya da ön doldurduğun değer sunucunun otomatik moderasyon kuralına takıldıMetni değiştir.
interaction_already_acknowledgedBu etkileşime zaten yanıt verdin, örneğin önce type: 5Formu ilk yanıt olarak gönder.
interaction_timeout3 saniye geçtiFormu kodunda hazır tut, açmadan önce dışarıya gitme.

Kişinin gönderirken alabileceği hatalar sana gelmez:

KodNe oldu
modal_expiredForm 1 saatten eski, üç kez gönderildi, ya da başka bir kişinin veya kanalın
validation_failedZorunlu alan boş ya da yalnız boşluk, uzunluk dışında, menüde kişinin erişemediği bir değer
missing_access, missing_permissionsKişi kanalı artık göremiyor ya da zaman aşımında
application_unavailableBotun sunucudan çıkarıldı ya da kapatıldı
command_forbiddenForm bir komuttan açıldı ve komutun izin kuralları artık kişiye izin vermiyor
rate_limited, interaction_busyKişinin ya da tüm botların sınırı doldu

Bu sayfayı yapay zekaya verirsen

Sırada ne var

  • Komutlar: form açabilen eğik çizgi, kullanıcı ve mesaj komutları
  • Bileşenler: form açabilen butonlar ve seçim menüleri
  • Etkileşimler: form gönderimine verilen yanıt türleri ve takip mesajları