
# Mesajlar ve Konuşmalar

Messages API, herhangi bir kişiye mesaj göndermenize, bir konuşmayı okumanıza, gönderdiğiniz bir mesajı düzeltmenize veya silmenize, bir mesaja tepki vermenize, tam bir sohbet oturumu dizisini çekmenize, bir dökümü dışa aktarmanıza ve sohbetleri okundu veya okunmadı olarak işaretlemenize olanak tanır; üstelik tüm bunları gelen kutusunu açmadan yapabilirsiniz.

Bu sayfadaki tüm yollar `https://api.youraiconnector.com/v1` temel URL'sine göredir. Her istek API anahtarınızı gerektirir — gönderme yollarının tam listesi için [Kimlik Doğrulama](authentication.md) bölümüne bakın. Aşağıdaki örnekler `X-API-Key` başlığını kullanır; bir cURL örneği ise `?apiKey=` sorgu biçimini de gösterir.

> **Teslimat nasıl çalışır:** Bir mesaj göndermek, mesajın ulaşmasını **beklemez**. API mesajınızı kabul eder, hemen bir mesaj kimliği ile yanıt verir ve ardından mesajı arka planda kişinin kanalında (WhatsApp, SMS, Instagram vb.) teslim eder. Bir mesajın gerçekten teslim edilip edilmediğini veya okunup okunmadığını takip etmek için [Webhooks](webhooks.md) ile durum güncellemelerini dinleyin; yoklama (polling) yapmayın. Gönderme yanıtı yalnızca mesajın kabul edildiğini onaylar.

---

## Mesaj gönder

Göndermenin iki yolu vardır. Kişiyi halihazırda nasıl tanımladığınıza uygun olanı seçin:

- **Kişi kimliği ile gönder** — kişinin kimliğini zaten biliyorsunuz (örneğin, kişiyi API aracılığıyla oluşturdunuz veya bir web kancasından aldınız). `POST /contacts/{contactId}/send-message` kullanın.
- **Kişi kimliği (identity) ile gönder** — kişinin telefon numarasını, Instagram kimliğini vb. biliyorsunuz ancak dahili kimliğini bilmiyorsunuz. `POST /contacts/send` kullanın ve platformun doğru kişiyi bulmasını sağlayın.

Her ikisi de mesajı aynı şekilde sıraya alır ve kişinin bulunduğu kanaldan teslim eder. Bir taşıma yöntemi seçmezsiniz; platform, WhatsApp kişilerini WhatsApp üzerinden, SMS kişilerini SMS üzerinden vb. yönlendirir.

### Kişi kimliği ile gönder

`POST /contacts/{contactId}/send-message`

