# Başlangıç: ilk botun

Birkaç dakika sonra sunucunda kendi botun olacak ve ilk mesajını yazmış olacak. Ardından `!ping` yazılınca yanıt veren küçük bir program yazacağız.

Bunun için bir N'oluyo hesabı, yönettiğin bir sunucu, bir terminal ve `curl` yeterli. Son adımdaki program için Node.js 22 ya da üstü de gerekir; sürümünü `node --version` ile görebilirsin. Sözcükler yabancı geliyorsa önce [Temel kavramlar](https://noluyo.net/gelistirici/kavramlar.md) sayfasına göz at.

> **Not:** Uygulama oluşturmak için e-posta adresinin doğrulanmış olması gerekir. Doğrulamadıysan portal bunu söyler; gelen kutundaki bağlantıya tıklaman yeter.

## 1. Portalı aç

[Geliştirici portalına](https://noluyo.net/gelistirici/uygulamalar) git ve her zamanki gibi N'oluyo hesabınla giriş yap.

## 2. Uygulamanı oluştur

**Yeni uygulama** düğmesine bas ve iki şey yaz:

- **Uygulama adı:** Botunun sunucularda görünen adı, en çok 32 karakter.
- **Bot kullanıcı adı:** 4 ile 32 karakter arası; küçük harf, rakam, `_` ve `.` olabilir. Sonradan değiştirilemez.

Sonra **Oluştur**'a bas.

## 3. Token'ı kopyala

Karşına botun token'ı çıkar. **Kopyala** ile alıp güvenli bir yere kaydet, çünkü **bir daha gösterilmez**. Kaybedersen uygulama sayfasındaki **Token'ı yenile** ile yenisini alırsın.

> **Uyarı:** Token'ı bilen herkes botunu kullanabilir. Kimseyle paylaşma, koda yazıp depoya gönderme. Ayrıntılar [Güvenlik](https://noluyo.net/gelistirici/guvenlik.md) sayfasında.

Kaydettikten sonra **Kopyaladım, devam et**'e bas.

## 4. Botu sunucuna ekle

Uygulama sayfasındaki **Ekleme bağlantısı** bölümünde bota vereceğin izinleri seç. Bu rehber için üçü yeterli:

- Kanalları görüntüle
- Mesaj gönder
- Mesaj geçmişini oku

Bağlantı `izin=68608` ile biter. **Bağlantıyı aç**'a bas, açılan sayfada **Sunucu** listesinden sunucunu seç ve **Sunucuya ekle**'ye bas.

Bot artık sunucunda. Kendi adını taşıyan bir rol de aldı; seçtiğin izinler bu rolde durur.

## 5. İlk isteğini gönder

Şimdi botu **REST** ile konuşturacaksın. REST, programının belirli bir adrese HTTP isteği gönderip yanıt aldığı yoldur; bir sayfa açmaya benzer, ama yanıt JSON olarak gelir. Buradan sonra tek ihtiyacın token. Terminalde tanımla:

```bash
export BOT_TOKEN='kopyaladigin_token'
```

Önce token'ın çalıştığını deneyelim: bu istek botun kendi bilgilerini döndürür. Başlıktaki `Bot` sözcüğüne dikkat et:

```bash
curl "https://noluyo.net/api/v1/users/@me" \
  -H "Authorization: Bot $BOT_TOKEN"
```

Botun bulunduğu sunucuları listele ve sunucunun `id` değerini al. API'de sunucuya `guild` denir.

```bash
curl "https://noluyo.net/api/v1/users/@me/guilds" \
  -H "Authorization: Bot $BOT_TOKEN"

export GUILD_ID='sunucu id degeri'
```

Kanalları listele ve `"type": 0` olan (metin) bir kanalın `id` değerini al:

```bash
curl "https://noluyo.net/api/v1/guilds/$GUILD_ID/channels" \
  -H "Authorization: Bot $BOT_TOKEN"

export CHANNEL_ID='kanal id degeri'
```

Şimdi mesajı gönder:

```bash tab=curl
curl -i -X POST "https://noluyo.net/api/v1/channels/$CHANNEL_ID/messages" \
  -H "Authorization: Bot $BOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"content":"Merhaba, ben yeni botum!"}'
```

```js tab=JavaScript
const { BOT_TOKEN, CHANNEL_ID } = process.env;

const res = await fetch(`https://noluyo.net/api/v1/channels/${CHANNEL_ID}/messages`, {
  method: "POST",
  headers: {
    Authorization: `Bot ${BOT_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ content: "Merhaba, ben yeni botum!" }),
});
console.log(res.status, await res.json());
```

Mesaj kanalda görünür. Yanıt `200` ile mesaj nesnesi olarak gelir. `-i` sayesinde `X-RateLimit-*` başlıklarını da görürsün; bunları [Hız sınırları](https://noluyo.net/gelistirici/rate-limit.md) sayfasında açıklıyoruz.

## 6. Biraz daha dene

Önceki yanıttaki `id` değerini al:

```bash
export MESSAGE_ID='yanittaki id degeri'
```

Emoji adreste URL kodlanmış olmalıdır. `%F0%9F%91%8B`, 👋 emojisidir. Portaldaki ekleme bağlantısında **Tepki ekle**'yi işaretlemediysen tepki izni sunucunun `@everyone` rolünden gelir; sunucuda kapatılmışsa `403 missing_permissions` alırsın.

```bash
# Tepki ver (204)
curl -i -X PUT "https://noluyo.net/api/v1/channels/$CHANNEL_ID/messages/$MESSAGE_ID/reactions/%F0%9F%91%8B/@me" \
  -H "Authorization: Bot $BOT_TOKEN"

# Düzenle (200)
curl -X PATCH "https://noluyo.net/api/v1/channels/$CHANNEL_ID/messages/$MESSAGE_ID" \
  -H "Authorization: Bot $BOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"content":"Merhaba, bu mesaj duzenlendi."}'

# Son mesajları oku (200)
curl "https://noluyo.net/api/v1/channels/$CHANNEL_ID/messages?limit=5" \
  -H "Authorization: Bot $BOT_TOKEN"

# Sil (204)
curl -i -X DELETE "https://noluyo.net/api/v1/channels/$CHANNEL_ID/messages/$MESSAGE_ID" \
  -H "Authorization: Bot $BOT_TOKEN"
```

## 7. Küçük bir bot yaz

Şimdiye kadar her isteği sen gönderdin. Gerçek bir bot ise kanalda olanları duyar ve kendisi yanıt verir. Bunu [gateway](https://noluyo.net/gelistirici/gateway.md) sağlar: programın N'oluyo'ya bir `WebSocket` bağlantısı açar, yeni mesajlar bu bağlantıdan anında gelir.

**Önce Mesaj içeriği'ni aç.** Bot, `!ping` yazıldığını ancak mesajların metnini okuyabilirse anlar ve bu ayrı bir intent'tir. **Intent**, botun hangi olayları almak istediğini söylediği seçimdir. Portalda uygulama sayfasına dön, **Ayrıcalıklı intent'ler** bölümünde **Mesaj içeriği**'ni aç. Açmazsan program `4014` koduyla kapanır.

Örnek Node.js 22 ya da üstü ister: bu sürümlerde `WebSocket` hazırdır, ek paket gerekmez. `bot.mjs` adıyla kaydet:

```js title=bot.mjs
const API = "https://noluyo.net/api/v1";
const { BOT_TOKEN } = process.env;
const headers = { Authorization: `Bot ${BOT_TOKEN}`, "Content-Type": "application/json" };

// Sunucu mesajları (1 << 9) ve mesaj içeriği (1 << 15).
const INTENTS = (1 << 9) | (1 << 15);
// Bu kodlarda yeniden bağlanmak işe yarar; diğerlerinde kodu düzeltmek gerekir.
const RETRY = [4000, 4008, 4010];

const res = await fetch(`${API}/gateway/bot`, { headers });
if (!res.ok) throw new Error(`GET /gateway/bot: ${res.status}`);
const { url } = await res.json();

let me;

async function reply(message) {
  const sent = await fetch(`${API}/channels/${message.channel_id}/messages`, {
    method: "POST",
    headers,
    body: JSON.stringify({ content: "pong!", message_reference: { message_id: message.id } }),
  });
  if (!sent.ok) console.error("yanıt gitmedi", sent.status, await sent.text());
}

function connect() {
  const ws = new WebSocket(url);
  let heartbeat;
  let seq = null;
  const send = (op, d) => {
    if (ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify({ op, d }));
  };

  ws.onerror = () => {};

  ws.onmessage = (e) => {
    const { op, d, s, t } = JSON.parse(e.data);
    if (s) seq = s;
    if (op === 10) {
      heartbeat = setInterval(() => send(1, seq), d.heartbeat_interval);
      send(2, { token: BOT_TOKEN, intents: INTENTS });
    } else if (t === "READY") {
      me = d.user.id;
      console.log(d.user.username, "bağlandı");
    } else if (t === "MESSAGE_CREATE" && d.author.id !== me && d.content === "!ping") {
      reply(d).catch(console.error);
    }
  };

  ws.onclose = (e) => {
    clearInterval(heartbeat);
    console.error("bağlantı kapandı", e.code, e.reason);
    if (e.code >= 4000 && !RETRY.includes(e.code)) process.exit(1);
    setTimeout(connect, 5000);
  };
}

connect();
```

```bash
BOT_TOKEN="$BOT_TOKEN" node bot.mjs
```

Terminalde botun adını görünce kanala `!ping` yaz, bot yanıt versin.

Bağlantıdan gidip gelen her JSON mesajına **çerçeve** denir. Çerçevenin `op` alanındaki sayı, onun ne olduğunu söyler: `op 10` sunucunun selamı, `op 1` heartbeat, `op 2` kendini tanıtma (identify). Kod sırayla şunları yapar:

1. `GET /gateway/bot` ile bağlanacağı adresi sorar. Bu adresi koda yazma, buradan öğren.
2. Bağlantı açılınca gelen `op 10` çerçevesindeki aralıkla heartbeat göndermeye başlar. Bu, bağlantının canlı kalmasını sağlar.
3. `op 2` (identify) ile token'ını ve istediği olayları söyler.
4. `READY` gelince kendi ID'sini öğrenir. Bot kendi mesajlarını da duyduğu için bu gerekli.
5. Her `MESSAGE_CREATE`'te metne bakar, `!ping` ise REST ile yanıt gönderir. Yanıt için **Mesaj geçmişini oku** izni gerekir; kanalın mesajlarını duyması için de **Kanalları görüntüle**.

Bağlantı koparsa bu küçük bot 5 saniye sonra baştan bağlanır ve arada yazılanları kaçırır. Kaçırmamak için oturumu sürdürmek gerekir; [Gateway](https://noluyo.net/gelistirici/gateway.md) sayfası bunu anlatır ve sonunda hazır bir istemci verir.

> **Not:** **Mesaj içeriği**'ni açmak istemezsen `INTENTS` değerini `1 << 9` yap, koşuldaki `d.content === "!ping"` yerine `d.content.includes("!ping")` yaz ve kanala `@botun !ping` diye botu etiketleyerek yaz. Bu intent olmadan bot yalnızca kendisini etiketleyen mesajların metnini görür, diğerlerinde `content` boş gelir. Kural [Intent'ler](https://noluyo.net/gelistirici/intentler.md) sayfasında.

REST hâlâ gerekli: gateway yalnızca o andan sonra olanları anlatır ve yalnızca bot dinler. Mesaj göndermek, silmek ve geçmiş mesajları okumak REST işidir. Geçmiş okumalar da aynı içerik kuralına uyar.

## Sonraki adım: ilk butonun

Botun mesajına buton da ekleyebilir. Bu istek kanala tek butonlu bir mesaj atar:

```bash
curl -X POST "https://noluyo.net/api/v1/channels/$CHANNEL_ID/messages" \
  -H "Authorization: Bot $BOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"content":"Hazır mısın?","components":[{"type":1,"components":[{"type":2,"style":1,"label":"Hazırım","custom_id":"hazir"}]}]}'
```

Butona şimdi basarsan birkaç saniye sonra "Bot yanıt vermedi." görürsün: basma botuna `INTERACTION_CREATE` olarak gider ve bot 3 saniye içinde yanıt vermelidir. Yanıt veren ilk botun için [Örnekler](https://noluyo.net/gelistirici/ornekler.md#butonla-anket) sayfasındaki anketle başla. Akışın tamamı [Bileşenler](https://noluyo.net/gelistirici/bilesenler.md), yanıt türleri [Etkileşimler](https://noluyo.net/gelistirici/etkilesimler.md), kartlar [Embed'ler](https://noluyo.net/gelistirici/embedler.md) sayfasında.

## Resmi kütüphaneler

Ham HTTP ve WebSocket çerçevelerini kendin yönetmek yerine bağlantı sürdürmeyi (`resume`), hız sınırı kuyruklarını ve shard aralıklarını senin yerine yöneten resmi paketleri kullanabilirsin:

- Node.js 22+ için: [JavaScript kütüphanesi](https://noluyo.net/gelistirici/kutuphane-js.md)
- Python 3.11+ için: [Python kütüphanesi](https://noluyo.net/gelistirici/kutuphane-python.md)
- Kopyala-çalıştır dokuz örnek: [Tarifler](https://noluyo.net/gelistirici/tarifler.md)

## Bu sayfayı yapay zekaya verirsen

> **İpucu:** Bu hızlı başlangıç sayfasını bir yapay zeka asistanına verirken şu kuralları ekle:
>
> - Taban adres `https://noluyo.net/api/v1` olmalı; bot token'ı koda yazılmadan `process.env.BOT_TOKEN` ile okunmalıdır.
> - Mesaj beklemek için döngüde kanal okunmaz (`fetch` ile yoklama yapılmaz); canlı olaylar WebSocket gateway ya da resmi `noluyo-bot` kütüphanesi üzerinden dinlenir.
> - `MESSAGE_CONTENT` açık değilse etiketlenmeyen mesajlarda `content` boş gelir (`4014` hatası almamak için ayrıcalıklı intent önce portalda açılır).

## Sırada ne var

- [Gateway](https://noluyo.net/gelistirici/gateway.md): bağlantının tamamı, kopunca sürdürmek, hazır istemci
- [Ses](https://noluyo.net/gelistirici/ses.md): ses kanalına girip dosya ya da akış yayınlamak; bot kimseyi duyamaz
- [Intent'ler](https://noluyo.net/gelistirici/intentler.md): hangi olayları istediğin, mesaj içeriği kuralı
- [Kimlik doğrulama](https://noluyo.net/gelistirici/kimlik.md): token ve istek kuralları
- [Uygulamalar](https://noluyo.net/gelistirici/bot-uygulamalari.md): portal, bot rolü, herkese açık botlar
- [İzinler](https://noluyo.net/gelistirici/izinler.md): izin değerleri ve rol sıralaması
- [Hız sınırları](https://noluyo.net/gelistirici/rate-limit.md): sınırlar ve 429 yanıtları
- [Hatalar](https://noluyo.net/gelistirici/hatalar.md): tüm hata kodları
- [Değişiklikler](https://noluyo.net/gelistirici/degisiklikler.md): API'de neler değişti
- [Örnekler](https://noluyo.net/gelistirici/ornekler.md): zamanlı duyuru, sözcük filtresi, butonlu anket ve rol seçici gibi küçük botlar
- [REST referansı](https://noluyo.net/gelistirici/api.md): tüm rotalar; her birinde örnek istek, örnek yanıt ve hata kodları var
