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

الأحداث

POST /v1/events — أحداث عامة يتتبعها التاجر (مشاهدات صفحة، عملاء محتملون، تحليلات مخصصة). نفس مخطط HMAC المستعمل في الاشتراكات، بدون إزالة تكرار email/phone.

بقلم: Support

متتبّع أحداث عام الغرض. استخدمه لأي شيء تحتاج تحليلات عليه ولا يكون اشتراكًا:

  • مشاهدات الصفحة

  • إرسال نماذج العملاء المحتملين (Lead)

  • تتبع النقرات على صفحات الهبوط

  • أحداث مخصصة يحددها التاجر

إن كانت بياناتك تحمل هوية مستخدم ذات معنى (email/phone)، استخدم /v1/signups بدلًا منها — تمنحك إزالة تكرار لكل مستخدم. /v1/events للبيانات عالية الحجم بلا هوية.

المصادقة

مفتاح عام + HMAC. نفس مخطط /v1/signups. خادمك الخلفي يوقّع كل نداء.

⚠️ تنبيه — أمران يعطّلان أي مفتاح جديد تمامًا

  • بوابة البرنامج التجريبي. الـ API مُقيَّد بالبرنامج التجريبي في الإنتاج. المفتاح الذي لم تُسجّله DZBuild يُرجع 403 forbidden "API is in pilot mode; key not enrolled" في كل نداء.

  • تأخير التفعيل. المفتاح العام الجديد ليس صالحًا للاستعمال لحظة إنشائه. وإلى أن يُفعَّل لهذه النقاط ستحصل على 401 unauthorized "Invalid or revoked public key". راسل الدعم إن ظلّ مفتاح جديد مرفوضًا بعد انتظار قصير.

والإلغاء ليس فوريًا كذلك: بعد إلغاء مفتاح عام قد تظل النداءات مقبولة لفترة قصيرة. إن احتجت إيقاف مفتاح فورًا، راسل الدعم.

الجسم

{
  "name":       "lead_submitted",
  "properties": { "plan": "pro", "country": "DZ", "form": "footer" },
  "nonce":      "32-hex-single-use"
}

الحقل

النوع

إلزامي

ملاحظات

name

string ≤ 64

اسم الحدث. snake_case مستحسن.

properties

object

قيم قابلة لـ JSON. تُحفظ كما هي.

nonce

32-hex string

لاستخدام واحد، إلى الأبد. انظر إزالة التكرار — نافذة الساعة هي الحارس الخارجي فقط؛ فالـ nonce لا يصلح مرتين أبدًا.

كما يجب أن تحمل طلبات POST ترويسة Idempotency-Key (بحد أقصى 64 حرفًا، من مجموعة المحارف [A-Za-z0-9_-:.]). بدونها تحصل على 400 bad_request ولا يدخل الحدث الطابور أصلًا. والـ nonce ذو الـ 32 خانة ست عشرية الذي تولّده أصلًا قيمة صالحة — أعد استعماله.

name هو ما ستصفّي به لاحقًا، لذا التزم بمعجم صغير ثابت — تجنّب توليد الأسماء ديناميكيًا (مثل viewed_product_42 سيء؛ استخدم name="viewed_product" مع properties.product_id=42).

الاستجابة 202

{
  "data": { "status": "queued", "kind": "event", "store_id": 13 },
  "meta": { "request_id": "...", "api_version": "v1", "edge": true }
}

نفس تدفّق الاشتراكات: يُقبَل في ~30 مللي ثانية، ويُخزَّن خلال 5 ثوانٍ تقريبًا.

إزالة التكرار

إزالة التكرار تعتمد على الـ nonce وحده، لكل متجر. لا توجد إزالة تكرار قائمة على البريد.

المكرَّر يُسقَط بالكامل: لا يُخزَّن شيء، ولا يتحرك أي عدّاد استهلاك، ولا شيء في الـ API يخبرك بحدوث ذلك. فالنداء أرجع 202 رغم ذلك، لأن إزالة التكرار تحدث بعد القبول. أي أن المكرَّر غير مرئي لك — ولّد دائمًا nonce جديدًا.

