Analytics API
توفّر Analytics API وصولاً برمجياً إلى تحليلات المنتج، بما فيها استعلامات الأحداث والمسارات والتحليل الاستبقائي وتحليل المسارات.
كل نقاط النهاية في هذه الصفحة نسبية إلى عنوان الأساس https://api-eu1.joryio.com/api. راجع نظرة عامة على API.
المصادقة
تتطلب جميع النقاط المصادقة بمفتاح API:
Authorization: Bearer YOUR_API_KEY
X-Workspace-Id: YOUR_WORKSPACE_ID
مستكشف الأحداث
عرض الأحداث
احصل على ملخص لجميع الأحداث المتتبعة.
GET /analytics/events
معاملات الاستعلام:
| المعامل | النوع | الوصف |
|---|---|---|
| startDate | string | تاريخ البدء، YYYY-MM-DD |
| endDate | string | تاريخ النهاية، YYYY-MM-DD |
| search | string | تصفية باسم الحدث |
| limit | number | أقصى نتائج، الافتراضي 100 |
| channels | string | اختياري. احتساب أحداث الرسائل وأحداث داخل التطبيق على هذه القنوات فقط، مفصولة بفواصل - راجع تصفية القنوات |
الاستجابة:
{
"events": [
{
"eventName": "signup_completed",
"totalCount": 15420,
"uniqueUsers": 12350,
"lastSeen": "2024-01-15T14:30:00Z"
}
],
"total": 45
}
تصفية القنوات
تقبل GET /analytics/events وPOST /analytics/events/trend وPOST /analytics/events/query مرشحًا اختياريًا channels. ينطبق فقط على أحداث الرسائل (message.*) وأحداث داخل التطبيق (in_app.*): تُحتسب هذه فقط عندما تكون قناتها في القائمة. الأحداث التي لا قناة لها - المشتريات والجلسات والأحداث المخصصة - تُحتسب دائمًا، أيًا كانت القائمة.
- القنوات:
email,sms,whatsapp,push,viber,webhook,wallet,in_app,connector. تُرفض أي قيمة أخرى بالرمز400. - يقبل
GETقائمة مفصولة بفواصل (channels=email,sms)؛ وتقبل مساراتPOSTمصفوفة JSON ("channels": ["email", "sms"]). - عند الإغفال: لا تصفية - الأرقام نفسها كما قبل وجود المعامل. فارغ (
channels=أو[]): لا أحداث رسائل ولا أحداث داخل التطبيق إطلاقًا.
عند إرسال channels، تُرجع GET /analytics/events أيضًا hiddenByChannel: أحداث الرسائل وأحداث داخل التطبيق التي استبعدها المرشح، لكل قناة.
{
"events": [],
"total": 45,
"hiddenByChannel": [{ "channel": "webhook", "count": 4012 }]
}
الحصول على اتجاه حدث
احصل على أعداد الأحداث مع مرور الوقت.
POST /analytics/events/trend
يقبل المرشح الاختياري channels - راجع تصفية القنوات.
نص الطلب:
{
"eventNames": ["signup_completed", "purchase_completed"],
"startDate": "2024-01-01",
"endDate": "2024-01-31",
"timeGranularity": "day"
}
الاستجابة:
[
{
"date": "2024-01-01",
"count": 523,
"uniqueUsers": 498
}
]
الحصول على خصائص حدث
اعرض خصائص حدث محدد.
GET /analytics/events/:eventName/properties
الاستجابة:
[
{
"propertyName": "plan_type",
"valueCount": 4
},
{
"propertyName": "source",
"valueCount": 12
}
]
الحصول على توزيع خاصية
احصل على توزيع قيم خاصية لحدث.
POST /analytics/events/property-breakdown
نص الطلب:
{
"eventName": "purchase_completed",
"property": "payment_method",
"startDate": "2024-01-01",
"endDate": "2024-01-31"
}
الاستجابة:
{
"total": 5420,
"values": [
{ "value": "credit_card", "count": 3250, "percentage": 59.96 },
{ "value": "paypal", "count": 1520, "percentage": 28.04 },
{ "value": "bank_transfer", "count": 650, "percentage": 11.99 }
]
}
تحليل المسار
إنشاء مسار
احفظ تعريف مسار جديد.
POST /analytics/funnels
نص الطلب:
{
"name": "Signup to Purchase",
"steps": [
{
"id": "step_1",
"order": 0,
"eventName": "signup_completed",
"filters": []
},
{
"id": "step_2",
"order": 1,
"eventName": "onboarding_completed",
"filters": []
},
{
"id": "step_3",
"order": 2,
"eventName": "purchase_completed",
"filters": []
}
],
"conversionWindowDays": 7
}
عرض المسارات
GET /analytics/funnels
تحليل مسار
شغّل التحليل على مسار محفوظ.
POST /analytics/funnels/:id/analyze
نص الطلب:
{
"startDate": "2024-01-01",
"endDate": "2024-01-31",
"breakdown": {
"type": "event_property",
"property": "utm_source"
}
}
الاستجابة:
{
"totalUsers": 10000,
"overallConversion": 12.5,
"steps": [
{
"id": "step_1",
"order": 0,
"eventName": "signup_completed",
"enteredCount": 10000,
"conversionRate": 100,
"dropOffRate": 0
},
{
"id": "step_2",
"order": 1,
"eventName": "onboarding_completed",
"enteredCount": 6500,
"conversionRate": 65,
"dropOffRate": 35
},
{
"id": "step_3",
"order": 2,
"eventName": "purchase_completed",
"enteredCount": 1250,
"conversionRate": 19.23,
"dropOffRate": 80.77
}
],
"breakdown": [
{
"breakdownValue": "google",
"overallConversion": 15.2,
"steps": [...]
}
]
}
تحليل مسار سريع
حلّل من دون حفظ.
POST /analytics/funnels/quick-analysis
تحليل الاحتفاظ
تحليل الاحتفاظ
POST /analytics/retention/analyze
نص الطلب:
{
"startEvent": "signup_completed",
"returnEvent": "session_started",
"startDate": "2024-01-01",
"endDate": "2024-01-31",
"timeUnit": "week",
"periods": 8
}
الاستجابة:
{
"timeUnit": "week",
"cohorts": [
{
"cohortDate": "2024-01-01",
"cohortSize": 1250,
"periods": [
{ "period": 0, "retained": 1250, "retentionRate": 100 },
{ "period": 1, "retained": 562, "retentionRate": 44.96 },
{ "period": 2, "retained": 375, "retentionRate": 30.0 }
]
}
],
"overallRetention": [100, 45.2, 31.5, 25.8, 22.1, 19.5, 17.8, 16.2]
}
تصدير الاحتفاظ
POST /analytics/retention/export
مقارنة الاحتفاظ بين الشرائح
يشغّل التحليل الاستبقائي نفسه على شريحة واحدة حتى 10 شرائح محفوظة ويعيد صفًا لكل شريحة، ليمكن مقارنة منحنياتها. حلّ هذا محل POST /analytics/retention/compare-cohorts الذي لم يعد موجودًا.
POST /analytics/retention/compare-segments
نص الطلب:
{
"segmentIds": ["seg_9f2a", "seg_71bc"],
"startDate": "2024-01-01",
"endDate": "2024-01-31",
"entryEvent": "signup_completed",
"returnEvent": "session_started",
"timeUnit": "week",
"periods": 8
}
| الحقل | مطلوب | الوصف |
|---|---|---|
segmentIds | نعم | من معرّف شريحة واحد إلى 10. |
startDate, endDate | نعم | النافذة التي تُقرأ منها أحداث الدخول. |
entryEvent | لا | الإجراء الذي يضع المستخدم في دفعة. |
returnEvent | لا | الإجراء الذي يُحتسب عودةً. |
timeUnit | لا | day أو week أو month. |
periods | لا | عدد الفترات المتتبَّعة. |
الاستجابة:
[
{
"segmentId": "seg_9f2a",
"segmentName": "Power users",
"retention": { "timeUnit": "week", "cohorts": [], "overallRetention": [] },
"resolvedUsers": 4820,
"analyzedUsers": 4820,
"truncated": false
},
{
"segmentId": "seg_71bc",
"segmentName": "All customers",
"retention": { "timeUnit": "week", "cohorts": [], "overallRetention": [] },
"resolvedUsers": 480000,
"analyzedUsers": 50000,
"truncated": true
}
]
| الحقل | الوصف |
|---|---|
resolvedUsers | الحجم الحقيقي للشريحة، أي كل عضو انحلّت إليه. |
analyzedUsers | عدد الأعضاء الذين حُسب منهم retention. يساوي resolvedUsers ما لم تتجاوز الشريحة الحد. |
truncated | true حين تتجاوز الشريحة حد 50,000 عضو، فيصف retention عندها عينة عشوائية حتمية من analyzedUsers عضوًا، لا أول N وهو ما كان سيكون منحازًا. أفصح عن الرقمين معًا أينما عرضت النسب. |
error | يظهر حين تتعذّر مقارنة هذه الشريحة تحديدًا. تُعاد بقية الصفوف كالمعتاد، والصف الفاشل لا يحمل نسبًا، فلا تعرضه كـ 0%. |
يعيد بيانات CSV.
تحليل المسارات
تحليل المسارات
POST /analytics/paths/analyze
نص الطلب:
{
"startDate": "2024-01-01",
"endDate": "2024-01-31",
"startEvent": "landing_page_view",
"direction": "forward",
"maxSteps": 5,
"minPathCount": 10,
"minPathPercent": 0.5,
"maxBranchesPerStep": 5,
"excludeEvents": ["heartbeat", "scroll"]
}
يضبط minPathCount، المستخدمين المطلقين، وminPathPercent، نسبة المستخدمين المؤهلين من 0 إلى 100، عتبة التكرار: يجب أن يتجاوز المسار الأكبر منهما، فتحافظ النسبة على قابلية الاستخدام في مساحات العمل بمختلف الأحجام. ويحد maxBranchesPerStep، من 1 إلى 50 والافتراضي 8، مخطط التدفق إلى أبرز الأحداث التالية في كل خطوة ليبقى مقروءاً مع الحجم الكبير.
الاستجابة:
{
"totalUsers": 25000,
"totalPaths": 342,
"paths": [
{
"path": ["landing_page_view", "signup_started", "signup_completed"],
"count": 3250,
"percentage": 13.0
}
],
"sankey": {
"nodes": [
{ "id": "landing_page_view_0", "name": "landing_page_view" }
],
"links": [
{ "source": "landing_page_view_0", "target": "signup_started_1", "value": 5200 }
]
}
}
لوحات التحكم
إنشاء لوحة تحكم
POST /analytics/dashboards
نص الطلب:
{
"name": "Executive Dashboard",
"description": "Key metrics overview",
"widgets": [
{
"id": "widget-1",
"type": "metric",
"title": "Active Users",
"config": {
"eventName": "session_started",
"metric": "unique_users"
},
"layout": { "x": 0, "y": 0, "width": 3, "height": 2 }
}
]
}
عرض لوحات التحكم
GET /analytics/dashboards
الحصول على لوحة تحكم
GET /analytics/dashboards/:id
تحديث لوحة تحكم
PUT /analytics/dashboards/:id
حذف لوحة تحكم
DELETE /analytics/dashboards/:id
التحليلات الفورية
الحصول على المستخدمين النشطين
GET /analytics/realtime/active-users
الاستجابة:
{
"count": 1523,
"trend": 5.2
}
تدفق أحداث حي، SSE
GET /analytics/realtime/events/stream
يعيد تدفق Server-Sent Events للأحداث الحية.
القياس التزايدي
نقطتا نهاية تجيبان عن سؤالين لا تستطيع التقارير المعتادة الإجابة عنهما: هل تسببت الرسائل في شيء، وهل أرسل أكثر من اللازم. وكلتاهما مبنية على مجموعة التحكم العامة - شريحة من جهات الاتصال تُختار عشوائيًا وتُستبعد من كل التسويق، حتى يوجد ما يُقارَن به بصدق.
الأثر مقابل مجموعة التحكم العامة
GET /analytics/global-holdout?startDate=2026-08-01&endDate=2026-08-31
التحويلات والإيرادات لكل من تلقى تسويقًا في الفترة، مقابل المجموعة المستبعدة عشوائيًا.
النتيجة مغلّفة داخل uplift. تكون { "uplift": null } عندما لا تكون هناك مجموعة تحكم عامة قيد التشغيل - لا يوجد ما يُقارَن به، والنتيجة غير المقيسة ليست صفرًا.
الاستجابة:
{
"uplift": {
"treatmentRecipients": 41280,
"treatmentConverters": 1650,
"treatmentRevenue": 82560,
"treatmentRevenuePerRecipient": 2.0,
"controlRecipients": 4600,
"controlConverters": 138,
"controlRevenue": 6900,
"controlRevenuePerRecipient": 1.5,
"incrementalRevenue": 20640,
"upliftPct": 33.3,
"significance": {
"controlRate": 0.03,
"treatmentRate": 0.04,
"pValue": 0.002,
"significant": true,
"controlInterval": [0.0255, 0.0353],
"treatmentInterval": [0.0381, 0.0419],
"reason": "significant",
"minConvertersPerArm": 10
},
"currency": "EUR",
"mixedCurrency": false,
"windowHours": 168
}
}
يختبر significance.significant معدل التحويل لا الإيراد: فالإيراد لكل مستلم متصل وذو ذيل ثقيل، واختبار النسب عليه يُخرج أرقامًا تبدو واثقة ولا تعني شيئًا. تعامل مع incrementalRevenue ((treatmentRevenuePerRecipient - controlRevenuePerRecipient) x treatmentRecipients) كتقدير تأتي مصداقيته من significance.significant لا من دقته هو. يكون significance بقيمة null عندما لا يكون لأحد الذراعين مستلمون؛ ويوضح reason سبب عدم دلالة النتيجة بعد (not_enough_conversions أو no_difference_detected). ويكون upliftPct بقيمة null عندما لا يحقق ذراع التحكم أي إيراد. windowHours هو نافذة السلوك التي قيس فيها الذراعان (الافتراضي 168)، وmixedCurrency يكون true عندما تمتد المشتريات لأكثر من عملة واحدة - لا يُطبَّق أي تحويل عملات.
تكرار الرسائل
GET /analytics/message-frequency?startDate=2026-08-01&endDate=2026-08-31
التحويلات بحسب عدد الرسائل التي تلقاها الشخص، مقسّمة بحسب ما إذا كان متفاعلًا بالفعل قبل الفترة.
الاستجابة:
{
"buckets": [
{ "bucket": "0", "tier": "engaged", "people": 2300, "buyers": 69, "purchaseRate": 3.0, "converters": 69, "conversionRate": 3.0,
"revenue": 3450, "revenuePerPerson": 1.5, "randomised": true },
{ "bucket": "1", "tier": "engaged", "people": 8100, "buyers": 405, "purchaseRate": 5.0, "converters": 405, "conversionRate": 5.0,
"revenue": 20250, "revenuePerPerson": 2.5 },
{ "bucket": "6-9", "tier": "engaged", "people": 1200, "buyers": 48, "purchaseRate": 4.0, "converters": 48, "conversionRate": 4.0,
"revenue": 4800, "revenuePerPerson": 4.0 }
],
"anchored": true,
"currency": "EUR",
"mixedCurrency": false,
"priorWindowDays": 90
}
الفئات هي 0 و1 و2 و3 و4-5 و6-9 و10+. والحقل tier إما engaged أو quiet، ويُحدَّد من عمليات الفتح والنقر خلال priorWindowDays السابقة للفترة - وليس داخلها أبدًا، فذلك سيكون دائريًا.
حقلان يحددان كيف يجوز قراءة الأرقام:
- يظهر
randomisedفقط على فئة0مبنية من مجموعة التحكم العامة. أما الصفر المبني بأي طريقة أخرى فهو أشخاص لم يتلقوا شيئًا مصادفةً، ولم يتلقوا لأسباب تجعلهم أيضًا أقل احتمالًا للشراء. - يكون
anchoredبقيمةtrueعند وجود هذا الصفر. وعندما يكونfalseلا توجد فئة0إطلاقًا، وهذا مقصود: فالخط الأساس المُختلَق سيقع تحديدًا عند النقطة التي يُقاس مقابلها كل رقم آخر.
اقرأ المنحنى وأنت تعلم أن الانحياز يعمل في اتجاه واحد. فمن يتلقون رسائل أكثر أكثر تفاعلًا من البداية، ولذلك يُدفع الخط إلى الأعلى مهما كانت الحقيقة. الخط الصاعد لا يثبت شيئًا، بينما الخط الذي يستوي أو ينخفض عند التكرارات الأعلى جدير بالثقة - فقد ظهر رغم انحياز يعمل ضده.
يحصي converters الطلبات بكل العملات؛ بينما يجمع revenue العملة المهيمنة وحدها، المذكورة في currency. وعندما يكون mixedCurrency بقيمة true فإن عمود المال شريحة واحدة لا مجموعًا بأسعار صرف.
buyers وpurchaseRate هما مشتريات (طلبات)، لا تحويلات: يشمل المنحنى مساحة العمل كلها، فلا يوجد هدف حملة أو رحلة لاحتسابه. converters وconversionRate هما الرقمان نفساهما باسميهما القديمين، أُبقي عليهما للعملاء الحاليين.
أداء المحتوى
GET /analytics/content-performance?startDate=2026-08-01&endDate=2026-08-31&channel=email
نسب الفتح والنقر والشراء بعد الإرسال حسب ماهية الرسالة - النبرة ونوع العرض والدعوة إلى إجراء والطول والتخصيص والصور والموضوع - عبر كل قالب ونسخة حملة ورسالة رحلة. channel اختياري.
الاستجابة:
{
"startDate": "2026-08-01",
"endDate": "2026-08-31",
"channel": null,
"minReached": 100,
"conversionWindowHours": 168,
"taxonomyVersion": "t1",
"totals": { "sent": 18400, "reached": 12100, "labelledSent": 17900, "unlabelledSent": 500, "identities": 42, "labelledIdentities": 40, "noGoalSent": 2300 },
"fields": {
"tone": [
{ "value": "friendly", "sent": 9100, "reached": 6000, "opened": 2520, "clicked": 420, "converted": 150, "goalReached": 5000, "bought": 180, "openRate": 42.0, "clickRate": 7.0, "conversionRate": 3.0, "purchaseRate": 3.0 },
{ "value": "urgent", "sent": 2200, "reached": 1500, "opened": 720, "clicked": 150, "converted": 0, "goalReached": 0, "bought": 60, "openRate": 48.0, "clickRate": 10.0, "conversionRate": null, "purchaseRate": 4.0 },
{ "value": "premium", "sent": 90, "reached": 80, "opened": 30, "clicked": 4, "converted": 1, "goalReached": 80, "bought": 1, "openRate": null, "clickRate": null, "conversionRate": null, "purchaseRate": null }
],
"offerType": [ "..." ],
"ctaType": [ "..." ]
},
"mergeFields": {
"version": "m2",
"measuredSent": 17400,
"pendingSent": 500,
"buckets": [
{
"field": "user.first_name", "placement": "subject", "usage": "merge", "channels": ["email"],
"with": { "sent": 6100, "reached": 4200, "opened": 1932, "clicked": 315, "converted": 120, "goalReached": 3800, "bought": 130, "openRate": 46.0, "clickRate": 7.5, "conversionRate": 3.16, "purchaseRate": 3.1 },
"without": { "sent": 8800, "reached": 5900, "opened": 2242, "clicked": 354, "converted": 140, "goalReached": 5200, "bought": 160, "openRate": 38.0, "clickRate": 6.0, "conversionRate": 2.69, "purchaseRate": 2.71 }
}
],
"other": null
}
}
يحتوي fields على قائمة لكل وسم (tone، urgency، offerType، ctaType، lengthBand، personalizationDepth، imageryPresent، primaryTopic)، مرتبة حسب الأشخاص الذين وُصل إليهم. تحسب النسب الأشخاص الفريدين مع استبعاد الروبوتات؛ وopenRate وclickRate نسبة من الأشخاص الذين سُلِّمت إليهم الرسالة (Push: من reached؛ In-app: من المعروضة) - القاعدة نفسها لمعدلات الحملات (راجع كيف تُحسب معدلات الفتح والنقر). تكون النسبة null دون minReached شخصًا، وفي قناة لا تستطيع قياسها (الإشعارات لا فتح فيها). conversionRate وpurchaseRate موصوفان أدناه. totals.unlabelledSent هو حركة لا وسم لمحتواها بعد؛ POST /ai/content/backfill (لوحة التحكم) يوسم المحتوى الحالي.
conversionRate وconverted هما هدف التحويل الخاص بكل رسالة - هدف حملتها أو رحلتها، محسوبًا بنافذة ذلك الهدف ونموذج الإسناد الخاص به ومنسوبًا إلى النسخة أو رسالة الرحلة التي ينسب إليها النموذج - من goalReached، أي الأشخاص الذين وصلتهم رسائل لها هدف. الصف الذي لا تحمل فيه أي رسالة هدفًا فيه conversionRate: null، والقالب المُرسل وحده لا يُحتسب تحويلًا أبدًا. totals.noGoalSent هو الحركة بلا هدف. purchaseRate وbought هما رقم الطلبات: شراء الشخص نفسه خلال conversionWindowHours بعد الإرسال، نافذة بسيطة أيًا كان الهدف. حتى 2026-10-14 كان conversionRate هو نسبة الشراء هذه.
يقارن mergeFields المحتوى حسب حقل الدمج: دلو واحد لكل اسم حقل وplacement (subject، preheader، title، body، cta، link - عنوان رابط؛ تُحسب متغيرات {{n}} في WhatsApp كالحقل المربوطة به) وusage (merge = معروض، conditional = يقرّر فقط ما يُعرض)، مع الأعداد والنسب نفسها لعمليات الإرسال الموسومة التي تستخدمه (with) ولعمليات الإرسال الموسومة على channels نفسها التي لا تستخدمه (without). ينطبق حد minReached على كل جانب. أسماء الحقول فقط، وليس القيم أبدًا. تُعرض حتى 100 تركيبة، الأكثر وصولًا إلى الأشخاص أولًا؛ ويُجمع الباقي في other ولا يُحذف. pendingSent هو حركة موسومة لم تُقرأ حقول الدمج الخاصة بها بعد؛ وهي ليست في أي جانب. المقارنة ارتباط وليست سببًا.
استجابات الأخطاء
تعيد كل النقاط استجابات الخطأ القياسية:
{
"statusCode": 400,
"message": "Invalid date range",
"error": "Bad Request"
}
| رمز الحالة | الوصف |
|---|---|
| 400 | طلب غير صالح أو خطأ تحقق |
| 401 | غير مصادق |
| 403 | ممنوع |
| 404 | المورد غير موجود |
| 500 | خطأ داخلي في الخادم |