واجهة API من PriceZag — اربط بيانات الأسعار بأنظمتك

استخدم واجهة JSON API من PriceZag للاطلاع على أسعار المنافسين ومخزونهم، وإدارة المنتجات وقواعد إعادة التسعير، وتنزيل التقارير، وأتمتة سير العمل.

مثال سريع باستخدام curl

نعلم أن المطورين يفضلون رؤية شيفرة قابلة للتشغيل أولاً. تنشئ هذه الأوامر منتجاً تجريبياً ثم تسترجعه. استبدل MYAPIKEY بمفتاح حسابك (راجع مفتاح API).
إنشاء منتج تجريبي:
curl -vX POST 'https://pricezag.com/api/v3/MYAPIKEY' -d '{"actions":[{"a":"productCreate","code":"000-SOME-TEST-PRODUCT","name":"Some Test Product created via PriceZag API","price":12.34,"currency":"USD"}]}'
(ستؤدي إعادة تشغيل الأمر إلى خطأ لأن المنتج موجود بالفعل)
والآن يمكنك استرجاع المنتج الذي أنشأته:
curl -X POST 'https://pricezag.com/api/v3/MYAPIKEY' -d '{"actions":[{"a":"productGet","code":"000-SOME-TEST-PRODUCT"}]}' | python -mjson.tool
(احذف | python -mjson.tool إذا لم تكن هذه الأداة لتنسيق استجابة JSON متوفرة في الطرفية لديك)

نظرة عامة

ما الذي يمكنك فعله باستخدام API من PriceZag

تتيح واجهة JSON API من PriceZag لبرامجك وأنظمتك التعامل مباشرة مع أسعار المنافسين ومخزونهم الذي نراقبه. يمكنك قراءة بيانات المنتجات، وإدارة المنتجات والفئات، وحساب القيم وفق قواعد إعادة التسعير، وإعداد التنبيهات، وتنزيل جداول بيانات مخصصة. يمكنك استخدام API مع أي منصة تجارة إلكترونية أو لغة برمجة قادرة على إرسال طلبات HTTPS ومعالجة JSON.

يمكنك أيضاً أن تطلب من مساعد الذكاء الاصطناعي المفضل لديك كتابة البرامج نيابة عنك. أعطه رابط هذه الوثائق (https://pricezag.com/integrations/api)، واشرح ما تريد أتمتته، وحدد لغة البرمجة أو منصة التجارة الإلكترونية التي تستخدمها. حافظ على سرية مفتاح API ولا تلصقه في محادثة مع الذكاء الاصطناعي.

تتولى PriceZag المراقبة داخل منصتها، لذا فإن API اختياري. يفيدك عندما تريد ربط نظامك بهذه البيانات. Shopify و WooCommerce توفران أيضاً تكاملاً مباشراً.

مفتاح API والأذونات

في حساب PriceZag، افتح Automation > API. انقر على Reveal the current API key لعرض مفتاحك الحالي، أو على Change the API key لاستبداله. تتطلب العمليتان إدخال كلمة مرور الحساب. ويجب أن يمتلك المستخدم الأذونات المناسبة لعرض مفاتيح API أو إنشائها. إذا لم تكن لديه هذه الأذونات، فعليه التواصل مع مسؤول الحساب.

حافظ على سرية مفتاح API. قد يسمح المفتاح بإجراء تغييرات واسعة على بيانات الحساب، بما فيها الحذف. لا تضعه في مستودعات شيفرة عامة أو في شيفرة تعمل داخل المتصفح أو في محادثات الذكاء الاصطناعي. إذا استعنت بشخص لبناء تكامل، فأنشئ له مستخدماً في PriceZag بالأذونات المناسبة، وغيّر مفتاح API عند الحاجة.

يعتمد الوصول إلى API على اشتراكك. مع الوصول الكامل، يمكن لبرامجك التعامل مع جميع المنتجات. بدونه، يمكن الوصول فقط إلى أول 10 منتجات مرتبة أبجدياً ورقمياً بحسب الرمز المرجعي. على سبيل المثال، إذا كان لديك 1,000 منتج برموز تبدأ من SKU0001 إلى SKU1000، يستطيع API الوصول إلى الرموز من SKU0001 إلى SKU0010. تشمل التجربة المجانية لمدة 14 يوماً وصولاً كاملاً إلى API. ويمكن أيضاً تفعيل الوصول الكامل كخيار ضمن الاشتراك.

سجل نشاط API وآخر طلب

تعرض صفحة Automation > API في حسابك وقت آخر طلب API وزر API Activity Log. راجعهما إذا تعطل برنامج لتتحقق مما إذا وصلت الطلبات إلى PriceZag ولتتقصى الأخطاء أو التغييرات غير المتوقعة.

تظهر التغييرات التي تتم عبر API أيضاً في History of Edits في أنحاء الحساب، باسم المستخدم API. على سبيل المثال، قد يعرض سجل المنتج Price edited by API بدلاً من Price edited by JOHN. تدعم PriceZag عدة مستخدمين في الحساب نفسه، بحيث يمكنك التمييز بين التغييرات الآلية وتعديلات أعضاء الفريق.

عنوان URL للطلبات وطرق إرسالها

تستخدم جميع طلبات API عنوان HTTPS نفسه. أرسل طلبات POST إلى هذا العنوان، مع استبدال MYAPIKEY بمفتاحك:

https://pricezag.com/api/v3/MYAPIKEY

العمليات التي تريد تنفيذها عبر API ("actions") ومعاملاتها توضع في متن طلب JSON، وليس في عنوان URL.
أرسل كائن JSON يحتوي على عملية واحدة أو أكثر في متن طلب POST. يبقى عنوان URL ثابتاً سواء قرأت منتجاً أو حدّثت الأسعار أو نزّلت جدول بيانات.

لا يمكنك إرسال POST؟
كحل أخير، يمكنك إرسال طلب GET يتضمن متن JSON مشفراً بصيغة base64 ضمن معامل ?data= في عنوان URL. ولأن طول عناوين URL محدود، يوصى بشدة باستخدام POST.

كيف تعمل عمليات API

ما نسميه عملية هو إجراء في حسابك، مثل تعديل حقول منتج أو تغيير قاعدة إعادة تسعير أو قراءة أسعار جميع منافسي منتج معين.
تنفذ واجهة API وواجهة المستخدم (UI) الوظائف نفسها في الخادم، ولذلك يمكن تنفيذ معظم الإجراءات المتاحة في الواجهة عبر API أيضاً.
عند إرسال طلب API، تحتوي بيانات JSON على مصفوفة تضم جميع العمليات المطلوب تنفيذها، من عملية واحدة حتى 1,000 عملية كحد أقصى في الطلب. مثلاً، يمكنك إعادة تسمية ثلاثة منتجات وإنشاء فئة جديدة ضمن طلب واحد بأربع عمليات. ويمكنك أيضاً استرجاع بيانات 1,000 منتج دفعة واحدة باستخدام 1,000 عملية "productGet".
تنفذ العمليات بالترتيب الوارد في المصفوفة. فإذا أنشأت قاعدة إعادة تسعير ثم ربطت بها منتجات، فاحفظ هذا الترتيب حتى تكون القاعدة موجودة عند تعديل المنتجات.
في أسفل الصفحة ستجد قائمة جميع العمليات المتاحة.

كائن طلب JSON

للبرامج والشيفرة التي ينشئها الذكاء الاصطناعي: تتضمن الأمثلة المرجعية أدناه // تعليقات و ... عناصر نائبة لتوضيح الحقول. هذه أمثلة توضيحية وليست JSON صالحاً للإرسال كما هو. احذف التعليقات واستبدل العناصر النائبة قبل إرسال الطلب. مثالَا curl أعلاه يحتويان على متون JSON صالحة.

يجب أن تتكون بيانات POST كلها من كائن JSON واحد {...} يحتوي على مصفوفة العمليات المطلوب تنفيذها.
{
	"stopOnFailure"	: 1,  // (اختياري) يتابع النظام عادة إلى العملية التالية حتى بعد فشل عملية. القيمة 1 توقف التنفيذ.

	// مصفوفة جميع العمليات:
	"actions" : [
		// العملية 1:
		{
			"a"	: "someActionName",  // اسم العملية هو دائماً قيمة الحقل "a" في كائن العملية.
			"xx"	: "some parameter this action needs"	// كل ما عدا "a" هو المعاملات التي تحتاجها العملية.
		},
		// العملية 2:
		{
			"a"	: "anotherActionName",
			"abc"	: "some parameter this action needs",
			"xyz"	: {"x":"some object this action needs", "y":5, "z":6}
		},
		// العملية 3:
		{
			"a"	: "aThirdAction",
			"xyz"	: ["some array this action needs", "..."]
		}
	]
}

استجابة الخادم ورموز HTTP

يعيد الخادم نصاً بصيغة text/plain عند وجود خطأ في تنسيق الطلب أو عندما يكون الحساب معطلاً مثلاً. يحتوي النص حينها على رسالة الخطأ.
إذا كان الطلب صحيحاً، فستتلقى عادة كائن JSON كاستجابة، باستثناء بعض العمليات المعلَّمة كاستثناءات، مثل تنزيل جدول بيانات. يمكنك التحقق من ذلك عبر ترويسة الاستجابة Content-Type: application/json من الخادم.
رمز استجابة HTTP هو:
◄ 200 عندما تنجح جميع العمليات (وتعد النتيجة المحايدة ok=0 نجاحاً أيضاً)
◄ 406 عندما تنجح بعض العمليات وتفشل أخرى.
◄ 422 عندما تفشل جميع العمليات، ولكن ليس للأسباب المذكورة أدناه.
◄ 400 عندما يتعذر تحليل كائن JSON المستلم.
◄ 403 عندما تفشل المصادقة (غالباً بسبب مفتاح API غير صحيح).
يمكنك الاعتماد على رموز الاستجابة هذه في برامجك. وإذا احتجت تفاصيل إضافية، يوفر كائن JSON المُعاد معلومات أكثر:
{
	"ok"		: 15,  // عدد العمليات المنفذة بنجاح (ok>0 لكل عملية)
	"errors"	: 0,  // عدد العمليات التي أعادت خطأ (ok<0)
	"actionsCount"	: 20,  // العدد الإجمالي للعمليات المطلوبة أولاً (طول مصفوفة "actions")
	// يمكن استنتاج أن 5 عمليات أعادت ok=0: لم تفشل لكنها لم تغيّر شيئاً.
	
	// مصفوفة العمليات المطلوبة أصلاً، بالترتيب نفسه:
	"actions" : [
		...
		// كائن الاستجابة لكل عملية:
		{
			"a"	: "someActionName",
			"ok"	: 4,		// النتيجة: ‎>0 نجاح، 0 دون تغيير، ‎<0 خطأ
						// مثلاً، تظهر 0 إذا ضبطت سعر المنتج على قيمته الحالية.
						// تظهر -1 إذا لم يكن المنتج موجوداً.
						// يعتمد معنى الرقم الموجب على العملية، وغالباً يشير إلى عدد الحقول أو العناصر المتغيرة.
			"error"	: "...",  // رسالة الخطأ إذا كان ok<0
						// رسائل الخطأ لدينا مفصلة جداً. يُنصح بتسجيلها
						// لأنها تحتوي على المعلومات اللازمة لفهم سبب المشكلة.
			...	// أي بيانات أخرى تعيدها العملية بحسب نوعها.
		},
		...
	]
}

أمثلة؟

أحياناً تكون الأمثلة أوضح. راجع المزيد من الأمثلة في أسفل هذه الصفحة.

حدود معدل الطلبات والجدولة

لدينا جدار حماية يحمينا ويحميك من الهجمات أو سيل الطلبات. إذا حظر الجدار مضيفاً، فقد يبدو موقعنا متوقفاً: لا اتصال ولا استجابة ولا رد على ping.
لتجنب حظر طلباتك المشروعة:
◄ لا تستخدم مفتاح API غير صحيح؛ جدار الحماية لا يتسامح مع محاولات كثيرة بمفاتيح خاطئة، كما هو الحال مع كلمات مرور الموقع.
◄ اجمع عمليات متعددة في طلب واحد ضمن كائن JSON واحد (بحد أقصى 1,000). لإنشاء 1,000 منتج أرسل طلباً واحداً لا 1,000 طلب.
◄ إذا اضطررت لإرسال طلبات كثيرة، انتظر 500 مللي ثانية بين الطلبات وأعد استخدام اتصال HTTPS نفسه. إنشاء اتصال جديد لكل طلب خطأ شائع. لا تبرر الطلبات الكثيرة عادة إلا عند تحديث مئات الآلاف من المنتجات، بواقع 1,000 عملية لكل طلب.
لا نفرض حداً ثابتاً لمعدل الطلبات؛ يقرر جدار الحماية بناءً على عشرات المعايير. استخدم معدل طلبات معقولاً.
 
الطلبات المجدولة:
إذا جدولت الطلبات بفواصل منتظمة، فأضف تأخيراً عشوائياً حتى لا ترسلها في بداية الدقيقة بالضبط (الثانية 0). يرسل عملاء كثيرون طلباتهم في الوقت نفسه؛ توزيعها يقلل التأخير واحتمال انتهاء المهلة عند ازدحام الخادم.

جميع عمليات API المتاحة

تجد أدناه معاملات كل عملية وأمثلة الطلبات والاستجابات. تنقلك القائمة الموجودة يسار الصفحة مباشرة إلى كل عملية.

المنتجات

العمليةالغرض
productCreateإنشاء منتج جديد
productEditتعديل منتج موجود
productCompetitorsتعديل روابط المنافسين لمنتج (دون استبدالها جميعاً)
productCategoriesتعديل فئات منتج واحد أو عدة منتجات (دون استبدالها جميعاً)
productRepricingربط منتجات كثيرة بقاعدة إعادة تسعير
productDeleteحذف منتج واحد أو عدة منتجات
productGetاسترجاع منتج (بما في ذلك بيانات منافسيه)
productGetAllاسترجاع جميع المنتجات (بما في ذلك بيانات منافسيها)

الفئات

العمليةالغرض
categoryCreateإنشاء فئة جديدة
categoryEditتعديل فئة موجودة
categoryDeleteحذف فئة واحدة أو عدة فئات
categoryCopyنسخ المنتجات أو نقلها بين الفئات
categoryGetاسترجاع فئة
categoryGetAllاسترجاع جميع الفئات

التنبيهات

العمليةالغرض
alertRecipientCreateإنشاء مستلم تنبيهات جديد
alertRecipientEditتعديل مستلم تنبيهات و/أو قواعده
alertRecipientDeleteحذف مستلم تنبيهات
alertRuleEditتعديل قاعدة تنبيه موجودة لمستلم
alertRuleCreate ?هذه العملية غير موجودة. استخدم alertRecipientEdit مع مصفوفة "rulesAdd".
alertRuleDelete ?هذه العملية غير موجودة. استخدم alertRecipientEdit مع مصفوفة "rulesRemove".
alertGetAllاسترجاع جميع مستلمي التنبيهات وقواعدهم

قواعد إعادة التسعير

العمليةالغرض
repricingCreateإنشاء قاعدة إعادة تسعير
repricingEditتعديل قاعدة إعادة تسعير موجودة
repricingDeleteحذف قاعدة إعادة تسعير
repricingGetAllاسترجاع جميع قواعد إعادة التسعير

جداول البيانات

العمليةالغرض
spreadsheetDownloadتنزيل جدول بيانات
spreadsheetPresetEditإعادة تسمية إعداد مسبق لجدول بيانات أو حذفه
spreadsheetAutoCreateإنشاء تصدير تلقائي لجدول بيانات
spreadsheetAutoEditتعديل تصدير تلقائي لجدول بيانات

المنافسون والمزيد

العمليةالغرض
competitorDeleteAllحذف منافس من جميع المنتجات أو الفئات
mathEditإعداد أو تعديل حسابات الأسعار لنطاق منافس

المنتجات

productCreate — إنشاء منتج جديد

هذه هي الوظيفة نفسها التي تستخدمها واجهة المستخدم في صفحة New Product .
{ "actions" : [
	...
	{
		"a"		: "productCreate",
		"code"		: "UNIQUE-REF-CODE",  // من 1 إلى 80 محرفاً ([a-z\d][a-z\d_-]{0,78}[a-z\d])؛ دون حساسية لحالة الأحرف (تحول إلى أحرف كبيرة).
		"name"		: "The Product Name",  // من 1 إلى 200 محرف كحد أقصى
		"price"		: 1234.90,  // انتبه للفواصل والنقاط: لا فاصل للآلاف، والفاصل العشري نقطة.
		"currency"	: "USD",
		"cost"		: 1234.90,  // (اختياري)
		"costCurrency"	: "USD",  // مطلوب إذا تم تقديم cost
		"repricingRule"	: "The Rule Name",  // (اختياري) قاعدة إعادة التسعير المرتبطة (فارغ = معطّلة؛ غير موجودة = خطأ)
		"myWebsite"	: "https://...",  // (اختياري) رابط URL أو shopify:productId:variantId أو woocommerce:productId(:variationId)
		"competitors"	: ["https://...", "https://..."],  // (اختياري)
		"categories"	: ["The Category 1", "The Category 2"],  // (اختياري) فئات المنتج (إذا لم توجد تُنشأ)
		"comments"	: "Some comments\nAnd another line",  // (اختياري) 1,000 محرف UTF-8 كحد أقصى
		"custom_someFieldName1"	: "Value of custom field",		// (اختياري)
		"custom_someFieldName2"	: "Value of other\nCustom\tField",  // (اختياري)
		// الحقول المخصصة لاستخدامك الداخلي، مثل استخدامها أعمدةً عند تصدير جدول بيانات.
		// حتى 20 حقلاً مخصصاً لكل منتج. اسم الحقل حتى 40 حرفاً أو رقماً أو شرطة سفلية (حساس لحالة الأحرف)، دون بادئة "custom_"؛ أي 47 مع البادئة.
		// تقتصر قيمة الحقل على 500 بايت، وليس بالضرورة 500 محرف. يمكن تقديم رقم مثل custom_varname:123.
		// لكن API يعيد دائماً سلسلة نصية مثل custom_varname:"123"، فحوّل النوع عند الحاجة.
		// لحذف حقل مخصص، اضبط قيمته على "". ينطبق الحذف في productEdit وليس productCreate.
	},
	...
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"	: "productCreate",
			"ok"	: 1,
			"code"	: "REF-CODE",  // رمز المنتج النهائي في قاعدة البيانات (قد نحول بعض المحارف الخاصة).
		},
		...
	]
}

