# التكرار الآمن

كل طلبات `POST` و `PATCH` و `DELETE` تتطلب رأس `Idempotency-Key`. ويقبل `PUT` هذا الرأس أيضًا: إذا أرسلت معه مفتاحًا طُبّقت عليه قواعد هذه الصفحة، وإذا أرسلته بلا مفتاح نُفّذ الطلب في كل مرة يصل فيها.

```
Idempotency-Key: order-create-2026-04-30-abc123
```

الصيغة: من 1 إلى 64 حرفًا من `[A-Za-z0-9_-:.]`.

استخدم قيمة ثابتة وفريدة لكل عملية منطقية (مثل UUID مولَّد من جانب العميل).

## أين تحدث إعادة التشغيل فعليًا[​](#أين-تحدث-إعادة-التشغيل-فعليًا "رابط مباشر إلى أين تحدث إعادة التشغيل فعليًا")

تجري إعادة التشغيل على المنصة نفسها، لذلك يتصرّف `https://api.dzbuild.app/v1` والاسم البديل `dzbuild.com/api/v1` بالطريقة ذاتها. تُحفَظ الاستجابة لمدة 24 ساعة، وتعود الإعادات مع رأس `Idempotency-Replay: 1`.

إذا أعدت إرسال `POST /v1/orders` بالمفتاح نفسه والمحتوى نفسه، تتلقى الاستجابة الأولى ولا تُنشأ طلبية ثانية، أيًّا كان العنوان الذي تستدعيه.

نطاق التخزين المؤقت مرتبط بـ`key_id` الخاص بك **مع** قيمة `Idempotency-Key`: القيمة نفسها المرسلة بمفتاح API مختلف لا تُلغي التكرار.

ولا يزال `POST /v1/signups` و`POST /v1/events` يتطلبان الرأس، غير أنهما يُقبلان بشكل غير متزامن ولا تُخزَّن استجابتهما إطلاقًا، فلا توجد ذاكرة إعادة تشغيل تحمي هذين المسارين.

أما `POST /v1/keys` و`POST /v1/webhooks` فيُرجعان سرًّا لا يظهر إلا مرة واحدة، لذلك لا تُخزَّن استجابتهما هي الأخرى. إعادة المحاولة بالمفتاح نفسه تنفّذ النداء من جديد، وقد تُنشئ مفتاحًا ثانيًا أو `webhook` ثانيًا. راجع `GET /v1/keys` أو `GET /v1/webhooks` قبل أن تعيد محاولة أحدهما.

التكرار الآمن يحمي من إعادة المحاولة لا من التسابق

لا تُحفَظ الاستجابة إلا بعد انتهاء الطلب الأول، لذا فطلبان مكرَّران متزامنان فعليًا قد يُنفَّذان كلاهما. رتّب عمليات الكتابة المعرّضة للتكرار تسلسليًا من جانبك.

## المفاتيح مرتبطة بمحتوى الطلب[​](#المفاتيح-مرتبطة-بمحتوى-الطلب "رابط مباشر إلى المفاتيح مرتبطة بمحتوى الطلب")

يرتبط المفتاح بأول طلب استُعمل فيه: طريقته ومساره ومحتواه، أما سلسلة الاستعلام (query string) فلا تدخل في المقارنة. إعادة استخدام مفتاح مع محتوى أو مسار أو طريقة **مختلفة** تُرجع `422` مع الكود `idempotency_key_reuse` دون تنفيذ أي شيء. يُقارَن المحتوى بايتًا ببايت، فيجب أن تحمل إعادة المحاولة البايتات نفسها التي أُرسلت في المحاولة الأولى، لا نسخة أعدت بناءها بترتيب مختلف للحقول أو بمسافات مختلفة. ولّد مفتاحًا واحدًا لكل عملية منطقية (UUID جديد)، لا مفتاحًا لكل نقطة نهاية أو لكل جلسة أو لكل يوم.

## الأخطاء تُخزَّن أيضًا[​](#الأخطاء-تُخزَّن-أيضًا "رابط مباشر إلى الأخطاء تُخزَّن أيضًا")

استجابة `4xx` الناتجة عن عملية كتابة تُحفظ وتُعاد لمدة 24 ساعة. بعد تصحيح خطأ في التحقق، أرسل الطلب المصحَّح بمفتاح `Idempotency-Key` **جديد**، لأن المفتاح القديم يجيب بـ `422 idempotency_key_reuse` على المحتوى المعدَّل. أما حالات الرفض التي تقع قبل وصول طلبك إلى معالجه فلا تُخزَّن إطلاقًا، ومنها `401`، وردود `403` المتعلقة بالتسجيل في البرنامج التجريبي أو بالخطة أو بحالة التطبيق، وكل ردود `429`، وغياب `Idempotency-Key` أو خطأ تنسيقه. وردّ `403` بسبب صلاحية ناقصة يصدر عن المعالج نفسه، فيُخزَّن مثل أي `4xx` آخر. كذلك استجابات `5xx` لا تُخزَّن ويمكن إعادة المحاولة بالمفتاح نفسه. انظر [الأخطاء](https://dzbuild.com/ar/ar/api-docs/errors.md).

## كيف تميّز الإعادة عن النداء الجديد[​](#كيف-تميّز-الإعادة-عن-النداء-الجديد "رابط مباشر إلى كيف تميّز الإعادة عن النداء الجديد")

اعتمد على الرأس `Idempotency-Replay: 1`. فالإعادة تعني أنه لم يحدث أي أثر جانبي جديد، وبالتالي تجاوز أي معالجة لاحقة محلية كنت ستنفّذها بعد كتابة حقيقية.

ولا تخلط بينه وبين `X-Cache`، فهو ترويسة منفصلة خاصة بطلبات `GET` وحدها وقيمتها دائمًا `MISS`.