| Alan | Gerekli | Açıklama |
|---|---|---|
| `body` | Evet | Gönderilecek mesaj metni. |
| `mediaUrl` | Hayır | Eklenecek medya dosyasının (görsel, belge vb.) URL'si. |
| `mediaContentType` | Hayır | Eklenen medyanın MIME türü, örneğin `image/jpeg`. |
| `pauseBot` | Hayır | `true`, mesaj gönderilirken bu kişi için yapay zekayı duraklatır — bir insanın devralması içindir. Bkz. [Yapay zekayı duraklatma veya devam ettirme](#pause-or-resume-the-ai-for-one-contact). |
| `clearIncompleteReply` | Hayır | `true`, yarım kalmış bir bot yanıtını atar, böylece mesajınızdan sonra devam etmez. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/contacts/contact123/send-message" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "body": "Hi! Your appointment is confirmed for tomorrow at 10:00."
  }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/contacts/contact123/send-message",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      body: "Hi! Your appointment is confirmed for tomorrow at 10:00.",
    }),
  }
);
const data = await res.json();
console.log(data.messageId);
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/contacts/contact123/send-message",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={"body": "Hi! Your appointment is confirmed for tomorrow at 10:00."},
)
print(res.json()["messageId"])
```

**Yanıt** (`200 OK`):

```json
{
  "success": true,
  "messageId": "aB3dE5fG7hI9jK1lM2nO",
  "contactId": "contact123",
  "channel": "whatsapp",
  "message": "Message created successfully. Delivery is being processed."
}
```

### Kişi kimliği (identity) ile gönder

`POST /contacts/send`

Bunu, kişinin dahili kimliğine sahip olmadığınızda kullanın. Mesaj `body` değerini ve **ya** bir `contact_id` **ya da** o kanalla eşleşen kimlik alanı ile birlikte bir `channel` sağlayın.

| Alan | Gerekli | Açıklama |
|---|---|---|
| `body` | Evet | Gönderilecek mesaj metni. |
| `contact_id` | Hayır | Mevcut bir kişiye ait kimlik (ID). Ayarlandığında, aşağıdaki kimlik alanlarına gerek kalmaz. |
| `channel` | Hayır | Mesajın gönderileceği kanal. `contact_id` belirtilmediğinde gereklidir. Giden mesaj gönderilebilen 14 kanaldan biri: `whatsapp`, `whatsapp_web`, `sms`, `instagram`, `instagram_private`, `messenger`, `telegram`, `chat-widget`, `custom`, `email`, `line`, `imessage`, `linkedin`, `viber`. |
| `phone_number` | Hayır | Kişinin uluslararası formatta telefon numarası. `whatsapp`, `whatsapp_web` ve `sms` ile birlikte kullanılır. |
| `instagram_id` | Hayır | Kişinin Instagram kullanıcı kimliği. `instagram` ile birlikte kullanılır. |
| `messenger_id` | Hayır | Kişinin Messenger kullanıcı kimliği. `messenger` ile birlikte kullanılır. |
| `telegram_user_id` | Hayır | Kişinin Telegram kullanıcı kimliği. `telegram` ile birlikte kullanılır. |
| `media_url` | Hayır | Eklenecek medya dosyasının URL'si. |
| `media_content_type` | Hayır | Ekli medyanın MIME türü, örneğin `image/jpeg`. |

**Hangi kanallar kimlik bilgisi ile çözümlenebilir.** 14 kanaldan sadece altısı `contact_id` yerine bir kimlik alanı kabul eder: `whatsapp`, `whatsapp_web` ve `sms`, `phone_number` ile; `instagram`, `instagram_id` ile; `messenger`, `messenger_id` ile ve `telegram`, `telegram_user_id` ile aranır. Diğer sekizi — `instagram_private`, `chat-widget`, `custom`, `email`, `line`, `imessage`, `linkedin` ve `viber` — aranabilecek genel bir kimliğe sahip değildir, bu nedenle bu kanallar üzerinden gönderim yapmak `contact_id` gerektirir; yalnızca `channel` geçmek, `contact_id` bilgisinin gerekli olduğunu belirten bir `400` döndürür.

**cURL** (`?apiKey=` sorgu formunu kullanarak)

```bash
curl -X POST "https://api.youraiconnector.com/v1/contacts/send?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "whatsapp",
    "phone_number": "+31612345678",
    "body": "Hi! Your appointment is confirmed."
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/contacts/send", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    channel: "whatsapp",
    phone_number: "+31612345678",
    body: "Hi! Your appointment is confirmed.",
  }),
});
const data = await res.json();
console.log(data.message_id, data.channel);
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/contacts/send",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
        "channel": "whatsapp",
        "phone_number": "+31612345678",
        "body": "Hi! Your appointment is confirmed.",
    },
)
data = res.json()
print(data["message_id"], data["channel"])
```

**Yanıt** (`201 Created`):

```json
{
  "success": true,
  "message_id": "aB3dE5fG7hI9jK1lM2nO",
  "contact_id": "contact123",
  "channel": "whatsapp"
}
```

> **Bir mesaj neden reddedilebilir:** Rahatsız etmeyin veya gizli modu açık olan bir kişi giden mesajları alamaz — istek `422` hatasıyla başarısız olur. Sağladığınız kimlik veya tanımlayıcı ile eşleşen bir kişi yoksa, `404` alırsınız.

---

## Bir kişinin mesajlarını listele

`GET /contacts/{contactId}/messages`

Bir kişinin mesajlarını, imleç tabanlı sayfalama ile en yeniden başlayacak şekilde döndürür.

| Sorgu parametresi | Gerekli | Açıklama |
|---|---|---|
| `limit` | Hayır | Sayfa boyutu. Varsayılan `50`, maksimum `100`. |
| `cursor` | Hayır | Önceki bir yanıttan gelen `next_cursor` değeri. İmleçten daha eski mesajları döndürür. |
| `filter` | Hayır | İçerik türüne göre filtrele: `all` (varsayılan), `text`, `media` veya `tool_use`. |
| `direction` | Hayır | Yöne göre filtrele: `all` (varsayılan), `inbound` (kişiden alınan) veya `outbound` (sizin tarafınızdan gönderilen). |

> **Filtreleme ve sayfalama hakkında not:** `filter` ve `direction` filtreleri, okunduktan sonra her sayfaya uygulanır, bu nedenle filtrelenmiş bir sayfa `limit` değerinden daha az öğe içerebilir. `next_cursor` tüm konuşma boyunca ilerlemeye devam eder, bu nedenle `next_cursor` değeri `null` olana kadar sayfalamaya devam edin.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/contacts/contact123/messages?limit=50&direction=inbound" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const params = new URLSearchParams({ limit: "50", direction: "inbound" });
const res = await fetch(
  `https://api.youraiconnector.com/v1/contacts/contact123/messages?${params}`,
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
console.log(data.messages, data.next_cursor);
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/contacts/contact123/messages",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"limit": 50, "direction": "inbound"},
)
data = res.json()
print(data["messages"], data["next_cursor"])
```

**Yanıt** (`200 OK`):

```json
{
  "success": true,
  "contact_id": "contact123",
  "messages": [
    {
      "id": "aB3dE5fG7hI9jK1lM2nO",
      "body": "Hi! Thanks for reaching out.",
      "direction": "inbound",
      "channel": "whatsapp",
      "status": "delivered",
      "type": null,
      "timestamp": "2026-06-01T10:00:00.000Z",
      "media_url": null,
      "media_content_type": null,
      "bot_reply": false
    }
  ],
  "next_cursor": "cD4eF6gH8iJ0kL2mN3oP"
}
```

### Mesaj alanları

| Alan | Açıklama |
|---|---|
| `id` | Mesajın benzersiz kimliği. |
| `body` | Mesajın metin içeriği. |
| `direction` | `inbound` (kişiden alınan) veya `outbound` (hesabınız tarafından gönderilen). |
| `channel` | Mesajın gönderildiği veya alındığı kanal (örneğin `whatsapp`, `sms`, `instagram`). |
| `status` | Mevcut iletim durumu, örneğin `Created`, `sent`, `delivered`, `read`, `failed`. |
| `type` | Mesaj türü. Düz metin mesajları `null` türündedir; otomatik asistan aracı etkinliği `tool_use` olarak işaretlenir. |
| `timestamp` | Mesajın oluşturulduğu ISO 8601 zamanı. |
| `media_url` | Varsa, ekli bir medya dosyasının URL'si. |
| `media_content_type` | Varsa, ekli medyanın MIME türü. |
| `bot_reply` | Mesaj yapay zeka asistanı tarafından oluşturulduğunda `true` değerini alır. |
| `score` | Mesaj için verdiğiniz puan: `1` beğenme, `-1` beğenmeme, `0` puanlanmadığında. Bkz. [Bir mesajı puanlayın veya yıldızlayın](#rate-or-star-a-message). |
| `is_important` | Mesaj yıldızlandığında `true` değerini alır. |
| `is_deleted` | Mesaj silindiğinde `true` değerini alır. Silinen mesajlar listede kalır ancak `body` ve `media_url` alanları boştur. |
| `reactions` | Mesajdaki emoji tepkileri, her iki taraftan da. Her zaman bir dizidir; tepki yoksa boştur. Her giriş `emoji`, `from_phone_number`, `from_me` (tepki size aitse `true`) ve `reacted_at` içerir. |

---

## Sohbet oturumlarını listele

Bir sohbet oturumu, bir kişiyle yapılan tek bir konuşma penceresidir: kişi konuşmaya başladığında açılır ve konuşma sona erdiğinde kapanır. Oturumlar, uzun bir geçmişi tek bir sonsuz liste yerine okunabilir konuşmalara bölmenizi sağlar.

### Tüm kişilerdeki son oturumlar

`GET /chat-sessions/recent`

Hesaptaki her kişi genelinde, son X saat içinde başlayan oturumları en yeniden başlayarak döndürür.

| Sorgu parametresi | Gerekli | Açıklama |
|---|---|---|
| `hours` | Evet | Ne kadar geriye gidileceği (saat cinsinden). Pozitif bir tam sayı olmalıdır. |
| `status` | Hayır | Yalnızca şu duruma sahip oturumları döndür: `ChatSessionOpened` veya `ChatSessionClosed`. |
| `limit` | Hayır | Döndürülecek maksimum oturum sayısı. Varsayılan `100`, maksimum `100`. |
| `includeMessages` | Hayır | `true`, her oturuma bir `messages` dizisi ekler. Yanıtı çok daha büyük hale getirdiği için varsayılan olarak kapalıdır. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/chat-sessions/recent?hours=24&status=ChatSessionClosed" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const params = new URLSearchParams({ hours: "24", status: "ChatSessionClosed" });
const res = await fetch(`https://api.youraiconnector.com/v1/chat-sessions/recent?${params}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
console.log(data.data.total_sessions, data.data.sessions);
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/chat-sessions/recent",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"hours": 24, "status": "ChatSessionClosed"},
)
data = res.json()["data"]
print(data["total_sessions"], data["sessions"])
```

**Yanıt** (`200 OK`):

```json
{
  "success": true,
  "data": {
    "hours_ago": 24,
    "total_sessions": 2,
    "sessions": [
      {
        "session_id": "session456",
        "contact_id": "contact123",
        "contact_name": "Jane Doe",
        "contact_phone": "+31612345678",
        "contact_email": "jane@example.com",
        "start_date_time": "2026-06-01T09:55:00.000Z",
        "end_date_time": "2026-06-01T10:20:00.000Z",
        "status": "ChatSessionClosed",
        "tag": "Booking enquiry"
      }
    ]
  }
}
```

### Bir kişi için tüm oturumlar

`GET /chat-sessions/{contactId}`

Tek bir kişi için tüm sohbet oturumlarını döndürür. Yukarıdakiyle aynı `status`, `limit` ve `includeMessages` parametrelerini kullanır; `hours` burada geçerli değildir.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/chat-sessions/contact123?limit=20" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Yanıt** (`200 OK`):

```json
{
  "success": true,
  "data": {
    "contact_id": "contact123",
    "contact_name": "Jane Doe",
    "total_sessions": 2,
    "sessions": [
      {
        "id": "session456",
        "start_date_time": "2026-06-01T09:55:00.000Z",
        "end_date_time": "2026-06-01T10:20:00.000Z",
        "status": "ChatSessionClosed",
        "tag": "Booking enquiry"
      }
    ]
  }
}
```

> **Oturum kimliği alan adları iki uç nokta arasında farklılık gösterir.** Son oturumlar listesi buna `session_id` der (ayrıca kişinin ayrıntılarını da taşır, çünkü oturumlar birçok kişiden gelir); kişi bazlı liste ise `id` olarak adlandırır. Aşağıdaki tam diziyi çekerken `{sessionId}` olarak her iki değeri de kullanabilirsiniz.

`includeMessages=true` olduğunda, her oturum `id`, `body`, `direction`, `timestamp`, `type`, `channel` ve `status` içeren girişlere sahip bir `messages` dizisi kazanır.

---

## Bir sohbet oturumu dizisini getir

`GET /contacts/{contactId}/chat-sessions/{sessionId}/messages`

Bir sohbet oturumu, bir kişinin mesajlarını tek bir konuşma penceresinde gruplandırır. Bu uç nokta, oturumun meta verileriyle birlikte tek bir oturumun tam dizisini **en eskiden başlayarak** döndürür. Bir kişi için oturum kimliklerini sohbet oturumları uç noktaları aracılığıyla bulabilirsiniz.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/contacts/contact123/chat-sessions/session456/messages" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/contacts/contact123/chat-sessions/session456/messages",
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
console.log(data.session, data.messages);
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/contacts/contact123/chat-sessions/session456/messages",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
print(data["session"], data["messages"])
```