productEdit — تعديل منتج موجود

هذه هي الوظيفة نفسها التي تستخدمها الواجهة عند تعديل حقل في صفحة المنتج، إلا أن الواجهة ترسل كل حقل على حدة، بينما يسمح API بتعديل الاسم والسعر مثلاً في طلب واحد.
{ "actions" : [
	...
	{
		"a"		: "productEdit",
		"code"		: "REF-CODE",
		...		// يقبل معاملات productCreate نفسها، وجميعها اختيارية.
		"newCode"	: "REF-CODE-RENAMED",  // (اختياري)
		"competitors"	: ["https://...", "https://..."],  // إذا قُدم، يستبدل جميع روابط المنافسين الحالية.
		// لإضافة روابط أو حذفها دون استبدال الكل، استخدم productCompetitors بدلاً منها.
		"categories"	: ["The Category 1", "The Category 2"],  // إذا قُدم، يستبدل جميع الفئات الحالية. استخدم productCategories أو categoryEdit بدلاً منه.
		"custom_someFieldName"	: "New value or empty to delete that custom field",
		// الحد الأقصى 20 حقلاً مخصصاً لكل منتج؛ قد تحتاج إلى حذف حقول قديمة بالقيمة "" قبل إضافة غيرها.
	},
	...
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"	: "productEdit",
			"ok"	: 3,  // عدد التغييرات المنفذة (مثلاً سعري + رابطَي منافسين = 3).
			"code"	: "REF-CODE",  // الرمز النهائي الجديد في قاعدة البيانات (قد نحول بعض المحارف الخاصة).
		},
		...
	]
}

productCompetitors — تعديل روابط المنافسين لمنتج

عدّل روابط المنافسين لمنتج دون استبدالها كلها (بخلاف عملية productEdit ).
{ "actions" : [
	...
	{
		"a"			: "productCompetitors",
		"code"			: "REF-CODE",
		"competitorsAdd"	: ["https://...", "https://..."],  // (اختياري) إضافة هذه الروابط إلى روابط المنافسين الحالية.
		"competitorsRemove"	: ["https://...", "example.com/a0ff80...5f00", "example.net"],  // (اختياري) إزالة منافسين. يمكن أن يكون كل عنصر:
		// رابط URL (مع أي تعديل hashtag). التسميات اختيارية.
		// قيمة "ref" للمنافس (كما تعيدها العمليات الأخرى: النطاق الجذري متبوعاً ببصمة md5 من 32 محرفاً).
		// نطاق جذري أو اسم مضيف كامل؛ تُزال جميع روابط المنتج من هذا النطاق.
		// يمكن أيضاً أن تكون "competitorsAdd" و"competitorsRemove" سلاسل نصية بدلاً من مصفوفات بعنصر واحد.
		// تتم الإزالة قبل الإضافة، بحيث يمكنك إزالة نطاق كامل ثم إضافة رابط منه.
	},
	...
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"			: "productCompetitors",
			"ok"			: 3,  // عدد روابط المنافسين التي تغيرت.
			"competitorsAdded"	: 2,  // عدد روابط المنافسين المضافة للمنتج.
			"competitorsRemoved"	: 1,  // عدد روابط المنافسين المحذوفة من المنتج.
			// أخطاء:
			// إضافة رابط موجود مسبقاً لا تُعد خطأ (ok=0).
			// إزالة رابط كامل أو "ref" غير موجود تنتج خطأ (ok=-1).
			// إزالة روابط نطاق غير موجود لا تُعد خطأ (ok=0).
		},
		...
	]
}

productCategories — تعديل فئات منتج واحد أو أكثر

عدّل فئات منتج أو عدة منتجات دون استبدال جميع الفئات (بخلاف productEdit).
هذه هي الوظيفة نفسها التي تستخدمها الواجهة عندما تفتح All Products، وتحدد منتجات ثم تنقر على Selected Products › Edit Categories. يمكنك مراجعة الصفحة لمزيد من التفاصيل.
يمكنك أيضاً مراجعة عملية categoryEdit لتختار ما يناسبك.
{ "actions" : [
	...
	{
		"a"			: "productCategories",
		"code"			: "REF-CODE",  // سلسلة دون حساسية لحالة الأحرف، أو:
		"code"			: ["REF-CODE-1", "REF-CODE-2"],  // يمكن أيضاً تمرير مصفوفة منتجات (حتى 100,000).
		"categoriesRemove"	: ["The Category 1", "The Category 2"],  // (اختياري) أزل أولاً من هذه الفئات.
		"categoriesRemoveAll"	: 1,  // (اختياري) أزل أولاً من جميع الفئات، كما في productEdit.
		"deleteEmptyCategories"	: 1,  // أي فئة تصبح فارغة
		// نتيجة إزالة المنتجات ستُحذف.
		"categoriesAdd"		: ["The Category 1", "The Category 2"],  // (اختياري) أضف بعدها إلى هذه الفئات (تُنشأ إن لم تكن موجودة).
		"categoriesAddClear"	: 1,  // (اختياري) أفرغ فئات الوجهة أولاً قبل إضافة المنتجات.
	},
	...
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"	: "productCategories",
			"ok"	: 3,  // عدد المنتجات المعدلة.
		},
		...
	]
}

productRepricing — ربط منتجات كثيرة بقاعدة إعادة تسعير