الـ nonce محروس على مرحلتين، بعمرين مختلفين:

  • لمدة ساعة واحدة يُرفض الـ nonce المعاد استعماله رفضًا صريحًا بـ 401 unauthorized "Nonce reused".

  • وإلى الأبد بعد ذلك، يُقبل الـ nonce المُعاد تدويره بـ 202 ثم يُهمَل بصمت — بلا خطأ، وبلا حدث.

مثال عملي: تتبع مشاهدات الصفحة (Node.js، خادمي)

import crypto from 'node:crypto';export async function trackEvent(name, properties = {}) {
  const KEY_ID = process.env.DZ_PUBLIC_KEY;
  const SECRET = process.env.DZ_SIGNING_SECRET;
  const nonce = crypto.randomBytes(16).toString('hex');
  const ts    = Math.floor(Date.now() / 1000).toString();
  const body  = JSON.stringify({ name, properties, nonce });
  const hash  = crypto.createHash('sha256').update(body).digest('hex');
  const sig   = crypto.createHmac('sha256', SECRET).update(`${KEY_ID}\n${nonce}\n${ts}\n${hash}`).digest('hex');  await fetch('https://api.dzbuild.app/v1/events', {
    method: 'POST',
    headers: {
      'Authorization': `DZ-Public ${KEY_ID}`,
      'X-DZ-Timestamp': ts, 'X-DZ-Nonce': nonce, 'X-DZ-Signature': sig,
      'Idempotency-Key': nonce,          // إلزامية في كل POST
      'Content-Type': 'application/json',
    },
    body,
  });
}// داخل Express middleware:
app.use((req, res, next) => {
  trackEvent('page_view', { path: req.path, ua: req.get('user-agent') }).catch(() => {});
  next();
});

لاحظ أننا لا ننتظر النداء من middleware مشاهدات الصفحة — fire-and-forget لكي لا يُحظر طلب المستخدم. الـ API يردّ في ~30 مللي ثانية على أي حال، لكن هذا يحمي من مشاكل شبكة عابرة.

ما يُحسب من حصتك

كل نداء /v1/events يصل فعلًا يزيد usage.event.total و usage.event.billable. لا يوجد "قراءات مجانية ثم كتابات قابلة للفوترة" هنا — الأحداث قابلة للفوترة من الطلب الأول. أما المكرَّرات (نفس الـ nonce) فلا تحرّك أي عدّاد، لأنها لا تُخزَّن أصلًا.

إن ارتفع حجم الأحداث، اجمع من جانبك: خزّنها في طابور خاص، واطلق نداء /v1/events لكل حدث منطقي على دفعات من 1 (لا نقبل دُفعات في v1؛ ميزة لـ v1.1 للقياس عالي الحجم).

الأخطاء

نفس /v1/signups. انظر الأخطاء. والثلاثة التي توقع الناس على هذه النقطة تحديدًا:

HTTP

الكود / الرسالة

السبب

400

bad_request "Idempotency-Key header is required for write requests"

الترويسة مفقودة

400

bad_request "Idempotency-Key must be <=64 chars, [A-Za-z0-9_-:.]"

أطول من اللازم، أو يستعمل محارف خارج تلك المجموعة (محارف base64 وهي + و / و = مرفوضة)

403

forbidden "API is in pilot mode; key not enrolled"

المفتاح غير مُسجَّل في البرنامج التجريبي

متى لا تستعمل /v1/events

  • لـ طلبات الواجهة — لوحة تحكم التاجر تسجّلها أصلًا، وتكرارها هنا يضخّم عدد أحداثك فقط. ولاحظ أن طلبات الواجهة لا تُطلق webhook order.created في API v1؛ الطلبات المُنشأة عبر POST /v1/orders وحدها تفعل ذلك (انظر كتالوج الأحداث).

  • لـ أحداث داخلية لا تتعلق ببيانات التاجر (استهلاك CPU، نتائج cache). استعمل APM حقيقيًا.

  • لـ أحجام ضخمة (أكثر من مليون حدث/يوم). ابنِ خط تحليلاتك واصدّر فقط التجميعات هنا.

هل أجاب هذا عن سؤالك؟