تسجيل الدخولابدأ الفترة التجريبية المجانية
Meta Tech Provider

إرسال واستقبال WhatsApp من PHP وLaravel

الاستقبال مسار في Laravel يجيب عن طلب GET الخاص بتحقق Meta ويقبل طلبات POST، ويقرأ المعاملات بالأسماء hub_mode وhub_verify_token وhub_challenge لأن PHP يحوّل النقاط إلى شرطات سفلية. أما الإرسال فطلب POST واحد عبر Http::withToken() إلى نقطة النهاية (endpoint) الخاصة بالرسائل في Cloud API، مع معرّف الرقم (phone number id) ورمز الوصول (token). ولا حاجة إلى أي حزمة SDK للقيام بذلك.

hub_challenge

يحوّل PHP النقاط في أسماء المتغيرات الواردة إلى شرطات سفلية، لذا يُقرأ hub.challenge باسم hub_challenge.

routes/api.php

مسارات واجهة برمجة التطبيقات (API) في Laravel عديمة الحالة، وينشئها الأمر install:api وتُخدَّم تحت /api وخارج حماية CSRF الخاصة بمجموعة web.

v25.0

إصدار Graph API الوارد في أمثلة Meta الحالية لإرسال الرسائل، عبر POST /{phone-number-id}/messages.

كيف تستقبل رسائل WhatsApp في Laravel؟

بتعريف مسارين على المسار نفسه في routes/api.php: واحد لـ GET وآخر لـ POST. شغّل php artisan install:api أولاً إذا لم يكن الملف موجوداً. مسارات API عديمة الحالة وخارج مجموعة web، فلا يُرفض طلب POST القادم من Meta. أما إذا وُضع المسار في routes/web.php فيُرفض الطلب لغياب رمز CSRF المطلوب.

مسار GET يجيب عن تحقق Meta. ترسل Meta الحقول hub.mode وhub.verify_token وhub.challenge، لكن PHP يستبدل النقاط في أسماء المتغيرات الواردة بشرطات سفلية، فيرى Laravel الأسماء hub_mode وhub_verify_token وhub_challenge. الشيفرة التي تقرأ الأسماء ذات النقاط تحصل على null ولا ينجح التحقق أبداً. أعد قيمة challenge كنص عادي، وليس عبر response()->json().

أما مسار POST فيمرّر الحمولة إلى مهمة في الطابور ويعيد 200 فوراً. ضع مفتاحاً عشوائياً طويلاً في المسار وتحقق منه في المسارين: توقّع Meta عمليات التسليم بالسر الخاص بتطبيق Tech Provider، لذا لا يمكنك التحقق من ترويسة التوقيع من جهتك.

routes/api.php: verification and event intake
use App\Jobs\HandleWhatsAppEvent;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::get('/whatsapp/{key}', function (Request $request, string $key) {
    abort_unless(hash_equals(config('services.whatsapp.url_key'), $key), 404);

    // PHP turns hub.mode into hub_mode: read the underscored names
    if ($request->query('hub_mode') === 'subscribe'
        && hash_equals(config('services.whatsapp.verify_token'),
                       (string) $request->query('hub_verify_token'))) {
        return response((string) $request->query('hub_challenge'), 200)
            ->header('Content-Type', 'text/plain');
    }

    abort(403);
});

Route::post('/whatsapp/{key}', function (Request $request, string $key) {
    abort_unless(hash_equals(config('services.whatsapp.url_key'), $key), 404);

    HandleWhatsAppEvent::dispatch($request->json()->all());

    return response('', 200);
});

كيف ترسل رسالة WhatsApp من Laravel؟

بعميل HTTP في Laravel: طلب POST واحد إلى نقطة النهاية الخاصة بالرسائل لمعرّف الرقم، مع رمز الوصول كرمز Bearer. القيمتان تأتيان من الاتصال، وتظهران في لوحة التحكم وتعيدهما الأداة get_api_credentials، ومكانهما config/services.php مدعوماً بمتغيرات البيئة وليس الشيفرة نفسها.

يعتمد شكل الجسم على التوقيت. خلال 24 ساعة من آخر رسالة للعميل، يعمل كائن text كما في المثال أدناه. وخارج هذه النافذة تقبل Meta كائن template فقط، يحدد قالباً معتمداً ولغته، ويفشل النص الحر بالخطأ 131047. والاستجابة هي المكان الذي ترى فيه ذلك: الطلب الفاشل يعيد كائن error يبيّن رمزه سبب المشكلة، فسجّله بدلاً من تجاهله.