اربط حتى 100,000 منتج بقاعدة إعادة تسعير واحدة.
تشبه هذه عملية productEdit ، لكن حد 1,000 عملية لكل طلب يعني أنك تحتاج إلى 50 طلباً لربط 50,000 منتج بالطريقة الأخرى، وسيكون التنفيذ أبطأ بكثير.
إذا أردت تعديل عدد قليل من المنتجات، فقد تكون عملية productEdit أنسب.
{ "actions" : [
	...
	{
		"a"			: "productRepricing",
		"repricingRule"		: "The Rule Name",  // دون حساسية لحالة الأحرف؛ "" تعني بلا قاعدة (تعطيل إعادة التسعير).
		"products"		: ["REF-CODE-1", "REF-CODE-2"],  // دون حساسية لحالة الأحرف (حتى 100,000).
	},
	...
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"		: "productRepricing",
			"ok"		: 10,  // عدد المنتجات المعدلة.
			// إذا كانت جميع المنتجات مرتبطة بهذه القاعدة بالفعل، فالنتيجة ok=0.
		},
		...
	]
}

productDelete — حذف منتج واحد أو عدة منتجات

تحذير: يُحذف المنتج وروابط منافسيه من الحساب فوراً وبصورة نهائية دون إمكانية استعادتها.
هذه هي الوظيفة نفسها التي تستخدمها الواجهة عندما تفتح All Products، وتحدد منتجات ثم تنقر على Selected Products › Delete.
{ "actions" : [
	...
	{
		"a"	: "productDelete",
		"code"	: "REF-CODE",  // سلسلة دون حساسية لحالة الأحرف، أو:
		"code"	: ["REF-CODE-1", "REF-CODE-2"],  // يمكن أيضاً تمرير مصفوفة لحذف عدة منتجات (حتى 100,000).
		"deleteEmptyCategories"	: 1,  // أي فئة تصبح فارغة
		// التي تصبح فارغة نتيجة حذف المنتجات ستُحذف أيضاً.
	},
	...
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"	: "productDelete",
			"ok"	: 2,  // عدد المنتجات المحذوفة بنجاح.
		},
		...
	]
}

productGet — استرجاع منتج

{ "actions" : [
	...
	{
		"a"			: "productGet",
		"code"			: "REF-CODE",  // دون حساسية لحالة الأحرف.
		"currency"		: "EUR",  // (اختياري) حوّل جميع المبالغ إلى هذه العملة بدلاً من عملة سعر المنتج.
		"withStats"		: 1,  // (اختياري) أعد كائن الإحصاءات.
		"noCompetitors"		: 1,  // (اختياري) لا تُعد مصفوفة المنافسين لتقليل حجم البيانات.
		"noComments"		: 1,  // (اختياري) لا تُعد التعليقات (...)
		"withScreenshots"	: 1,  // (اختياري) أعد رابط أحدث لقطة شاشة لكل منافس.
		"sickMax"		: 2,  // (اختياري، الافتراضي 1) من 0 إلى 3: أعد روابط المنافسين بمستوى تعطل لا يتجاوز N.
	},
	...
] }
تعيد هذه العملية جميع معلومات المنتج، بما فيها أسعار المنافسين ومخزونهم الحالي.
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"			: "productGet",
			"ok"			: 1,
			"code"			: "REF-CODE",
			"name"			: "The Product Name",
			"price"			: 1234.90,  // سعرك، دائماً بالعملة الأصلية.
			"currency"		: "USD",  // العملة الأصلية للحقل "price".
			"convCurrency"		: "EUR",  // العملة التي تظهر بها المبالغ المحوّلة ("currency" المقدمة أو عملة سعر المنتج).
			"priceConv"		: 1234.90,  // سعرك بعد التحويل باستخدام "convCurrency"، أو مساوٍ لـ"price".
			"cost"			: 1234.90,
			"costCurrency"		: "USD",
			"costPriceConv"		: 1234.90,  // تكلفتك محوّلة إلى عملة السعر "currency".
			"costConv"		: 1234.90,  // تكلفتك محوّلة إلى "convCurrency".
			"margin"		: 10.5,  // نسبة مئوية (قد تكون سالبة).
			"repricingRule"		: "The Rule Name",  // متغيرات إعادة التسعير الثلاثة هذه لا تظهر عند عدم وجود قاعدة.
			"reprice"		: 1234.90,  // المبلغ الحالي المحسوب وفق repricingRule.
			"repriceCurrency"	: "USD",  // مطابق لـ"convCurrency"؛ مذكور هنا للتوضيح.
			"myWebsite"		: "https://...",
			"created"		: 1234567890,  // وقت إنشاء المنتج بتوقيت Epoch.
			"createdBy"		: "SOMEUSER",  // اسم مستخدم أو "API".
			"edited"		: 1234567890,  // وقت Epoch لآخر تعديل، إن وُجد.
			"editedBy"		: "SOMEUSER",  // اسم مستخدم أو "API".
			"comments"		: "Some comments\nAnd another line",
			"commentsLast"		: 1234567890,  // وقت Epoch لآخر تعديل للتعليقات، إن وُجد.
			"commentsLastBy"	: "SOMEUSER",  // اسم مستخدم أو "API".
			"categories"		: ["The Category 1", "The Category 2"],
			"stats"		: {
				// لا تدخل في الإحصاءات إلا الروابط بمستوى تعطل 0 أو 1، بغض النظر عن "sickMax".
				// جميع المبالغ بوحدة "convCurrency": إما "currency" المحددة أو عملة المنتج الأصلية.
				// تحذير: عند عدم توفر مبلغ (مثل compIn* بلا منافسين متاحين)، تكون القيمة 0.
				"rank"			: 1.23,  // ترتيب سعرك (1 = لا أحد أقل منك سعراً).
				"rankIn"		: 1.23,  // ترتيبك بين المنافسين المتوفر لديهم مخزون.
				"compCount"		: 3,  // عدد المنافسين ذوي السعر الصالح.
				"compInCount"		: 3,  // عدد المنافسين المتوفر لديهم مخزون.
				"compOutCount"		: 3,  // عدد المنافسين الذين نفد مخزونهم.
				"compAvg"		: 123.56,  // متوسط أسعار جميع المنافسين.
				"compAvgVsMe"		: 123.56,  // الفارق بوحدة convCurrency بين سعرك ومتوسط المنافسين (السالب = سعرك أقل).
				"compInAvg"		: 123.56,  // متوسط أسعار المنافسين المتوفر لديهم مخزون.
				"compInAvgVsMe"		: 123.56,  // مثل "compAvgVsMe" ولكن للمنافسين المتوفر لديهم مخزون فقط.
				"compLowest"		: 123.56,  // أقل المنافسين سعراً.
				"compLowestVsMe"	: 123.56,  // مثل "compAvgVsMe" ولكن للأقل سعراً بدلاً من المتوسط.
				"compInLowest"		: 123.56,  // أقل منافس سعراً ممن لديهم مخزون.
				"compInLowestVsMe"	: 123.56,  // مثل "compInAvgVsMe" ولكن ...
				"compHighest"		: 123.56,  // أعلى المنافسين سعراً.
				"compHighestVsMe"	: 123.56,  // مثل "compAvgVsMe" ولكن ...
				"compInHighest"		: 123.56,  // أعلى منافس سعراً ممن لديهم مخزون.
				"compInHighestVsMe"	: 123.56,  // مثل "compInAvgVsMe" ولكن ...
			},
			"competitors"	: [
				// مصفوفة منافسين من الأرخص إلى الأغلى، وكل منافس كائن:
				...
				{
					"url"		: "https://...",  // يشمل أي تعديل hashtag أضفته.
					"ref"		: "example.com/123abc...def",
					// مرجع الرابط: النطاق الجذري متبوعاً ببصمة md5 من 32 محرفاً؛ هكذا نعرّف الروابط داخلياً.
					"domain"	: "example.com",  // النطاق الجذري لهذا المنافس.
					"price"		: 1234.90,  // آخر مبلغ رُصد على الموقع، بعد أي حسابات وفق إعداداتك.
					"currency"	: "USD",  // العملة المكتشفة على الموقع.
					"priceConv"	: 1234.90,  // السعر محوّل إلى "convCurrency".
					"stock"		: "5",  // المخزون (سلسلة نصية): "A" = متوفر، "2" = قطعتان، "0" = نفد، "" = غير معروف.
					"salesWk"	: 123,  // المبيعات الأسبوعية المقدرة إن توفرت (انظر علامة الاستفهام في صفحة المنتج).
					"screenshotURL"	: "https://pricezag.com/.../screenshot.png",
					// إذا فُعّل "withScreenshots": رابط أحدث لقطة شاشة، متاح علناً عبر الرابط الطويل دون تسجيل دخول.
					"confidence"	: 98,
					// نسبة الثقة في صحة السعر المستخرج (راجع شرح (?) في صفحة المنتج).
					// دون 70% (قابل للتعديل) نعرض علامة استفهام بجانب السعر لبيان أنه غير موثوق.
					// هذا مستقل عن مستوى التعطل: قد يكون الرابط معطلاً حالياً رغم ثقتنا بصحة السعر السابق،
					// أو سليماً من حيث الزيارة لكننا غير متأكدين من السعر المستخرج.
					"sick"		: 0,  // مستوى تعطل الرابط من 0 إلى 3.
					// 0: نجحت آخر زيارة وعُثر على سعر في الصفحة.
					// 1: فشلت آخر زيارة لكننا نجحنا مؤخراً؛ هذا أمر عادي.
					// 2: لم نتمكن من الحصول على سعر صالح منذ أيام عديدة.
					// 3: لم نتمكن من الحصول على سعر صالح منذ أسابيع عديدة.
					// لا يظهر الحقلان "price" و"priceConv" إلا عندما يكون مستوى التعطل 0 أو 1. لا توجد أسعار للمستويين 2 و3.
				},
				...
			],
			"custom"	: {
				// هذه هي حقولك المخصصة. للتفاصيل افتح
				// صفحة منتج في الواجهة وانقر على (?) بجانب مربع CUSTOM FIELDS.
				// إذا لم توجد حقول مخصصة، يُحذف كائن "custom" بالكامل.
				"variable_1"	: "value 1",  // تُعاد القيم دائماً كسلاسل نصية حتى إن كانت أرقاماً.
				"variable_2"	: "value 2",  // ولا توجد قيمة فارغة، لأنها كانت ستؤدي إلى حذف المتغير.
				...
			}
		},
		...
	]
}

productGetAll — استرجاع جميع المنتجات

احرص على ضبط timeout على قيمة مرتفعة بما يكفي، فقد يستغرق الخادم وقتاً بحسب عدد المنتجات والمنافسين.
{ "actions" : [
	...
	{
		"a"			: "productGetAll",
		"currency"		: "EUR",  // (اختياري) حوّل جميع المبالغ إلى هذه العملة بدلاً من عملة كل منتج.
		"withStats"		: 1,  // (اختياري) أعد كائن الإحصاءات.
		"noCompetitors"		: 1,  // (اختياري) لا تُعد مصفوفة المنافسين لتقليل حجم البيانات.
		"noComments"		: 1,  // (اختياري) لا تُعد التعليقات (...)
		"withScreenshots"	: 1,  // (اختياري) أعد رابط أحدث لقطة شاشة لكل منافس.
		"sickMax"		: 2,  // (اختياري، الافتراضي 1) من 0 إلى 3: أعد روابط المنافسين بمستوى تعطل لا يتجاوز N.
	},
	...
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"		: "productGetAll",
			"ok"		: 10,  // إجمالي عدد المنتجات.
			"products"	: [ // مصفوفة منتجات مرتبة أبجدياً ورقمياً حسب الرمز المرجعي؛ كل منتج كائن:
				...
				{ ... },  // كائن منتج مطابق لما تعيده productGet أعلاه.
				...
			],
		},
		...
	]
}
قد تفيدك أيضاً عملية categoryGet .

الفئات

categoryCreate — إنشاء فئة جديدة

هذه هي الوظيفة نفسها التي تستخدمها واجهة المستخدم في صفحة Categories، عند النقر على زر New Category . يتيح API أيضاً إسناد المنتجات أثناء إنشاء الفئة.
بخلاف عمليات أخرى تقبل فئات موجودة وجديدة (مثل productCreate)، تفشل هذه العملية إذا كانت الفئة موجودة بالفعل.
{ "actions" : [
	...
	{
		"a"		: "categoryCreate",
		"name"		: "The New Category Name",
		"name"		: ["New Category 1", "New Category 2"],  // يمكن أيضاً تمرير مصفوفة.
		"products"	: ["REF-CODE-1", "REF-CODE-2"],  // (اختياري) أضف هذه المنتجات إلى الفئة أو الفئات عند إنشائها.
		"comments"	: "Some comments\nAnd another line",  // (اختياري) 1,000 محرف UTF-8 كحد أقصى
	},
	...
] }

