الرموز الترويجية
هذه النقاط الأربع تدير الرموز الترويجية للمتجر، أي الرموز التي يكتبها الزبون عند إتمام الطلب ليدفع أقل. وهي تعمل على الرموز نفسها الموجودة في صفحة الرموز الترويجية بلوحة التحكم، المشروحة في رموز الخصم، وتستطيع أيضاً تغيير نص الرمز، وهذا ما لا تسمح به لوحة التحكم.
يُخصم الرمز من المجموع الفرعي للمنتجات، ولا يُخصم أبداً من التوصيل. الرمز من نوع percentage يأخذ تلك النسبة من المجموع الفرعي. والرمز من نوع fixed يطرح مبلغه بالدينار، ولا يطرح أبداً أكثر من المجموع الفرعي. لا يمكن حصر رمز في منتج أو فئة أو زبون، ولا وضع سقف للخصم على سلة كبيرة، ولا منح التوصيل المجاني به.
قبل أن تبدأ
- يجب أن تكون إضافة الرموز الترويجية مفعّلة في المتجر (
/dashboard/addons). القائمة تعمل بدونها وتُخبرك بحالتها فيaddon_enabled. كل كتابة تُرجع409 addon_inactiveما دامت الإضافة معطّلة، ولا يستطيع الزبائن استعمال أي رمز عند إتمام الطلب خلال ذلك. - يحتاج المفتاح صلاحيات الرموز الترويجية. المفاتيح المُنشأة من لوحة التحكم (
/dashboard/api) تحصل على الاثنتين. الصلاحيات تُجمَّد لحظة إنشاء المفتاح، فالمفتاح الذي لا يملكهما يُرجع403 forbidden: أنشئ مفتاحاً جديداً من لوحة التحكم. - الحقلان
starts_atوexpires_atبتوقيت الجزائر، بالشكلYYYY-MM-DD HH:MM:SS.
| النطاق | الوصف |
|---|---|
promos:read | الاطلاع على الرموز الترويجية. |
promos:write | إنشاء الرموز الترويجية وتعديلها وحذفها. هذا يغيّر الأسعار التي يدفعها زبائنك. |
كائن الرمز الترويجي
| الحقل | النوع | المعنى |
|---|---|---|
id | int | رقم الرمز في المتجر. |
code | string | ما يكتبه الزبون. بأحرف كبيرة، A-Z و0-9 و- و_، وفريد داخل المتجر. |
discount_type | string | percentage أو fixed. |
discount_value | number | النسبة (أكبر من 0 وحتى 100) أو المبلغ بالدينار. |
min_order_amount | number أو null | المجموع الفرعي للمنتجات الذي يجب أن يبلغه الطلب حتى يُطبَّق الرمز. null تعني بلا حد أدنى. |
max_uses | int أو null | عدد الطلبات التي يمكنها استعمال الرمز. null تعني بلا حد. |
used_count | int | عدد الطلبات التي استعملته. للقراءة فقط. |
is_active | bool | الرمز غير المفعّل يُرفض عند إتمام الطلب. |
starts_at | string أو null | قبل هذا الوقت يُرفض الرمز. null تعني أنه يعمل فوراً. |
expires_at | string أو null | بعد هذا الوقت يُرفض الرمز. null تعني أنه لا ينتهي أبداً. |
created_at، updated_at | string | YYYY-MM-DD HH:MM:SS، بتوقيت الخادم. |
GET /v1/promo-codes
رموز المتجر، الأحدث أولاً. لا يوجد نداء يقرأ رمزاً واحداً برقمه: تصفّح هذه القائمة.
المصادقة: مفتاح منصة بصلاحية promos:read.
معاملات الاستعلام
| المعامل | النوع | الافتراضي | ملاحظات |
|---|---|---|---|
is_active | string | لا شيء | true أو 1 أو yes أو on تُرجع الرموز المفعّلة. أي قيمة أخرى تُرجع الرموز المعطّلة. اتركه للحصول على كل الرموز. |
limit | int | 50 | من 1 إلى 200. |
cursor | string | لا شيء | قيمة next_cursor من الصفحة السابقة. انظر الترقيم. |
الطلب
curl 'https://api.dzbuild.app/v1/promo-codes?is_active=true' \
-H "Authorization: Bearer $DZ_KEY"
الاستجابة 200
{
"data": {
"items": [
{
"id": 20,
"code": "WELCOME10",
"discount_type": "percentage",
"discount_value": 10,
"min_order_amount": 3000,
"max_uses": 100,
"used_count": 7,
"is_active": true,
"starts_at": null,
"expires_at": "2026-11-30 23:59:00",
"created_at": "2026-10-06 14:20:11",
"updated_at": "2026-10-06 14:20:11"
}
],
"next_cursor": null,
"has_more": false,
"addon_enabled": true
}
}
يُبيّن addon_enabled إن كانت إضافة الرموز الترويجية مفعّلة. عندما تكون قيمته false تبقى القائمة تعمل، لكن الكتابة تفشل ولا يستطيع الزبائن استعمال الرموز.
POST /v1/promo-codes
يُنشئ رمزاً. يعمل الرمز عند إتمام الطلب بمجرد إنشائه، إلا إذا أرسلت is_active: false أو starts_at بتاريخ لاحق.
المصادقة: مفتاح منصة بصلاحية promos:write. يتطلب Idempotency-Key.
الجسم
| الحقل | النوع | إلزامي | ملاحظات |
|---|---|---|---|
code | string | نعم | تُحذف المسافات من طرفيه وتتحوّل الأحرف إلى كبيرة، ثم يجب أن يكون من 2 إلى 30 حرفاً من A-Z أو 0-9 أو - أو _. الرمز الموجود من قبل في المتجر يُرجع 409 code_exists. |
discount_type | string | نعم | percentage أو fixed، بأحرف كبيرة أو صغيرة. لا توجد قيمة افتراضية. |
discount_value | number | نعم | أكبر من 0. لا يتجاوز 100 مع percentage، والقيمة 100 تحتاج تأكيد التاجر (انظر قسم خصم 100% أسفله). لا حد أعلى مع fixed. |
min_order_amount | number أو null | لا | الحد الأدنى للمجموع الفرعي للمنتجات بالدينار. 0 أو "" أو null تعني بلا حد أدنى. |
max_uses | int أو null | لا | 1 أو أكثر. 0 أو "" أو null تعني بلا حد. |
is_active | bool | لا | الافتراضي true. أرسل قيمة JSON منطقية: النص "false" مثلاً يُقرأ true. |
starts_at | string أو null | لا | صيغة تاريخ وساعة شائعة، مثل 2026-11-01 08:00 أو نص بصيغة ISO 8601. يُخزَّن بالشكل YYYY-MM-DD HH:MM:SS بتوقيت الجزائر، والقيمة التي تحمل فارقاً عن UTC تُحوَّل. null أو "" تعني بلا تاريخ بدء. |
expires_at | string أو null | لا | الصيغ نفسها. يجب أن يكون في المستقبل وبعد starts_at. null أو "" تعني بلا تاريخ انتهاء. |
confirm_token | string | لا | لخصم 100% فقط. |
confirm_full_discount | bool | لا | لخصم 100% فقط. |
الطلب
curl -X POST 'https://api.dzbuild.app/v1/promo-codes' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: promo-welcome10-create" \
-d '{"code": "welcome10", "discount_type": "percentage", "discount_value": 10, "min_order_amount": 3000, "max_uses": 100, "expires_at": "2026-11-30 23:59"}'
الاستجابة 201
{
"data": {
"id": 20,
"code": "WELCOME10",
"discount_type": "percentage",
"discount_value": 10,
"min_order_amount": 3000,
"max_uses": 100,
"used_count": 0,
"is_active": true,
"starts_at": null,
"expires_at": "2026-11-30 23:59:00",
"created_at": "2026-10-06 14:20:11",
"updated_at": "2026-10-06 14:20:11"
}
}
PATCH /v1/promo-codes/{id}
يغيّر الحقول التي ترسلها فقط، بقواعد الإنشاء نفسها. الحقل الذي لا ترسله يحتفظ بقيمته.
المصادقة: مفتاح منصة بصلاحية promos:write. يتطلب Idempotency-Key.
- يمكن تغيير
code. يجب ألا يكون النص الجديد مستعملاً في المتجر، وإلا يُرجع النداء409 code_exists. - يُفحص
discount_typeوdiscount_valueمعاً. إرسالdiscount_type: "percentage"وحده على رمزfixedبـ 500 د.ج يُرجع422 invalid_discount_value، لأن 500 أكبر من 100. أرسل الحقلين. - يجب أن يكون
expires_atالجديد في المستقبل. الرمز المنتهي الصلاحية يبقى قابلاً للتعديل ما دمت لا ترسلexpires_at. - لا يمكن كتابة
used_count. - الجسم الفارغ لا يغيّر شيئاً ويُرجع الرمز.
- رمز متجر آخر يُرجع
404، مثل رمز غير موجود.
الطلب
curl -X PATCH 'https://api.dzbuild.app/v1/promo-codes/20' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: promo-20-extend" \
-d '{"max_uses": 200, "expires_at": "2026-12-31 23:59"}'
الاستجابة 200
{
"data": {
"id": 20,
"code": "WELCOME10",
"discount_type": "percentage",
"discount_value": 10,
"min_order_amount": 3000,
"max_uses": 200,
"used_count": 7,
"is_active": true,
"starts_at": null,
"expires_at": "2026-12-31 23:59:00",
"created_at": "2026-10-06 14:20:11",
"updated_at": "2026-10-20 09:05:42"
}
}
DELETE /v1/promo-codes/{id}
يحذف الرمز، فلا يستطيع الزبائن استعماله بعدها. الطلبات التي استعملته من قبل تحتفظ بخصمها. لإيقاف رمز مؤقتاً دون أن تفقد عدد استعمالاته، أرسل is_active: false عبر PATCH بدل الحذف.
المصادقة: مفتاح منصة بصلاحية promos:write. يتطلب Idempotency-Key.
الطلب
curl -X DELETE 'https://api.dzbuild.app/v1/promo-codes/20' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Idempotency-Key: promo-20-delete"
الاستجابة 200
{
"data": {
"deleted": true,
"id": 20
}
}
خصم 100%
رمز percentage بقيمة 100 يجعل المنتجات مجانية لكل زبون يملك الرمز. الإنشاء، أو التعديل الذي يرسل discount_type أو discount_value، لا يُكتب من النداء الأول إذا كانت النتيجة رمز percentage بنسبة 100%:
- يُرجع النداء
422 confirmation_requiredولا يكتب شيئاً. يحمل الخطأconfirm_token(يُستعمل مرة واحدة، صالح600ثانية) وactionوwill_change، وهو ملخّص تعرضه على التاجر. - بعد موافقة التاجر، أعد الجسم نفسه مع إضافة
confirm_tokenوبـIdempotency-Keyجديد (المفتاح الأول مربوط بالجسم الذي لا يحمل رمز التأكيد). رمز التأكيد المنتهي، أو المستعمل من قبل، أو الذي لم يعد يطابق الطلب، يُرجع422 confirmation_staleمع رمز تأكيد جديد.
بمفتاح مُنشأ من لوحة التحكم يمكنك تجاوز هذه الجولة بإرسال confirm_full_discount: true في النداء الأول. أما DZBuild Copilot فلا يستطيع استعمال هذا الحقل ويمرّ دائماً عبر رمز التأكيد.
{
"error": {
"code": "confirmation_required",
"message": "A 100% discount makes every order free ...",
"confirm_token": "cft_xxxxxxxxxxxxxxxx",
"confirm_token_expires_in": 600,
"action": "promo.full_discount:new",
"will_change": {
"action": "Create a promo code that makes orders free",
"code": "FREEGIFT",
"discount": "100% off the whole order subtotal",
"reversible": true,
"note": "Any customer with this code pays 0 for the goods. Orders already placed with it cannot be reversed by deleting the code."
}
}
}
في التعديل، ينتهي action برقم الرمز بدل new، ويصبح نص will_change.action هو Change promo code #20 to make orders free.
curl -X POST 'https://api.dzbuild.app/v1/promo-codes' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: promo-freegift-approved" \
-d '{"code": "FREEGIFT", "discount_type": "percentage", "discount_value": 100, "max_uses": 1, "confirm_token": "cft_REPLACE_WITH_TOKEN"}'
سجل التغييرات والتراجع
كل إنشاء وتعديل وحذف يتم عبر الواجهة البرمجية يُسجَّل. الرموز التي تُعدَّل من صفحة لوحة التحكم لا تُسجَّل، فلا يمكن التراجع عنها عبر الواجهة البرمجية.
- يعرض
GET /v1/changes?entity=promo_codeتغييرات الرموز الترويجية، الأحدث أولاً، بصلاحيةstore:read. كل عنصر يحملidالتغيير، ورقم الرمز فيentity_id، وaction(createأوupdateأوdelete) وsummary. - يحتاج
POST /v1/changes/{id}/undoإلىpromos:writeوإلىIdempotency-Keyوإلى أن تكون الإضافة مفعّلة، مثل أي كتابة. - التراجع عن تعديل يُرجع القيم السابقة دون أي تأكيد، حتى لو كانت خصماً بـ 100% أو تاريخ انتهاء قد مضى. وإذا حُذف الرمز بعد ذلك، يُرجع التراجع
422 restore_target_missing. - التراجع عن حذف يُعيد إنشاء الرمز مع عدد استعمالاته، ويحتفظ برقمه إذا كان هذا الرقم ما يزال شاغراً.
- التراجع عن إنشاء يُرجع
422 nothing_to_restore: احذف الرمز بدلاً من ذلك. - لا يستطيع رمز التطبيق المثبّت قراءة التغييرات ولا التراجع عنها: كلاهما يُرجع
403 forbidden.
curl -X POST 'https://api.dzbuild.app/v1/changes/500/undo' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Idempotency-Key: undo-500"
{
"data": {
"undone": true,
"change_id": 500,
"entity": "promo_code",
"undo_change_id": 510
}
}
التغيير الذي يُتراجع عنه مرة ثانية يُرجع 409 already_undone.
الأخطاء
| HTTP | الرمز | السبب |
|---|---|---|
| 400 | bad_request | الرقم في المسار ليس أرقاماً فقط، أو الجسم ليس JSON صالحاً، أو Idempotency-Key غائب أو غير صالح. |
| 403 | forbidden | Missing scope: promos:read أو Missing scope: promos:write، أو API access requires an active Enterprise plan لمفتاح تاجر متجره ليس على خطة Enterprise سارية. |
| 404 | not_found | لا يوجد رمز ترويجي بهذا الرقم في المتجر. |
| 409 | addon_inactive | إضافة الرموز الترويجية غير مفعّلة في المتجر. في الكتابة فقط. |
| 409 | code_exists | رمز آخر في المتجر يحمل هذا النص. |
| 422 | invalid_code | code أقصر من حرفين أو أطول من 30 حرفاً، أو يحتوي حرفاً غير A-Z و0-9 و- و_. |
| 422 | invalid_discount_type | discount_type غائب، أو ليس percentage ولا fixed. |
| 422 | invalid_discount_value | discount_value غائب، أو ليس رقماً، أو يساوي 0 أو أقل، أو أكبر من 100 مع percentage. |
| 422 | invalid_min_order_amount | min_order_amount ليس رقماً. |
| 422 | invalid_max_uses | max_uses ليس رقماً، أو أقل من 1. |
| 422 | invalid_starts_at، invalid_expires_at | تعذّرت قراءة التاريخ. |
| 422 | expires_at_in_past | قيمة expires_at التي أرسلتها ليست في المستقبل. |
| 422 | invalid_date_window | expires_at ليس بعد starts_at. |
| 422 | confirmation_required، confirmation_stale | خصم 100% ينتظر موافقة التاجر. انظر القسم أعلاه. |
| 422 | idempotency_key_reuse | استُعمل Idempotency-Key نفسه مع جسم أو مسار مختلف. |
| 500 | server_error | فشلت الكتابة. أعد المحاولة بـ Idempotency-Key نفسه. |
استجابة 4xx تُحفظ مع Idempotency-Key الخاص بها 24 ساعة، وتُعاد لكل إعادة محاولة بالجسم نفسه. بعد تفعيل الإضافة أو تصحيح الجسم، أرسل النداء بمفتاح جديد. الأخطاء المشتركة بين كل النقاط، مثل 401 و402 و429، موجودة في الأخطاء، وقواعد إعادة المحاولة في Idempotency.
حدود معروفة
- قد تتجاوز الاستعمالات
max_uses. عندما يُتمّ عدة زبائن طلباتهم بالرمز نفسه في اللحظة نفسها، قد يتجاوزused_countقيمةmax_uses. - لا يوجد
webhook. إنشاء رمز ترويجي أو تعديله أو حذفه لا يُرسل أي حدثwebhook.