**Yanıt** (`200 OK`):

```json
{
  "success": true,
  "contact_id": "contact123",
  "session": {
    "id": "session456",
    "status": "ChatSessionClosed",
    "start_date_time": "2026-06-01T09:55:00.000Z",
    "end_date_time": "2026-06-01T10:20:00.000Z",
    "tag": "Booking enquiry"
  },
  "messages": [
    {
      "id": "aB3dE5fG7hI9jK1lM2nO",
      "body": "Hi! Thanks for reaching out.",
      "direction": "inbound",
      "channel": "whatsapp",
      "status": "delivered",
      "type": null,
      "timestamp": "2026-06-01T09:55:00.000Z",
      "media_url": null,
      "media_content_type": null,
      "bot_reply": false
    }
  ]
}
```

`session` nesnesi `status` (etkin olduğunda `ChatSessionOpened`, sona erdiğinde `ChatSessionClosed`), `start_date_time`, `end_date_time` ve insan tarafından okunabilir bir `tag` bildirir. `messages` dizisi, liste uç noktasıyla aynı [mesaj alanlarını](#message-fields) kullanır.

---

## Mesajları düzenle, sil ve tepki ver

Bu uç noktalar, bir mesaj gönderildikten sonra üzerinde değişiklik yapar. Bunlardan ikisi, kendi kopyanızın yanı sıra kişinin kanalına da ulaşır, bu nedenle bunları bağlamadan önce bölüm girişini okuyun; nelerin mümkün olduğu tamamen konuşmanın gerçekleştiği kanala bağlıdır.

**Her kanalın izin verdikleri**

| Eylem | Kişinin kopyasını değiştirebilen kanallar | Zaman sınırı |
|---|---|---|
| Gönderilen bir mesajı düzenle | Sohbet aracı, WhatsApp Web, Telegram, LinkedIn | Sohbet aracında sınır yok, WhatsApp Web'de 15 dakika, Telegram'da 48 saat, LinkedIn'de 60 dakika |
| Herkes için sil | Sohbet aracı, WhatsApp Web, Telegram, LinkedIn | LinkedIn'de 60 dakika; diğerlerinde yayınlanmış bir sınır yoktur |
| Emoji ile tepki ver | WhatsApp Web, Telegram | Yok |

Diğer tüm kanallarda — WhatsApp Business API, SMS, Instagram, Messenger, e-posta, LINE, özel kanallar — silme işlemi mesajı gelen kutunuzdan kaldırır ancak kişi kendi kopyasını tutmaya devam eder ve düzenleme veya tepki verme işlemleri hiç mümkün değildir.

### Bir mesajı düzenle

`POST /contacts/{contactId}/messages/{messageId}/edit`

Zaten gönderdiğiniz bir mesajı, kişinin cihazında ve sizin kopyanızda yeniden yazar.

| Alan | Gerekli | Açıklama |
|---|---|---|
| `body` | Evet | Yeni mesaj metni. Boş olmamalı ve en fazla 4096 karakter olabilir. |

Silmenin aksine, bu işlem kanal reddettiğinde **açıkça başarısız olur**: bir `409` alırsınız ve kopyanız tam olarak kişinin sahip olduğu şekilde kalır, çünkü kişinin hiç almadığı bir düzenlemeyi göstermek iki tarafın uyumunu bozar. `edit_reason` alanı size nedenini söyler — kanalın düzenleme penceresi kapanmıştır, kanalın bağlantısı kesilmiştir veya başka bir sorun oluşmuştur.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1/edit" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "body": "Sorry - I meant Thursday at 3pm." }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1/edit",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ body: "Sorry - I meant Thursday at 3pm." }),
  }
);
const data = await res.json();
console.log(data.edited, data.edit_reason);
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1/edit",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={"body": "Sorry - I meant Thursday at 3pm."},
)
data = res.json()
print(data.get("edited"), data.get("edit_reason"))
```

**Yanıt** (`200 OK`):

```json
{
  "success": true,
  "contact_id": "contact123",
  "message_id": "msg_1",
  "edited": true,
  "edit_reason": "edit_dispatched"
}
```

Kanal düzenlemeyi kabul etmezse bunun yerine bir `409` alırsınız ve hiçbir şey değiştirilmez:

```json
{
  "success": false,
  "error": "The message could not be edited",
  "edit_reason": "channel_disconnected"
}
```

Zaten silinmiş bir mesaj, hiç düzenleme yapamayan bir kanal ve kanalı için çok eski olan bir mesajın tümü `400` döndürür — istek kanala asla ulaşmaz.

### Bir mesajı sil

`DELETE /contacts/{contactId}/messages/{messageId}`

Mesajı konuşmanızdan kaldırır ve kanalın izin verdiği durumlarda kişinin kopyasını da geri çeker. İstek gövdesi yoktur.

Bu, mesaj mevcut olduğunda, kişinin kopyası geri çekilemese bile her zaman `200` yanıtını verir — sizin kopyanız **silinmiştir**, bu nedenle bir hata mesajı yanıltıcı olur. Kullanıcıya gerçekte ne olduğunu söylemek için yanıttaki üç alanı okuyun:

| Alan | Açıklama |
|---|---|
| `revoke_supported` | Bu kanalın mesajları geri çekip çekemeyeceği. |
| `revoked` | Kişinin cihazındaki kopyanın kaldırılıp kaldırılmadığı. |
| `revoke_reason` | `revoked` değeri `false` olduğunda neden kaldırılmadığı — örneğin `revoke_window_closed` veya `already_deleted`. |

**cURL**

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1",
  { method: "DELETE", headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
console.log(data.revoked, data.revoke_reason);
```