categoryEdit — تعديل فئة موجودة

يمكنك أيضاً مراجعة عملية productCategories لتختار ما يناسبك.
{ "actions" : [
	...
	{
		"a"			: "categoryEdit",
		"name"			: "The Category Name",		// دون حساسية لحالة الأحرف.
		"newName"		: "The Category Renamed",  // (اختياري)
		"products"		: ["REF-CODE-1", "REF-CODE-2"],  // (اختياري) استبدل قائمة المنتجات كاملة.
		"productsAdd"		: ["REF-CODE-1", "REF-CODE-2"],  // (اختياري) أضف هذه المنتجات إلى الفئة.
		"productsRemove"	: ["REF-CODE-3", "REF-CODE-4"],  // (اختياري) أزل هذه المنتجات من الفئة دون حذفها.
		"comments"		: "To overwrite the comments.",  // (اختياري) 1,000 محرف UTF-8 كحد أقصى
	},
	...
] }
في الواقع، "products"، "productsAdd" و "productsRemove" تغير جميعها المنتجات التابعة للفئة، لكن بطرق مختلفة. لإزالة جميع المنتجات من الفئة استخدم "products" : []
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"			: "categoryEdit",
			"ok"			: 5,  // عدد التغييرات المنفذة.
			// إعادة التسمية أو تعديل التعليقات يُحسب تغييراً واحداً، وكذلك إضافة أو إزالة كل منتج.
			"name"			: "The Category Name",  // الاسم الجديد إذا تغير، وإلا فالاسم السابق.
			"productsCount"		: 30,  // عدد المنتجات الحالي في هذه الفئة، سواء تغير أم لا.
			"productsAdded"		: 2,  // عدد المنتجات المضافة إلى الفئة.
			"productsRemoved"	: 2,  // عدد المنتجات المزالة من الفئة.
		},
		...
	]
}

categoryDelete — حذف فئة واحدة أو عدة فئات

هذه هي الوظيفة نفسها التي تستخدمها الواجهة عندما تفتح Categories وتحدد الفئات ثم تنقر على Selected Categories › Delete.
{ "actions" : [
	...
	{
		"a"			: "categoryDelete",
		"name"			: "The Category Name",  // سلسلة دون حساسية لحالة الأحرف، أو:
		"name"			: ["Category 1", "Category 2"],  // يمكن أيضاً تمرير مصفوفة لحذف عدة فئات (بحد أقصى 1,000).
		"deleteProducts"	: 1,
		// افتراضياً تُحذف الفئة وتزول عضوية المنتجات فيها فقط،
		// لكن مع deleteProducts تُحذف جميع منتجات الفئة دون طلب تأكيد،
		// وتُحذف معها روابط المنافسين دون أي إمكانية لاستعادتها!
	},
	...
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"			: "categoryDelete",
			"ok"			: 2,  // عدد الفئات المحذوفة.
			"productsCount"		: 123,  // عدد المنتجات المعنية بهذه الفئات.
			"productsDeleted"	: 123,  // عدد المنتجات المحذوفة نتيجة الخيار "deleteProducts".
			// يُحسب المنتج الذي ينتمي إلى عدة فئات محددة مرة واحدة فقط.
		},
		...
	]
}

categoryCopy — نسخ المنتجات أو نقلها بين الفئات

انسخ المنتجات أو انقلها من الفئات المصدر إلى فئات وجهة موجودة أو جديدة. ويمكنك أيضاً دمج الفئات (راجع الأمثلة في نهاية الصفحة).
لا تحذف هذه العملية أياً من المنتجات؛ إنها تغير فقط الفئات التي تنتمي إليها.
هذه هي الوظيفة نفسها التي تستخدمها الواجهة عندما تفتح Categories وتحدد الفئات ثم تنقر على Selected Categories › Copy & More. يمكنك مراجعة الصفحة لمزيد من التفاصيل.
{ "actions" : [
	...
	{
		"a"			: "categoryCopy",
		"categoriesFrom"	: ["Category 1", "Category 2"],  // طابق المنتجات من هذه الفئات المصدر.
		"removeMode"		: "cat",  // (اختياري) أزل المنتجات المقابلة من فئات "categoriesFrom" المقدمة.
		"removeMode"		: "all",  // (اختياري) أزل المنتجات من جميع فئاتها.
		// إذا حُذف "removeMode"، تبقى المنتجات في "categoriesFrom" وتُضاف إلى "categoriesTo" (نسخ لا نقل).
		"deleteMode"		: "cat",  // (اختياري) احذف فئات "categoriesFrom" بعد نسخ المنتجات.
		"deleteMode"		: "all",  // (اختياري) احذف جميع الفئات التي تنتمي إليها هذه المنتجات.
		// إذا حُذف "deleteMode"، تبقى فئات "categoriesFrom" حتى بعد إزالة المنتجات منها باستخدام "removeMode".
		"categoriesTo"		: ["Another Category 1", "Another Category 2"],
		// أضف جميع المنتجات المطابقة إلى فئات الوجهة (تُنشأ إن لم تكن موجودة).
		"categoriesToClear"	: 1,  // (اختياري) أفرغ فئات الوجهة أولاً قبل إضافة المنتجات.
	},
	...
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"			: "categoryCopy",
			"ok"			: 3,  // عدد الفئات التي تغيرت، المصدر والوجهة.
			// "ok" يساوي مجموع categoriesModified + categoriesCreated + categoriesDeleted.
			"categoriesModified"	: 2,  // عدد الفئات الموجودة التي تغيرت (المصدر والوجهة).
			"categoriesCreated"	: 1,  // عدد الفئات الجديدة المنشأة.
			"categoriesDeleted"	: 0,  // عدد الفئات المحذوفة بسبب "deleteMode".
			"productsCount"		: 123,  // عدد المنتجات المطابقة لـ"categoriesFrom" المقدم.
			// يُحسب المنتج المنتمي إلى عدة فئات في "categoriesFrom" مرة واحدة فقط.
		},
		...
	]
}

categoryGet — استرجاع فئة

{ "actions" : [
	...
	{
		"a"		: "categoryGet",
		"name"		: "The Category Name",  // دون حساسية لحالة الأحرف.
		"currency"	: "EUR",  // مطلوب إذا استخدمت withStats أو withProducts؛ عملة الإحصاءات.
		"withStats"	: 1,  // أعد الإحصاءات أيضاً (أبطأ).
		"withProducts"	: 1,  // أعد منتجات الفئة أيضاً (قد ينتج بيانات كثيرة).
		"noCompetitors"	: 1,  // مع withProducts: لا تُعد مصفوفة المنافسين لتصغير البيانات.
		"noComments"	: 1,  // مع withProducts: لا تُعد تعليقات المنتجات (تظل تعليقات الفئة معادة).
	},
	...
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"			: "categoryGet",
			"ok"			: 1,
			"name"			: "The Category Name",
			"created"		: 1234567890,  // وقت Epoch.
			"createdBy"		: "SOMEUSER",  // اسم مستخدم أو "API".
			"comments"		: "Comments of this category",
			"commentsLast"		: 1234567890,  // وقت Epoch لآخر تعديل للتعليقات، إن وُجد.
			"commentsLastBy"	: "SOMEUSER",  // اسم مستخدم أو "API".
			"productsCount"		: 10,  // عدد المنتجات في هذه الفئة.
			"stats"		: {
				// هذه هي الإحصاءات المعروضة في صفحة الفئة وأعمدة قائمة الفئات بالواجهة.
				// للتفاصيل، أضفها أعمدةً في قائمة الفئات وانقر على (?).
				// جميع المبالغ بعملة "currency" المحددة في الطلب.
				// تحذير: عند عدم توفر مبلغ (مثل compIn* بلا منافسين متاحين)، تكون القيمة 0.
				"priceAvg"		: 123.45,  // متوسط سعرك.
				"costAvg"		: 123.45,  // لا تدخل في هذا المتوسط إلا المنتجات التي لها تكلفة معروفة.
				"marginAvg"		: 10.5,  // نسبة مئوية (قد تكون سالبة؛ تُحسب المنتجات ذات التكلفة فقط).
				"rankAvg"		: 1.23,  // متوسط ترتيب سعرك (1 = لا منافس أقل سعراً منك).
				"rankInAvg"		: 1.23,  // متوسط ترتيبك بين المنافسين المتوفر لديهم مخزون.
				"productsCountComp"	: 9,  // عدد المنتجات التي لها منافسون.
				"productsCountCompIn"	: 7,  // عدد المنتجات التي لها منافسون متوفر لديهم مخزون.
				"compAvg"		: 123.56,  // متوسط متوسطات أسعار جميع المنافسين.
				"compAvgVsMe"		: 123.56,  // متوسط الفارق بالعملة المحددة بين سعرك وأسعار المنافسين (السالب = سعرك أقل).
				"compInAvg"		: 123.56,  // مثل "compAvg" لكن للمنافسين المتوفر لديهم مخزون فقط.
				"compInAvgVsMe"		: 123.56,  // مثل "compAvgVsMe" ولكن للمنافسين المتوفر لديهم مخزون فقط.
				"compLowest"		: 123.56,  // مثل "compAvg" ولكن متوسط أقل منافس سعراً لكل منتج.
				"compLowestVsMe"	: 123.56,  // مثل "compAvgVsMe" ولكن ...
				"compInLowest"		: 123.56,  // مثل "compInAvg" ولكن ...
				"compInLowestVsMe"	: 123.56,  // مثل "compInAvgVsMe" ولكن ...
				"compHighest"		: 123.56,  // مثل "compAvg" ولكن متوسط أعلى منافس سعراً لكل منتج.
				"compHighestVsMe"	: 123.56,  // مثل "compAvgVsMe" ولكن ...
				"compInHighest"		: 123.56,  // مثل "compInAvg" ولكن ...
				"compInHighestVsMe"	: 123.56,  // مثل "compInAvgVsMe" ولكن ...
			},
			"products"	: [ // مصفوفة منتجات مرتبة أبجدياً ورقمياً حسب الرمز المرجعي؛ كل منتج كائن:
				...
				{ ... },  // كائن منتج كما تعيده productGet.
				...
			],
		},
		...
	]
}

categoryGetAll — استرجاع جميع الفئات

بخلاف categoryGet، فإن عملية categoryGetAll لا تعيد بيانات تفصيلية لكل منتج، لأن المنتج قد ينتمي إلى عدة فئات مما ينتج بيانات ضخمة ومكررة. إذا أردت تفاصيل المنتجات، استخدم categoryGet لكل فئة، أو productGetAll ثم رتب النتائج حسب الفئة.
{ "actions" : [
	...
	{
		"a"		: "categoryGetAll",
		"withStats"	: 1,  // أعد الإحصاءات أيضاً (أبطأ).
		"noComments"	: 1,  // لا تُعد التعليقات لتقليل حجم البيانات.
		"noProducts"	: 1,  // لا تُعد مصفوفة المنتجات (...).
	},
	...
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"		: "categoryGetAll",
			"ok"		: 10,  // إجمالي عدد الفئات (طول مصفوفة "categories").
			"categories"	: [ // مصفوفة الفئات مرتبة أبجدياً؛ كل فئة كائن:
				...
				{
					"name"			: "The Category Name",
					"created"		: 1234567890,  // وقت Epoch.
					"createdBy"		: "SOMEUSER",  // اسم مستخدم أو "API".
					"comments"		: "Comments of this category",
					"commentsLast"		: 1234567890,  // وقت Epoch لآخر تعديل للتعليقات، إن وُجد.
					"commentsLastBy"	: "SOMEUSER",  // اسم مستخدم أو "API".
					"productsCount"		: 2,  // عدد المنتجات في هذه الفئة.
					"products"	: ["REF-CODE-1", "REF-CODE-2"],  // الرموز المرجعية لمنتجاتها مرتبة، ما لم يكن noProducts=1.
					"stats"		: {
						// إذا فُعّل "withStats"، نفس كائن الإحصاءات الذي تعيده categoryGet أعلاه.
						...
					},
				}
				...
			],
		},
		...
	]
}

