أرسل حملة من الطرف إلى الطرف
يمشي هذا الدليل دورة حياة الحملة كاملة عبر الواجهة البرمجية: إنشاء مسودة، وربط جمهور، ومعاينة التخصيص، وتشغيل الـ dry-run السابق للإطلاق، والإطلاق، وقياس النتيجة. اتبعه مرة واحدة وستعمل السلسلة نفسها على كل قناة — SMS وWhatsApp والبريد الإلكتروني وRCS والصوت وpush. يمكن لمستخدمي الـ SDK تشغيل دورة الحياة كاملة أدناه من دون cURL: كل خطوة تقترن كتلة curl فيها بتبويب Node SDK — المساعد المُكتبorbit.campaigns.* حيث يوجد، وإلا المهرب العام orbit.request(method, path, body) الذي يغطي كل نقطة في سطح الواجهة البرمجية.
لِمخططات الطلب والاستجابة راجع مرجع واجهة campaigns البرمجية. تغطي هذه الصفحة سير العمل؛ ويغطي دليل اختبار A/B المتغيرات، فيما يغطي أفضل الممارسات وقوائم opt-out تفاصيل التوصيل والامتثال — تُربط أدناه بدل تكرارها.
1. المتطلبات المسبقة
- مفتاح واجهة برمجية بنطاق
campaigns:write. تقبل كل قراءة أدناه (معاينة الجمهور، الـ dry-run، الإحصاءات) أيضًاcampaigns:read، لكن أفعال الإطلاق تتطلب write. أنشئ المفاتيح أو حررها في لوحة التحكم تحت Settings → API keys. - Node SDK (اختياري).
npm install @devotel-orbit/nodeإذا كنت تفضل تبويبات الـ SDK على cURL. - هوية إرسال لقناتك. لـ SMS/MMS يعني ذلك رقمًا أو مجمع مرسلين بالتسجيلات الصحيحة (يتطلب A2P في الولايات المتحدة 10DLC)؛ ولـ WhatsApp حساب WABA متصلًا؛ ولبريد الإلكتروني نطاق إرسال موثقًا.
- مصدر جمهور معتمد. قائمة جهات اتصال، أو شريحة حية، أو CSV بعناوين المستلمين، أو جمهور CRM خارجي (قائمة HubSpot / تقرير Salesforce)، أو مجموعة معرفات جهات اتصال منتقاة يدويًا. يجب أن يأتي الجمهور من مستلمين مشتركين — فمعالجة الـ suppression وإلغاء الاشتراك تُفرض وقت الإرسال ولا تُترك للمرسل.
2. أنشئ حملة المسودة
أنشئ الحملة بقناة وجمهور وmessage_template. القالب اختياري عند الإنشاء — مسودة بلا قالب لا يمكن إطلاقها — لكن توفيره منذ البداية يُبقي المسودة مكتملة.
name / channel / message_template الأساسي. لتمرير الجسم الكامل الموضح في تبويب curl (type وaudience_type وsend_time_optimization …) يقبل مهرب الـ SDK orbit.request("POST", "/campaigns", body) أي حقول. يتطلب أيٌّ من الشكلين نطاق campaigns:write على مفتاحك.
الحقول الأساسية عند الإنشاء:
يعيد الاستجابة الحملة بحالة
draft. لا يُرسل شيء حتى تطلقها الخطوة 6 صراحة.
3. اربط الجمهور وتحقق منه
ثلاثة أشكال للجمهور هي الشائعة؛ وتُعاين كلها بالطريقة نفسها. قائمة أو شريحة. مرّرaudience_type: "list" | "segment" مع audience_id، أو واصف audience_source من CRM. تُقيَّم الشرائح حيًّا وقت الإرسال، لذا تستمر الشريحة النامية في العمل.
مستلمو CSV. لقائمة تُستخدم مرة واحدة، أرسل العناوين بطلب POST مباشرة في مصفوفة variables.csv_recipients على الحملة (بصيغة E.164 لقنوات الهاتف). تخزنها الحملة، ويعلّم المحلل الإدخالات غير القابلة للتسليم بدل اختراع مستلمين.
اختيارات يدوية. audience_type: "manual" مع variables.manual_contact_ids يستهدف معرفات جهات اتصال محددة — بحساب الأهلية نفسه المستخدم مع القائمة.
قبل الإطلاق، احسب دائمًا إلى ماذا يحلّ الجمهور. يقبل POST /api/v1/campaigns/audience/preview شكل الجمهور نفسه الذي تحمله الحملة ويعيد matching_count إضافة إلى عينة من 10 جهات اتصال:
channel وستعيد الاستجابة أيضًا إسقاطًا صافيًا: إجمالي التطابقات ناقص صفوف قائمة الـ suppression، وناقص حالات opt-out على مستوى القناة، وناقص جهات الاتصال التي لا تملك عنوانًا قابلًا للتسليم لتلك القناة (مثل غياب البريد الإلكتروني المسجل لحملة بريدية). يعرض تقدير استرشادي frequency_capped عدد الإرسالات التي سيحجبها سقف التردد تقريبًا. تُخزَّن المعاينة مؤقتًا خمس دقائق لكل معيار، لذا فإن إعادة رسم الدرج نفسه رخيصة.
إذا عاد matching_count صفرًا، أصلح الجمهور قبل المضي — يبلغ الـ dry-run (الخطوة 5) عن الجماهير الفارغة بصوت عالٍ، لكن المعاينة هي مكان التكرار والتصحيح.
4. التخصيص واللغة
تستخدم القوالب عناصر نائبة بصيغة{{token}} تُحل لكل مستلم من حقول جهات الاتصال ومن variables الحملة — و{{first_name}} هو الحالة الشائعة. تسقط الرموز غير المحلولة إلى سلاسل فارغة وقت الإرسال، وتخبرك نقطة المعاينة أي الرموز تُحل لكل جهة اتصال، فيُلتقط خطأ إملائي مثل {{frist_name}} قبل الإطلاق.
لترجمة قالب محفوظ إلى لغة أخرى استخدم POST /api/v1/campaigns/templates/translate، الذي يعيد كتابة جسم القالب للغة المستهدفة مع الحفاظ على الرموز وتعليمات opt-out. ضمانتان يجب تذكرهما:
- تُحفظ الرموز حرفيًا عبر الترجمة.
- تبقى تعليمة opt-out الوحيدة مرة واحدة بالضبط (متطلب مشغلي الشبكات).
5. ما قبل الإطلاق: شغّل الـ dry-run
قبل الإطلاق، أرسل الـ dry-run بطلب POST. إنه للقراءة فقط — لا يعدّل أي حالة، ولا يمس المحفظة، ولا يضع أي مهمة في الطابور — فاستدعِه مع كل ضغطة مفتاح في المعالج إن شئت.audience.total_in_audience— العدد الإجمالي للتطابقات.audience.suppressed/opted_out/unreachable— شرائح الإسقاط الصافي (قائمة الـ suppression، وحالات opt-out لكل قناة، وغياب عنوان القناة).audience.held_out— المستلمون المقتطعون في شريحة التحكم لقياس الزيادة عندما يكونvariables.campaign_holdout_percentمضبوطًا؛ ويُستبعدون من التسليم.audience.deliverable— العدد الصافي الدقيق الذي سيحاول الإطلاق الوصول إليه.cost.unit_price_cents/cost.total_cents— تُسعَّر عبر المحلل نفسه الذي يستخدمه مسار الإرسال، فيتطابق الرقم مع خصم المحفظة ضمن حدود التقريب.cost.balance_cents/cost.sufficient— فحص المحفظة؛ الـ dry-run الأخضر يستلزم بوابة رصيد خضراء عند الإطلاق.quiet_hours.skipped_estimateوquiet_hours.window— نسبة التجاوز المتوقعة من ساعات الهدوء بتوقيت المستلم المحلي، إضافة إلى النافذة المحلولة قيد التقييم.channel_waterfall— القناة الأساسية وشكل التراجع بين القنوات، لتتحقق من RCS ← SMS (أو أي سلسلة ضبطتها) قبل الضغط على إرسال.warnings[]— مشكلات غير حاجبة (لا مزود مسجلًا للقناة، ساعات هدوء تغلق النافذة بالكامل …) تُعرض منفصلة عن الإخفاقات الصارمة.
- الموافقات. إذا كانت مؤسستك تتطلب توقيع مشرف، يعيد الإطلاق (
POST /campaigns/:id/send) حالة انتظار موافقة بدل الإرسال؛ ويقع طابور الموافِقين عندGET /campaigns/approvals/pending، وإعدادات المؤسسة الافتراضية عندGET/PUT /campaigns/approvals/settings. - جاهزية المزود. يفحص الـ dry-run نظافة القوائم وتسجيل المزود ضمنيًا عبر تحذيراته — قناة بلا مزود مهيأ تظهر هناك بدل أن تفشل وقت الإرسال.
warnings: [] وcost.sufficient: true يخلي سبيل الإطلاق.
6. أطلق واختر شكل الإرسال
أطلق بـPOST /api/v1/campaigns/cmp_abc123/send (أو بـscheduled_at لدفعة مستقبلية). أربعة أشكال إرسال تختار منها:
Blast. دفعة واحدة في وقت واحد. type: "blast". أبسط الأشكال — يخرج الجمهور القابل للتسليم كاملًا في مرور واحد بوتيرة throttle_rate.
سلسلة Drip. type: "drip" مع مصفوفة steps (حتى 50 خطوة). لكل خطوة قناتها وتأخيرها وحارس شرط القراءة الاختياري. الـmessage_template على الحملة هو رسالة الترحيب للخطوة 0. يظهر تقدم الـ Drip تحت GET /campaigns/:id/drip-analytics.
Journey. type: "journey" — تسجيل مدفوع بالأحداث مع تحليلات لكل عقدة عند GET /campaigns/:id/journey-analytics وتفصيلات عقد عند GET /campaigns/:id/journey/node-analytics. تجري نقطة محاكاة الـ journey (POST /campaigns/journeys/simulate) تشغيلًا تجريبيًا للرسم البياني قبل الإطلاق كما يفعل الـ dry-run للـ blast مع الجماهير. يمشي دليل باني رحلات الحملات اللوحة المرئية وبوابات التحقق من الرسم البياني والمحاكي وربط أهداف التحويل من الطرف إلى الطرف.
سلّم التراجع بين القنوات. في الحملات متعددة القنوات، مصفوفة channels سلسلة مرتبة (بعمق أقصى مفروض وبلا قنوات مكررة). تحمل كل مدخلة غير أخيرة مُطلق fallback_on — failed أو no_delivery أو no_engagement — إضافة إلى نافذة fallback_after_seconds. المدخلة الأخيرة نهائية ولا تحمل حقول تراجع. وعندما توجد السلسلة يجب أن يساوي channel على المستوى الأعلى مدخلتها الأولى. يقارن دليل سلاسل التراجع الموحَّد هذا السطح بسياسة cascade_policy لكل رسالة وسلاسل ملفات Verify، ويمشي أمثلة عملية لكليهما.
أيًّا كان الشكل، تنطبق ضوابط الوتيرة هذه:
- Throttle. يحد
throttle_rate(رسائل/ثانية) من سرعة الإرسال — الافتراضي على المنصة 50 رسالة/ثانية؛ والقيمة 0 الصريحة تعني الافتراضي أيضًا. - الإرسال الذكي. يجدول
send_time_optimization: "recipient-optimal"كل مستلم في نافذة أفضل وقت له التالية من ملفات التفاعل، ويفرد التسليم على الساعات الأربع والعشرين التالية. عاينه أولًا بـPOST /campaigns/:id/preview-smart-sendالذي يعيد أوقاتًا مقترحة لكل جهة اتصال إضافة إلى تلميحnext_best_channelللعينة. ولقياس ما إذا كان التوقيت نفسه يؤتي ثماره، اشترك في شريحة hold-out لكل مستلم عبرvariables.smart_send_holdout_pct— انظر الخطوة 7. - معاينة القناة. إذا كانت قناة الحملة ما تزال مفتوحة، تحقق منها على عينة من المستلمين بـ
POST /messages/route-preview— توصية الموجّه الذكي وسلسلة التراجع وكلفة كل رسالة ودرجة التفاعل، من دون إرسال شيء. لتسليح تلك السلسلة للإرسال (فيتدرج الفشل النهائي بدل التوقف عند أول قناة) مرّرcascade_policyفي الطلب نفسه — يغطي دليل سلاسل تراجع الإرسال الذكي شكل السياسة لكل رسالة، ويمشي دليل معاينة المسار الذكي النقطة ونمط خط الإرسال. - نافذة الإرسال. يؤجل
send_window: { start_local_hour, end_local_hour }المستلمين الذين يقع وقتهم المحلي خارج النافذة — نافذة موجبة لكل مستلم، تختلف عن ساعات الهدوء (فلتر سالب).
7. راقب وقِس
إحصاءات حية. يعيدGET /campaigns/:id/stats مجاميع sent وdelivered وfailed وopened وclicked وreplied. ومن الـ SDK يكون ذلك orbit.request("GET", \/campaigns/$/stats`)— المهرب مجددًا، إذ يتوقف المورد المُكتب عندsend. ولتفصيل أدق تعرض حملات drip وjourney تباعًا /drip-analytics و/journey-analytics و/journey/node-analytics`. تتبع إعادات المحاولة سياسة إعادة المحاولة في المراسلة — فتُعاد الإخفاقات ذات الرموز القابلة لإعادة المحاولة إلى الطابور حتى تستنفد السياسة.
معايير الخروج. أعلن أهداف التحويل معاييرَ خروج (أو exit_goals في الـ drips): عندما تبلغ جهة اتصال الهدف (مثل purchase_completed) تغادر السلسلة بدل تلقي الباقي. تحقق من معايير الخروج وقت الحفظ؛ ويفرضها المقيّم وقت التشغيل.
رفع الـ Holdout. إذا ضبطت الحملة hold-out (campaign_holdout_percent في variables، أو ab_holdout_percent في اختبارات A/B) يقارن GET /campaigns/:id/holdout-lift شريحة المعالجة بالتحكم ويعيد فرق معدل التحويل مع فاصل ثقة Wald — لترى ما إذا كانت الرسالة قد تفوقت على عدم فعل شيء، لا أي متغير فاز فحسب. تعرض الـ journeys الأمر نفسه تحت GET /campaigns/:id/journey/holdout-lift؛ والإرسال الذكي تحت GET /campaigns/:id/smart-send-holdout-lift.
Hold-out الإرسال الذكي (توقيت لكل مستلم). يجيب الـ holdout على مستوى الحملة أعلاه عن سؤال «هل أفاد الإرسال أصلًا؟» — فلا تتلقى شريحة التحكم أي رسالة. لعزل تحسين وقت الإرسال نفسه، اضبط variables.smart_send_holdout_pct (من 0 إلى 50، وتُقلم القيم فوق 50) على حملة recipient-optimal. تحتفظ هذه الشريحة من المستلمين بالجدول الطبيعي السابق للتحسين فيما ينال الباقون أفضل وقت متوقع لهم؛ ويتلقى الفريقان الحملة، فيعزل القياس التوقيت. الإسناد حتمي لكل جهة اتصال (ثابت عبر الإيقاف/الاستئناف وإعادة الإطلاق) ويستخدم بذرة خاصة به غير مترابطة مع الـ holdout على مستوى الحملة. عدم الضبط أو 0 يعني لا hold-out. اقرأ النتيجة بـGET /campaigns/:id/smart-send-holdout-lift الذي يعيد configured وholdout_pct والـlift الأساسي على إشارة التحويل بالنقر، وتفصيل metrics يُقيَّم على delivered/read/replied لتنال القنوات بلا روابط (SMS العادي ومعظم WhatsApp) رقمًا حقيقيًا أيضًا. حملة بلا hold-out مضبوط تعيد configured: false مع 200 لا خطأ.
ROI / ROAS. يعيد GET /campaigns/:id/roas الإيراد المنسوب (بتفصيلي اللمسة الأخيرة واللمسات المتعددة) وقمع النقر والإيراد الزائد على الـ holdout. ويعرض GET /campaigns/:id/roas/touchpoints مساهمة كل لمسة. استخدم GET /campaigns/:id/cost و/campaigns/:id/export لمطابقة الإنفاق وسحب الصفوف الخام.
قياس متكرر. في الحملات المتكررة المجدولة تنطبق نقاط الإحصاءات نفسها على كل حدوث؛ ويجمّع GET /campaigns/stats عبر الحملات.
8. اشترك في webhooks الحملة
سجّل نقطة النهاية (راجع نظرة عامة على webhooks) واشترك في أحداثcampaign.* لتشغيل CRM خاص بك أو إنذاراتك:
campaign.created/campaign.updated/campaign.deletedcampaign.started/campaign.paused/campaign.resumed/campaign.cancelled/campaign.completedcampaign.drip_step.sent/campaign.drip_step.completed/campaign.drip.completed
9. استكشاف الأخطاء وإصلاحها
- يحلّ الجمهور إلى صفر. أعد تشغيل معاينة الجمهور مع تمرير
channel؛ يخبرك الإسقاط الصافي أي شريحة أفرغته (كله suppressed، أو كله opt-out، أو لا عنوان قابلًا للوصول). أصلح القائمة أو تغطية عناوين القناة، لا الحملة. - يعرض الـ dry-run تحذيرات حمراء. إدخالات
warnings[]صريحة — «no provider registered» تعني أن القناة بلا هوية إرسال مهيأة؛ و«quiet hours fully closed» تعني أن النافذة المحلولة ترفض كل ساعة محلية؛ و«insufficient balance» تعنيcost.sufficient: false. أزل التحذير وأعد تشغيل الـ dry-run. - يعيد الإطلاق 402 أو شكل انتظار موافقة. فشل فحص الرصيد، أو أن سير عمل الموافقات مفعّل — إمّا اشحن المحفظة أو انتظر
POST /campaigns/approvals/:id/approve. - حملة journey عالقة في paused. تتوقف الحملة تلقائيًا عند بلوغ
credit_cap_usd_centsأو عند شرط drip معطوب. افحصGET /campaigns/:id/statsوأزل العائق ثمPOST /campaigns/:id/resume. تحتفظ الـ journeys المتوقفة بحالة التسجيل؛ ويستأنف الاستمرار من حيث توقفت. - يفرد الإرسال الذكي التسليم أكثر من اللازم. يوزع
recipient-optimalالإرسالات عمدًا على 24 ساعة. إذا كنت تحتاج دفعة واحدة، اضبطsend_time_optimization: "fixed"واستخدمsend_windowإذا امتد المستلمون عبر مناطق زمنية.
مثال عملي: promo تجزئة، من المسودة إلى التحليلات
عرض SMS صيفي لقائمة VIP، مع hold-out ليكون رقم الرفع حقيقيًا.- أنشئ المسودة.
- عاين الجمهور.
matching_count سليمًا، وشريحة suppressed + opted_out صغيرة، وunreachable يساوي صفرًا.
- شغّل الـ dry-run.
audience.deliverable (صافي بعد الـ hold-out بنسبة 10%) وcost.sufficient: true وعدم وجود تحذيرات.
- عاين أوقات الإرسال الذكي (اختياري).
- أطلق.
-
اشترك في أحداث دورة الحياة (
campaign.startedوcampaign.completed) واقرأ الإحصاءات مع تراكم حالات التسليم. - قِس. بعد اكتمال الإرسال:
orbit.request() للباقي: