يمكنك باستخدام WhatsApp Flows إنشاء رسائل تفاعلية للمستخدمين لإكمال الإجراءات مباشرةً على واتساب. تتيح لك عمليات الدفق إنشاء شاشات لتفاعل المستخدم. على سبيل المثال، يمكنك إنشاء نماذج إدخال بسيطة لتجميع بيانات العملاء المحتملين أو إرسال عمليات المراجعة. بالإضافة إلى ذلك، يمكنك تصميم عمليات دفق معقدة عبر عدة شاشات لجدولة المواعيد.
سيتناول هذا الدليل إرشادات حول إنشاء تطبيق Node.js يتيح للمستخدمين حجز المواعيد من خلال WhatsApp Flows. وستتمكن من إنشاء دفق على منصة واتساب للأعمال، ثم تكوين webhook لتلقي استجابة الدفق وحجز الموعد.
لاتِّباع هذا العرض التوضيحي، تأكَّد من حصولك على ما يلي:
هناك طريقتان لإنشاء دفق على واتساب: أداة إنشاء عمليات الدفق، والتي يمكن الوصول إليها عبر مدير واتساب، وواجهة Flows API. يستخدِم هذا العرض التوضيحي أداة إنشاء Flows.
في القائمة اليمنى بلوحة معلومات مدير واتساب، حدِّد أدوات الحسابات. ثم انقر على عمليات الدفق.
انقر على خيار إنشاء دفق الموجود في الزاوية العلوية اليسرى.
في مربع الحوار الذي يظهر، املأ تفاصيل دفق الموعد:
انقر على إرسال لإنشاء الدفق.
يمكنك معاينة الدفق على يسار واجهة مستخدم أداة الإنشاء. تتيح شاشة الموعد للمستخدم اختيار تفاصيل الموعد، مثل الموقع والتاريخ. سيقوم المستخدم بإدخال معلوماته في شاشة التفاصيل. تعرض شاشة الملخص ملخص حجز الموعد. تعرض آخر شاشة شروط الشركة.
يظل الدفق في حالة المسودة بينما تقوم بتعديله. يمكنك حاليًا مشاركته مع فريقك لأغراض الاختبار فقط. ولمشاركته مع جمهور أكبر، يجب نشره أولاً. ومع ذلك، لا يمكنك تعديل الدفق بمجرد نشره. نظرًا لأنك ستظل بحاجة إلى إضافة عنوان URL لنقطة النهاية لدفق الموعد هذا، اترك الدفق كمسودة في الوقت الحالي وانتقِل إلى الخطوة التالية؛ حيث ستقوم بتكوين نقطة النهاية.
تتيح لك WhatsApp Flows الاتصال بنقطة نهاية خارجية. بإمكان نقطة النهاية هذه توفير بيانات ديناميكية للدفق والتحكم في التوجيه. كما أنها تتلقى الاستجابات التي يتم إرسالها بواسطة المستخدم من الدفق.
لأغراض تتعلق بالاختبار، يستخدم هذا الدليل Glitch لاستضافة نقطة النهاية. يُعَد استخدام Glitch أمرًا اختياريًا تمامًا، وليس مطلوبًا لاستخدام عمليات الدفق. يمكنك نسخ الرمز البرمجي لنقطة النهاية من GitHub وتشغيله في أي بيئة تفضلها.
يمكنك الوصول إلى الرمز البرمجي لنقطة النهاية في Glitch وإعادة مزجه للحصول على النطاق الفريد الخاص بك. لمزج الرمز، انقر على Remix "مزج" في أعلى الصفحة. سيظهر نطاق فريد كعنصر نائب في عنصر الإدخال على الجانب الأيمن من صفحة Glitch.
قبل المتابعة، دعنا نتحدث عن الرمز البرمجي. هناك أربعة ملفات بلغة JavaScript في دليل src
: encryption.js
وflow.js
وkeyGenerator.js
وserver.js
. ملف الإدخال هو server.js
؛ لذا دعنا نلقي نظرة عليه أولاً.
يبدأ ملف server.js
بتكوين تطبيق Express لاستخدام ملف express.json
الوسيط لتحليل طلبات JSON الواردة. بعد ذلك، يقوم بتحميل متغيرات البيئة اللازمة لنقطة النهاية.
const { APP_SECRET, PRIVATE_KEY, PASSPHRASE, PORT = "3000" } = process.env;
يُستخدم APP_SECRET
في عملية التحقق من التوقيع. ويساعدك على التحقق من إذا ما كانت الرسالة واردة عبر واتساب أم لا، وبالتالي تكون معالجتها آمنة. ستقوم بإضافته إلى ملف .env
.
للوصول إلى APP_SECRET
، انتقِل إلى لوحة المعلومات في التطبيق على Meta للمطوّرين. في جزء التنقل على الجانب الأيمن ضمن إعدادات التطبيق، اختر أساسية. انقر على عرض ضمن المفتاح السري للتطبيق وانسح المفتاح السري. بعد ذلك، عُد إلى Glitch، وافتح ملف .env
، ثم أنشِئ متغيرًا باسم APP_SECRET
باستخدام المفتاح السري الذي نسخته.
يساعد PRIVATE_KEY
على فك تشفير الرسائل المستلمة. سيتم استخدام PASSPHRASE
للتحقق من المفتاح الخاص. إلى جانب المفتاح الخاص، تحتاج أيضًا إلى المفتاح العام المقابل له، والذي ستقوم بتحميله لاحقًا. لا تستخدم أبدًا المفاتيح الخاصة لحسابات الإنتاج الخاصة بك هنا. أنشِئ مفتاحًا خاصًا مؤقتًا للاختبار على Glitch، ثم استبدله بمفتاح الإنتاج في البنية الأساسية لديك.
أنشِئ الإقران بين المفتاح العام والخاص من خلال تشغيل الأمر الوارد أدناه في وحدة Glitch الطرفية. استبدِل <your-passphrase>
بعبارة المرور المخصصة لك. يمكنك الوصول إلى وحدة Glitch الطرفية بالنقر على علامة التبويب TERMINAL "الوحدة الطرفية" في أسفل الصفحة.
node src/keyGenerator.js <your-passphrase>
انسخ عبارة المرور والمفتاح الخاص والصقهما في ملف .env
. انقر على الملف المُسمى .env في الشريط الجانبي الأيسر ، ثم انقر على ✏️ Plain text "✏️ نص بسيط" في الأعلى. لا تقم بتعديله مباشرةً من واجهة المستخدم؛ لأن ذلك سيؤدي إلى تعطيل تنسيق المفتاح الخاص بك.
بعد تعيين متغيرات البيئة، انسخ المفتاح العام الذي أنشأته ثم حمِّل الملف العام عبر واجهة Graph API.
يحتوي ملف server.js
أيضًا على نقطة نهاية POST
تقوم بتنفيذ خطوات مختلفة:
if (!PRIVATE_KEY) { throw new Error('Private key is empty. Please check your env variable "PRIVATE_KEY".'); }
isRequestSignatureValid
الموجودة أسفل الملف: if(!isRequestSignatureValid(req)) { // Return status code 432 if request signature does not match. // To learn more about return error codes visit: https://developers.facebook.com/docs/whatsapp/flows/reference/error-codes#endpoint_error_codes return res.status(432).send(); }
decryptRequest
الموجودة في ملف encryption.js
: let decryptedRequest = null; try { decryptedRequest = decryptRequest(req.body, PRIVATE_KEY, PASSPHRASE); } catch (err) { console.error(err); if (err instanceof FlowEndpointException) { return res.status(err.statusCode).send(); } return res.status(500).send(); } const { aesKeyBuffer, initialVectorBuffer, decryptedBody } = decryptedRequest; console.log("💬 Decrypted Request:", decryptedBody);
getNextScreen
بشكل مفصل لاحقًا. const screenResponse = await getNextScreen(decryptedBody);
console.log("👉 Response to Encrypt:", screenResponse);
res.send(encryptResponse(screenResponse, aesKeyBuffer, initialVectorBuffer));
يحتوي هذا الملف على منطق تشفير الرسائل المتبادلة وفك تشفيرها لأغراض أمنية. لن يركز هذا العرض التوضيحي على كيفية عمل الملف.
يساعد هذا الملف على إنشاء المفاتيح الخاصة والعامة، كما رأيت سابقًا. كما هو الحال مع ملف encryption.js
، لن يشرح هذا العرض التوضيحي ملف keyGenerator.js
بالتفصيل.
يحتوي هذا الملف على منطق التعامل مع الدفق. ويبدأ بكائن تم تعيينه بالاسم SCREEN_RESPONSES
. يحتوي الكائن على معرفات الشاشة والتفاصيل المتعلقة بها، مثل البيانات المعدة مسبقًا المستخدمة في عمليات تبادل البيانات. تم إنشاء هذا الكائن من خلال أداة إنشاء عمليات الدفق ضمن "..." > نقطة نهاية > أجزاء الرمز البرمجي > الاستجابات. في نفس الكائن، يتوفر لديك أيضًا معرف آخر، SUCCESS
، والذي يتم إرساله مرة أخرى إلى جهاز العميل عند اكتمال الدفق بنجاح. ويؤدي هذا إلى إغلاق الدفق.
تحتوي وظيفة getNextScreen
على المنطق الذي يوجه نقطة النهاية بشأن بيانات الدفق التي سيتم عرضها للمستخدم. ويبدأ باستخراج البيانات اللازمة من الرسالة التي تم فك تشفيرها.
const { screen, data, version, action, flow_token } = decryptedBody;
تتلقى نقاط نهاية WhatsApp Flows عادةً ثلاثة طلبات:
data_exchange
data.error
ping
يمكنك العثور على التفاصيل الخاصة بكل طلب في وثائق نقطة النهاية.
تتعامل الوظيفة مع التحقق من الصحة وإشعارات الأخطاء باستخدام بيانات if
وتستجيب وفقًا لذلك، كما هو موضح في جزء الرمز البرمجي أدناه:
// handle health check request if (action === "ping") { return { version, data: { status: "active", }, }; } // handle error notification if (data?.error) { console.warn("Received client error:", data); return { version, data: { acknowledged: true, }, }; }
عند قيام المستخدم بالنقر على زر الدعوة لاتخاذ إجراء (CTA) الخاص بالدفق، يتم إطلاق إجراء INIT
. يقوم هذا الإجراء بإرجاع شاشة الموعد مع البيانات. كما يقوم أيضًا بتعطيل القوائم المنسدلة للموقع والتاريخ والوقت لضمان قيام المستخدم بملء جميع الحقول.
على سبيل المثال، يتم تمكين القائمة المنسدلة للتاريخ فقط عند ملء القائمة المنسدلة للموقع. تتم معالجة تمكين وتعطيل الحقول عند تلقي طلب data_exchange
.
// handle initial request when opening the flow and display APPOINTMENT screen if (action === "INIT") { return { ...SCREEN_RESPONSES.APPOINTMENT, data: { ...SCREEN_RESPONSES.APPOINTMENT.data, // these fields are disabled initially. Each field is enabled when previous fields are selected is_location_enabled: false, is_date_enabled: false, is_time_enabled: false, }, }; }
بالنسبة إلى إجراءات data_exchange
، يتم استخدام بنية تبديل الحالة لتحديد البيانات التي سيتم إرسالها مرة أخرى بناءً على معرف الشاشة. إذا كان معرف الشاشة عبارة عن APPOINTMENT
، فسيتم تمكين الحقول المنسدلة فقط عند تحديد القوائم المنسدلة السابقة.
// Each field is enabled only when previous fields are selected is_location_enabled: Boolean(data.department), is_date_enabled: Boolean(data.department) && Boolean(data.location), is_time_enabled: Boolean(data.department) && Boolean(data.location) && Boolean(data.date)
بالنسبة إلى شاشة التفاصيل، يتم استخراج عناوين خصائص كائن البيانات، مثل الموقع والقسم، من كائن SCREEN_RESPONSES.APPOINTMENT.data
. يفترض هذا الرمز البرمجي وجود تطابق صالح؛ لذا لاحظ أنه قد يؤدي إلى حدوث خطأ إذا لم يتم العثور على كائن مطابق.
الآن، لنأخذ مثالاً لكائن الموقع. يتم تحديد اختيار كائن الموقع المحدد من خلال مطابقة إعدادات id
للكائنات الموجودة في المصفوفة مع قيمة data.location
.
const departmentName = SCREEN_RESPONSES.APPOINTMENT.data.department.find( (dept) => dept.id === data.department ).title; const locationName = SCREEN_RESPONSES.APPOINTMENT.data.location.find( (loc) => loc.id === data.location ).title; const dateName = SCREEN_RESPONSES.APPOINTMENT.data.date.find( (date) => date.id === data.date
).title;
يتم بعد ذلك ربط القيم في سلسلة وإرسالها مرة أخرة في الاستجابة لعرض شاشة "الملخص".
const appointment = `${departmentName} at ${locationName} ${dateName} at ${data.time}`; const details = `Name: ${data.name} Email: ${data.email} Phone: ${data.phone} "${data.more_details}"`; return { ...SCREEN_RESPONSES.SUMMARY, data: { appointment, details, // return the same fields sent from client back to submit in the next step ...data, }, };
بعد إرسال شاشة "الملخص" من العميل، يتم إرسال استجابة النجاح إلى جهاز العميل لتمييز الدفق على أنه مكتمل. يُعَد flow_token
معرفًا فريدًا يمكنك تعيينه عند إرسال الدفق إلى المستخدم.
// send success response to complete and close the flow return { ...SCREEN_RESPONSES.SUCCESS, data: { extension_message_response: { params: { flow_token, }, }, }, };
لا تحتوي شاشة "الشروط" على أي بيانات يمكن تبادلها؛ وبالتالي فإن نقطة النهاية لا تتعامل معها.
في الجزء العلوي الأيسر من صفحة Glitch، يمكنك نسخ عنوان URL من خلال النقر على أيقونة قائمة النقاط الثلاث الرأسية وتحديد Copy Link "نسخ الرابط". يمكنك أيضًا الحصول على الرابط بالنقر على Share "مشاركة" في الزاوية العلوية اليمنى.
انتقِل إلى محرر الدفق. انقر على إعداد في الشعار البني الذي يظهر أعلى المحرر.
سيظهر إشعار منبثق يسمح لك بتكوين عنوان URI لنقطة النهاية ورقم هاتف النشاط التجاري والتطبيق على Meta للمطوّرين. بعد إجراء التكوينات اللازمة، قم بالتحقق من سلامة الأداء. أولاً، قم بتشغيل المعاينة التفاعلية وتأكد من تحديد طلب بيانات ضمن طلب البيانات الموجودة في الشاشة الأولى في إعدادات المعاينة التفاعلية. يؤدي هذا إلى إرسال طلب إلى نقطة النهاية لاسترداد البيانات للشاشة الأولى، والتحقق من توفر نقطة النهاية ومن قيامك بتنفيذ التحقق من سلامة الأداء.
بعد ذلك، قم بنشر الدفق عن طريق النقر على أيقونة النقاط الثلاث الأفقية (...) واختيار نشر. سيؤدي هذا إلى إرسال طلب التحقق من سلامة الأداء إلى نقطة النهاية الخاصة بك من خلال action === "ping"
للتحقق من إعداد نقطة النهاية قبل النشر.
بعد إكمال عمليات التكوين، قم بتبديل زر المعاينة التفاعلية مرة أخرى في واجهة مستخدم أداة إنشاء واتساب لاختبار الدفق. في الإشعار المنبثق الذي يظهر، حدِّد رقم الهاتف واختر خيار طلب بيانات ضمن طلب البيانات الموجودة في الشاشة الأولى. أغلِق الدفق بالنقر على أيقونة X لبدء اختبار الدفق من جديد من زر الدعوة لاتخاذ إجراء.
افتح سجل Glitch بالنقر على علامة التبويب LOGS "السجلات". امسح السجل بالنقر على Clear "مسح". ثم عُد إلى معاينة واجهة مستخدم أداة إنشاء واتساب. انقر على معاينة الدفق. سترى شيئًا كالتالي:
يمكنك الآن العودة إلى سجلات Glitch. ستشاهد إجراء INIT
، ورمز الدفق، وتفاصيل أخرى ضمن الطلب الذي تم فك تشفيره. هناك أيضًا استجابة للتشفير يتم إرسالها مرة أخرى إلى دفق المستخدم بمجرد تحديد القائمة المنسدلة للقسم.
انتقِل إلى تحديد القسم. لاحظ أنه تم تعيين is_location_enabled
إلى true
وتغيير الإجراء إلى data_exchange
.
استمر في اختبار الدفق ولاحظ تغييرات البيانات في سجلات Glitch. سيتم إنشاء سجلات مماثلة عندما يتفاعل المستخدمون مع الدفق من أجهزتهم المحمولة.
في القسم التالي، ستقوم بإنشاء webhook ليعمل على إرسال رسالة تأكيد إلى المستخدم عند حجز موعد.
عندما يكمل المستخدم الدفق، يتم إرسال رسالة تشير إلى اكتمال الدفق إلى webhook المشترك. من خلال الـ webhook هذا، يمكنك إعلام المستخدم بأنه تم حجز موعده بنجاح من خلال رسالة في الدردشة. كما هو الحال مع نقطة النهاية، ستستخدم أيضًا Glitch للاختبار. يمكنك الوصول إلى الرمز البرمجي ومزجه هنا.
يُعَد استخدام Glitch أمرًا اختياريًا تمامًا - وليس مطلوبًا لاستخدام عمليات الدفق. يمكنك نسخ رمز webhook البرمجي من GitHub وتشغيله في أي بيئة تفضلها.
لتعيين متغيرات البيئة، افتح ملف .env
على Glitch. قم بتعيين VERIFY_TOKEN
لأي سلسلة تفضلها، وFLOW_ID
مع معرف الدفق الخاص بك، وGRAPH_API_TOKEN
إلى رمز الوصول الخاص بحسابك على واتساب للأعمال. يمكنك الحصول على رمز الوصول من لوحة المعلومات الخاصة بتطبيقك على Meta للمطوّرين عند النقر على إعداد واجهة API ضمن قسم واتساب في جزء التنقل على الجانب الأيمن.
في الصفحة التي يتم عرضها، انقر على الزر نسخ ضمن بطاقة رمز وصول مؤقت. الصق المفتاح في ملف .env
لديك.
في حسابك على Meta للمطوّرين، انقر على قائمة التكوين ضمن واتساب في جزء التنقل على الجانب الأيمن.
في بطاقة Webhook، انقر على تعديل. في مربع الحوار الذي سيفتح، الصق عنوان URL المنسوخ الخاص بـ Glitch، وألحق /webhook
به في الحقل عنوان URL للاستدعاء. في حقل التحقق من الرمز، أضِف الرمز من المتغير .env
في الملف TOKEN
. بمجرد الانتهاء، انقر على تحقق وحفظ. سيتم إغلاق مربع الحوار والعودة إلى الشاشة الرئيسية. انقر على إدارة وقم بتحديد حقل الرسائل. أصبح webhook جاهزًا الآن.
يحتوي الرمز البرمجي على مسارين: POST /webhook
وGET /webhook
. يتعامل مسار GET
مع طلبات التحقق من الـ webhook عن طريق التحقق من الرمز المقدم مقابل رمز التحقق المحدد مسبقًا والاستجابة برموز الحالة المناسبة ورمز التحدي.
const verify_token = process.env.VERIFY_TOKEN; // Parse params from the webhook verification request let mode = req.query["hub.mode"]; let token = req.query["hub.verify_token"]; let challenge = req.query["hub.challenge"]; if (mode && token) { if (mode === "subscribe" && token === verify_token) { console.log("WEBHOOK_VERIFIED"); res.status(200).send(challenge); } else { res.sendStatus(403); } }
يقوم مسار POST /webhook
بمعالجة إشعارات webhook الواردة. يمكن أن تحتوي طلبات Webhook على حمولات بيانات مختلفة. لذلك، يقوم الرمز البرمجي أدناه بقراءة الرسالة ورقم هاتف النشاط التجاري عن طريق الوصول إلى حقول الطلب بشكل آمن في حالة عدم تحديدها.
const message = req.body.entry?.[0]?.changes[0]?.value?.messages?.[0]; const business_phone_number_id =
req.body.entry?.[0].changes?.[0].value?.metadata?.phone_number_id;
ثم يقوم بعد ذلك بالتحقق من إذا ما كان الطلب الوارد مخصصًا لرسالة من نوع "text"
التي تحتوي على كلمة "موعد". إذا كانت الرسالة تحتوي على هذه الكلمة، فسيتم إرسال الدفق إلى المستخدم. يتم إرسال رسالة الدفق باستخدام flow_action: "data_exchange
،"
مما يعني أن الدفق سيقدم طلب INIT
إلى نقطة النهاية عند إطلاقه للحصول على الشاشة والبيانات الأولية.
if ( message.type === "text" && // for demo purposes, send the flow message whenever a user sends a message containing "appointment" message.text.body.toLowerCase().includes("appointment") ) { // send flow message as per the docs here https://developers.facebook.com/docs/whatsapp/flows/gettingstarted/sendingaflow#interactive-message-parameters await axios({ method: "POST", url: `https://graph.facebook.com/v18.0/${business_phone_number_id}/messages`, headers: { Authorization: `Bearer ${GRAPH_API_TOKEN}`, }, data: { messaging_product: "whatsapp", to: message.from, type: "interactive", interactive: { type: "flow", header: { type: "text", text: "Hello there 👋", }, body: { text: "Ready to transform your space? Schedule a personalized consultation with our expert team!", }, footer: { text: "Click the button below to proceed", }, action: { name: "flow", parameters: { flow_id: FLOW_ID, flow_message_version: "3", // replace flow_token with a unique identifier for this flow message to track it in your endpoint & webhook flow_token: "<FLOW_TOKEN_PLACEHOLDER>", flow_cta: "Book an appointment", flow_action: "data_exchange", }, }, }, }, }); } ...
إذا لم يكن نوع الرسالة الواردة عبارة عن "text"
، فإن الرمز يتحقق من إذا ما كان نوع الرسالة هو "interactive
."
يشير النوع التفاعلي "nfm_reply"
إلى أن الرسالة الواردة هي استجابة لدفق. وبعد ذلك، يقوم بإعادة إرسال رسالة "لقد قمت بحجز موعد بنجاح" إلى المستخدم.
... if ( message.type === "interactive" && message.interactive?.type === "nfm_reply" ) { // send confirmation message await axios({ method: "POST", url: `https://graph.facebook.com/v18.0/${business_phone_number_id}/messages`, headers: { Authorization: `Bearer ${GRAPH_API_TOKEN}`, }, data: { messaging_product: "whatsapp", to: message.from, text: { body: "You've successfully booked an appointment" }, }, }); } ...
ثم يقوم بتمييز الرسالة الواردة كمقروءة؛ حتى يرى المستخدم العلامات الزرقاء.
... // mark incoming message as read await axios({ method: "POST", url: `https://graph.facebook.com/v18.0/${business_phone_number_id}/messages`, headers: { Authorization: `Bearer ${GRAPH_API_TOKEN}`, }, data: { messaging_product: "whatsapp", status: "read", message_id: message.id, }, }); ...
في هذا المثال، يرسل المستخدم رسالة إلى رقمك تحتوي على كلمة "موعد"، ثم يتلقى رسالة الدفق. يمكنك أيضًا اختيار إرسال الدفق بعد تفاعل مختلف أو كقالب رسالة.
سيتلقى المستخدم رسالة دفق تحتوي على زر دعوة لاتخاذ إجراء لحجز موعد؛ حيث يمكنه ملء التفاصيل الخاصة به. بعد ذلك، سيتلقى رسالة تأكيد عند إكمال الدفق.
لقد تعرَّفت في هذا الدليل، على كيفية إعداد دفق على واتساب لجدولة المواعيد بشكل سلس. باستخدام واجهة مستخدم أداة إنشاء الدفق، قمتَ بإنشاء نموذج لجمع تفاصيل المواعيد من المستخدمين.
تلغي عمليات الدفق الحاجة إلى إعادة توجيه المستخدمين إلى موقع ويب خارجي لحجز المواعيد؛ مما يعزز تجربة العملاء. تتيح العملية المباشرة للمستخدمين إكمال الحجوزات مباشرةً من داخل واتساب. بالإضافة إلى جدولة المواعيد، يمكنك استخدام WhatsApp Flows لجمع ملاحظات حول خدمة العملاء، أو مساعدة المستخدمين على الاشتراك في العروض الترويجية أو القوائم البريدية. وتوفر ميزة WhatsApp Flows أيضًا المرونة اللازمة للاتصال بواجهات API خارجية أو تطبيقات أخرى في نقطة النهاية لديك.
يُعَد إنشاء WhatsApp Flows أمرًا سهلاً باستخدام واجهة مستخدم أداة إنشاء الدفق. ومع ذلك، يمكنك أيضًا استخدام واجهة Flow API لإنشاء عمليات الدفق برمجيًا. لمزيد من المعلومات، يمكنك الرجوع إلى وثائق WhatsApp Flows.