المحادثات وجهات الاتصال
اقرأ محادثات رقم مربوط، وتصرّف فيها، واستعلم عن الأشخاص الموجودين فيها. وكل ما في هذه الصفحة موجود في الـ API وفي لوحة التحكم معًا، بالأجسام والاستجابات نفسها.
لمن تعود القائمة
محادثات الرقم تعيش على الهاتف وعند واتساب. ومعظمها أقدم من Sendveo تمامًا، وتُوسَم كمقروءة وتُؤرشَف وتُكتَم من الجهاز نفسه. لا تملك Sendveo تلك القائمة ولا تحاول امتلاكها. وما تحتفظ به هو مرآة لها: معرّف Sendveo ثابت لكل محادثة، وآخر ما وردها من مؤشرات، وأسماء المشاركين، وسجلّ مزامنة التاريخ الذي لا يجد واتساب مكانًا لحفظه.
ثلاث نتائج ستلاحظها. عدّاد غير المقروء وarchived وmuted ملك لهم، وتكتب Sendveo فوق نسختها في كل قراءة: فالمحادثة المؤرشفة من الهاتف تعود مؤرشفة دون أن يُخبَر Sendveo بذلك. ويمكن مخاطبة المحادثة بطريقتين: فـchatId هو نصّ واتساب نفسه، لم يتغيّر منذ الإصدار V1، وid هو معرّف Sendveo cht_… إلى جانبه؛ وكل مسار أدناه يقبل أيًّا منهما. ومعرّف محادثة جاء من العدم يعني 404: فلا بد أن يكون المعرّف قد وصلك من القائمة أو من رسالة محفوظة أو من webhook. أما المحادثة التي لم ترها إلا في webhook فتعمل رغم ذلك: إذ يُبنى سطرها من الرسائل التي تحتفظ بها Sendveo بدل الردّ بـ 404.
سرد المحادثات
يعني channelId «أيّ أرقامي». وبرقم واحد مربوط يُستنتج وحده؛ أما مع عدة أرقام فهو غامض فعلًا، لذا فإغفاله يعطي 400 على channelId بدل تخمين قد يسرد محادثات رقم تحت رقم آخر.
curl "https://api.sendveo.com/v1/chats?channelId=chn_sales01&limit=50" \
-H "X-API-KEY: sv_live_your_key_here"{
"chats": [
{
"id": "cht_m8k3x7q2a1b4",
"chatId": "120363001122334455@g.us",
"channelId": "chn_sales01",
"kind": "group",
"name": "Atlas team - deliveries",
"phone": null,
"unreadCount": 1,
"archived": false,
"muted": true,
"mutedUntil": null,
"lastMessageAt": "2026-09-16T11:42:00Z",
"lastMessagePreview": "The Rabat round leaves at 8am tomorrow.",
"sync": { "status": "done", "lastSyncedAt": "2026-09-16T11:50:00Z", "storedMessages": 214 }
}
],
"cursor": "eyJvIjo1MH0",
"channelId": "chn_sales01"
}kind إما direct أو group. وphone هو الطرف المقابل في المحادثة المباشرة وnull في المجموعة، وهو null أيضًا لجهة اتصال في وضع الخصوصية. وmuted: true مع mutedUntil: null تعني كتمًا بلا تاريخ انتهاء، والكتم الذي انقضى تاريخه يُقرأ muted: false. وsync.status واحد من never أو started أو running أو done أو error أو gone.
محادثة واحدة
لا يظهر members إلا عند قراءة محادثة واحدة وفي الردّ على تغيير في الأعضاء. وتغفله القائمة عن قصد: فإدراجه يعني استدعاءً إضافيًا للخدمة الأعلى عن كل محادثة.
{
"chat": {
"id": "cht_m8k3x7q2a1b4",
"chatId": "120363001122334455@g.us",
"kind": "group",
"members": [
{ "id": "cmb_1", "phone": "+212661234567", "name": null, "role": "super_admin",
"self": true, "joinedAt": "2026-09-01T08:00:00Z", "leftAt": null },
{ "id": "cmb_2", "phone": "+212670111222", "name": "Khadija Alaoui", "role": "admin",
"self": false, "joinedAt": "2026-09-01T08:00:00Z", "leftAt": null }
]
}
}الأرشفة والكتم
يعيد كل من هذه المسارات المحادثة بحالتها الجديدة، فلا شيء يحتاج إلى توفيق: اعرض ما يعود إليك. وتذكّر أن المؤشرات ملك لواتساب، فللعميل أن يتراجع عن أيٍّ منها من هاتفه هو.
التصفية وتقسيم الصفحات
cursor يخصّ واتساب، وهو مبهم، ويكون null حين لا توجد صفحة تالية. و?unread=true يصفّي عند المصدر؛ أما ?archived= ومرشّح المجموعات فيُطبَّقان بعد عودة الصفحة، لأن واتساب لا يوفّر مرشّحًا كهذا.
لذا قد تكون الصفحة المصفّاة أقصر من limit، بل فارغة أحيانًا، بينما cursor ما زال غير فارغ. فواصِل التصفّح حتى يصير cursor بقيمة null. ولا تعتبر الصفحة القصيرة نهاية القائمة: فهذا هو الخطأ الوحيد الذي تغري به هذه الواجهة، وهو يخفي محادثات في صمت.
مزامنة السجلّ
يعيد GET /v1/messages?chatId=… ما تحتفظ به Sendveo، وهو افتراضيًا ما وصل عبر الـ webhook منذ ربط الرقم. والمزامنة تسحب رسائل أقدم إلى ذلك المخزن ليصير السجلّ موجودًا فيه كذلك.
curl -X POST https://api.sendveo.com/v1/chats/cht_m8k3x7q2a1b4/sync \
-H "X-API-KEY: sv_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{ "limit": 100 }'{ "chatId": "cht_m8k3x7q2a1b4", "status": "done", "stored": 100, "storedTotal": 100, "hasMore": true }يبيّن stored عدد الرسائل التي أضافها هذا الاستدعاء تحديدًا؛ وstoredTotal هو المجموع التراكمي للمحادثة. وhasMore: true تعني استدعِ الطريق مرة أخرى: إذ يُحفظ مؤشر على الخادم، فيكمل الاستدعاء التالي من حيث توقّف هذا. والعملية لا يغيّرها التكرار: فكل رسالة تُكتب عبر آلية إزالة التكرار نفسها التي يستعملها الـ webhook الحيّ، لذا لا يحفظ التكرار شيئًا ويردّ بـ stored: 0.
الحدّ الأقصى لكل محادثة: مزامنة واحدة في الدقيقة، لا لكل بيانات اعتماد، لأن اعتمادين يزامنان محادثة واحدة يساويان عمل مزامنة واحدة عند المصدر. وبتجاوز الحدّ، 429 RATE_LIMITED مع Retry-After بالثواني.
status: "running" حالة طبيعية وليست إخفاقًا: فمزامنة واتساب الخلفية قد تكون ما تزال تمرّ على المحادثة بينما يعيد هذا الاستدعاء الصفحة التي أمكنه تقديمها. فاستدعِ مرة أخرى. وstatus: "gone" تعني أن المحادثة لم تعد موجودة عند المصدر، وstored يساوي 0، ولا شيء يستحق إعادة المحاولة. وأي حالة لا تعرفها Sendveo يُبلَّغ عنها بوصفها running، لا done أبدًا: فالقول إن المزامنة انتهت ونحن لا نعلم يجعل السجلّ الناقص يبدو وكأنه غير موجود أصلًا.
جهات الاتصال
لا تكتب Sendveo جهة اتصال في أي مكان أبدًا. فلا دفتر عناوين ولا جدول لجهات الاتصال: جهة الاتصال رقم، وكل ما يُعرف عنه يُقرأ من واتساب لحظة سؤالك.
curl https://api.sendveo.com/v1/contacts/%2B212670111222 \
-H "X-API-KEY: sv_live_your_key_here"{
"contact": {
"phone": "+212670111222",
"onWhatsApp": true,
"name": "Khadija Alaoui",
"business": false,
"about": "Available",
"pictureUrl": "https://api.sendveo.com/v1/contacts/%2B212670111222/picture"
}
}الرقم غير الموجود على واتساب يعطي 200 مع onWhatsApp: false، لا 404. فالاثنان يعنيان أمرين مختلفين ولا بد أن تميّز بينهما: «لا وجود لهذا الرقم على واتساب» جواب عن العالم، بينما 404 هنا سيعني «ليس رقمك» أو «لا وجود لهذا المسار». وحين يكون onWhatsApp بقيمة false، فلا معنى لبقية حقول الكائن. وname هو ما تنشره جهة الاتصال، وإلا فالاسم الذي استنتجته Sendveo من محادثة معها؛ وabout هو سطر حالتها حين تسمح إعدادات خصوصيتها بإظهاره.
الرقم المشوّه يعطي 400 VALIDATION_FAILED على phone. والصيغ نفسها المقبولة عند الإرسال مقبولة هنا (+212661234567 و212661234567 و00212661234567، بمسافات أو شُرَط أو نقاط أو أقواس)؛ أما الصيغة المحلية التي تبدأ بصفر فمرفوضة، لأنها بلا بلد تخمين، والتخمين يراسل شخصًا غريبًا.
الصور
يعيد مسارا الصور البايتات، وكلاهما وسيط لا إعادة توجيه أبدًا. والسبب خاص بالصور: فواتساب يعيد رابط صورة يصفه بأنه مؤقّت، على مضيفه هو، لذا فتضمين ذلك الرابط يعطيك صورًا شخصية تنكسر وفق جدول شخص آخر، واسم مضيف خارجي داخل DOM صفحتك. أما رابط Sendveo فلا ينتهي ولا يسمّي أحدًا.
تحمل الاستجابة Content-Type من اختيار Sendveo، أي image/jpeg أو image/png أو image/webp أو image/gif، لا منقولًا كما ورد: وأي نوع آخر يُقدَّم بوصفه application/octet-stream ليُنزّله المتصفح بدل عرضه. ويُضاف إليها Cache-Control: private, no-store وX-Content-Type-Options: nosniff وContent-Security-Policy مشدّدة. ولا يُخزَّن شيء، فكل طلب استدعاء واحد للخدمة الأعلى. والحدّ الأقصى 2 ميغابايت؛ والصورة الأكبر تعطي 404 بدل جسم منقوص.
جهة اتصال بلا صورة، وأخرى تخفيها، وعطب عابر عند المصدر: ثلاثتها لا تُميَّز من هنا وكلها تردّ 404. فعامِلها على أنها «لا صورة» واعرض الأحرف الأولى؛ فهي ليست خطأ يستحق رسالة. وpictureUrl لجهة الاتصال يكون null حين يقول واتساب إنه لا صورة لها؛ أما pictureUrl للمجموعة فحاضر دائمًا، لذا فالردّ 404 هناك هو الجواب الصادق.
التحقق من الأرقام
{ "numbers": ["+212670111222", "212670111222", "+212699999999", "not a number"] }{
"results": [
{ "phone": "+212670111222", "onWhatsApp": true },
{ "phone": "+212670111222", "onWhatsApp": true },
{ "phone": "+212699999999", "onWhatsApp": false },
{ "phone": "not a number", "onWhatsApp": false }
]
}جواب واحد عن كل سطر أرسلته، بالترتيب، حتى السطور التي ليست أرقامًا أصلًا، فهذه تعود كما وردت مع onWhatsApp: false. فعمود جدول فيه خلية واحدة خاطئة يحصل على جواب لكل سطر، بدل 400 بسبب أسوئها. والأرقام تُوحَّد صيغتها، والمكرّر يكلّف استدعاءً واحدًا عند المصدر لا اثنين.
تعيد القيمة المنطقية ولا شيء غيرها: لا اسم ولا صورة. فسؤال «هل يمكنني مراسلة هذا الرقم» سؤال توجيه، ولا داعي لأن يكون سؤال إفشاء: اطلب ملف رقم تتعامل معه فعلًا، واحدًا واحدًا. والحدّ 50 رقمًا في الاستدعاء الواحد و20 استدعاءً لكل عميل في الدقيقة؛ والقائمة الفارغة أو ما زاد على 50 يعطي 400 على numbers، وبتجاوز حدّ الاستدعاءات يكون الردّ 429 مع Retry-After. وهذه هي الواجهة الوحيدة هنا التي يمكن توجيهها إلى أرقام لا علاقة لك بها، ولذلك هي محدودة ومُقاسة ولها نطاقها الخاص.
النطاقات
القراءة والكتابة مفصولتان، ومزامنة السجلّ في جانب الكتابة لأنها تكتب رسائل في مخزنك: فبيانات اعتماد للقراءة فقط يجب ألا تستطيع تغيير ما يعيده GET /messages. و*:read يمنح chats:read وcontacts:read شأن كل نطاق قراءة آخر. والمفاتيح الصادرة قبل وجود هذه النطاقات لا تحملها: أصدر مفتاحًا جديدًا بدل تعديل مفتاح قديم.
| النطاق | ما يمنحه |
|---|---|
| chats:read | سرد المحادثات وقراءتها. |
| chats:manage | الأرشفة والكتم ومزامنة السجلّ. |
| contacts:read | ملفات جهات الاتصال وصورها، والتحقق من الوجود على واتساب. |