API לאנליטיקה
ה־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 | אופציונלי. ספירת אירועי הודעה ו-In-App רק בערוצים האלה, מופרדים בפסיקים - ראו סינון לפי ערוץ |
תגובה:
{
"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 (in_app.*): אלה נספרים רק כשהערוץ שלהם נמצא ברשימה. אירועים ללא ערוץ - רכישות, סשנים, אירועים מותאמים אישית - נספרים תמיד, בלי קשר לרשימה.
- ערוצים:
email,sms,whatsapp,push,viber,webhook,wallet,in_app,connector. כל ערך אחר נדחה עם400. GETמקבל רשימה מופרדת בפסיקים (channels=email,sms); נתיבי ה-POSTמקבלים מערך JSON ("channels": ["email", "sms"]).- בלי הפרמטר: אין סינון - אותם מספרים כמו לפני שהפרמטר נוסף. ריק (
channels=או[]): אף אירוע הודעה או In-App.
כש-channels נשלח, GET /analytics/events מחזיר גם hiddenByChannel: אירועי ההודעה וה-In-App שהסינון השמיט, לפי ערוץ.
{
"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
מחזיר נתוני CSV.
השוואת שימור בין סגמנטים
מריץ את אותו ניתוח שימור על 1 עד 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 | לא | הפעולה שמכניסה משתמש ל-Cohort. |
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%. |
ניתוח נתיבים
ניתוח נתיבים
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"]
}
תגובה:
{
"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 | שגיאת שרת פנימית |