> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hamla.io/llms.txt
> Use this file to discover all available pages before exploring further.

# أحداث حملة

> أخبر حملة بما يحدث داخل نظامك — تسجيل، دفعة، حجز — وحوّل كل لحظة منها إلى حملة تسويقية أو شريحة أو هدف.

حملة لا تتصرّف إلا بما تراه.

هي ترى موقعك أصلاً — السكربت يتابع الزيارات والنقرات والسلات وحده. لكنها لا ترى داخل نظامك. حين يدفع أحدهم، أو يلغي اشتراكه، أو يحجز موعداً، أو ينهي درساً، فكل هذا يحدث في قاعدة بياناتك **أنت**، وحملة لا تعلم عنه شيئاً.

**حدث حملة** هو أن تخبرها: *هذا حدث الآن.*

```
«عمر اشترك للتو.»
```

هذه هي الفكرة كلها. والباقي على حملة — تجد عمر، تكتب الحدث في سجلّه، تنقله من «تجربة» إلى «عميل»، وإذا كانت هناك حملة تنتظر هذه اللحظة بالذات، تنطلق.

### لماذا تستحق عشر دقائق من وقت مبرمجك

| بدون أحداث            | مع الأحداث                                                                |
| --------------------- | ------------------------------------------------------------------------- |
| عمر زار صفحة الأسعار. | عمر زار صفحة الأسعار، واشترك يوم الثلاثاء، ولم يفتح التطبيق منذ 12 يوماً. |

الأولى تصلح لنشرة بريدية. الثانية تصلح لاستعادته.

## أرسل أول حدث

<Steps>
  <Step title="احصل على مفتاح سري">
    لوحة التحكم ← **الإعدادات ← مفاتيح API**. المطلوب هو المفتاح **السري**، ويبدأ بـ `sk_live_`.

    احتفظ به على خادمك فقط. هو يستطيع الكتابة في بيانات عملائك، فتعامل معه كأنه كلمة مرور قاعدة البيانات: يجب ألّا يظهر أبداً في صفحة ويب أو تطبيق جوال.
  </Step>

  <Step title="أرسل الحدث من مكان حدوثه">
    في الكود الموجود لديك أصلاً — استقبال الدفع، تأكيد الحجز، تسجيل مستخدم جديد — أضف نداءً واحداً.

    ```bash theme={null}
    curl -X POST https://app.hamla.io/api/sdk/track \
      -H "Authorization: Bearer sk_live_xxx" \
      -H "Content-Type: application/json" \
      -d '{
        "event": "subscription_started",
        "type": "purchase",
        "identity": { "email": "omar@raqmi.co" },
        "value": 29,
        "currency": "JOD"
      }'
    ```

    وعلى Node.js، حزمة `npm install @gethamla/node` تعطيك الشيء نفسه مع طابور إرسال وإعادة محاولة جاهزة:

    ```ts theme={null}
    import { Hamla } from '@gethamla/node';
    const hamla = new Hamla(); // يقرأ HAMLA_API_KEY

    hamla.track({
      event: 'subscription_started',
      type: 'purchase',
      identity: { email: 'omar@raqmi.co' },
      value: 29,
      currency: 'JOD',
    });
    ```

    المطلوب شيئان فقط: **مَن** (`identity` — بريد أو رقم هاتف أو معرّف المستخدم لديك) و**ماذا** (`event` — أي اسم تختاره).
  </Step>

  <Step title="تأكد من وصوله">
    افتح صفحة جهة الاتصال في حملة. ستجد الحدث في سجلّها الزمني، بوقت حدوثه.

    بهذا اكتملت الدورة. وكل ما يلي هو ما تستطيع فعله به الآن.
  </Step>
</Steps>

## مَن هو الشخص

يجيب عنه حقل `identity`، و**واحد منه يكفي**. لن ترسل الثلاثة أبداً، ولن تحتاج بريداً إلكترونياً أبداً.

| أرسل                                   | حين يكون هذا ما لديك                                  |
| -------------------------------------- | ----------------------------------------------------- |
| `{ "email": "omar@raqmi.co" }`         | الحسابات والنشرات والفواتير                           |
| `{ "phone": "+962790000000" }`         | العيادات والمطاعم والتوصيل وكل ما يبدأ من واتساب      |
| `{ "platformCustomerId": "user_812" }` | معرّف المستخدم لديك — وغالباً هو كل ما يحمله الويبهوك |

عيادة لم تسأل أحداً يوماً عن بريده الإلكتروني عميلة من الطراز الأول في حملة: أرسل رقم الهاتف وحده، دائماً.

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