التنبيهات

alertRecipientCreate — إنشاء مستلم تنبيهات جديد

هذه هي الوظيفة نفسها التي تستخدمها الواجهة عندما تفتح Alerts وتنقر على New Recipient .
للحصول على تفاصيل كل حقل، انقر على أيقونات علامات الاستفهام الخضراء في حسابك.
{ "actions" : [
	...
	{
		"a"		: "alertRecipientCreate",
		"email"		: "john@example.net",  // يمكن أيضاً إدخال رقم هاتف لتنبيهات SMS؛ راجع المساعدة بالواجهة.
		"name"		: "john",  // اسم عرض بسيط، عادة الاسم الأول (دون حساسية لحالة الأحرف).
		"maxFrequency"	: 1800,  // (اختياري، الافتراضي 7200) راجع المساعدة في الواجهة.
		"simplify"	: 0,  // (اختياري، الافتراضي 1) تفعيل التبسيط؛ راجع المساعدة بالواجهة.
		"sleepEnabled"	: 1,  // (اختياري) تفعيل فترة عدم الإزعاج.
		"sleepFrom"	: "18:30",  // (فقط عند sleepEnabled) تنسيق 24 ساعة.
		"sleepTo"	: "07:00",  // (فقط عند sleepEnabled) تنسيق 24 ساعة.
		"timezone"	: "America/Los_Angeles",  // (فقط عند sleepEnabled) مسار ملف Linux ضمن /usr/share/zoneinfo.
				// تُستبدل المسافات بشرطات سفلية.
				// ابحث عن المنطقة الزمنية في نموذج [New Recipient] بالواجهة للتأكد من القيمة الصحيحة.
		"status"	: "hold",  // (اختياري) اضبط "hold" أو "disable". أي قيمة أخرى مثل "" تعني نشطاً.
		"rules"		: [...],  // (اختياري) قواعد التنبيه الأولية (مصفوفة كائنات قواعد)، مثل "rulesAdd" في alertRecipientEdit أدناه.
	},
	...
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"	: "alertRecipientCreate",
			"ok"	: 1,
		},
		...
	]
}

alertRecipientEdit — تعديل مستلم تنبيهات و/أو قواعده

هذه هي الوظيفة نفسها التي تستخدمها الواجهة عندما تفتح Alerts وتنقر على Settings أو Rules الخاصة بالمستلم.
للحصول على تفاصيل كل حقل، انقر على أيقونات علامات الاستفهام الخضراء في حسابك.
تعرض صفحة "email" يحدد المستلم الذي سيجري تحديثه. وتغير الحقول الأخرى إعدادات ذلك المستلم.
{ "actions" : [
	...
	{
		"a"		: "alertRecipientEdit",
		"email"		: "john@example.net",  // البريد الإلكتروني أو الهاتف الحالي (بالتنسيق الذي تعيده alertGetAll).
		"newEmail"	: "john2@example.net",  // (اختياري) بريد إلكتروني أو رقم هاتف جديد؛ راجع المساعدة بالواجهة.
		"name"		: "john2",  // (اختياري) اسم جديد.
		"maxFrequency"	: 1800,  // (اختياري) راجع المساعدة بالواجهة.
		"simplify"	: 1,  // (اختياري) تفعيل التبسيط؛ راجع المساعدة بالواجهة.
		"sleepEnabled"	: 1,  // (اختياري) تفعيل فترة عدم الإزعاج.
		"sleepFrom"	: "18:30",  // (فقط عند sleepEnabled) تنسيق 24 ساعة.
		"sleepTo"	: "07:00",  // (فقط عند sleepEnabled) تنسيق 24 ساعة.
		"timezone"	: "America/Los_Angeles",  // (عند sleepEnabled فقط) راجع alertRecipientCreate أعلاه.
		"status"	: "hold",  // (اختياري) "hold" أو "disable"؛ أي قيمة أخرى مثل "" تجعل الحالة "active".
		"rules"		: [{ruleObject}, {ruleObject}],  // (اختياري) استبدال جميع القواعد الحالية (مصفوفة فارغة لإزالة الكل).
				  // لا ترسل مصفوفة "rules" إذا أردت الاحتفاظ بالقواعد الحالية.
		"rulesAdd"	: [ // (اختياري) إضافة هذه القواعد إلى القواعد الحالية.
			...
			{  // هذا هو تنسيق كائن القاعدة:
				"name"		: "me_cross_avg",  // في صفحة Alerts افتح [Rules] > [+ New Rule] واختر قاعدة لعرض اسمها في API.
				"disabled"	: 1,  // (اختياري) قد لا يكون إنشاء قاعدة معطلة منطقياً، لكن alertRuleEdit قد يستخدم ذلك.
				"var_n"		: 123.00,  // يتحول المتغير "X" إلى "var_x"،
				"var_c"		: "USD",  // لذا استخدم المعاملات التي تتطلبها القاعدة،
				"var_h"		: 24,  // وبعض القواعد لا تحتاج إلى أي متغير.
				"direction"	: "both",  // أو "drop" أو "rise" إذا كانت للقاعدة جهة.
				"categories"	: ["The Category 1", "The Category 2"],  // (اختياري) فارغ أو محذوف = جميع المنتجات.
				"ignoreOos"	: 1,  // (اختياري) تجاهل المنافسين الذين نفد مخزونهم (راجع الواجهة).
				"urlInclude"	: "",  // (اختياري، دون حساسية لحالة الأحرف).
				"urlExclude"	: "amazon",  // (اختياري، دون حساسية لحالة الأحرف).
				// "ruleNumber" هو معرّف القاعدة، مثلاً لتعديلها أو حذفها لاحقاً.
				// سيظهر عند قراءة القواعد، لكن لا يمكنك تحديده بنفسك.
			}
			...
		],
		"rulesRemove"	: [1,4,7],  // (اختياري) قيم "ruleNumber" للقواعد المراد إزالتها.
					// تحصل على "ruleNumber" من عملية alertGetAll أدناه.
					// لإزالة جميع القواعد استخدم "rules" = [] ببساطة.
	},
	...
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"	: "alertRecipientEdit",
			"ok"	: 3,  // عدد التغييرات (المتغيرات والقواعد المضافة أو المحذوفة).
		},
		...
	]
}

alertRecipientDelete — حذف مستلم تنبيهات

الحذف نهائي. تُحذف جميع قواعد تنبيهات هذا المستلم وسجلاتها فوراً دون إمكانية استعادتها.
{ "actions" : [
	...
	{
		"a"		: "alertRecipientDelete",
		"email"		: "john@example.net",  // البريد الإلكتروني أو الهاتف الحالي (بالتنسيق الذي تعيده alertGetAll).
	},
	...
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"	: "alertRecipientDelete",
			"ok"	: 1,
		},
		...
	]
}

alertRuleEdit — تعديل قاعدة تنبيه موجودة

تتيح هذه العملية تعديل قاعدة تنبيه موجودة واحدة بدلاً من استبدال قواعد أو إضافة قواعد. وتستخدم غالباً لتغيير المتغير N أو تفعيل قاعدة أو تعطيلها.
لإزالة قاعدة، استخدم مصفوفة "rulesRemove" في عملية alertRecipientEdit ؛ ولإضافة قاعدة جديدة استخدم مصفوفة "rulesAdd" في العملية نفسها.
{ "actions" : [
	...
	{
		"a"		: "alertRuleEdit",
		"email"		: "john@example.net",  // بريد المستلم الإلكتروني أو هاتفه، بالتنسيق الذي تعيده alertGetAll.
		"ruleNumber"	: 1,  // الرقم المرجعي للقاعدة المراد تعديلها كما تعيده alertGetAll.
		"rule"		: {
			// المتغيرات المطلوب استبدالها؛ راجع "rulesAdd" في alertRecipientEdit أعلاه لتنسيق كائن القاعدة.
			"disabled"	: 1,  // مثلاً لتفعيل قاعدة أو تعطيلها.
			"var_n"		: 5,  // أو أي متغير آخر مثل N بحسب نوع القاعدة.
			...
		},
	},
	...
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"	: "alertRuleEdit",
			"ok"	: 1,  // عدد المتغيرات المعدلة.
		},
		...
	]
}

alertGetAll — استرجاع جميع مستلمي التنبيهات وقواعدهم

{ "actions" : [
	...
	{
		"a"	: "alertGetAll",
		// هذه العملية لا تأخذ معاملات.
	},
	...
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"		: "alertGetAll",
			"ok"		: 3,  // عدد المستلمين (طول مصفوفة "recipients").
			"recipients"	: [ // مصفوفة جميع المستلمين؛ كل واحد كائن كما في alertRecipientCreate أعلاه.
				...
				{
					"email"		: "john@example.net",
					"name"		: "john",
					"maxFrequency"	: 1800,
					"simplify"	: 0,
					"sleepEnabled"	: 1,
					"sleepFrom"	: "18:30",
					"sleepTo"	: "07:00",
					"timezone"	: "America/Los_Angeles",
					"status"	: "active",
					"rules"		: [ // مصفوفة قواعد؛ كل واحدة كائن موضح في alertRecipientEdit أعلاه.
						...
						{
							"ruleNumber"	: 4,  // رقم مرجعي يُستخدم عند تعديل هذه القاعدة بواسطة alertRuleEdit.
							"name"		: "me_cross_avg",
							"disabled"	: 0,
							"var_n"		: "123.00",  // تُعاد جميع المتغيرات كسلاسل نصية حتى لو كانت أرقاماً.
							"var_c"		: "USD",
							"var_h"		: "24",
							"direction"	: "both",
							"categories"	: [],  // قيمة فارغة = جميع المنتجات.
							"ignoreOos"	: 0,
							"urlInclude"	: "",
							"urlExclude"	: "amazon",
						}
						...
					],
				}
				...
			],
		},
		...
	]
}

قواعد إعادة التسعير

repricingCreate — إنشاء قاعدة إعادة تسعير

