Linework Developers
AR
احصل على الوصول

دليل · chat:write

روبوت دردشة لدعم العملاء

أجب عن الأشخاص الذين يراسلون حسابك: أسئلة الطلبات، ومواعيد العمل، والأسئلة الشائعة. وحوِّل المحادثة إلى شخص حقيقي عند الحاجة.

نطاقات الصلاحية: chat:read، chat:write (اختياري: orders:read للبحث عن الطلبات).

قاعدة مكافحة الرسائل المزعجة#

لا يمكن للروبوت أن يكتب إلا حيث سبق أن كتب الطرف الآخر، أو إلى الأشخاص الذين يتابعون الحساب. أي شيء آخر يفشل بالخطأ 403 CHAT_NOT_ALLOWED. ويسري الحظر دائمًا (403 CHAT_BLOCKED). هذا يجعل روبوتات الدعم سهلة والتواصل غير المرغوب فيه مستحيلًا — بحكم التصميم.

نقاط النهاية#

نقطة النهايةالاستخدام
GET /conversationsمحادثاتك، الأحدث نشاطًا أولًا (مقسّمة إلى صفحات).
GET /conversations/{id}/messagesرسائل محادثة، الأحدث أولًا (مقسّمة إلى صفحات).
POST /conversations/{id}/messagesردّ في محادثة موجودة.
POST /messagesراسل مستخدمًا عبر معرّفه (تُفتح المحادثة عند الحاجة). يخضع لقاعدة مكافحة الرسائل المزعجة.

1. ابحث عن المحادثات التي تحتاج إلى رد#

curl "https://api.linework.app/open/v1/conversations?limit=20" \
  -H "Authorization: Bearer $LINEWORK_API_KEY"

لكل محادثة فيها نشاط جديد، اقرأ أحدث الرسائل وتحقّق ممن كتب آخر رسالة: إن لم يكن أنت، فقد يكون لدى الروبوت ما يجيب به.

curl "https://api.linework.app/open/v1/conversations/c_3391/messages?limit=10" \
  -H "Authorization: Bearer $LINEWORK_API_KEY"

2. ردّ#

curl https://api.linework.app/open/v1/conversations/c_3391/messages \
  -H "Authorization: Bearer $LINEWORK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "text": "Hi! We are open Monday to Saturday, 9:00–19:00." }'

3. روبوت استطلاع كامل#

const API = "https://api.linework.app/open/v1";
const headers = { Authorization: `Bearer ${process.env.LINEWORK_API_KEY}`, "Content-Type": "application/json" };
const get = (p) => fetch(API + p, { headers }).then((r) => r.json());

const me = await get("/me");
const answered = new Set(); // in production: a database

async function tick() {
  const convs = await get("/conversations?limit=20");
  for (const conv of convs.data) {
    const msgs = await get(`/conversations/${conv.id}/messages?limit=5`);
    const last = msgs.data[0]; // newest first
    if (!last || last.senderId === me.id || answered.has(last.id)) continue;

    const reply = answer(last.text);
    answered.add(last.id);
    if (!reply) continue; // a human will answer

    const res = await fetch(`${API}/conversations/${conv.id}/messages`, {
      method: "POST", headers, body: JSON.stringify({ text: reply }),
    });
    if (res.status === 429) return; // quota or rate limit: try again later
  }
}

function answer(text = "") {
  if (/hours|open|orari/i.test(text)) return "We are open Monday to Saturday, 9:00–19:00.";
  if (/order|ordine/i.test(text)) return "Send me your order number and I will check it for you.";
  return null;
}

setInterval(() => tick().catch(console.error), 30_000);
import os, re, time, requests

API = "https://api.linework.app/open/v1"
s = requests.Session()
s.headers["Authorization"] = f"Bearer {os.environ['LINEWORK_API_KEY']}"

me = s.get(API + "/me", timeout=30).json()
answered = set()  # in production: a database

def answer(text):
    if re.search(r"hours|open|orari", text or "", re.I):
        return "We are open Monday to Saturday, 9:00–19:00."
    if re.search(r"order|ordine", text or "", re.I):
        return "Send me your order number and I will check it for you."
    return None

def tick():
    convs = s.get(API + "/conversations", params={"limit": 20}, timeout=30).json()
    for conv in convs["data"]:
        msgs = s.get(f"{API}/conversations/{conv['id']}/messages", params={"limit": 5}, timeout=30).json()
        last = msgs["data"][0] if msgs["data"] else None  # newest first
        if not last or last["senderId"] == me["id"] or last["id"] in answered:
            continue
        answered.add(last["id"])
        reply = answer(last.get("text"))
        if not reply:
            continue  # a human will answer
        r = s.post(f"{API}/conversations/{conv['id']}/messages", json={"text": reply}, timeout=30)
        if r.status_code == 429:
            return  # quota or rate limit: try again later

while True:
    tick()
    time.sleep(30)

أسماء الحقول مثل senderId معروضة للتوضيح فقط: راجع مخطّط الرسالة في مرجع API.

الاستطلاع بلباقة#

  • استطلع كل 15–60 ثانية. استدعاء واحد لـ /conversations مع بضع قراءات للرسائل في كل دورة يبقى أقل بكثير من 120 طلبًا في الدقيقة.
  • لا تفتح إلا المحادثات التي تغيّر آخر نشاط فيها منذ الدورة السابقة.
  • الحصة اليومية هي 500 رسالة لكل حساب.

كن روبوتًا جيدًا#

  • اذكر في الرد الأول أنك روبوت، وأخبر الناس كيف يصلون إلى شخص حقيقي.
  • لا ترسل أبدًا عروضًا ترويجية لأشخاص لم يطلبوها، ولا ترسل أبدًا الرسالة نفسها إلى عدد كبير من الأشخاص.
  • لا تطلب كلمات المرور أو بيانات الدفع أو الرموز في الدردشة.
  • توقّف عندما يطلب منك الناس التوقّف.