<Note>
  الهوية ليست إذناً. معرفة رقم هاتف أحدهم هي ما يتيح لحملة أن تعرفه، وليست موافقة على إرسال رسالة نصية أو واتساب إليه. تلك موافقة منفصلة، وحملة تفصل بينهما عن قصد.
</Note>

### وبماذا تناديه

الهوية تقول *من*. ولا تقول بماذا تناديه — وجهة الاتصال بلا اسم هي سبب خروج `مرحباً {{contact.firstName}}` هكذا: `مرحباً صديقي`.

الأسماء تمرّ عبر `identify`، المسار الرفيق لـ `track`:

```bash theme={null}
curl -X POST https://app.hamla.io/api/sdk/identify \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "identity": { "phone": "+962790000000" },
    "profile": { "name": "سارة آل عتيبي" },
    "method": "booking"
  }'
```

```ts theme={null}
hamla.identify({
  identity: { email: 'omar@raqmi.co' },
  profile: { name: 'عمر آل صالح' },
  method: 'signup',
});
```

أرسل الاسم بالشكل الذي تخزّنه به أصلاً:

| الحقل                                    | استخدمه حين                                                        |
| ---------------------------------------- | ------------------------------------------------------------------ |
| `profile.name`                           | يكون لديك حقل اسم واحد — نموذج تسجيل، أو ملف جوجل، أو معظم الأنظمة |
| `profile.firstName` / `profile.lastName` | تكون قاعدة بياناتك تفصلهما أصلاً                                   |

يُقسَّم `name` عند وصوله: الكلمة الأولى هي الاسم الأول والبقية اسم العائلة، فيُنادى صاحب «سارة آل عتيبي» باسم **سارة** وصاحب «محمد بن عبد الله» باسم **محمد**. وإن أرسلت الشكلين معاً غلبت الأجزاء الصريحة، حقلاً حقلاً.

نادِه حيثما تعرفهم أصلاً — التسجيل أو الدفع أو تسجيل الدخول. ومناداته عند كل تسجيل دخول آمنة وتستحق: حملة تملأ الناقص ولا تستبدل اسماً موجوداً أبداً، فيبقى أي تصحيح يجريه الشخص في ملفه.

<Note>
  يقبل `profile` أيضاً `country` و`city` و`language` و`timezone`. وحقل `timezone` هو ما يُبقي خطوة «بعد يوم» خارج ليل المستلم — حزمة المتصفح تملؤه عنك، وعلى الخادم أن يرسله حين يعرفه.
</Note>

## والآن استخدمه

إرسال الحدث هو الخطوة الأولى فقط. وهذا ما هو *لأجله*.

### ١. ابدأ حملة في اللحظة نفسها

افتح حملة ← **متى تبدأ الحملة؟** ← **حدث في تطبيق** ← التطبيق: **أحداث تطبيقك** ← **اسم الحدث**، واكتبه.

هذا كل شيء. كل شخص يُطلق هذا الحدث من الآن فصاعداً تصله رسالتك. ليس غداً، ولا في الدفعة التالية — بل في حينه.

<Note>
  يجب أن يطابق الاسم ما يرسله كودك حرفياً: `treatment_completed` وليس `Treatment Completed`. وبمجرد وصول الحدث مرة واحدة، يظهر في القائمة فتختاره بدل كتابته.
</Note>

وتحت الاسم خيار **يمكن الدخول مرة أخرى لاحقاً**:

* **مغلق** — يُسجَّل كل شخص مرة واحدة فقط، للأبد. مناسب لسلسلة الترحيب.
* **مفتوح** — يمكن تسجيله مرة أخرى في فترة لاحقة. مناسب للتجديدات والشراء المتكرر والفحص الدوري.

### ٢. ابنِ منه شريحة

فور وصول أول حدث `purchase`، يظهر حقلان جديدان في بنّاء الشرائح تحت مجموعة **الأحداث**:

| الحقل                     | معناه           | يجيب على أسئلة مثل                                                  |
| ------------------------- | --------------- | ------------------------------------------------------------------- |
| **purchase — آخر مرة**    | متى حدث آخر مرة | «اشترى قبل أكثر من 60 يوماً»، «اشترى خلال 7 أيام»، «لم يشترِ أبداً» |
| **purchase — عدد المرات** | العدد التراكمي  | «اشترى 3 مرات أو أكثر»، «اشترى مرة واحدة فقط»                       |

لا أحد ينشئ هذين الحقلين. هما موجودان لأنك أرسلت الحدث.