هذه هي الوظيفة نفسها التي تستخدمها الواجهة عندما تفتح Repricing وانقر على New Repricing Rule .
للحصول على تفاصيل كل حقل، انقر على أيقونات علامات الاستفهام الخضراء في حسابك.
كيف تربط المنتجات بالقاعدة؟ بتعديل المنتجات نفسها باستخدام productEdit أو productRepricing . القاعدة لا «تحتوي» على منتجات فعلياً؛ بل يشير كل منتج إلى القاعدة التي يستخدمها.
{ "actions" : [
	...
	{
		"a"	: "repricingCreate",
		"name"	: "The Rule Name",  // 50 محرفاً كحد أقصى.
		"init"	: { // كائن تحديد السعر المبدئي (السطر الأول "Set my price to").
			"target"	: "cheapest_n",  // (راجع القائمة أدناه).
			"var_n"		: 3,  // فقط إذا تطلب الهدف متغير N.
			"plusAmount"	: -2,  // موجب = فوق، سالب = تحت.
			"plusCurrency"	: "%",  // عملة (مثلاً "USD") أو "%".
			// المعنى: «اضبط سعري أقل بنسبة 2% من متوسط أسعار أرخص ثلاثة منافسين».
			// تحذير: بخلاف كائنات "never" أدناه، لا يوجد "direction" للمحدد المبدئي. إشارة "plusAmount" تحدد فوق/تحت.
		},
		"never"	: [ // (اختياري) شروط «لكن لا تسمح أبداً» تُنفذ بالترتيب (حتى 10).
			{
				"target"	: "cheapest_n_in",  // (راجع القائمة أدناه).
				"var_n"		: 1,  // فقط إذا تطلب الهدف متغير N.
				"direction"	: "below",  // أو "above".
				"plusAmount"	: -10,  // موجب للإضافة وسالب للطرح (مطلوب حتى لو كان 0).
				"plusCurrency"	: "USD",  // عملة أو "%" (مطلوب حتى إذا كان plusAmount=0).
				// المعنى: «لكن لا يقل أبداً عن أرخص منافس متوفر لديه مخزون ناقص 10.00 USD».
			},
			{
				"target"	: "cost",
				"direction"	: "below",
				"plusAmount"	: 5,
				"plusCurrency"	: "%",
				// المعنى: «لكن لا يقل أبداً عن تكلفتي مضافاً إليها 5%».
			}
		],
		"ignoreDomains"	: "amazon ebay.com MyLabel1",  // (اختياري) نطاقات أو تسميات منافسين لتجاهلها (دون حساسية لحالة الأحرف؛ راجع الواجهة).
		"charm"		: "none|zeros|charm",  // (اختياري، الافتراضي "none") التسعير النفسي؛ "" و"none" وحذف القيمة تعني الشيء نفسه.
		"confidence"	: 82,  // (اختياري، الافتراضي 70) الحد الأدنى لنسبة الثقة 0–99 (راجع الواجهة).
		"disabled"	: 1,  // (اختياري)
	},
	...
] }
// جميع قيم "target" المتاحة:
// "average": متوسط جميع المنافسين.
// "average_in": متوسط المنافسين المتوفر لديهم مخزون.
// "cheapest_n": متوسط أرخص N منافسين (أو الأرخص إذا N=1).
// "cheapest_n_in": متوسط أرخص N منافسين متوفر لديهم مخزون.
// "highest_n": متوسط أعلى N منافسين سعراً.
// "highest_n_in": متوسط أعلى N منافسين سعراً ممن لديهم مخزون.
// "cost": تكلفتي.
// "me_avg_n": متوسط سعري خلال آخر N ساعة (للحد من سرعة تغير السعر).
// "domain:example.com": سعر example.com (الأدنى إذا تعددت الروابط من النطاق).
// "domainIn:example.com": سعر example.com فقط إذا كان المنتج متوفراً.
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"	: "repricingCreate",
			"ok"	: 3,  // عدد الكائنات المحللة والمحفوظة بنجاح (مثلاً init + never[0] + never[1] = 3).
			"name"	: "The Rule Name",  // اسم القاعدة النهائي في قاعدة البيانات (قد تُحوّل المحارف الخاصة).
		},
		...
	]
}

repricingEdit — تعديل قاعدة إعادة تسعير موجودة

تعديل قاعدة إعادة تسعير موجودة.
راجع repricingCreate أعلاه لفهم كيفية عمل هذه المتغيرات.
تغيّر هذه العملية القاعدة نفسها، لا المنتجات المرتبطة بها. لربط المنتجات بالقواعد استخدم productEdit أو productRepricing أنسب.
{ "actions" : [
	...
	{
		"a"		: "repricingEdit",
		"name"		: "The Rule Name",  // دون حساسية لحالة الأحرف.
		"newName"	: "The Rule Renamed",  // (اختياري) 50 محرفاً كحد أقصى.
		"init"		: { // (اختياري) استبدال متغيرات كائن التحديد المبدئي المقدمة (راجع repricingCreate).
			"plusAmount"	: 1,  // مثلاً يمكنك تغيير "plusAmount" فقط وإبقاء بقية المتغيرات كما هي.
			// تحذير: إذا احتاج "target" الجديد إلى المتغير N، فعليك تقديم "var_n".
		},
		"never"		: [...], // (اختياري) يمكنك استبدال مصفوفة "never" كلها، لكن يُفضل غالباً استخدام never_*.
		// يعني هذا أن "never":[] يمحو جميع الشروط. للاحتفاظ بها، احذف هذا المتغير من الطلب.
		"never_0"	: { // (اختياري) استبدل كائن «لكن لا تسمح أبداً» الأول (فهرس المصفوفة 0).
			"var_n"		: 2,  // مثلاً يمكنك تغيير "var_n" فقط مع إبقاء بقية المتغيرات.
		},
		"never_2"	: {
			"target"	: "",  // تعطيل شرط «لكن لا تسمح أبداً» الثالث (فهرس المصفوفة 2).
			// إذا ضُبط "target" على ""، فلا داعي للاهتمام بباقي متغيرات الكائن.
			// تؤدي "never_2":{} النتيجة نفسها.
		},
		"never_6"	: {...}, // يمكن أن يكون شرطاً جديداً من «لكن لا تسمح أبداً»، وحينها يجب تقديم جميع المتغيرات كما في repricingCreate.
		// "never_9" هو الحد الأقصى لأن مصفوفة "never" تتسع إلى 10 عناصر.
		"ignoreDomains"	: "",  // (اختياري) مثل repricingCreate.
		"charm"		: "zeros",  // (اختياري) ...
		"confidence"	: 82,  // (اختياري) ...
		"disabled"	: 1,  // (اختياري) 0 لتفعيل قاعدة معطلة حالياً.
	},
	...
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"	: "repricingEdit",
			"ok"	: 3,  // عدد التغييرات (مثلاً متغير في never_N وآخر في "init" و"charm").
			"name"	: "The Rule Name",  // الاسم النهائي الجديد في قاعدة البيانات (قد تُحوّل المحارف الخاصة).
		},
		...
	]
}

repricingDelete — حذف قاعدة إعادة تسعير

الحذف نهائي. تُحذف القاعدة فوراً وبصورة نهائية. وستصبح المنتجات التي كانت تستخدمها بلا قاعدة، فتفشل إعادة تسعيرها.
{ "actions" : [
	...
	{
		"a"		: "repricingDelete",
		"name"		: "The Rule Name",  // دون حساسية لحالة الأحرف.
		"onlyIfUnused"	: 1,  // (اختياري) للأمان، أعد خطأ إذا كانت منتجات تستخدم هذه القاعدة.
	},
	...
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"		: "repricingDelete",
			"ok"		: 1,
			"productsCount"	: 10,  // عدد المنتجات التي كانت تستخدم هذه القاعدة وأصبحت بلا قاعدة.
		},
		...
	]
}

repricingGetAll — استرجاع جميع قواعد إعادة التسعير

راجع أولاً repricingCreate أعلاه، لأن تنسيق البيانات المعادة هنا يشبه كثيراً تنسيق ما ترسله إلى repricingCreate.
{ "actions" : [
	...
	{
		"a"	: "repricingGetAll",
		// هذه العملية لا تأخذ معاملات أخرى.
	},
	...
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"	: "repricingGetAll",
			"ok"	: 10,  // إجمالي عدد القواعد (طول مصفوفة "rules").
			"rules"	: [ // مصفوفة قواعد إعادة التسعير مرتبة أبجدياً؛ كل قاعدة كائن:
				...
				{
					"name"		: "Some Repricing Rule",
					"created"	: 1234567890,  // وقت Epoch لإنشاء القاعدة.
					"createdBy"	: "SOMEUSER",  // اسم مستخدم أو "API".
					"edited"	: 1234567890,  // وقت آخر تعديل، إن وُجد، وإلا فلا يظهر الحقل.
					"editedBy"	: "SOMEUSER",  // اسم مستخدم أو "API"، أو قد يكون غائباً.
					"disabled"	: 1234567890,  // إذا كانت القاعدة معطلة، يظهر وقت Epoch لآخر تعطيل؛ وإلا فلا يظهر.
					"disabledBy"	: "SOMEUSER",  // اسم مستخدم أو "API"، أو قد يكون غائباً.
					"productsCount"	: 10,  // عدد المنتجات التي تستخدم القاعدة حالياً.
					"ignoreDomains"	: "amazon ebay.com MyLabel1",  // النطاقات أو تسميات المنافسين التي يتم تجاهلها (راجع الواجهة).
					"charm"		: "charm",  // وضع التسعير النفسي (none|zeros|charm).
					"confidence"	: 82,  // الحد الأدنى لنسبة الثقة 0–99 (راجع الواجهة).
					"init"	: { // كائن تحديد السعر المبدئي (السطر الأول "Set my price to").
						"target"	: "cheapest_n",  // (راجع القائمة في repricingCreate).
						"var_n"		: 3,  // إذا كان الهدف يتطلب N، وإلا فلا يظهر الحقل.
						"plusAmount"	: -2,  // موجب = فوق، سالب = تحت.
						"plusCurrency"	: "%",  // عملة (مثلاً "USD") أو "%".
						// المعنى: «اضبط سعري أقل بنسبة 2% من متوسط أسعار أرخص ثلاثة منافسين».
						// تحذير: بخلاف كائنات "never" أدناه، لا يوجد "direction" للمحدد المبدئي. إشارة "plusAmount" تحدد فوق/تحت.
					},
					"never"	: [ // كائنات «لكن لا تسمح أبداً»، بترتيب التنفيذ.
						{
							"target"	: "cheapest_n_in",
							"var_n"		: 1,
							"direction"	: "below",  // أو "above".
							"plusAmount"	: -10,  // موجب للإضافة وسالب للطرح.
							"plusCurrency"	: "USD",  // عملة أو "%".
							// المعنى: «لكن لا يقل أبداً عن أرخص منافس متوفر لديه مخزون ناقص 10.00 USD».
						},
						{},  // هذا يعني أنك تركت السطر الثاني من شروط «لكن لا تسمح أبداً» فارغاً.
						{
							"target"	: "cost",
							"direction"	: "below",
							"plusAmount"	: 5,
							"plusCurrency"	: "%",
							// المعنى: «لكن لا يقل أبداً عن تكلفتي مضافاً إليها 5%».
						}
					],
				}
				...
			],
		},
		...
	]
}

جداول البيانات

spreadsheetDownload — تنزيل جدول بيانات