**Python**

```python
import requests

res = requests.delete(
    "https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
print(data["revoked"], data["revoke_reason"])
```

**Yanıt** (`200 OK`):

```json
{
  "success": true,
  "contact_id": "contact123",
  "message_id": "msg_1",
  "revoke_supported": true,
  "revoked": true,
  "revoke_reason": "revoke_dispatched"
}
```

> Silinen iletiler konuşma geçmişinden kaldırılmaz. Bunlar `GET /contacts/{contactId}/messages` içinde `is_deleted: true` ve boş bir `body` ve `media_url` ile kalır.

### Birden fazla iletiyi aynı anda silme

`POST /contacts/{contactId}/messages/bulk-delete`

Bir grup iletiyi yalnızca kendi tarafınızdan temizler. İçerikler ve ekler boşaltılır, ancak **karşı tarafın cihazında hiçbir şey geri alınmaz** — bir iletiyi tamamen geri çekmek için, yukarıdaki tekli ileti uç noktasını kullanarak tek tek silin.

| Alan | Gerekli | Açıklama |
|---|---|---|
| `message_ids` | Evet | İstek başına 500'e kadar, boş olmayan bir ileti kimliği dizisi. `messageIds`, takma ad olarak kabul edilir. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/contacts/contact123/messages/bulk-delete" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "message_ids": ["msg_1", "msg_2"] }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/contacts/contact123/messages/bulk-delete",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ message_ids: ["msg_1", "msg_2"] }),
  }
);
console.log((await res.json()).deleted);
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/contacts/contact123/messages/bulk-delete",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={"message_ids": ["msg_1", "msg_2"]},
)
print(res.json()["deleted"])
```

**Yanıt** (`200 OK`):

```json
{
  "success": true,
  "contact_id": "contact123",
  "deleted": 2
}
```

### Bir iletiye tepki verme

`POST /contacts/{contactId}/messages/{messageId}/react`

Bir iletiye kendi emoji tepkinizi ekler veya boş bir dize göndererek tepkinizi geri alır. Karşı tarafın kendi tepkilerine asla dokunulmaz.

| Alan | Gerekli | Açıklama |
|---|---|---|
| `emoji` | Evet | Tepki olarak verilecek emoji veya tepkinizi kaldırmak için `""`. Boşluk içermeyen, en fazla 16 karakterlik tek bir dize olmalıdır. |

Düzenleme işleminde olduğu gibi, bu işlem karşı tarafın hiç almadığı bir tepkiyi göstermek yerine başarısız olur ve hata, yeniden denemenin mantıklı olup olmadığını size bildirir:

- `422` — bu konuşmada asla iletilemez: kanal tepkileri desteklemiyor, iletinin kanal tarafında bir kimliği yok veya emoji, kanalın izin verdiği kümenin dışında.
- `409` — kanala anlık olarak ulaşılamadı. Yeniden deneme işe yarayabilir.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1/react" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "emoji": "👍" }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1/react",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ emoji: "👍" }),
  }
);
const data = await res.json();
console.log(data.reactions);
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1/react",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={"emoji": "👍"},
)
print(res.json()["reactions"])
```

