هذا الدليل موجّه للمطوّرين وفِرَق التكامل التقني الذين يربطون أنظمتهم المكتوبة بلغة PHP بمنصة فاتورة ضمن الفاتورة الإلكترونية في السعودية. موضوعه واحد ومحدّد: أمثلة كود PHP حقيقية وقابلة للنسخ تبني مسار إرسال الفاتورة من أوله إلى آخره. من بناء ترويسة المصادقة، إلى حساب قيمة التجزئة، إلى ترميز المستند، إلى إرسال الطلب وقراءة الاستجابة ومعالجة الأخطاء.
لا نشرح هنا القصة المفاهيمية للربط مع هيئة الزكاة والضريبة والجمارك (ZATCA) كخطوة أعمال، فتلك لها أدلتها المستقلة. نفترض أنك مطوّر PHP يكتب الكود الآن، وتريد نماذج تشغّلها مباشرة. لكل مفهوم تقني نشير إلى دليله المرجعي: المصادقة لتفاصيل ترويسة Authorization، ونقاط نهاية API لكتالوج العناوين والترويسات، وإرسال الفاتورة للتسلسل الكامل خطوة بخطوة.
الأمثلة هنا مكتوبة بأسلوبين: دوال PHP أصيلة تعتمد على امتداد cURL المدمج، ونسخة موازية تستخدم مكتبة Guzzle لمن يفضّل واجهة أحدث. كلاهما يؤدي نفس الوظيفة، فاختر ما يناسب بنية مشروعك. كل مقطع كود يسبقه شرح لما يفعله، ويتبعه توضيح لما يجب أن تنتبه إليه.
قبل أن تبدأ، ثبّت في ذهنك مبدأً واحدًا يحكم كل ما يلي: واجهات الفوترة في منصة فاتورة لا تستخدم OAuth. لا توجد نقطة نهاية لطلب رمز وصول مؤقت. المصادقة تعتمد على شهادة الختم التشفيري (CSID) وسرّها المرافق، تُرسلان في كل طلب عبر ترويسة Basic. هذا يبسّط كود PHP لديك، لأنك لا تدير دورة حياة رمز ولا تتعامل مع انتهاء صلاحيته في منتصف الإرسال.
دع قيود يتولّى التكامل التقني مع منصة فاتورة
بدلًا من بناء طبقة التوقيع والمصادقة وحساب التجزئة بنفسك، يصدر قيود فواتيرك موقّعة ومتوافقة مع متطلبات الهيئة من اليوم الأول، فتتفرّغ لتطوير نظامك لا لإدارة الشهادات.
ما الذي تجهّزه في بيئة PHP قبل أول مثال
قبل أن تكتب أول سطر، تأكّد أن بيئتك تحوي أربعة أشياء. أولها امتداد cURL مفعّل، وهو متوفّر افتراضيًا في معظم تثبيتات PHP. ثانيها امتداد OpenSSL لحساب التجزئة والتعامل مع الشهادة. ثالثها مكتبة موثوقة لبناء مستند UBL، فصياغة XML يدويًا بسلاسل نصية مصدر شائع للأخطاء. ورابعها بيانات اعتماد جهازك: معرّف الشهادة (CSID) وسرّه المرافق.
تحقّق من توفّر الامتدادين بأمر سطر واحد قبل أن تبني أي شيء فوقهما:
لاحظ أننا نتحقّق من الامتدادات صراحةً ونرمي استثناءً واضحًا عند غيابها. هذا أفضل من رسالة خطأ غامضة تظهر متأخرة عند أول استدعاء لدالة cURL. اجعل هذا الفحص جزءًا من تهيئة نظامك، لا اختبارًا تشغّله مرة وتنساه.
ضع بيانات الاعتماد في إعدادات النظام أو متغيّرات البيئة، لا داخل الكود. هذا الفصل يسهّل التبديل بين بيئة الاختبار وبيئة الإنتاج، ويمنع تسريب السرّ في مستودع الكود. نقرأها في الأمثلة التالية من متغيّرات بيئة:
العنوان الأساسي يختلف بين البيئتين. بيئة الاختبار للامتثال والتطوير، وبيئة الإنتاج للفواتير الحقيقية. المسار النسبي نفسه في كلتيهما، يتغيّر العنوان الأساسي فقط. ثبّته في الإعداد كما رأيت أعلاه، ولا تضمّنه داخل الكود مباشرة.
بناء مستند UBL قبل التوقيع
قبل أي مصادقة أو تجزئة، يجب أن يوجد مستند الفاتورة نفسه بصيغة XML متوافقة مع UBL 2.1. لا تبنِ هذا المستند بسلاسل نصية تجمعها يدويًا، فهذا مصدر شائع للأخطاء التي تظهر متأخرة عند الرفض لا عند الكتابة. استخدم مكتبة موثوقة لتركيب XML، واملأها من بيانات أعمالك المنظّمة.
للتوضيح فقط، هذا هيكل مبسّط يبيّن كيف تجهّز بيانات الفاتورة في PHP قبل تمريرها لمكتبة بناء UBL. المستند الفعلي يحوي حقولًا أكثر تفرضها المواصفة، لكن المبدأ أن تفصل بيانات الأعمال عن صياغة XML:
لاحظ الحقل previousHash. تقرأه من طبقة تخزينك، وهو تجزئة الفاتورة السابقة التي تربط السلسلة. الفاتورة الأولى تستخدم القيمة الابتدائية المعرّفة في المواصفة. كذلك تذكّر أن المستند بصيغة UBL يلزمه محتوى عربي إلزامي بحكم متطلبات الهيئة، مع إمكانية إضافة الإنجليزية بجانبه، فاحرص أن تكون أسماء البائع والمشتري والبنود بالعربية داخل XML.
دالة توليد المعرّف الفريد بسيطة. تنتج معرّفًا عشوائيًا وفق معيار UUID الإصدار الرابع، وتولّده مرة واحدة لكل فاتورة وتحفظه:
بعد بناء المستند تأتي خطوة التوقيع بالمفتاح الخاص المرتبط بشهادة CSID. التوقيع عملية تشفيرية دقيقة تعتمد على مكتبة متخصّصة، ولا يُنصح بكتابتها من الصفر. ما يهمّك في كود PHP أن التوقيع يأتي بعد اكتمال بناء XML وقبل حساب التجزئة، لأن أي تعديل لاحق على المستند يُبطل التوقيع ويُبطل التجزئة المحسوبة عليه.
بناء ترويسة Authorization بالـ Base64
أول لبنة في أي طلب هي ترويسة المصادقة. الصيغة بسيطة: اجمع معرّف الشهادة والسرّ بنقطتين بينهما، ثم رمّز الناتج بـ Base64، ثم ضعه بعد كلمة Basic. ما يُرسل هو معرّف الشهادة (الذي يحمل المفتاح العام) مع السرّ، لا المفتاح الخاص. المفتاح الخاص يبقى محليًا للتوقيع فقط.
الشكل المنطقي للترويسة قبل الكود:
وهذه دالة PHP تبنيها. نستخدم base64_encode المدمجة، فلا حاجة لأي مكتبة خارجية لهذه الخطوة:
انتبه إلى أن base64_encode في PHP لا تضيف أي مسافات أو أسطر جديدة، وهذا ما نريده تمامًا. بعض اللغات تكسر الناتج إلى أسطر عند طول معيّن، فيرفض الطلب. في PHP لا تواجه هذه المشكلة، لكن إن نقلت البيانات يدويًا تأكّد أن السلسلة سطر واحد متصل بلا فراغات.
الترويسة نفسها موحّدة عبر الواجهات الأربع للمنصة (الامتثال والإصدار والمصادقة والإبلاغ). تبني الدالة مرة واحدة، وتعيد استخدام مخرجها في كل طلب. الفرق الوحيد أنك في بيئة الاختبار تستخدم معرّف الامتثال، وفي الإنتاج تستخدم معرّف الإنتاج. لتفصيل أعمق راجع دليل المصادقة.
نقطة أمان جوهرية: عامل قيمة الترويسة كسرّ كامل، لا كنص عابر. لا تطبعها في سجلّات التصحيح، ولا تمرّرها في عنوان URL، ولا تخزّنها في ذاكرة مؤقّتة يصل إليها غيرك. ترميز Base64 ليس تشفيرًا، فمن يقرأ القيمة يفكّها فورًا ويحصل على السرّ. أبقِ بيانات الاعتماد في الذاكرة لحظة بناء الطلب فقط، ولا تكتبها على القرص إلا في خزينة أسرار مؤمّنة.
كيف تتحوّل بيانات الفاتورة إلى طلب موقّع في PHP
قبل أن نغوص في حساب التجزئة والإرسال، تساعدك خريطة سريعة على تثبيت ترتيب الخطوات. كل مخرَج خطوة هو مدخَل التالية، والترتيب ليس اختياريًا.
بناء ملف UBL والتوقيع
حساب التجزئة SHA-256
ترميز Base64 وبناء ترويسة Basic
POST للمقاصة أو الإبلاغ
قراءة الاستجابة وحفظ النتيجة
الخطوات من واحد إلى أربعة تجهّز المستند داخل خادمك. الخطوتان خمسة وستة تبنيان الطلب وترسلانه. الخطوة السابعة تقرأ الرد وتخزّنه. نمرّ عليها بالترتيب في الأقسام التالية بأمثلة PHP لكل واحدة.
حساب قيمة التجزئة invoiceHash بخوارزمية SHA-256
كل فاتورة تحمل قيمة تجزئة (invoiceHash) تُحسب من محتوى المستند الموقّع. تربط هذه القيمة الفاتورة بسابقتها فتشكّل سلسلة لا يمكن العبث بها. تُحسب التجزئة بخوارزمية SHA-256، ثم تُرمّز نتيجتها الثنائية بـ Base64.
المهم هنا دقيقة تقنية تُسقط كثيرًا: لا تجزّئ النص المقروء، بل التمثيل الثنائي الخام للتجزئة. في PHP نطلب من hash أن تعيد البايتات الخام عبر المعامل الثالث، ثم نرمّزها:
الخطأ الشائع أن يمرّر المطوّر false أو يحذف المعامل الثالث، فيجزّئ النص الست عشري بدل البايتات الخام، فتختلف القيمة عمّا تتوقّعه الهيئة ويُرفض الطلب. تذكّر دائمًا المعامل الثالث true.
قيمة التجزئة هذه أحد مدخلات الفاتورة التالية، لذلك خزّنها فور إصدار كل فاتورة. من يؤجّل بناء طبقة التخزين يكتشف لاحقًا أنه كسر سلسلة التجزئة لأنه لم يحفظ تجزئة الفاتورة السابقة. تفصيل سلسلة التجزئة في دليل إرسال الفاتورة.
سلسلة التجزئة هي ما يجعل دفتر فواتيرك غير قابل للعبث. تجزئة كل فاتورة تُحسب على محتوى يتضمّن تجزئة سابقتها، فلو حاول أحد تعديل فاتورة قديمة لانكسرت السلسلة كاملة بعدها. أول فاتورة في النظام تستخدم قيمة تجزئة ابتدائية معرّفة في المواصفة، ثم تبني كل فاتورة بعدها على ما قبلها. هذا يفرض ترتيبًا صارمًا: لا تصدر الفاتورة رقم اثنين قبل أن تخزّن تجزئة الفاتورة رقم واحد. في الأنظمة المتزامنة التي تصدر فواتير من خيوط متعددة، احرص على تسلسل الإصدار لكل جهاز حتى لا تتسابق خيوط على نفس العدّاد فتفسد السلسلة.
ترميز مستند UBL بـ Base64 وبناء جسم الطلب
الفاتورة نفسها مستند XML متوافق مع UBL 2.1، لكنها لا تُرسل XML خامًا. تُرمّز بـ Base64 وتُوضع داخل حقل JSON اسمه invoice. أي طلب لا يلتزم بهذا الغلاف يُرفض على البوابة مباشرة.
هذه الدالة تأخذ المستند الموقّع وقيمة التجزئة والمعرّف الفريد، وتبني جسم الطلب كاملًا بصيغة JSON:
نستخدم العلمين JSON_UNESCAPED_SLASHES وJSON_UNESCAPED_UNICODE لأن السلوك الافتراضي في PHP يهرّب الشرطات المائلة ويحوّل الحروف العربية إلى ترميز يونيكود مطوّل. هذا التهريب لا يكسر JSON تقنيًا، لكن إبقاء المخرج نظيفًا يسهّل تصحيح الأخطاء عند مقارنة ما أرسلته بما تتوقّعه المنصة.
المعرّف الفريد (UUID) قيمة فريدة لكل فاتورة. تولّدها مرة واحدة عند إنشاء الفاتورة وتحفظها. لا تعد توليدها عند إعادة الإرسال، وإلا عاملتها المنصة كفاتورة جديدة.
بنية جسم الطلب JSON الذي تستقبله المنصة
يساعدك تصوّر شكل الطلب النهائي على ربط الدوال السابقة ببعضها. الحقول الثلاثة الإلزامية وما يحمله كل منها:
invoiceHash: تجزئة الفاتورة SHA-256 (Base64)
uuid: المعرّف الفريد للفاتورة
invoice: الفاتورة بترميز Base64
لاحظ الفصل بين طبقتين: الترويسات تحمل هوية الطلب وإعداداته، وجسم JSON يحمل الفاتورة وبياناتها الوصفية. الترويسة Content-Type: application/json إلزامية لأن الجسم JSON رغم أن الفاتورة بداخله XML مرمّز.
إرسال الطلب إلى مسار المصادقة أو الإبلاغ عبر cURL
الآن نجمع كل ما سبق في طلب POST واحد. المسار يختلف حسب نوع الفاتورة: الفاتورة الضريبية القياسية (B2B) تُرسل إلى مسار المصادقة (Clearance) وتُصادَق قبل أن تصل للمشتري. الفاتورة الضريبية المبسّطة (B2C) تُرسل إلى مسار الإبلاغ (Reporting) خلال أربع وعشرين ساعة من إصدارها.
هذه دالة PHP أصيلة تستخدم cURL المدمجة. تبني الطلب، تضبط الترويسات، ترسله، وتعيد رمز الحالة والجسم معًا:
ضبطنا مهلتين: مهلة الاتصال (15 ثانية) ومهلة الطلب الكامل (60 ثانية). هذا يحمي نظامك من التعليق إن تأخّرت البوابة. في نقاط البيع عالية التردد قد تخفّض مهلة الطلب وتعتمد على إعادة المحاولة، كما سنرى بعد قليل.
المسار يُمرّر كوسيط، فتستدعي الدالة نفسها لكلا النوعين. للفاتورة القياسية:
كتالوج المسارات الكامل وترويساتها في دليل نقاط نهاية API. هنا نكتفي بالمسارين الأكثر استخدامًا في التشغيل اليومي.
جرّب قيود مجانًا لمدة 14 يومًا. بدون بطاقة ائتمان.
النسخة الموازية بمكتبة Guzzle
إن كان مشروعك يعتمد على Composer ويستخدم Guzzle، فالكود أقصر وأوضح. تثبّت المكتبة بأمر واحد:
ثم تبني العميل وترسل الطلب. Guzzle تتولّى ترميز الجسم وضبط الترويسات بواجهة أنظف من cURL الخام:
الفرق الجوهري في معالجة الأخطاء. Guzzle ترمي استثناءً عند رموز الحالة 400 وما فوق افتراضيًا. لذلك نلتقط RequestException ونستخرج منها الاستجابة، لأن جسم الخطأ نفسه يحوي رسائل التحقّق التي نحتاجها. لو لم نلتقط الاستثناء، لضاعت رسالة الخطأ التفصيلية من الهيئة.
مع Guzzle نمرّر الحمولة كمصفوفة عبر مفتاح json، فتتولّى المكتبة الترميز وضبط Content-Type. هذا يلغي الحاجة لدالة بناء الجسم اليدوية، لكن احرص أن تبقى قيمة الحقل invoice مرمّزة Base64 قبل تمريرها.
قراءة استجابة JSON وتمييز النجاح من الرفض
بعد الإرسال تعود استجابة JSON. عند النجاح في المصادقة تأتي بهذا الشكل:
الحقل clearanceStatus يحمل نتيجة المصادقة، وclearedInvoice يحمل النسخة المُصادَق عليها التي تخزّنها وتسلّمها للمشتري. أما في الإبلاغ فالحقل المقابل reportingStatus. هذه الدالة تقرأ الاستجابة وتحوّلها إلى نتيجة واضحة لنظامك:
انتبه إلى التحذيرات (warningMessages) حتى عند النجاح. الفاتورة قد تُصادَق مع تحذيرات لا تمنع القبول لكنها تشير إلى مشكلة تستحق المعالجة قبل أن تتحوّل لخطأ في تحديث لاحق للمواصفة. سجّل التحذيرات ولا تتجاهلها.
معالجة الأخطاء وإعادة المحاولة
ليست كل الأخطاء متساوية. بعضها دائم لا تصلحه إعادة المحاولة، وبعضها مؤقّت يستحق محاولة ثانية. التمييز بينها يحدّد سلوك نظامك.
رمز 401 يعني فشل المصادقة. لا تعد المحاولة، فالمشكلة في بيانات الاعتماد لا في الشبكة. شكل استجابته:
راجع عند 401 أن معرّف الشهادة والسرّ صحيحان، وأنك في البيئة المطابقة لهما (معرّف الامتثال لبيئة الاختبار، ومعرّف الإنتاج لبيئة الإنتاج). الخلط بين البيئتين سبب شائع لهذا الرمز. تفصيل أخطاء المصادقة في دليل المصادقة.
أما رمز 400 فيعني رفض الفاتورة لخطأ في محتواها أو توقيعها أو تجزئتها. لا تعد المحاولة بنفس المستند، بل اقرأ errorMessages لتعرف الحقل المرفوض. الرموز 500 و502 و503 ومهلة الاتصال تعني مشكلة مؤقّتة على البوابة تستحق إعادة محاولة. هذه الدالة تطبّق إعادة المحاولة مع تأخّر متصاعد للأخطاء المؤقّتة فقط:
القاعدة الذهبية: أعد المحاولة عند الأخطاء المؤقّتة فقط (الشبكة والبوابة)، ولا تعدها أبدًا عند 400 و401. إعادة إرسال فاتورة مرفوضة لخطأ في محتواها تكرّر الرفض وتثقل البوابة بلا فائدة. التأخّر المتصاعد (ثانيتان ثم أربع ثم ثمان) يمنح البوابة وقتًا للتعافي ويتجنّب إغراقها بمحاولات متتابعة.
احرص أن تكون عملية الإرسال آمنة لإعادة التنفيذ (idempotent) على مستوى نظامك. خزّن حالة كل فاتورة قبل الإرسال وحدّثها بعد الرد، حتى لا ترسل نفس الفاتورة مرتين إن انقطع التيار في منتصف العملية. المعرّف الفريد الثابت يساعد المنصة على التعرّف على إعادة الإرسال.
شجرة قرار معالجة الاستجابة في كود PHP
بعد كل إرسال يقف نظامك أمام قرار: هل أعتبر الفاتورة ناجحة، أم أعيد المحاولة، أم أوقف وأبلّغ عن خطأ دائم؟ يلخّص المخطط التالي المسار حسب رمز الحالة، وهو ما تترجمه الدوال السابقة إلى كود.
| رمز الحالة | الإجراء |
|---|---|
| 2xx | احفظ النتيجة المعتمَدة |
| 400/401 | خطأ دائم: صحّح، لا تُعِد |
| 5xx / مهلة | أعد المحاولة بتراجع أسّي |
المسار الأخضر هو النجاح. المسار الأحمر خطأ دائم لا يصلحه التكرار. المسار البرتقالي خطأ مؤقّت يستحق إعادة محاولة محسوبة. ترجمة هذا المخطط إلى كود هي بالضبط ما فعلته دالتا parseResponse وsubmitWithRetry أعلاه.
تجهيز الكود للإنتاج: التسجيل والمراقبة
الأمثلة السابقة تبني المسار الوظيفي. قبل تشغيله على فواتير حقيقية، أضف طبقة تسجيل تمنحك أثرًا تعود إليه عند أي مشكلة. سجّل لكل فاتورة معرّفها الفريد وعدّادها وقيمة تجزئتها ورمز حالة الاستجابة ووقتها. لا تسجّل بيانات الاعتماد ولا المفتاح الخاص ولا الجسم الكامل المرمّز في سجلّات يصل إليها كثيرون.
راقب معدّل الرفض كمؤشّر صحّة. ارتفاع مفاجئ في رمز 400 غالبًا يعني أن مكتبة بناء UBL لديك خرجت عن المواصفة بعد تحديث، أو أن حقلًا جديدًا أصبح إلزاميًا. ارتفاع رمز 401 يعني مشكلة في الشهادة أو قرب انتهائها. التسجيل المنظّم يحوّل هذه المؤشّرات من مفاجأة إلى تنبيه مبكّر.
أخيرًا، افصل إعدادات بيئة الاختبار عن الإنتاج فصلًا تامًا في نظامك. لا تجعل التبديل بينهما يعتمد على راية واحدة يسهل نسيانها، بل اجعل كل بيئة بمتغيّراتها الكاملة. إرسال فاتورة اختبار إلى الإنتاج، أو العكس، خطأ مكلف يصعب التراجع عنه بعد المصادقة.
كيف يساعدك قيود في التكامل التقني مع منصة فاتورة
كل ما سبق يوضّح حجم العمل التقني خلف فاتورة واحدة متوافقة: بناء UBL، توقيع، تجزئة، ترميز، إرسال، معالجة أخطاء، وإدارة شهادات بيئتين. بناء هذه الطبقة وصيانتها مع كل تحديث في المواصفة عبء مستمر على فريقك.
يتولّى قيود هذه الطبقة كاملة. يصدر فواتيرك موقّعة ومتوافقة مع المرحلة الثانية من الفوترة الإلكترونية، ويديّر شهادة الختم التشفيري (CSID) تلقائيًا، ويحفظ سلسلة التجزئة، ويتعامل مع المصادقة الفورية للفواتير القياسية والإبلاغ خلال أربع وعشرين ساعة للفواتير المبسّطة. أنت تركّز على نظامك، وقيود يتكفّل بالامتثال.
قيود لا يربط منشأتك بالهيئة نيابةً عنك في خطوة التسجيل الأولى، فتسجيل معرّف الشهادة لدى الهيئة مسؤوليتك، لكنه يرشدك خلالها. وهو لا يقدّم إقرار ضريبة القيمة المضافة عنك، بل يولّد بيانات الإقرار لتقدّمها أنت عبر بوابة الهيئة. ما يفعله قيود هو إزالة كل التعقيد التقني الذي قرأت عنه في هذا الدليل من على عاتقك.
دع قيود يتولّى التكامل التقني مع منصة فاتورة
بدلًا من بناء طبقة التوقيع والمصادقة وحساب التجزئة بنفسك، يصدر قيود فواتيرك موقّعة ومتوافقة مع متطلبات الهيئة من اليوم الأول، فتتفرّغ لتطوير نظامك لا لإدارة الشهادات.
الأسئلة الشائعة عن أمثلة التكامل بلغة PHP
هل أحتاج مكتبة خارجية لبناء ترويسة المصادقة في PHP؟
لا. دالة base64_encode المدمجة في PHP كافية لبناء ترويسة Authorization. تجمع معرّف الشهادة والسرّ بنقطتين بينهما، ترمّز الناتج، وتضيف كلمة Basic قبله. لا حاجة لأي حزمة Composer لهذه الخطوة تحديدًا.
ما الفرق بين استخدام cURL المدمجة ومكتبة Guzzle؟
كلاهما يرسل الطلب نفسه ويصل لنفس النتيجة. cURL المدمجة لا تحتاج تثبيتًا وتمنحك تحكّمًا دقيقًا في كل خيار. Guzzle أوضح وأقصر وتتولّى الترميز وضبط الترويسات، لكنها تتطلّب Composer وتحتاج التقاط الاستثناء لقراءة جسم الخطأ. اختر ما يناسب بنية مشروعك.
لماذا تُرفض فاتورتي رغم أن قيمة التجزئة تبدو صحيحة؟
السبب الأشهر تمرير المعامل الثالث في دالة hash خطأً. يجب أن يكون true ليعيد البايتات الخام قبل ترميز Base64. إن جزّأت النص الست عشري بدل البايتات الخام، اختلفت القيمة عمّا تتوقّعه الهيئة ورُفض الطلب.
متى أستخدم مسار المصادقة ومتى مسار الإبلاغ؟
الفاتورة الضريبية القياسية (B2B) تُرسل إلى مسار المصادقة (Clearance) وتُصادَق قبل تسليمها للمشتري. الفاتورة الضريبية المبسّطة (B2C) تُرسل إلى مسار الإبلاغ (Reporting) خلال أربع وعشرين ساعة من إصدارها. نوع الفاتورة يحدّد المسار.
كيف أتعامل مع رمز الحالة 401 في كود PHP؟
رمز 401 يعني فشل المصادقة، ولا تصلحه إعادة المحاولة. تحقّق أن معرّف الشهادة والسرّ صحيحان وأنك تستخدم بيانات اعتماد البيئة المطابقة: معرّف الامتثال لبيئة الاختبار ومعرّف الإنتاج لبيئة الإنتاج. الخلط بينهما سبب شائع لهذا الرمز.
هل أعيد محاولة الإرسال عند كل خطأ؟
لا. أعد المحاولة عند الأخطاء المؤقّتة فقط مثل 500 و502 و503 ومهلة الاتصال، مع تأخّر متصاعد بين المحاولات. لا تعد المحاولة عند 400 (رفض المحتوى) أو 401 (فشل المصادقة)، فهي أخطاء دائمة لا تحلّها المحاولة المتكرّرة.