هذه العملية استثناء: لا يمكن دمجها مع عمليات أخرى، وهي تعيد ملف جدول بيانات بدلاً من كائن استجابة JSON (إلا إذا استخدمت "savePreset" أو "downloadURL" أدناه)
وهي تعادل ما يمكنك فعله في صفحة Export في حسابك.
احرص على ضبط timeout على قيمة مرتفعة بما يكفي، فقد يستغرق إنشاء جدول بيانات كبير بعض الوقت.
طريقة سهلة: انقر على زر Show API equivalent في صفحة التصدير لإنشاء طلب JSON كامل (وأمر curl) يطابق الخيارات المحددة في النموذج.
{ "actions" : [
	{
		"a"		: "spreadsheetDownload",
		"preset"	: "Some Preset Name",  // (اختياري) بدلاً من إدخال التفاصيل أدناه، يمكنك استخدام أحد إعداداتك المسبقة أو إعداداتنا.
			// لإعدادك المسبق، قدم الاسم الكامل دون اسم المستخدم قبله أو العملة بعده.
			// لمعرفة أسماء إعداداتنا الافتراضية، افتح القائمة DIRECT DOWNLOAD في صفحة Export ومرر مؤشر الفأرة فوقها.
			// مثلاً "pricezag_backup" هو إعداد النسخ الاحتياطي الخاص بنا (راجع "Special BACKUP format to re-import" ضمن DIRECT DOWNLOAD).
			// يمكنك أيضاً تقديم متغيرات أخرى تتجاوز إعدادات القالب، مثل العملة أو التنسيق أو الفئات.
		"savePreset"	: "My New Preset Name",  // (اختياري) احفظ جميع الخيارات أدناه كإعداد مسبق جديد لاستخدامه في الواجهة وAPI.
			// استثناء للاستثناء: مع savePreset لا يتم تنزيل جدول بيانات، بل تعاد استجابة JSON عادية.
		"savePresetOverwrite"	: 1,  // (اختياري) استبدال إعداد مسبق موجود محدد في "savePreset"؛ وإلا يُعاد خطأ.
			// تحذير: الاستبدال يمحو كل إعدادات القالب السابق، وليس حقلاً واحداً فقط.
			// لإعادة تسمية إعداد مسبق أو حذفه، استخدم spreadsheetPresetEdit أدناه.
		"downloadURL"	: 1,  // (اختياري) استثناء آخر: بدلاً من ملف الجدول تُعاد استجابة JSON عادية مع "fileURL"،
			// وهو رابط عام للملف لا يتطلب مصادقة أو مفتاح API. يظل الملف متاحاً للجميع للتنزيل مدة 15 دقيقة.
			// تكون قيمة "ok" عدد الصفوف، ويظهر حجم الملف بالبايت في "fileSize".
		"format"	: "xlsx|xls|csv|csv-tab",  // الافتراضي csv عند استخدام API.
		"currency"	: "USD",  // مطلوب دون preset؛ العملة المستخدمة لكل المبالغ.
		"categories"	: ["Category 1", "Category 2"],  // أدرج فقط منتجات هذه الفئات؛ وإلا فجميع المنتجات.
		"historyPeriod"	: "prev_6mo",  // (اختياري، الافتراضي "now").
			// اقرأ أولاً شروح علامات الاستفهام (?) في صفحة Export عن الفترات التاريخية.
			// يحدد "historyPeriod" مدى الرجوع في التاريخ، قبل تقسيم البيانات إلى صفوف لكل منتج وفق "historyRow".
			// "now": بلا تاريخ؛ البيانات الحالية فقط (دون "historyRow").
			// "all": كامل الفترة منذ التسجيل، أو على الأقل للمنتجات المعنية. قد يكون بطيئاً.
			// "1234500000-1237800000": فترة مخصصة بين وقتَي Epoch للبداية والنهاية.
			// "123h": آخر 123 ساعة دون محاذاة للساعة؛ ينتهي النطاق الآن.
			// "cur_123(d|wk|mo|yr)": آخر 123 يوماً/أسبوعاً/شهراً/سنة، بما فيها الفترة الحالية غير المكتملة. "cur_2mo" في اليوم العاشر يغطي 40 يوماً.
			// "prev_123(d|wk|mo|yr)": آخر 123 فترة مكتملة. "prev_2mo" يوم 10 فبراير يغطي 62 يوماً من ديسمبر ويناير.
			// تبدأ فترات cur_* وprev_* وتنتهي prev_* عند منتصف الليل السابق، بينما تنتهي cur_* الآن،
			// لذا يغطي "cur_2d" عند الظهر آخر 36 ساعة، بينما يغطي "prev_2d" 48 ساعة تنتهي قبل 12 ساعة.
		"historyRow"	: "2w",  // مطلوب إذا لم يكن "historyPeriod" هو "now".
			// يحدد "historyRow" المدة التي يمثلها كل صف (متوسط الفترة)، ولهذا قد توجد عدة صفوف للمنتج، إلا عند "all".
			// يمكن اعتبار "historyRow" طريقة تقسيم "historyPeriod" إلى صفوف منفصلة لكل منتج.
			// "all": متوسط كامل historyPeriod في صف واحد لكل منتج.
			// "123(d|wk|mo|qt|yr)": فترات تقويمية من 123 يوماً/أسبوعاً/شهراً/ربع سنة/سنة تبدأ عند منتصف الليل. يمكن حذف الرقم إذا كان 1، مثل "wk" بدلاً من "1wk".
			// إذا نزّلت يوم السبت مع historyRow:"7d"، يمثل كل صف متوسط الفترة من السبت 00:00 إلى الجمعة 23:59.
			// أما historyRow:"1wk"، فيمثل كل صف أسبوعاً من الاثنين 00:00 إلى الأحد 23:59، والصف الأخير الأسبوع الحالي غير المكتمل من الاثنين إلى السبت.
			// ◀ حد 500,000 صف: ترفض الواجهة وAPI إعدادات التاريخ التي تنتج أكثر من نصف مليون صف.
			// قد يحدث ذلك بسهولة مع historyRow:"day" عندما يغطي historyPeriod مدى 365 يوماً و1,400 منتج.
			// في هذه الحالة نزّل جدولاً منفصلاً لكل فئة تضم بضع مئات من المنتجات.
		"timezone"	: "America/Los_Angeles",  // (اختياري، الافتراضي "UTC") بتنسيق مسار Linux داخل /usr/share/zoneinfo.
			// تُستبدل المسافات بشرطات سفلية.
			// تُحتاج المنطقة الزمنية فقط إذا كانت خيارات history* تعتمد على فترات تقويمية (لتحديد منتصف الليل).
			// تستخدم الواجهة المنطقة الزمنية المضبوطة للمستخدم؛ أما API فيحتاج إلى تقديمها ضمن الطلب.
		// ========== الأعمدة ==========
		// تحدد متغيرات column* الأعمدة التي تظهر في الجدول (راجع نموذج Export بالواجهة).
		// افتراضياً تكون جميعها 0 (العمود غائب)، باستثناء Code.
		"columnCode"		: 1,  // لا يمكن إزالة عمود REF-CODE لكل منتج.
		"columnName"		: 1,  // اسم المنتج.
		"columnCategories"	: 1,  // الفئات التي ينتمي إليها المنتج ("Category 1; Category 2" في خلية واحدة).
		"columnComments"	: 1,  // تعليقات المنتج.
		"columnCreated"		: 1,  // تاريخ إنشاء المنتج في النظام YYYY/MM/DD.
		"columnCustom"		: 1,  // الحقول المخصصة لمنتجاتك (عمود لكل متغير فريد).
		"columnPrice"		: 1,  // سعر المنتج بالعملة المطلوبة، وليس عملته الأصلية.
		"columnCost"		: 1,  // تكلفة المنتج (بالعملة المطلوبة).
		"columnMargin"		: 1,  // نسبة هامش الربح بناءً على السعر والتكلفة.
		"columnRank"		: 1,  // ترتيب سعري.
		"columnInRank"		: 1,  // ترتيبي بين المنافسين المتوفر لديهم مخزون.
		"columnMyWebsite"	: 1,  // رابط موقعي الإلكتروني.
		"columnReprice"		: 1,  // مبلغ إعادة التسعير (بالعملة المطلوبة).
		"columnRepricingRule"	: 1,  // اسم قاعدة إعادة التسعير.
		"columnRecommended"	: 1,  // السعر المقترح (راجع المساعدة في صفحة Export).
		"columnCompUrls"	: 1,  // روابط المنافسين، رابط في كل عمود.
		"columnCompUrlsJoin"	: 1,  // روابط المنافسين مفصولة بمسافات في خلية واحدة.
		"columnCompMinMaxAvg"	: 1,  // يضيف ثلاثة أعمدة: الحد الأدنى والأقصى ومتوسط المنافسين.
		"columnInCompMinMaxAvg"	: 1,  // يضيف ثلاثة أعمدة: الأدنى والأقصى والمتوسط للمنافسين المتوفر لديهم مخزون.
		"columnCompPrice"	: 1,  // عمود لكل منافس وسعره (بالعملة المطلوبة).
		"columnCompStock"	: 1,  // عمود لكل منافس ومخزونه (123|IN|OUT).
		"columnCompSales"	: 1,  // عمود لكل منافس ومبيعاته الأسبوعية.
		"columnCompRank"	: 1,  // عمود لكل منافس وترتيبه بين الجميع (بمن فيهم أنت).
		"columnCompInRank"	: 1,  // عمود لكل منافس وترتيبه بين المتوفر لديهم مخزون (بمن فيهم أنت).
		// ========== معاملات متقدمة غير رسمية ==========
		// هناك خيارات غير رسمية لا نوثقها بالتفصيل، وبعضها تستخدمه "pricezag_backup".
		"originalCurrencies"	: 1,  // بدلاً من تحويل المبالغ إلى عملتك المحددة كأرقام، تصبح الخلايا نصوصاً تتضمن العملة الأصلية ("123.90 USD").
		"keepUrlLabels"		: 1,  // عادة نحذف تسميات روابط المنافسين؛ هذا الخيار يحتفظ بها، وهو مفيد للنسخ الاحتياطي.
		"csvSeparator"		: ";",  // استخدم فاصلاً مختلفاً في CSV بدلاً من الفاصلة أو علامة الجدولة.
		"csvNoQuote"		: 1,  // امنع استخدام علامات الاقتباس (") في CSV، لكن ذلك قد يُفسد تنسيقه.
	}
] }
// طريقة بسيطة لتنزيل نسخة احتياطية بصيغة CSV:
// curl --connect-timeout 15 --max-time 600 --retry 2 -X POST 'https://pricezag.com/api/v3/MYAPIKEY' -d '{"actions":[{"a":"spreadsheetDownload","preset":"pricezag_backup"}]}' -o pricezag-backup-20241225.csv

spreadsheetPresetEdit — إعادة تسمية إعداد مسبق لجدول بيانات أو حذفه

تعادل هذه العملية ما تفعله عندما تفتح صفحة Export ثم تنقر على Edit Presets .
تتيح هذه العملية إعادة التسمية أو الحذف فقط. لإنشاء إعداد مسبق جديد أو تعديل موجود، استخدم عملية spreadsheetDownload أعلاه.
{ "actions" : [
	{
		"a"		: "spreadsheetPresetEdit",
		"preset"	: "Some Preset Name",  // اسم الإعداد المسبق الحالي.
		"newName"	: "The Renamed Preset",  // لإعادة تسمية الإعداد المسبق.
		"delete"	: 1,  // يحذف إعداد "preset" هذا من حسابك.
		// لا يمكن حذف إعداد مسبق يُستخدم للتصدير التلقائي؛ ستعود رسالة خطأ.
		// يجب أولاً حذف عمليات التصدير التلقائي المجدولة التي تستخدمه (راجع Export).
	}
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"	: "spreadsheetPresetEdit",
			"ok"	: 1,
		},
		...
	]
}

spreadsheetAutoCreate — إنشاء تصدير تلقائي جديد

تعادل هذه العملية ما تفعله عندما تفتح صفحة Export ثم تنقر على Add a new Auto-Export .
{ "actions" : [
	{
		"a"			: "spreadsheetAutoCreate",
		"preset"		: "The Preset Name",
		"email"			: "john@example.net",
		"currency"		: "USD",  // (اختياري) الافتراضي "preset"، أي استخدام عملة الإعداد المسبق.
		"attach"		: "link",  // (اختياري، الافتراضي "attach") استخدم "attach" للمرفق أو "link" لرابط تنزيل مستضاف.
		"everyMonday"		: 1,  // أرسل جدول البيانات كل يوم اثنين.
		"everyTuesday"		: 1,  // وهكذا لبقية أيام الأسبوع حتى "everySunday".
		"everyMonthDay1"	: 15,  // أرسل في اليوم الخامس عشر من كل شهر.
		"everyMonthDay2"	: 21,  // وأيضاً في اليوم الحادي والعشرين من كل شهر.
		"everyMonthDay3"	: "last",  // وأيضاً في آخر يوم من الشهر.
			// تقبل everyMonthDay* الأرقام من 0 إلى 9، لعشرة أيام من الشهر كحد أقصى.
		"time"			: "3:59pm",  // تُقبل "15.59" وتحوّل إلى "3:59pm"؛ وكذلك "0:9" و"0.09" و"00:09" و"0:09am" متكافئة.
		"timezone"		: "America/Los_Angeles",  // (اختياري، الافتراضي "UTC") بتنسيق مسار Linux داخل /usr/share/zoneinfo.
			// تُحوّل المسافات في اسم المدينة إلى شرطات سفلية.
	}
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"	: "spreadsheetAutoCreate",
			"ok"	: 1,
			"id"	: "5gwi6fqa",  // المعرّف المرجعي لهذا التصدير التلقائي لتعديله لاحقاً (راجع spreadsheetAutoEdit).
		},
		...
	]
}

spreadsheetAutoEdit — تعديل تصدير تلقائي