اجمع بينهما وستحصل على أفضل عملائك وقد صمتوا: *اشترى 3 مرات فأكثر، وآخر مرة قبل أكثر من 60 يوماً*. هذه قائمة استعادة، وتبقى صحيحة إلى الأبد، لأن خادمك يواصل إرسال الأحداث.

<Note>
  مجموعة **الأحداث** لا تظهر في البنّاء إلا بعد وصول أول حدث من أي نوع. قبل ذلك لا يوجد ما تُصفّي عليه.
</Note>

### ٣. اجعله خط النهاية للحملة

يجب أن تتوقف الحملة عن مضايقة الشخص فور أن يفعل ما أردته منه.

داخل الحملة ← **نهاية التسلسل** ← **عند تحقق حدث** ← اختر حدثك.

الآن كل من يُطلق `subscription_started` يتوقف عن استقبال بقية الرسائل، ويُفحص ذلك قبل كل إرسال. والحدث نفسه يصبح مقياس نجاح الحملة في تقاريرك.

### ٤. أو اطلب فحسب

لست مضطراً لبناء أي شيء. اكتب:

> «كل من أنهى علاجاً الشهر الماضي ولم يحجز بعدها — أرسل له تذكيراً.»

حملة تقرأ الأحداث نفسها وتنفّذ.

### وأمران يحدثان تلقائياً

* **الشخص يتقدّم في رحلته.** بعض الأسماء لها معنى محدد: `trial_started` و`subscription_started` و`purchase` تنقل الشخص إلى مرحلة *القرار*، و`subscription_renewed` و`repeat_purchase` تنقله إلى *الاحتفاظ*. استخدم هذه الأسماء حين تناسبك وتبقى الرحلة صادقة بلا عمل إضافي. أما أسماؤك الخاصة فتُسجَّل كاملة، لكنها لا تحرّك المرحلة.
* **كل شيء يغذّي الأرقام.** التفاعل والتقييم ونسب المصدر تقرأ أحداثك، فتعكس التقارير ما حدث فعلاً في نشاطك التجاري، لا ما حدث في المتصفح وحده.

## الأحداث والسمات شيئان مختلفان

هذا هو التمييز الوحيد الذي يستحق الانتباه.

* ما **حدث في لحظة** هو **حدث**. يُحفظ للأبد ولا يُستبدل. *«ترقّى إلى Pro يوم الثلاثاء.»*
* ما هو **صحيح الآن** ويمكن أن يتغير هو **سمة**. القيمة الأحدث تفوز. *«الباقة هي Pro.»*

أرسل الاثنين معاً في النداء نفسه:

```json theme={null}
{
  "event": "subscription_started",
  "identity": { "email": "omar@raqmi.co" },
  "traits": { "plan": "pro", "subscription_status": "active" },
  "tags": ["paying"]
}
```

وأول مرة ترسل فيها مفتاح سمة جديداً، تنشئ حملة الحقل المخصص المقابل تلقائياً، وتستطيع الشرائح التصفية عليه فوراً. المفاتيح تُكتب بصيغة `snake_case`، والحقل يحتفظ بالنوع الذي وُلد به.

قاعدة سريعة: **السمات تجيب عن «من هذا الشخص اليوم»، والأحداث تجيب عن «ماذا فعل».** وأغلب الشرائح الجيدة تستخدم الاثنين.

## مثالان كاملان

### عيادة

نظام الحجز لديك يعرف أصلاً متى ينتهي العلاج. أرسله:

```json theme={null}
{ "event": "treatment_completed",
  "identity": { "phone": "+962790000000" },
  "properties": { "treatment": "cleaning" },
  "traits": { "last_treatment": "cleaning" } }
```

الآن، وبلا أي كود إضافي:

1. **مُطلِق** — حملة على `treatment_completed` ترسل رسالة متابعة بعد ساعة، مع تفعيل **يمكن الدخول مرة أخرى لاحقاً** لتعمل مع كل زيارة.
2. **شريحة** — *`treatment_completed` آخر مرة قبل أكثر من 180 يوماً* هم كل من حان موعد فحصهم.
3. **خط النهاية** — اجعل `appointment_booked` هو الهدف، فيتوقف التذكير عمّن أعاد الحجز.

### شركة برمجيات

خطاف الفوترة لديك يعمل أصلاً. أرسله:

```json theme={null}
{ "event": "subscription_started",
  "type": "purchase",
  "identity": { "email": "omar@raqmi.co", "platformCustomerId": "user_812" },
  "value": 29, "currency": "USD",
  "idempotencyKey": "invoice_9911",
  "traits": { "plan": "pro" } }
```

