المجموعات
المجموعة محادثة يشارك فيها أكثر من شخصين. وتُسرَد وتُنشأ وتُعدَّل من هنا، ويُراسَل فيها بواجهة الإرسال العادية.
سرد المجموعات
هذه قائمة المحادثات مصفّاة على المجموعات، لذا تنطبق عليها قاعدة الصفحة القصيرة: فالمرشّح يعمل بعد عودة الصفحة، ومن ثمّ قد تكون الصفحة قصيرة أو فارغة بينما cursor ما زال غير فارغ. فواصِل التصفّح حتى يصير المؤشر null. وGroup هو Chat بقيمة kind: "group" مع حقل واحد إضافي هو pictureUrl.
قراءة مجموعة واحدة تحمل members. وطلب محادثة ثنائية عبر مسار المجموعات يعطي 409 CONFLICT («هذه المحادثة ليست مجموعة»)، لا 404: فالمحادثة موجودة، لكنها ليست مجموعة.
إنشاء مجموعة
curl -X POST https://api.sendveo.com/v1/groups \
-H "X-API-KEY: sv_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{ "subject": "Deliveries north",
"members": ["+212670111222", "+212671333444"],
"text": "Welcome to the deliveries group." }'{
"group": {
"id": "cht_m8k3x7q2a1b4",
"chatId": "120363001122334455@g.us",
"channelId": "chn_sales01",
"kind": "group",
"name": "Deliveries north",
"pictureUrl": "https://api.sendveo.com/v1/groups/120363001122334455%40g.us/picture",
"members": [
{ "id": "cmb_1", "phone": "+212661234567", "name": null, "role": "super_admin", "self": true },
{ "id": "cmb_2", "phone": "+212670111222", "name": "Khadija Alaoui", "role": "member", "self": false }
]
}
}يُتحقَّق من كل عضو قبل إنشاء المجموعة. فواتساب لا يرفض عضوًا يتعذّر الوصول إليه، بل يستبعده بصمت: وعندها تعود المجموعة ناقصة شخصًا بلا تفسير. لذا تستعلم Sendveo عن كل واحد أولًا وترفض عملية الإنشاء كلها بالردّ 400 VALIDATION_FAILED وdetails[0].path = "members.N"، مسمّيةً الرقم. ولا يُنشأ شيء. ويجري الفحص نفسه عند إضافة عضو، بالمسار phone.
تُنشأ المجموعة ببدء محادثة فيها، فيصير text أول رسالة فيها. وإن أغفلته أُنشئت المجموعة دون قول شيء. والحدّ 50 عضوًا في الاستدعاء الواحد، تُوحَّد صيغها ويُزال تكرارها؛ والعضو المشوّه يعطي 400 يسمّي ترتيبه.
الأعضاء
يحمل العضو role: إما member أو admin أو super_admin. وقيمته member ما لم يفصح واتساب عن علامة إشراف، وشكل المشارك الذي ينشره لا يحمل أي علامة من هذا القبيل، فاعتبر الدور غير member موثوقًا، واعتبر member بمعنى «لم يُقَل لنا غير ذلك». ولا تبنِ على الدور فحصًا للصلاحيات: فواتساب يرفض أصلًا أي إجراء لا يحقّ للرقم تنفيذه، والفحص المبني على الدور سيخفي الإجراء عمّن يحقّ لهم القيام به.
يُضبَط leftAt بدل حذف السطر. فالرسالة من شخص غادر المجموعة الأسبوع الماضي ما زال يلزم أن تُنسَب إلى اسم.
إزالة رقمك أنت مرفوضة بالردّ 409 CONFLICT: «لإزالة رقمك من مجموعة، غادر المجموعة بدلًا من ذلك». وإلا فإن نصًّا برمجيًا يمرّ على قائمة الأعضاء سيغادر المجموعة سهوًا.
المغادرة
تعتمد المغادرة على الرقم الذي جرى التحقق منه وقت الربط، لا على رقم آتٍ من الطلب. والقناة التي لم يُقرأ رقمها للتأكد لا يمكنها المغادرة، وتردّ بـ 409 CONFLICT.
{ "left": true, "chatId": "cht_m8k3x7q2a1b4" }الإرسال إلى مجموعة
الإرسال إلى مجموعة هو POST /v1/messages مع chatId المجموعة. فهو معرّف محادثة عادي لا يحتاج واجهة جديدة ولا نطاقًا جديدًا: messages:send كالعادة. والتفاعلات وإعادة التوجيه والردود والمرفقات وإجراءا «مقروء» و«يكتب الآن» تعمل كلها في المجموعة تمامًا كما تعمل في المحادثة الثنائية.
curl -X POST https://api.sendveo.com/v1/messages \
-H "X-API-KEY: sv_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{ "channelId": "chn_sales01",
"chatId": "120363001122334455@g.us",
"text": "The gate code is unchanged." }'رسائل المجموعات
يُضاف حقلان إلى كل Message، وإلى الـ webhook message.received. وكلاهما إضافي، وكلاهما null في الرسالة الثنائية، وهو ما يظل يراه معالِج كُتب قبل وجود المجموعات.
{
"id": "msg_8Rm5",
"channelId": "chn_sales01",
"chatId": "120363001122334455@g.us",
"direction": "INBOUND",
"from": "+212671333444",
"senderName": "Omar Idrissi",
"text": "The Rabat round leaves at 8am tomorrow.",
"type": "text",
"status": "RECEIVED",
"group": { "chatId": "120363001122334455@g.us", "id": "cht_m8k3x7q2a1b4", "name": "Atlas team - deliveries" },
"author": { "phone": "+212671333444", "name": "Omar Idrissi" }
}group يحدّد المحادثة: فـgroup.id هو معرّف محادثة Sendveo حين تحتفظ Sendveo بالسطر، وnull فيما عدا ذلك، بينما group.chatId وgroup.name لهما معنى دائمًا. وauthor هو مَن قال الرسالة داخل المجموعة. وهو null في الرسالة الثنائية، لأن المرسِل هناك هو المحادثة نفسها وfrom يقول ذلك أصلًا، وnull كذلك في رسالة مجموعة صادرة، إذ قالها الرقم المربوط. ويحتفظ from بمعناه من الإصدار V1 ويحمل صاحب الرسالة في رسالة المجموعة الواردة، فيظل المعالِج الذي لا يعرف سوى from قادرًا على قراءة مرسِل.
صور المجموعات
pictureUrl للمجموعة حاضر دائمًا، والمجموعة التي لا صورة لها تردّ هناك بـ 404. وهذا طلب واحد بدل استدعاء إضافي عند المصدر لكل مجموعة في القائمة. وهو الوسيط نفسه الذي تستعمله صورة جهة الاتصال، بالقواعد نفسها: نوع محتوى مختار، ولا شيء يُخزَّن، وحدّ أقصى 2 ميغابايت.
أحداث المجموعات
تُعاد ثلاثة أحداث إلى الـ webhook الخاص بك. وهي تخصّ محادثة، لذا تحمل chat حيث تحمل أحداث الرسائل message، إضافة إلى by. والإزالة والمغادرة حدث واحد يفرّق بينهما member.removed؛ وإنشاء المجموعة وتغيير اسمها حدث واحد كذلك.
| الحدث | متى يقع | حقول إضافية |
|---|---|---|
| group.member_joined | أُضيف شخص إلى مجموعة. | member, by |
| group.member_left | غادر شخص، أو أُزيل. | member.removed, by |
| group.updated | أُنشئت مجموعة، أو تغيّر موضوعها. | subject, by |
النطاقات
قراءة المجموعات وتعديلها صلاحيتان منفصلتان. و*:read يمنح groups:read شأن كل نطاق قراءة آخر. والمفتاح الصادر قبل وجود هذه النطاقات لا يحملها ويردّ بـ 403؛ فأصدر مفتاحًا جديدًا.
| النطاق | ما يمنحه |
|---|---|
| groups:read | سرد المجموعات وقراءتها، وصور المجموعات. |
| groups:manage | إنشاء مجموعة وإضافة الأعضاء وإزالتهم والمغادرة. |