تعادل هذه العملية ما تفعله عندما تفتح صفحة Export، بالنقر على زر Edit في القائمة الموجودة تحت عنوان AUTO-EXPORT TO EMAIL.
{ "actions" : [
	{
		"a"			: "spreadsheetAutoEdit",
		"id"			: "5gwi6fqa",  // المعرّف المرجعي للتصدير التلقائي المطلوب تعديله.
			// يُعاد المعرّف في spreadsheetAutoCreate، ويظهر أيضاً في عنوان النافذة المنبثقة عند النقر على Edit للتصدير التلقائي.
		"disabled"		: 1,  // (اختياري) 0 لتفعيل تصدير تلقائي معطل حالياً.
		"delete"		: 1,  // (اختياري) احذف هذا التصدير التلقائي تماماً.
		// المعاملات التالية (كلها اختيارية) تطابق معاملات spreadsheetAutoCreate أعلاه.
		"preset"		: "The Preset Name",
		"email"			: "john@example.net",
		"currency"		: "USD",
		"attach"		: "link",
		"everyMonday"		: 1,  // تحذير: إذا قدمت متغيراً واحداً على الأقل من every*، تُمحى جميع قيم every* السابقة،
		"everyMonthDay1"	: 15,  // لذا إذا كانت "everyFriday"=1 سابقاً، فإن تعيين "everyMonthDay3" يلغي "everyFriday".
		// وهكذا؛ راجع spreadsheetAutoCreate لجميع متغيرات every*.
		"time"			: "3:59pm",
		"timezone"		: "America/Los_Angeles",
	}
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"	: "spreadsheetAutoEdit",
			"ok"	: 3,  // عدد التغييرات المنفذة.
		},
		...
	]
}

المنافسون والمزيد

competitorDeleteAll — حذف منافس من جميع المنتجات أو الفئات

تحذف هذه العملية روابط منافس بشكل جماعي من جميع المنتجات أو من المنتجات التابعة لفئات محددة.
تحذير: تُحذف روابط المنافسين من الحساب فوراً دون إمكانية استعادتها.
هذه هي الوظيفة نفسها في الواجهة عند فتح صفحة منافس والنقر على Delete from all Productsأو عند فتح صفحة فئة والنقر على (X) في قائمة المنافسين.
{ "actions" : [
	...
	{
		"a"		: "competitorDeleteAll",
		"domain"	: "competitordomain.com",
		"categories"	: ["The Category 1", "The Category 2"],  // (اختياري) إذا لم يُقدم، يجب استخدام "allProducts"=1.
		"allProducts"	: 1,  // (اختياري) الحذف من جميع المنتجات (يجب ألا يُقدم "categories").
		// يجب تقديم "categories" أو "allProducts" فقط، وليس كليهما ولا تركهما معاً.
	},
	...
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"	: "competitorDeleteAll",
			"ok"	: 10,  // عدد روابط URL المحذوفة.
		},
		...
	]
}

mathEdit — إعداد أو تعديل حسابات السعر لنطاق منافس

هذه هي الوظيفة نفسها التي تستخدمها الواجهة عندما تفتح Domains وتختار نطاق منافس من القائمة، ثم تنقر على Mathematically alter the price. يمكن ضبط كل خيارات ذلك النموذج أيضاً عبر عملية API mathEdit.
للحصول على تفاصيل كل حقل، انقر على أيقونات علامات الاستفهام الخضراء في حسابك.
{ "actions" : [
	...
	{
		"a"		: "mathEdit",
		"domain"	: "competitordomain.com",
		"clear"		: 1,  // (اختياري) تعطيل جميع الحسابات لهذا النطاق (وحذف كل الإعدادات السابقة).
		// إذا حددت clear:1 فلا تقدم أي شيء آخر أدناه، وإلا سيحدث خطأ.
		"math"	: [  // مصفوفة كتل الحسابات المطلوب تطبيقها.
			{  // هذا كائن كتلة حسابية، وجميع حقوله اختيارية.
				"categories"		: ["Category 1", "Category 2"],  // فقط للمنتجات التابعة لهذه الفئات.
				"theirPriceMin"		: 1234.90,  // فقط إذا كان سعرهم أكبر من N أو مساوياً له.
				"theirPriceMinCurrency"	: "USD",  // العملة (يمكن استخدام "original" لعملة الموقع الأصلية).
				"theirPriceMax"		: 1234.90,  // أقل من N أو مساوٍ له.
				"theirPriceMaxCurrency"	: "USD",  // عملة (...).
				"themMeMin"		: -20.00,  // فقط عندما يكون الفرق [سعرهم - سعري] أكبر من N أو مساوياً له (راجع الواجهة).
				"themMeMinCurrency"	: "USD",  // عملة أو "%" من سعرك (لا تستخدم "original" هنا).
				"themMeMax"		: -1.5,  // أقل من N أو مساوٍ له.
				"themMeMaxCurrency"	: "%",  // عملة (...).
				"addPre"		: -10.00,  // مبلغ يُضاف قبل الضرب، أو يُطرح إذا كان سالباً.
				"addPreCurrency"	: "USD",  // العملة (يمكن استخدام "original" لعملة الموقع الأصلية).
				"multiply"		: 1.1,  // اضرب في هذا المعامل.
				"divide"		: 1.1,  // أو اقسم عليه؛ لا تقدم الخيارين معاً.
				"addPost"		: 5.00,  // مبلغ يُضاف بعد الضرب، أو يُطرح إذا كان سالباً.
				"addPostCurrency"	: "USD",  // عملة (...).
				// يبدو معقداً؟ راجع المثال البسيط أسفل الاستجابة.
			},
			... // حتى عشر كتل إجمالاً، تُنفذ بالترتيب.
		],
		// حالياً لا يمكن تعديل متغير أو كتلة حسابية واحدة فقط. تقديم مصفوفة math يستبدل جميع الإعدادات.
		// تُتجاهل الكتلة التي لا تضرب ولا تقسم (غير مضبوطة أو قيمتها 1) وليس فيها addPre أو addPost غير صفري،
		// وإذا تم تجاهل جميع الكتل، فكأنك حذفت جميع الحسابات باستخدام clear:1.
		// بمعنى آخر، يجب أن يؤدي الحساب إلى تغيير فعلي لكي يُحفظ.
		// حيلة: لتعطيل حسابات نطاق مؤقتاً دون حذف إعداداتها،
		// يمكن تعيين categories : ["Some Empty Existing Category"].
	},
	...
] }
الاستجابة:
{
	...
	"actions" : [
		...
		{
			"a"	: "mathEdit",
			"ok"	: 3,  // عدد الكتل الحسابية المعدلة (الإزالة تُحسب تغييراً).
		},
		...
	]
}
مثال بسيط — إزالة ضريبة بنسبة 10% من جميع أسعار amazon.co.uk:
{ "actions" : [
	{
		"a"		: "mathEdit",
		"domain"	: "amazon.co.uk",
		"math"		: [
			{
				"divide"	: 1.1
			}
		]
	}
] }

المزيد من الأمثلة

هذه الطلبات هي بيانات POST يتم إرسالها إلى https://pricezag.com/api/v3/MYAPIKEY
◀ المثال 1 — تحديث تكلفة منتج
الطلب:
{
	"actions" : [
		{
			"a"		: "productEdit",
			"code"		: "SKU-1234",
			"cost"		: 140.50,
			"costCurrency"	: "EUR"
		}
	]
}
الاستجابة:
{
	"ok"		: 1,  // تعيد 0 إذا كانت تكلفة SKU-1234 مساوية بالفعل لهذه القيمة.
	"errors"	: 0,  // تعيد 1 إذا كان SKU-1234 غير موجود.
	"actionsCount"	: 1,
	"actions" : [
		{
			"a"	: "productEdit",
			"ok"	: 1  // تعيد 0 إذا كانت التكلفة مساوية، و-1 إذا لم يكن المنتج موجوداً.
		}
	]
}

◀ المثال 2 — استرجاع منتج غير موجود
الطلب:
{
	"actions" : [
		{
			"a"		: "productGet",
			"code"		: "NON-EXISTING-SKU",
			"currency"	: "USD"
		}
}
الاستجابة:
{
	"ok"		: 0,  // لأن أي عملية لم تُعد ok>0.
	"errors"	: 1,  // لأن عملية واحدة أعادت ok<0.
	"actionsCount"	: 1,
	"actions" : [
		{
			"a"	: "productGet",
			"ok"	: -1,  // هكذا تعرف أن العملية فشلت.
			"error"	: "Sorry, the product #NON-EXISTING-SKU does not exist. Maybe someone else just removed or renamed it?"
		}
	]
}

◀ المثال 3 — إنشاء فئة وقاعدة إعادة تسعير ثم منتجين مرتبطين بهما
الطلب:
{
	"actions" : [
		{
			"a"		: "categoryCreate",
			"name"		: "My New Category"
		},
		{
			"a"		: "repricingCreate",
			"name"		: "My New Repricing Rule",
			"init"	: {
				"target"	: "cheapest_n",
				"var_n"		: 2,
				"plusAmount"	: 0,
				"plusCurrency"	: "%"
				// المعنى: «اضبط سعري في المنتصف بين أرخص منافسين».
			},
			"never"	: [
				{
					"target"	: "cost",
					"direction"	: "below",
					"plusAmount"	: 5,
					"plusCurrency"	: "%"
					// المعنى: «لكن لا يقل أبداً عن تكلفتي مضافاً إليها 5%».
				}
			],
			"charm"		: "charm"
		},
		{
			"a"		: "productCreate",
			"code"		: "SKU-1001",
			"name"		: "My New Product 1",
			"price"		: 199.90,
			"currency"	: "USD",
			"cost"		: 112.00,
			"costCurrency"	: "USD",
			"repricingRule"	: "My New Repricing Rule",  // اسم القاعدة نفسها التي أنشأناها للتو.
			"categories"	: ["My New Category"],	// اسم الفئة نفسها التي أنشأناها للتو.
			// مع أن productCreate كان سينشئ الفئات غير الموجودة تلقائياً، لذا لم تكن categoryCreate ضرورية.
			"competitors"	: ["https://...", "https://..."]
		},
		{
			"a"		: "productCreate",
			"code"		: "SKU-1002",
			"name"		: "My New Product 2",
			"price"		: 59.95,
			"currency"	: "USD",
			"cost"		: 31.50,
			"costCurrency"	: "USD",
			"repricingRule"	: "My New Repricing Rule",
			"categories"	: ["My New Category"],
			"competitors"	: ["https://...", "https://..."]
		}
	]
}
الاستجابة:
{
	"ok"		: 4,  // لأن العمليات الأربع جميعها أعادت ok>0.
	"errors"	: 0,  // لأن أي عملية لم تُعد ok<0.
	"actionsCount"	: 4,
	"actions" : [
		{
			"a"	: "categoryCreate",
			"ok"	: 1
		},
		{
			"a"	: "repricingCreate",
			"ok"	: 1
		},
		{
			"a"	: "productCreate",
			"ok"	: 1
		},
		{
			"a"	: "productCreate",
			"ok"	: 1
		}
	]
}

◀ المثال 4 — دمج فئتين في فئة أخرى مع حذف الفئتين الأصليتين
الطلب:
{
	"actions" : [
		{
			"a"			: "categoryCopy",
			"categoriesFrom"	: ["Original Category 1", "Original Category 2"],
			"deleteMode"		: "cat",
			// لاحظ أن "removeMode":"cat" غير ضروري لأن deleteMode سيحذف الفئتين في كل الأحوال.
			"categoriesTo"		: ["A New Category"]
		}
}
الاستجابة:
{
	"ok"		: 1,  // لأن عملية واحدة أعادت ok>0.
	"errors"	: 0,  // لأن أي عملية لم تُعد ok<0.
	"actionsCount"	: 1,
	"actions" : [
		{
			"a"			: "categoryCopy",
			"ok"			: 3,  // لأن ثلاث فئات تغيرت: حُذفت الفئتان الأصليتان وأنشئت فئة وجهة واحدة.
			"categoriesCreated"	: 1,
			"categoriesDeleted"	: 2,
			"categoriesModified"	: 0,
			"productsCount"		: 123
		}
	]
}

◀ المثال 5 — تغيير المتغير N واتجاه قاعدة تنبيه
الطلب:
{
	"actions" : [
		{
			"a"		: "alertRuleEdit",
			"email"		: "john@example.net",
			"ruleNumber"	: 3,
			"rule"		: {
				"var_n"		: 1.5,
				"direction"	: "drop"
			}
		}
}
الاستجابة:
{
	"ok"		: 1,  // لأن عملية واحدة أعادت ok>0.
	"errors"	: 0,  // لأن أي عملية لم تُعد ok<0.
	"actionsCount"	: 1,
	"actions" : [
		{
			"a"	: "alertRuleEdit",
			"ok"	: 2  // لأن متغيرين عُدّلا بنجاح.
		}
	]
}