الآن:

1. **مُطلِق** — التهيئة تبدأ لحظة الدفع.
2. **شريحة** — *الباقة هي pro* تحصر أي حملة في العملاء الدافعين، وتبقى صحيحة مع كل ترقية أو انقطاع.
3. **الرحلة** — `subscription_started` ينقله إلى *القرار* وحده.
4. أرسل `subscription_expired` عند الانقطاع مع `traits: { "subscription_status": "expired" }`، فتمتلئ شريحة الاستعادة من تلقاء نفسها.

## أحضر تاريخك معك

لست مضطراً للبدء من الصفر. `POST /api/sdk/track/batch` يستقبل حتى 500 حدث سابق في الطلب الواحد — البنية نفسها، داخل مصفوفة `events`، ولكل حدث تاريخه الحقيقي في `occurredAt`.

دورة واحدة على جدول المستخدمين لديك تعطي معنى من اليوم الأول لشريحة مثل «اشترى سابقاً وصمت 60 يوماً».

<Warning>
  **التاريخ المستورد لا يرسل شيئاً أبداً.** الأحداث المستوردة تملأ الملفات والأعداد والشرائح، لكنها لا تبدأ حملات ولا تُطلق مُطلِقات دخول الشرائح. سنة من المشتريات القديمة يجب ألّا ترسل سنة من الرسائل الليلة.

  الأحداث الحيّة وحدها — عبر `/api/sdk/track` أو `hamla.track()` — هي ما يستطيع بدء حملة.
</Warning>

أعطِ كل صف مفتاح `idempotencyKey` (رقم الفاتورة أو الطلب لديك) ويصبح تشغيل السكربت كاملاً مرة أخرى آمناً.

## أسئلة شائعة

<AccordionGroup>
  <Accordion title="هل أحتاج السكربت أيضاً؟">
    كلٌّ منهما يغطي نصفاً مختلفاً. السكربت يرى المتصفح — الزيارات والمصادر والسلوك على الموقع. والأحداث تعرف قاعدة بياناتك — الباقات والمدفوعات والمحطات المهمة. كلٌّ منهما يعمل وحده، ومعاً ترى حملة الشخص كاملاً.
  </Accordion>

  <Accordion title="هل أستطيع الإرسال من المتصفح بدلاً من ذلك؟">
    نعم، لما يحدث فعلاً داخل الصفحة: `hamla.track('download_ebook', { asset: 'guide.pdf' })`. هذه تُعدّ أحداثاً متعمَّدة وتستطيع بدء حملة، ولا تحتاج أي مفتاح.

    أما كل ما يتعلق بالمال أو بسجلاتك الخاصة فمكانه الخادم، حيث يوجد المفتاح السري وحيث تكون الوقائع حقيقية.
  </Accordion>

  <Accordion title="ماذا لو أرسلت الحدث مرتين؟">
    بنفس `idempotencyKey` ← يُحتسب مرة واحدة، ويأتي في الرد `deduped: true`. وبدون مفتاح ← كل إرسال حدث مستقل، لأن الناس أحياناً يشترون مرتين فعلاً.
  </Accordion>

  <Accordion title="أي أسماء أستخدم؟">
    ما يسمّيها به نشاطك التجاري فعلاً. حملة لا تحتاج معرفة مفرداتك مسبقاً — العيادة ترسل `treatment_completed`، والمدرسة ترسل `lesson_finished`.

    السبب الوحيد لاستعارة أحد أسماء حملة هو مرحلة الرحلة: `purchase` و`trial_started` و`subscription_started` و`subscription_renewed` و`repeat_purchase` وأخواتها تنقل الشخص إلى الأمام تلقائياً.
  </Accordion>

  <Accordion title="الحملة لا تنطلق. لماذا؟">
    ثلاثة أسباب معتادة، بالترتيب:

    1. **الاسم غير مطابق.** المطابقة حرفية تماماً، وتفرّق بين الحروف الكبيرة والصغيرة.
    2. **الحدث دخل عبر مسار الدفعات.** الاستيراد لا يُطلق شيئاً أبداً.
    3. **الشخص مسجَّل من قبل.** فعّل **يمكن الدخول مرة أخرى لاحقاً** للحظات المتكررة.
  </Accordion>
</AccordionGroup>

تفاصيل كل حقل والحدود ورسائل الخطأ في [مرجع الأحداث](/ar/reference/events).
