> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chattler.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# المحادثات

> كيف تُحدَّد المحادثات وتُعزل وتُقرأ من جديد.

## محادثة واحدة لكل مستخدم خارجي

تُحدَّد المحادثة بشيئين: مفتاح API و`external_user_id` الذي ترسله. أنت لا تنشئ المحادثة صراحةً أبدًا؛ أول طلب دردشة لـ `external_user_id` جديد ينشئها، وكل رسالة لاحقة من المستخدم الخارجي نفسه عبر المفتاح نفسه تواصلها.

النتائج التي تستحق المعرفة:

* **العزل لكل مفتاح.** نفس `external_user_id` عبر مفتاحين مختلفين هو محادثتان مختلفتان، حتى عندما ينتمي المفتاحان إلى الوكيل نفسه. لا يرى المفتاح أبدًا حوارات مفتاح آخر أو قناة أخرى (Telegram، الودجت، وهكذا).
* **التدوير يحفظ السجل.** تدوير المفتاح يغيّر سره لا معرّفه، لذلك تبقى محادثاته مرتبطة به.
* **`external_user_id` ملك لك.** استخدم معرّفًا ثابتًا من نظامك، من 1-255 حرفًا. لا تضع فيه بيانات شخصية لا تريد تخزينها مع الحوار.
* **رد واحد في كل مرة.** إذا وصلت رسالة لمستخدم خارجي بينما ردّه السابق ما زال قيد التوليد، تجيب API بـ `409 conversation_busy` مع `Retry-After: 2`. انتظر ثم أعد الإرسال.

## عرض المحادثات

`GET /v1/agents/{agent_id}/conversations` يُرجع محادثات المفتاح، الأحدث تحديثًا أولًا. يمكن لمفاتيح `read-only` و`full` استدعاؤه.

| معامل الاستعلام        | المعنى                                                       |
| ---------------------- | ------------------------------------------------------------ |
| `external_user_id`     | محادثات هذا المستخدم الخارجي فقط                             |
| `date_from`، `date_to` | حدود ISO-8601 على `updated_at`؛ `date_to` غير شامل           |
| `limit`                | حجم الصفحة، 1-100 (الافتراضي 20)                             |
| `cursor`               | قيمة `next_cursor` من الصفحة السابقة؛ احذفه في الصفحة الأولى |

```bash theme={null}
curl "$CHATTLER_BASE_URL/v1/agents/$CHATTLER_AGENT_ID/conversations?limit=50" \
  -H "Authorization: Bearer $CHATTLER_API_KEY"
```

```json theme={null}
{
  "data": [
    {
      "id": "1c2e...",
      "external_user_id": "customer-123",
      "created_at": "2026-09-13T11:58:02Z",
      "updated_at": "2026-09-13T12:00:00Z",
      "last_message_preview": "The basic plan is $19 per month..."
    }
  ],
  "next_cursor": null
}
```

`last_message_preview` هو آخر نص من المستخدم أو المساعد، مقتطعًا إلى 160 حرفًا، أو `null` للمحادثة الفارغة.

## قراءة الرسائل

`GET /v1/agents/{agent_id}/conversations/{conversation_id}/messages` يُرجع رسائل محادثة واحدة، الأحدث أولًا. تُرجع رسائل `user` و`assistant` فقط؛ أما تبادلات الأدوات وصفوف نشاط الأدوات وموجّه النظام فلا تُكشف أبدًا.

| معامل الاستعلام        | المعنى                                             |
| ---------------------- | -------------------------------------------------- |
| `date_from`، `date_to` | حدود ISO-8601 على `created_at`؛ `date_to` غير شامل |
| `limit`                | حجم الصفحة، 1-100 (الافتراضي 20)                   |
| `cursor`               | قيمة `next_cursor` من الصفحة السابقة               |

لكل رسالة `id` و`role` (`user` أو `assistant`) و`type` (`text` أو `image` أو `file`...) و`content` (نص؛ الحمولات غير النصية تُعرض بنصها أو اسمها) و`created_at`.

معرّف المحادثة الذي ينتمي إلى مفتاح أو قناة أخرى، أو غير الموجود، يُرجع `404 conversation_not_found`. لا تفرّق API بين الحالتين.

## التصفّح

كل قائمة هي `{"data": [...], "next_cursor": "..." | null}`. أعد تمرير `next_cursor` في `cursor` لجلب الصفحة التالية، وتوقف عندما يصبح `null`. المؤشرات معتمة؛ المؤشر المشوّه يُرجع `422 validation_error`.

<CodeGroup>
  ```bash curl theme={null}
  # Walks every page; stops when next_cursor is null.
  cursor=""
  while :; do
    url="$CHATTLER_BASE_URL/v1/agents/$CHATTLER_AGENT_ID/conversations?limit=100"
    [ -n "$cursor" ] && url="$url&cursor=$cursor"
    page=$(curl -s "$url" -H "Authorization: Bearer $CHATTLER_API_KEY")
    echo "$page" | jq -c '.data[]'
    cursor=$(echo "$page" | jq -r '.next_cursor // empty')
    [ -z "$cursor" ] && break
  done
  ```

  ```python Python theme={null}
  import os

  import httpx

  BASE_URL = os.environ["CHATTLER_BASE_URL"]
  AGENT_ID = os.environ["CHATTLER_AGENT_ID"]
  HEADERS = {"Authorization": f"Bearer {os.environ['CHATTLER_API_KEY']}"}


  def iter_conversations():
      cursor = None
      while True:
          params = {"limit": 100}
          if cursor:
              params["cursor"] = cursor
          page = httpx.get(
              f"{BASE_URL}/v1/agents/{AGENT_ID}/conversations",
              headers=HEADERS,
              params=params,
          ).json()
          yield from page["data"]
          cursor = page["next_cursor"]
          if not cursor:
              break
  ```

  ```javascript Node theme={null}
  async function* iterConversations() {
    let cursor = null;
    for (;;) {
      const url = new URL(`${baseUrl}/v1/agents/${agentId}/conversations`);
      url.searchParams.set("limit", "100");
      if (cursor) url.searchParams.set("cursor", cursor);
      const page = await (
        await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } })
      ).json();
      yield* page.data;
      cursor = page.next_cursor;
      if (!cursor) break;
    }
  }
  ```
</CodeGroup>

## التواريخ

التواريخ بصيغة ISO-8601. القيم التي تحمل منطقة زمنية تُحوَّل إلى UTC، والقيم بلا منطقة زمنية تُقرأ على أنها UTC، و`date_to` غير شامل. قيمة `date_to` أسبق من `date_from` تُرجع `422 validation_error`.