**Yanıt** (`200 OK`):

```json
{
  "success": true,
  "contact_id": "contact123",
  "message_id": "msg_1",
  "reaction_supported": true,
  "reaction_reason": "reaction_dispatched",
  "reactions": [
    {
      "emoji": "👍",
      "from_phone_number": "+31612345678",
      "from_me": true,
      "reacted_at": "2026-06-01T10:05:00.000Z"
    }
  ]
}
```

`reactions` dizisi, iletideki hem sizin hem de karşı tarafın tepkilerini içeren tam kümedir. Bir `409` veya `422` durumunda dizi değişmeden döndürülür, bu nedenle doğrudan bu diziden görüntüleme yapan bir istemci, iletilmemiş bir tepkiyi asla göstermez.

### Bir iletiyi oylama veya yıldızlama

`PATCH /contacts/{contactId}/messages/{messageId}`

Bir iletiyi başparmak yukarı veya aşağı ile oylar ve/veya önemli olarak yıldızlar. Bu işlem yalnızca sizin tarafınızdaki kayıt tutma amaçlıdır; karşı tarafa hiçbir şey gönderilmez.

| Alan | Gerekli | Açıklama |
|---|---|---|
| `score` | Hayır | `1` beğenme, `-1` beğenmeme, `0` derecelendirmeyi temizler. |
| `is_important` | Hayır | `true` mesajı yıldızlar, `false` yıldızı kaldırır. `"true"` dizesi değil, gerçek bir boolean olmalıdır. |

İkisinden en az birini gönderin, aksi takdirde bir `400` alırsınız. Yalnızca gönderdiğiniz şey yazılır, bu nedenle bir mesajı yıldızlamak derecelendirmesini asla temizlemez ve bunun tersi de geçerlidir — ve yanıt yalnızca gönderdiğiniz alanları geri yansıtır.

**cURL**

```bash
curl -X PATCH "https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "score": 1, "is_important": true }'
```

**JavaScript**

```javascript
await fetch("https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1", {
  method: "PATCH",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ score: 1, is_important: true }),
});
```

**Python**

```python
import requests

requests.patch(
    "https://api.youraiconnector.com/v1/contacts/contact123/messages/msg_1",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"score": 1, "is_important": True},
)
```

**Yanıt** (`200 OK`):

```json
{
  "success": true,
  "contact_id": "contact123",
  "message_id": "msg_1",
  "score": 1,
  "is_important": true
}
```

---

## Mesajları okundu olarak işaretle

Okunmamış durumunu belirli mesajlar için veya tüm konuşma için temizleyebilirsiniz.

### Belirli mesajları okundu olarak işaretle

`POST /contacts/{contactId}/messages/mark-read`

Okundu olarak işaretlenecek mesajların kimliklerini iletin.

| Alan | Gerekli | Açıklama |
|---|---|---|
| `message_ids` | Evet | Boş olmayan bir mesaj kimlikleri dizisi (istek başına 500'e kadar). |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/contacts/contact123/messages/mark-read" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "message_ids": ["aB3dE5fG7hI9jK1lM2nO", "cD4eF6gH8iJ0kL2mN3oP"]
  }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/contacts/contact123/messages/mark-read",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      message_ids: ["aB3dE5fG7hI9jK1lM2nO", "cD4eF6gH8iJ0kL2mN3oP"],
    }),
  }
);
const data = await res.json();
console.log(data.marked_read);
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/contacts/contact123/messages/mark-read",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={"message_ids": ["aB3dE5fG7hI9jK1lM2nO", "cD4eF6gH8iJ0kL2mN3oP"]},
)
print(res.json()["marked_read"])
```

**Yanıt** (`200 OK`):

```json
{
  "success": true,
  "contact_id": "contact123",
  "marked_read": 2
}
```

### Tüm sohbeti okundu olarak işaretle

`POST /contacts/{contactId}/mark-read`

Gelen kutusundaki kişinin tüm konuşması için okunmamış rozetini temizler. İstek gövdesi gerekmez.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/contacts/contact123/mark-read" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/contacts/contact123/mark-read",
  { method: "POST", headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
console.log(data.success);
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/contacts/contact123/mark-read",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
print(res.json()["success"])
```

**Yanıt** (`200 OK`):

```json
{
  "success": true,
  "contact_id": "contact123"
}
```

### Tüm sohbeti okunmadı olarak işaretle

`POST /contacts/{contactId}/mark-unread`

Okunmadı rozetini konuşmaya geri koyar — ekibinizden biri bir sohbeti açtığında ancak geri devrettiğinde kullanışlıdır. İstek gövdesi gerekmez.

Bu yalnızca gelen kutusuna özel bir bayraktır: konuşmanın en son ne zaman okunduğunu **değiştirmez**, bu nedenle destekleyen kanallarda kişiye okundu bilgisi gönderilmez.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/contacts/contact123/mark-unread" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Yanıt** (`200 OK`):

```json
{
  "success": true,
  "contact_id": "contact123"
}
```

---

## Bir konuşmayı dışa aktar

Dışa aktarmalar, mesajlar arasında gezinmek yerine size tüm konuşmayı okunabilir bir döküm olarak verir. Her dışa aktarma uç noktası, mesaj listesindeki filtreyle eşleşen `all` (varsayılan), `text`, `media` veya `tool_use` değerinde bir `filter` kabul eder.

### Bir kişinin sohbetini dışa aktar

`GET /chat-exports/{contactId}`

| Sorgu parametresi | Gerekli | Açıklama |
|---|---|---|
| `format` | Hayır | `txt` (varsayılan), düz metin dökümüne bir indirme bağlantısı döndürür. `json`, mesajları yanıtta yapılandırılmış veri olarak döndürür. |
| `filter` | Hayır | `all` (varsayılan), `text`, `media` veya `tool_use`. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/chat-exports/contact123?format=json" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/chat-exports/contact123",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"format": "json"},
)
print(res.json()["data"]["messages"])
```

**`format=json` ile yanıt** (`200 OK`):

```json
{
  "success": true,
  "data": {
    "contact": {
      "id": "contact123",
      "name": "Jane Doe",
      "phone": "+31612345678",
      "email": "jane@example.com"
    },
    "messages": [
      {
        "body": "Hi! I have a question about my order.",
        "direction": "inbound",
        "timestamp": "2026-06-01T09:55:00.000Z",
        "type": "text",
        "media_url": null,
        "media_content_type": null,
        "name": null,
        "args": null
      }
    ]
  }
}
```

`format=txt` (varsayılan) ile, `data` bunun yerine oluşturulan döküm dosyasına bir indirme bağlantısıdır:

```json
{
  "success": true,
  "data": "https://storage.googleapis.com/.../chat-export-contact123-....txt"
}
```

> **İndirme bağlantısının ömrü kısadır.** Dosyayı depolamak yerine bağlantıyı alır almaz indirin — döküme tekrar ihtiyacınız olduğunda yeni bir dışa aktarma isteğinde bulunun.

### Tüm son konuşmaları dışa aktar

`GET /chat-exports/recent`

Son X saat içinde aktif olan tüm kişilerin konuşmalarını tek bir çağrıda dışa aktarır.

| Sorgu parametresi | Gerekli | Açıklama |
|---|---|---|
| `hours` | Evet | Geriye dönük olarak kaç saatlik aktiviteye bakılacağı. Pozitif bir tam sayı olmalıdır. |
| `format` | Hayır | `json` (varsayılan) kişi başına bir girdi döndürür. `txt`, içindeki tüm konuşmaları içeren tek bir indirilebilir metin dosyası döndürür. |
| `limit` | Hayır | Dışa aktarılacak maksimum kişi sayısı. Varsayılan `50`, maksimum `100`. |
| `filter` | Hayır | `all` (varsayılan), `text`, `media` veya `tool_use`. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/chat-exports/recent?hours=24&limit=25" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Yanıt** (`200 OK`):

```json
{
  "success": true,
  "data": {
    "hours_ago": 24,
    "total_contacts": 2,
    "exports": [
      {
        "contactId": "contact123",
        "contactName": "Jane Doe",
        "phoneNumber": "+31612345678",
        "email": "jane@example.com",
        "messageCount": 12,
        "chatExport": "Acme Export - Jane Doe\nPhone: +31612345678\n..."
      }
    ]
  }
}
```

`format=txt` ile yanıt, JSON yerine doğrudan indirme olarak gönderilen metin dosyasının kendisidir.

> Bu tek çağrı, eşleşen her kişinin tam geçmişini çeker, bu nedenle yoğun hesaplarda `hours` ve `limit` değerlerini makul tutun.

### Bir konuşma dökümünü kişiye e-posta ile gönderin

`POST /chat-exports/{contactId}/email`

Kişiye kendi konuşma dökümünü e-posta yoluyla gönderir — kendi sisteminizden yönetilen "bu sohbeti bana e-posta ile gönder" akışı.

| Alan | Gerekli | Açıklama |
|---|---|---|
| `recipient_email` | Hayır | Nereye gönderileceği. Varsayılan olarak kişinin kayıtlı e-posta adresidir. |
| `via` | Hayır | `auto` (varsayılan) en iyi rotayı seçer, `transactional` sistem e-postası olarak gönderir, `email_channel` bağlı e-posta kanalınızdan gönderir. |
| `note` | Hayır | Dökümün üzerinde gösterilecek kısa bir notunuz. 1000 karaktere kadar. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/chat-exports/contact123/email" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "note": "Here is a copy of our chat, as promised." }'
```

**Yanıt** (`200 OK`):

```json
{
  "success": true,
  "data": {
    "via": "transactional",
    "recipientEmail": "jane@example.com",
    "messageCount": 42,
    "omittedCount": 0
  }
}
```

`omittedCount`, e-postayı makul bir uzunlukta tutmak için en eski mesajlardan kaçının hariç tutulduğunu söyler. `200`, dökümün oluşturulduğunu ve gönderilmek üzere sıraya alındığını belirtir, henüz gelen kutusuna ulaştığı anlamına gelmez.

---

## Bir kişi için yapay zekayı duraklatma veya devam ettirme

`PUT /contacts/{contactId}`

Yapay zekanın bir kişiye yanıt vermesini durdurmak için `is_bot_active` değerini `false` olarak ayarlayın, konuşmayı geri vermek için tekrar `true` değerine getirin. Bir insan konuşmaya dahil olduğunda kullanmak istediğiniz devralma anahtarı budur: API ile gönderdiğiniz giden mesajlar, bot duraklatılmış olsa bile iletilmeye devam eder.

**cURL**

```bash
curl -X PUT "https://api.youraiconnector.com/v1/contacts/contact123" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "is_bot_active": false }'
```

**JavaScript**

```javascript
await fetch("https://api.youraiconnector.com/v1/contacts/contact123", {
  method: "PUT",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ is_bot_active: false }),
});
```

**Python**

```python
import requests

requests.put(
    "https://api.youraiconnector.com/v1/contacts/contact123",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"is_bot_active": False},
)
```

**Yanıt**

```json
{
  "success": true,
  "contact_id": "contact123"
}
```

**Yanıtın bir parçası olarak duraklatma**