لا شيء في الطلب خاص بـ EasyCoexistence. إنه الطلب نفسه الموجود في وثائق Meta، لذا يعمل أي عميل HTTP في PHP بالطريقة نفسها، سواء Guzzle أو cURL المباشر.

Send a text reply inside the 24 hour window
use Illuminate\Support\Facades\Http;

$response = Http::withToken(config('services.whatsapp.token'))
    ->post('https://graph.facebook.com/v25.0/'
        . config('services.whatsapp.phone_number_id') . '/messages', [
        'messaging_product' => 'whatsapp',
        'to' => '14155550188', // digits only, with country code
        'type' => 'text',
        'text' => ['body' => 'Thanks, we are on it.'],
    ]);

if ($response->failed()) {
    // error.code 131047: outside the window, send a template instead
    logger()->warning('WhatsApp send failed', $response->json('error', []));
}

ماذا يحتاج معالج Laravel في بيئة الإنتاج أكثر من ذلك؟

يحتاج إلى طابور حقيقي، وإزالة للتكرار، وفحص للنافذة الزمنية.

الطابور مهم لأن Meta تعيد المحاولة عندما تتأخر الاستجابة. لا يعود HandleWhatsAppEvent::dispatch() بسرعة إلا إذا كان اتصال الطابور حقيقياً ويعمل معه worker. أما مع المشغّل sync فتُنفَّذ المهمة داخل الطلب نفسه، فيتحول أي استدعاء بطيء لنموذج أو كتابة في قاعدة البيانات إلى تسليم مكرر.

أزل التكرار بالاعتماد على معرّف الرسالة، أي wamid في كل رسالة، لأن إعادة المحاولة أمر طبيعي وليست استثناءً. يكفي فهرس فريد على هذا العمود، أو قفل في الذاكرة المؤقتة مبني عليه.

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

الأخطاء الشائعة

  • قراءة hub.challenge بالنقطة. غيّر PHP اسمه إلى hub_challenge، فيعيد المعالج جسماً فارغاً ولا تتحقق Meta أبداً.
  • وضع خطاف الويب (webhook) في routes/web.php. طلب POST من Meta لا يحمل رمز CSRF فيُرفض بالخطأ 419.
  • الإرسال إلى طابور sync. تُنفَّذ المهمة قبل إعادة 200، وتُعاد محاولة المعالجة البطيئة، فتُعالَج الرسائل مرتين.
  • إعادة قيمة challenge عبر response()->json(). علامات الاقتباس حول القيمة تُفشل فحص Meta.
إنجاز ذلك باستخدام EasyCoexistence

اربط الرقم من easycoexistence.com، واجعل وجهة webhook هي مسار Laravel الذي يحمل مفتاحك، ثم اقرأ معرّف الرقم والرمز من لوحة التحكم. من US$ 9 لكل رقم شهرياً، وتنخفض إلى US$ 1 كلما أضفت أرقامًا، مع أول 3 أيام مجانية.

الأسئلة الشائعة

هل توجد حزمة SDK لـ PHP؟

ليس منّا، ولا حاجة إليها. الواجهة من Meta وموثقة لدى Meta، ويصل إليها عميل HTTP في Laravel أو Guzzle مباشرة.

هل يعمل هذا دون Laravel؟

نعم. في PHP العادي اقرأ $_GET['hub_challenge'] وأعده كنص من النوع text/plain، وأرسل عبر cURL. قاعدة الشرطة السفلية تنطبق على كل أطر PHP.

لماذا يحتاج عنوان URL إلى مفتاح في المسار؟

لأنه التحقق الوحيد الذي ينجح فعلاً. يعتمد توقيع Meta على السر الخاص بتطبيق Tech Provider ولا يُشارك أبداً، فيبقى سر العنوان هو ما يمنع الغرباء من إرسال أحداث مزيفة.

هل يستطيع الفريق مواصلة استخدام الهاتف؟

نعم. تُبقي Coexistence تطبيق WhatsApp Business يعمل على الرقم، وتصل الرسائل المرسلة من الهاتف إلى مسارك كأحداث echo.

تابع القراءة

هل أنت مستعد للبدء؟

أعد إعداد WhatsApp Coexistence خلال دقائق، وليس أشهر. يواصل التطبيق العمل على الهاتف.

ابدأ الفترة التجريبية المجانية

تم التحقق في

إرسال WhatsApp من PHP وLaravel