أخطاء 400 في Stripe webhook — مخاطر التحقق من التوقيع
يعني رمز الخطأ 400 الصادر من نقطة نهاية Stripe webhook في الغالب حدوث عدم تطابق في التوقيع. إليك آلية عمل توقيع webhook، والأخطاء الخمسة الأكثر شيوعاً، وكيفية التحقق من صحة إعدادك.
يعني رمز الاستجابة 400 الصادر من نقطة نهاية Stripe webhook في الغالب أحد أمرين: استُهلك جسم الطلب الخام قبل التحقق من التوقيع (الخطأ الأكثر شيوعاً في Next.js)، أو أن متغيّر البيئة STRIPE_WEBHOOK_SECRET لا يتطابق مع مفتاح توقيع نقطة النهاية في لوحة تحكم Stripe.
لماذا يهمّ استهلاك جسم الطلب الخام
يوقّع Stripe جسم الطلب الخام باستخدام HMAC-SHA256، ويُدرج التوقيع في ترويسة Stripe-Signature. لكي تتحقق منه، يجب أن تُمرّر نقطة نهايتك ذات البايتات الخام تماماً إلى stripe.webhooks.constructEvent() — لا نسخة محلّلة بـ JSON، ولا سلسلة نصية أُعيد بناؤها باستخدام JSON.stringify(). في Next.js App Router، استدعاء await request.json() قبل constructEvent() سيُسبّب هذه المشكلة — إذ يُطبّع تحليل JSON المسافات البيضاء وترتيب الحقول، فيُغيّر البايتات ويُبطل التوقيع.
// WRONG — json() parses first, raw bytes are lost:
const body = await request.json();
stripe.webhooks.constructEvent(JSON.stringify(body), sig, secret);
// CORRECT — use text() to preserve raw bytes:
const rawBody = await request.text();
const event = stripe.webhooks.constructEvent(rawBody, sig, secret);التحقق 2 — مفاتيح webhook المحلية مقابل الإنتاجية
يُنشئ أمر stripe listen في Stripe CLI مفتاح توقيع webhook مؤقتاً يختلف عن مفتاح توقيع نقطة نهايتك في الإنتاج الموجود في لوحة التحكم. استخدام مفتاح CLI في الإنتاج (أو العكس) يُسبّب خطأ 400 دائماً. يجب أن يكون STRIPE_WEBHOOK_SECRET في ملف .env.local هو مفتاح CLI للتطوير المحلي. يجب أن يكون نفس المتغيّر في بيئة Railway الإنتاجية هو مفتاح توقيع نقطة النهاية في لوحة التحكم — وهما قيمتان مختلفتان بالضرورة.
خطأ شائع: نسخ مفتاح التوقيع من مخرجات Stripe CLI إلى متغيّرات بيئة Railway الإنتاجية. مفتاح CLI يتجدّد في كل مرة تشغّل فيها stripe listen. استخدم مفتاح توقيع نقطة نهاية لوحة التحكم (الموجود في Stripe Dashboard ثم Developers ثم Webhooks ثم اختر نقطة النهاية ثم Signing secret) للبيئة الإنتاجية.
التحقق 3 — يجب أن يكون عنوان URL لـ webhook دقيقاً
تُسجّل لوحة تحكم Stripe الـ webhooks على عنوان URL محدد — إذا كانت نقطة نهايتك على /api/stripe/webhook، فيجب أن يكون عنوان URL المسجّل هو https://yoursite.velocms.org/api/stripe/webhook بالضبط (بدون شرطة مائلة في النهاية، مع النطاق الفرعي الصحيح). أي تعارض — حتى شرطة مائلة إضافية — يعني أن Stripe يُرسل إلى عنوان URL مختلف عن المعالج الخاص بك، فلا يصله الطلب أبداً.
الاختبار بدون Stripe CLI
لاختبار إعدادك في الإنتاج دون استخدام Stripe CLI، انتقل في لوحة التحكم إلى Stripe Dashboard ثم Developers ثم Webhooks ثم اختر نقطة نهايتك ثم Send test webhook. اختر نوع الحدث الذي تريد اختباره (checkout.session.completed هو الأكثر استخداماً مع VeloCMS)، انقر Send ثم راقب سجلات Railway. يستخدم webhook الاختباري مفتاح التوقيع الإنتاجي، لذا فإن استجابة 200 ناجحة تؤكد صحة إعدادك.