Bir insan yanıt göndererek devralıyorsa, ikinci bir çağrı yapmak yerine aynı istek içinde botu duraklatabilirsiniz. `POST /contacts/{contactId}/send-message` iki isteğe bağlı bayrağı kabul eder:

| Alan | Açıklama |
|---|---|
| `pauseBot` | `true`, mesaj gönderilirken bu kişi için yapay zekayı duraklatır. |
| `clearIncompleteReply` | `true`, yarım kalmış bir bot yanıtını atar, böylece sonrasında devam etmez. |

```bash
curl -X POST "https://api.youraiconnector.com/v1/contacts/contact123/send-message" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "body": "Hi, Sarah here - taking over from the assistant.",
    "pauseBot": true,
    "clearIncompleteReply": true
  }'
```

Yanıt, duraklatma uygulandığında `"botPaused": true` bilgisini içerir.

> Bir kişiyi [`POST /contacts/bulk-flag`](contacts.md) ile özel olarak işaretlemek, botu onlar için de duraklatır. Tüm alan listesi için [Kişiler](contacts.md) bölümüne bakın.

---

## Kendi gelen kutunuzu oluşturma

Bir gelen kutusunun ihtiyaç duyduğu her şey bu sayfada ve [Kişiler](contacts.md) bölümünde mevcuttur:

| İhtiyacınız olan | Uç nokta |
|---|---|
| Konuşmaları listele | `GET /contacts` |
| Bir konuşmayı oku | `GET /contacts/{contactId}/messages` |
| Bir kişinin sohbet oturumlarını listele | `GET /chat-sessions/{contactId}` |
| Yakın zamanda ne geldiğini gör | `GET /chat-sessions/recent` |
| Bir sohbet oturumunu oku | `GET /contacts/{contactId}/chat-sessions/{sessionId}/messages` |
| Manuel yanıt gönder | `POST /contacts/{contactId}/send-message` |
| Yeni gönderdiğiniz bir yanıtı düzelt | `POST /contacts/{contactId}/messages/{messageId}/edit` |
| Bir mesajı kaldır | `DELETE /contacts/{contactId}/messages/{messageId}` |
| Birkaç mesajı temizle | `POST /contacts/{contactId}/messages/bulk-delete` |
| Emoji ile tepki ver | `POST /contacts/{contactId}/messages/{messageId}/react` |
| Bir mesajı puanla veya yıldızla | `PATCH /contacts/{contactId}/messages/{messageId}` |
| Okundu olarak işaretle | `POST /contacts/{contactId}/mark-read` |
| Sohbeti ekibe geri devret | `POST /contacts/{contactId}/mark-unread` |
| Bir dökümü dışa aktar | `GET /chat-exports/{contactId}` |
| Yapay zekayı duraklat veya devam ettir | `PUT /contacts/{contactId}` ile `is_bot_active` |

Canlı güncellemeler için, bu API'yi bir zamanlayıcı ile sorgulamak yerine [Webhooks](webhooks.md) ile `New Message`, `Replies`, `Human Alerted` ve `Chat Concluded` olaylarına abone olun.

---

## Mesajlar API hataları

Mesaj uç noktaları standart hata zarfını döndürür:

```json
{
  "success": false,
  "error": "Contact not found"
}
```

| Durum | Bir mesaj uç noktasında ne zaman gerçekleşir |
|---|---|
| `400` | Gerekli bir alan eksik veya bir parametre geçersiz (hatalı `limit`, `hours`, `filter`, `direction`, `status`, boş veya 500'den fazla `message_ids` dizisi, geçersiz `cursor`, boş veya çok uzun düzenleme `body`, `-1`/`0`/`1` dışında bir `score` veya boşluklu ya da 16 karakterden uzun bir emoji). Ayrıca bir mesaj hiç düzenlenemediğinde döndürülür — silinmiş, kanalı düzenlemeyi desteklemiyor veya o kanalın düzenleme süresi geçmiş. |
| `404` | Kişi, sohbet oturumu veya sağlanan mesaj kimliklerinden biri bulunamadı. |
| `409` | Kanal şu anda değişikliği kabul etmiyor. Hiçbir şey yazılmadı: düzenlemede `edit_reason` nedenini söyler; tepkide, kanal anlık olarak ulaşılamaz durumdadır ve yeniden deneme işe yarayabilir. |
| `422` | Kişi giden mesajları alamaz (rahatsız etmeyin, özel veya desteklenmeyen bir kanal) ya da bu konuşmada bir tepki asla iletilemez (`reaction_reason` hangisi olduğunu söyler). |

Her uç noktanın döndürebileceği ortak kodlar — `401`, `403` (planınız API erişimini içermiyor), `429` (hız sınırı) ve `500` — yeniden deneme rehberliği ile birlikte [Hatalar ve Sayfalandırma](errors-and-pagination.md) bölümünde listelenmiştir.

---

## Sonraki adımlar

- [Web kancaları](webhooks.md) — yoklama yapmak yerine teslimat durumu güncellemelerini size iletilmesini sağlayın.
- [Kişiler](contacts.md) — mesaj gönderdiğiniz kişileri oluşturun ve arayın.
- [Randevular](appointments.md) — kişileriniz için randevuları ayırtın ve yönetin.
