إنتقل إلى المحتوى الرئيسي

الإعادة الآمنة (Idempotency)

أعطال الشبكة لا مفرّ منها. تستخدم الواجهة البرمجية العامة لمجيب رأس Idempotency-Key لجعل الإعادات آمنة — نفس المفتاح ونفس الجسم يُعيدان الاستجابة الأصلية، ولا يُرسلان مرّتين أبداً.

كيف أجعل الإعادات آمنة؟

أرسل أي نص يختاره العميل بطول حتى 255 حرفاً في رأس Idempotency-Key على كل POST يُنشئ أو يُرسل شيئاً:

curl -X POST https://api.mojeeb.app/v1/whatsapp/templates \
-H "Authorization: Bearer mk_live_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-12345-confirmation" \
-d '{
"agent_id": "12345678-1234-1234-1234-123456789012",
"from": "+15557654321",
"to": "+15551234567",
"template": { "name": "order_shipped", "language": "en" }
}'

الرأس اختياري لكن يُنصح به بشدة على أي إرسال. بدونه، إعادة محاولة الشبكة قد تُنتج رسالة مكرّرة.

ماذا يحدث عند الإعادة؟

السلوك يعتمد على ما إذا انتهى الطلب الأصلي وما إذا كان الجسم متطابقاً:

السيناريوالاستجابةHTTP
أول إرسال بهذا المفتاحاستجابة طبيعية202
نفس المفتاح + نفس الجسم، الأصلي ما زال قيد التنفيذidempotency_key_in_progress (مع Retry-After)409
نفس المفتاح + نفس الجسم، الأصلي اكتملإعادة الاستجابة الأصلية، رأس Idempotent-Replayed: trueالحالة الأصلية
نفس المفتاح + جسم مختلفidempotency_key_in_use_with_different_params422
مفتاح مختلفيُعالَج كطلب جديد

كم تُخزَّن الاستجابات؟

24 ساعة. بعدها، نفس مفتاح الإعادة يُعامَل كجديد. هذا يعني:

  • إعادة محاولة خلال 24 ساعة من الأصل تُعيد دائماً
  • إعادة محاولة بعد 24 ساعة هي إرسال جديد (وقد تُنتج تكراراً إن نجح الأصلي)

في معظم سير العمل 24 ساعة أكثر من كافية — اختر مفاتيح ثابتة مرتبطة بعملية أعمالك، لا UUIDs عشوائية تتغيّر بين المحاولات.

كيف أختار مفاتيح إعادة جيّدة؟

المفتاح الجيد ثابت، فريد، ومرتبط بعملية أعمال واحدة.

جيّد:

  • order-12345-confirmation
  • signup-456-welcome
  • appointment-reminder-2026-04-30-user-789

سيّئ:

  • الطوابع الزمنية (كل إعادة تأخذ واحدة مختلفة — يُفقِد المعنى)
  • UUIDs عشوائية تُولَّد وقت الطلب (نفس المشكلة)
  • نصوص عامة مثل retry-1 (تصادم بين العمليات)
  • مفاتيح مُعاد استخدامها مع أجسام رسائل مختلفة (يُحفّز اختلاف 422)

إن لم يكن لديك معرّف ثابت طبيعي، أنشئه مرة واحدة في بداية عمليتك وأعد استخدامه لكل إعادة محاولة لذلك الإرسال بالذات.

كيف يبدو الاختلاف؟

عند إعادة استخدام نفس المفتاح بجسم مختلف، الواجهة ترفض الطلب وتُعطيك معرّف الارتباط للإرسال الأصلي حتى تجده في سجلاتك:

{
"error": {
"type": "idempotency_error",
"code": "idempotency_key_in_use_with_different_params",
"message": "The idempotency key was used previously with a different request body. Use a different key for this operation.",
"correlation_id": "req_01KQE...",
"original_correlation_id": "req_01KQE..."
}
}

original_correlation_id هو معرّف التتبّع للطلب الذي ادّعى المفتاح أصلاً. ابحث في سجلات تطبيقك عن هذا المعرّف لترى ما أُرسل.

كيف تبدو إعادة محاولة قيد التنفيذ؟

إن أعدت المحاولة بينما الإرسال الأصلي ما زال يُعالَج (نادر، عادة في غضون ثوانٍ):

{
"error": {
"type": "idempotency_error",
"code": "idempotency_key_in_progress",
"message": "A request with this idempotency key is currently being processed. Retry shortly.",
"correlation_id": "req_01KQE..."
}
}

تحمل الاستجابة أيضاً رأس Retry-After بالثواني. انتظر هذه المدة، ثم أعد بنفس المفتاح ونفس الجسم — ستحصل إما على 202 (إن اكتمل الأصلي) أو 409 آخر (إن كان لا يزال قيد التنفيذ).

أسئلة شائعة

هل تُجزّئ الواجهة جسمي لاكتشاف الاختلاف؟

نعم. أول طلب بمفتاح معيّن يُخزّن hash بـSHA-256 للجسم المُقَنَّن. الطلبات اللاحقة تُعيد حساب الـhash وتقارن. ترتيب الحقول لا يهم؛ نُرتّب المفاتيح قبل التجزئة — {"a":1,"b":2} و {"b":2,"a":1} هما نفس الجسم منطقياً.

ماذا عن الإعادة الآمنة على طلبات GET؟

نقاط GET إعادة-آمنة بطبيعتها — استدعاؤها عدة مرات لا أثر له. رأس Idempotency-Key يُتجاهَل على GET؛ لا حاجة لإرساله.

هل أحتاج مفاتيح إعادة لاستعلامات الحالة؟

لا. GET /v1/whatsapp/messages/{id} للقراءة فقط.

ماذا لو كانت الاستجابة المُخزَّنة خطأ؟

إن فشل الطلب الأصلي بـ4xx وإعادة محاولتك تستخدم نفس المفتاح ونفس الجسم، تُعيد نفس استجابة الـ4xx. هذا متعمَّد — الفشل جزء من النتيجة المُخزَّنة، فيتعامل كودك معه بشكل مطابق للمحاولة الأولى. لإجبار إرسال جديد، استخدم مفتاحاً مختلفاً.

هل الاستجابات متطابقة بايت لبايت عند الإعادة؟

الإعادة تُطابق رمز الحالة الأصلي ونفس المحتوى المنطقي. ترتيب الحقول ووجود حقول null اختيارية قد يختلف بشكل طفيف بين الاستجابة الحية والإعادة — تفرّع على قيم id و status، لا على المساواة بايت لبايت.