דלג לתוכן הראשי

API של קמפיינים

יצירה, שיגור וניטור של קמפיינים באופן תכנותי.

כל נקודות הקצה בעמוד זה יחסיות לכתובת הבסיס: https://api-eu1.joryio.com - ראו סקירת API.

אימות

כל הבקשות דורשות אימות באמצעות מפתח API:

Authorization: Bearer jry_live_your_api_key_here
Content-Type: application/json

המפתח חייב לשאת את ההרשאה (scope) שכל נקודת קצה דורשת:

הרשאהנקודות קצה
campaigns:readרשימה, שליפה, סטטיסטיקות, נמענים, גרסאות, היסטוריה
campaigns:writeיצירה, עדכון, שכפול, ארכוב, תיוג, שחזור גרסה
campaigns:sendשליחה, השהיה, חידוש, ביטול, ניסיון חוזר, שליחות בדיקה, שליחה טרנזקציונית
campaigns:deleteמחיקה ומחיקה באצווה

ראו מפתחות API לניהול הרשאות.


יצירת קמפיין

נקודת קצה

POST /campaigns

גוף הבקשה

שדהסוגחובהתיאור
namestringכןשם הקמפיין (עד 255 תווים)
descriptionstringלאתיאור (עד 1000 תווים)
channelstringכןemail, sms, push, webhook, whatsapp, in_app או ai_optimized
variantsarrayכן*וריאנטים של ההודעה (חובה לכל ערוץ מלבד in_app)
targetingobjectלאקהל: userIds, filterGroups, excludeFilterGroups, filterOperator, subscriptionPreference
sendTypestringלאimmediate, scheduled, triggered, intelligent, recurring או ai_optimized
scheduledAtstringלאתאריך ISO 8601 עבור sendType: "scheduled"
scheduledTimezonestringלאאזור זמן IANA שבו מתפרש מועד התזמון
triggerConfigobjectלאכלל טריגר עבור sendType: "triggered"‏ - type, eventName, conditions, reEntry, cooldownHours
recurringScheduleobjectלאעבור sendType: "recurring"‏ - frequency‏ (daily/weekly/monthly/custom), cron, dayOfWeek, dayOfMonth, timeOfDay, timezone, endDate, maxOccurrences
conversionTrackingobjectלאprimaryConversion / secondaryConversions (שם אירוע + תנאי מאפיינים), conversionWindowHours, attributionModel‏ (first_touch/last_touch/linear)
emailConfigIdstringלאזהות שולח אימייל שמורה (לערוץ האימייל)
subscriptionCategoryIdstringלאקטגוריית הסכמה (רשימת מנויים) שתחתיה הקמפיין נשלח
sendVolumeLimitobjectלאenabled, maxSends, cadence‏ (lifetime/per_send)

תוכן הודעת In-App

כל וריאנט של In-App נושא את התוכן שנכתב עבורו ב־customContent. השדה mode קובע אילו שדות רלוונטיים:

modeשדותמוצג כ־
nativetitle, body, imageUrl, buttons, closeButton, backdropDismissible, styleהרכיבים של האפליקציה עצמה - ללא WebView
html (ברירת מחדל)html, cssקוד שנכתב על ידי המחבר בתוך WebView
drag_drophtml, css, grapejsDataכמו html; השדה grapejsData הוא מצב העורך הוויזואלי

אפשר להשמיט את mode, ואז המשמעות היא html.

{
"name": "Weekend offer",
"channel": "in_app",
"channelConfig": { "type": "modal", "triggers": [] },
"variants": [
{
"id": "v1",
"name": "Native",
"weight": 100,
"customContent": {
"mode": "native",
"title": "Weekend only",
"body": "Hi {{ firstName }}, members get 20% off through Sunday.",
"imageUrl": "https://cdn.example.com/weekend.png",
"buttons": [
{ "id": "cta", "text": "See offer", "action": "url", "url": "https://example.com/offer" },
{ "id": "later", "text": "Not now", "action": "dismiss" }
],
"closeButton": true,
"backdropDismissible": true,
"style": {
"backgroundColor": "#0A1240",
"textColor": "#FFFFFF",
"primaryButtonColor": "#00C8B7",
"cornerRadius": 18
}
}
}
]
}

שדות Native הם טקסט, לא markup. הם נשלחים לאפליקציה ללא escaping, כי האפליקציה מציגה אותם ב־View של טקסט - כך ש־A & B מגיע כ־A & B ולא כ־A & B. פרסונליזציה ב־Liquid פועלת ב־title, ב־body וב־text וב־url של הכפתורים.

buttons מוגבל ל־3. הערך action הוא אחד מ־dismiss, url או deep_link; עבור שני האחרונים נדרש url.

style - דריסות עיצוב אופציונליות

כל שדה הוא אופציונלי, ושדה חסר משמעו ירושה - צבע הרקע של האפליקציה, צבע הטקסט שלה, צבע ההדגשה והגופן שלה. הירושה הזו היא כל העניין בתוכן Native, לכן שלחו שדה רק כשהקמפיין באמת זקוק לו.

שדהטיפוסחל עלמשמעות
backgroundColorstringweb, iOS, Androidרקע הכרטיס
textColorstringweb, iOS, Androidכותרת וגוף ההודעה (הגוף מעט מרוכך)
primaryButtonColorstringweb, iOS, Androidצבע הכפתור הראשון
primaryButtonTextColorstringweb, iOS, Androidהטקסט שעליו. אם לא נשלח, נבחר שחור או לבן לפי הניגודיות מול צבע הכפתור
cornerRadiusnumberweb, iOS, Android0-48. לא חל על fullscreen, שם פינות מעוגלות היו חושפות את האפליקציה בפינות
fontSizenumberweb, iOS, Android10-32. גודל גוף ההודעה; הכותרת נגזרת ממנו. בנייד עדיין מוחלת גם הגדרת גודל הטקסט של המשתמש
titleWeightstringweb, iOS, Androidregular, medium, semibold, bold. לכותרת בלבד - גוף ההודעה נשאר רגיל לקריאוּת
textAlignstringweb, iOS, Androidauto (ברירת מחדל), start, center, end. ‏auto הולך לפי שפת ההודעה עצמה, כך שעברית וערבית נקראות מימין לשמאל גם באפליקציה באנגלית
fontFamilystringweb; בנייד מיטביבנייד חל רק אם האפליקציה ארזה את הגופן (iOS: רשום באפליקציה; Android: ‏res/font או משפחה מערכתית). אם הוא חסר, נשמר הגופן של האפליקציה במקום תחליף
customCssstringweb בלבדCSS בכתיבה ידנית, עד 20000 תווים. ה-SDK כותב מחדש כל סלקטור כך שיחול רק בתוך ההודעה לפני ההזרקה, ולכן כלל לא יכול להגיע לעמוד המארח, ו-@import מוסר. בטלפונים אין מנוע CSS והם מתעלמים ממנו

צבעים מועברים כפי שנכתבו - hex, ‏rgb() או מילת מפתח של CSS. ערך שהרנדרר לא מצליח לפרש חוזר לערך שנורש, במקום להכשיל את ההודעה.

ב-customCss אפשר לכוון לכרטיס עצמו, ל-h2, ל-p, ל-button.primary ול-button.secondary, והשדות שלמעלה נחשפים גם כמשתני CSS: --joryio-inapp-bg, --joryio-inapp-fg, --joryio-inapp-primary, --joryio-inapp-primary-fg, --joryio-inapp-radius ו---joryio-inapp-font.

תוכן HTML מחייב הסכמה מפורשת של האפליקציה. ערכות ה־SDK למובייל ולווב לא יציגו הודעת HTML אלא אם האפליקציה מגדירה allowHtmlJsInAppMessages באתחול, כי הודעה כזו מריצה JavaScript שנכתב על ידי המחבר בתוך האפליקציה. תוכן Native מוצג תמיד. ראו את המדריכים ל־Android, ל־iOS ול־Web.

| sendRateLimit | object | לא | enabled, maxPerMinute | | quietTimeOverride | object | לא | דריסת שעות שקט ברמת הקמפיין | | utmSettings | object | לא | עקיפה ברמת הקמפיין להגדרות UTM ולתיוג קישורים | | channelConfig | object | לא | הגדרות ספציפיות לערוץ (המבנה תלוי בערוץ) | | stoConfig / abTestConfig | object | לא | הגדרות אופטימיזציית זמן שליחה / בדיקת A/B | | resendPolicy | string | לא | מדיניות השליחה החוזרת של Send again בקמפיין חד־פעמי: only_new (ברירת מחדל), everyone או cooldown | | resendCooldownDays | number | לא | חלון זמן (בימים) עבור resendPolicy: "cooldown" | | tags | string[] | לא | תגיות | | status | string | לא | draft, scheduled, active, paused, completed או cancelled |

מבנה וריאנט

כל פריט ב-variants:

שדהסוגחובהתיאור
idstringכןמזהה הווריאנט
namestringכןשם הווריאנט
weightnumberכןנתח תעבורה, 0–100 (סכום המשקלים חייב להתאים לכללי הערוץ)
messageobjectלאהודעת הערוץ. אימייל: subject, preheader, from, fromName, html או templateId, text. SMS‏: body, from, shortenLinks. פוש: title, body, icon, image, data. וואטסאפ: messageType‏ (template/reply), templateId, wabaId, variableMapping, replyText. Webhook‏: url, method, headers, body, auth, bodyType
isControlGroupbooleanלאמסמן את הווריאנט כקבוצת ביקורת שאינה נכללת בשליחה (ומאפשר למדוד שיפור יחסי)

דוגמת בקשה

curl -X POST https://api-eu1.joryio.com/campaigns \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "July Newsletter",
"channel": "email",
"sendType": "scheduled",
"scheduledAt": "2026-07-20T10:00:00.000Z",
"scheduledTimezone": "America/New_York",
"variants": [
{
"id": "variant-a",
"name": "Variant A",
"weight": 100,
"message": {
"subject": "Your July update",
"from": "news@example.com",
"fromName": "Example",
"html": "<h1>Hello {{ user.firstName }}</h1>"
}
}
],
"targeting": {
"filterGroups": [
{
"filters": [
{ "type": "attribute", "field": "plan", "operator": "equals", "value": "premium" }
],
"operator": "AND"
}
]
}
}'

תגובה

הפעולה מחזירה את אובייקט הקמפיין שנוצר:

{
"id": "8f14e45f-ceea-467f-a11d-2f4b6a1c9e3b",
"name": "July Newsletter",
"channel": "email",
"status": "scheduled",
"sendType": "scheduled",
"scheduledAt": "2026-07-20T14:00:00.000Z",
"variants": [ ... ],
"targeting": { ... },
"tags": [],
"createdAt": "2026-07-12T09:00:00.000Z",
"updatedAt": "2026-07-12T09:00:00.000Z"
}

רשימת קמפיינים

נקודת קצה

GET /campaigns

פרמטרי שאילתה

פרמטרסוגברירת מחדלתיאור
statusstring-סינון לפי סטטוס (מופרד בפסיקים לריבוי ערכים)
channelstring-סינון לפי ערוץ (מופרד בפסיקים)
tagsstring-סינון לפי תגיות (מופרד בפסיקים)
qstring-חיפוש טקסט חופשי
createdBy / editedBystring-סינון לפי יוצר / עורך אחרון (מזהי משתמשים מופרדים בפסיקים)
createdFromstring-רק קמפיינים שנוצרו בתאריך ISO זה או אחריו
pagenumber1מספר עמוד
limitnumber20תוצאות לעמוד (לכל היותר 100)

דוגמת בקשה

curl -X GET "https://api-eu1.joryio.com/campaigns?status=active&channel=email&limit=50" \
-H "Authorization: Bearer jry_live_your_api_key"

תגובה

{
"data": [
{ "id": "8f14e45f-ceea-467f-a11d-2f4b6a1c9e3b", "name": "July Newsletter", "channel": "email", "status": "active" }
],
"pagination": {
"total": 23,
"page": 1,
"limit": 50,
"offset": 0,
"totalPages": 1,
"hasMore": false
}
}

שליפת קמפיין

GET /campaigns/:campaignId
curl -X GET https://api-eu1.joryio.com/campaigns/8f14e45f-ceea-467f-a11d-2f4b6a1c9e3b \
-H "Authorization: Bearer jry_live_your_api_key"

מחזירה את אובייקט הקמפיין המלא. סטטוס הקמפיין הוא אחד מ: draft, scheduled, active, paused, completed, cancelled, archived, failed (שגיאת שליחה קבועה - ראו failureReason).


עדכון קמפיין

PUT /campaigns/:campaignId

הגוף מקבל את אותם שדות כמו יצירת קמפיין - כולם אופציונליים; רק השדות שנשלחו מתעדכנים.

curl -X PUT https://api-eu1.joryio.com/campaigns/8f14e45f-ceea-467f-a11d-2f4b6a1c9e3b \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "name": "July Newsletter v2" }'
עריכת קמפיין פעיל

קמפיינים מבוססי טריגר וקמפיינים חוזרים נשארים active לאורך כל חייהם. עריכת קמפיין active אינה משנה את מה שנשלח כעת - העריכות נשמרות כטיוטה ממתינה. קראו ל־POST /campaigns/:campaignId/publish כדי להחיל אותן באופן אטומי על הקמפיין הפעיל, או ל־POST /campaigns/:campaignId/discard-draft כדי לבטל אותן. קמפיינים במצב טיוטה מתעדכנים במקום, ללא שלב פרסום.


מחיקת קמפיין

DELETE /campaigns/:campaignId

מחזירה 204 No Content. רק טיוטות שמעולם לא רצו נמחקות סופית; קמפיינים עם היסטוריית שליחה עדיף לארכב (POST /campaigns/:campaignId/archive) - הארכוב עוצר את השליחה ומשמר את האנליטיקה.


מחזור חיים של קמפיין

שיטהנתיבתיאור
POST/campaigns/:campaignId/sendשיגור הקמפיין (מתחיל שליחה / מפעיל קמפיין מבוסס-טריגר)
POST/campaigns/:campaignId/pauseהשהיית קמפיין רץ
POST/campaigns/:campaignId/resumeחידוש קמפיין מושהה
POST/campaigns/:campaignId/publishהחלת עריכות שנשמרו במאגר על קמפיין פעיל באופן אטומי (400 אם אין עריכות ממתינות)
POST/campaigns/:campaignId/discard-draftביטול עריכות שנשמרו במאגר עבור קמפיין פעיל (ללא פעולה אם אין)
POST/campaigns/:campaignId/cancelביטול קמפיין
POST/campaigns/:campaignId/resendשליחה חוזרת ("שלח שוב") של קמפיין חד-פעמי שהושלם, לפי resendPolicy שלו
POST/campaigns/:campaignId/retryניסיון חוזר לקמפיין failed (מחזיר אותו ל-scheduled)
POST/campaigns/:campaignId/preview-launchסיכום טרום-שיגור (גודל קהל, בדיקות) ללא שליחה
POST/campaigns/:campaignId/duplicateשכפול קמפיין
POST/campaigns/:campaignId/archiveארכוב (עוצר שליחה, שומר היסטוריה)
POST/campaigns/:campaignId/unarchiveשחזור למצב לא-שולח (יש להפעיל מחדש במפורש כדי לשלוח שוב)
POST/campaigns/:campaignId/stop-recurringעצירת מופעים עתידיים של קמפיין מחזורי
curl -X POST https://api-eu1.joryio.com/campaigns/8f14e45f-ceea-467f-a11d-2f4b6a1c9e3b/send \
-H "Authorization: Bearer jry_live_your_api_key"
שליחה חוזרת (מדיניות שליחה חוזרת)

קמפיין חד-פעמי שהושלם ניתן לשליחה חוזרת עם POST /campaigns/:campaignId/resend. מי מקבל אותו נקבע לפי resendPolicy של הקמפיין:

  • only_new (ברירת מחדל) - מדלג על מי שכבר קיבל את הקמפיין; רק משתמשים שטרם קיבלו אותו נכללים.
  • everyone - שליחה חוזרת לכל הקהל, כולל מי שכבר קיבל.
  • cooldown - שליחה חוזרת לכולם חוץ ממי שקיבל הודעה ב-resendCooldownDays הימים האחרונים.

כללי הסכמה וחסימה נאכפים תמיד. מגבלות תדירות פועלות לפי הדגל ignoreTouchingRules של הקמפיין. קמפיינים מבוססי טריגר משתמשים ב־triggerConfig.reEntry; קמפיינים מחזוריים נשלחים שוב לפי לוח הזמנים. הפעולה מחזירה 400 עבור סוגים אלה, עבור in-app או עבור קמפיין שטרם סיים לשלוח.


סטטיסטיקות קמפיין

GET /campaigns/:campaignId/stats

פרמטרי שאילתה: startDate, endDate (ISO 8601, אופציונליים).

תגובה

{
"campaignId": "8f14e45f-ceea-467f-a11d-2f4b6a1c9e3b",
"name": "July Newsletter",
"channel": "email",
"status": "completed",
"stats": {
"queued": 1200,
"sent": 1180,
"delivered": 1150,
"failed": 30,
"opened": 640,
"clicked": 210
},
"conversionStats": { ... },
"revenue": { ... },
"uplift": null,
"conversionTracking": { ... },
"startedAt": "2026-07-20T14:00:00.000Z",
"completedAt": "2026-07-20T14:12:00.000Z",
"createdAt": "2026-07-12T09:00:00.000Z"
}

conversionStats ו-revenue מאוכלסים כאשר מוגדר מעקב המרות; uplift מאוכלס רק כאשר וריאנט מסומן isControlGroup.

נקודות קצה נוספות לסטטיסטיקות

שיטהנתיבתיאור
GET/campaigns/:campaignId/variant-statsסטטיסטיקות A/B לפי וריאנט עם מובהקות סטטיסטית (startDate/endDate)
GET/campaigns/:campaignId/linksסטטיסטיקות הקלקה על קישורים (startDate/endDate)
GET/campaigns/:campaignId/failure-reasonsכשלי מסירה מקובצים לפי קוד שגיאת DLR ([{ code, reason, count }])
GET/campaigns/:campaignId/time-to-engageכמה זמן לקח לנמענים לפתוח או ללחוץ, בקבוצות - נמדד לכל נמען מרגע השליחה שלו, ולכן רלוונטי לקמפיינים מבוססי טריגר
GET/campaigns/:campaignId/send-occurrencesפילוח לפי שליחה עבור קמפיין חוזר, לפי תאריך השליחה - מעורבות משויכת לשליחה שקדמה לה
GET/campaigns/:campaignId/recipientsנמענים עם סטטוס ההודעה האחרון, בעימוד (status, limit עד 200, offset)
GET/campaigns/:campaignId/recipients/:userIdציר זמן של אירועי ההודעות של משתמש בקמפיין זה
GET/campaigns/:campaignId/in-app-statsסטטיסטיקות תצוגה של קמפיין in-app. כולל את displayFrequency - התפלגות החשיפות לכל משתמש בצורת { tailBucket, buckets: [{ displays, users, impressions }], maxPerUser }. ספירות בגובה tailBucket ומעלה מקובצות לדלי אחד, ולכן displays === tailBucket פירושו "כמות זו או יותר"; לחישוב ממוצע יש להשתמש ב-impressions של כל דלי (ולא ב-displays * users), ו-maxPerUser הוא המשתמש שנחשף הכי הרבה פעמים
GET/campaigns/:campaignId/impressionsרשימת חשיפות in-app‏ (limit, offset, startDate, endDate)

שליחת הודעה טרנזקציונית

שליחת הודעה חד-פעמית למשתמש בודד ללא יצירת קמפיין.

POST /campaigns/transactional/send

גוף הבקשה

שדהסוגחובהתיאור
userIdstringכןמזהה המשתמש היעד
channelstringכןemail, sms או push
messageobjectכןsubject (אימייל), body (טקסט), html (אימייל)
triggerDataobjectלאהקשר זמין לפרסונליזציה (type, name, properties, metadata)
idempotencyKeystringלאמפתח למניעת כפילויות שסיפק הקורא - ניסיון חוזר עם אותו מפתח אינו נשלח פעמיים
curl -X POST https://api-eu1.joryio.com/campaigns/transactional/send \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"userId": "user_123",
"channel": "email",
"message": {
"subject": "Your receipt",
"html": "<p>Thanks for your order, {{ user.firstName }}.</p>"
},
"idempotencyKey": "order-98421-receipt"
}'

נקודות קצה נוספות

שיטהנתיבתיאור
POST/campaigns/previewתצוגה מקדימה של משתמשים שתואמים לקריטריוני קהל היעד (גוף: targeting, ולפי הצורך limit עד 500, ‏channel, ‏webAppId)
POST/campaigns/spam-checkבדיקת ספאם לתוכן אימייל לפני שליחה
GET/campaigns/:campaignId/versionsרשימת תמונות מצב שמורות של גרסאות
GET/campaigns/:campaignId/versions/compare?v1=&v2=השוואת שתי גרסאות
GET/campaigns/:campaignId/versions/:versionIdשליפת תמונת מצב של גרסה
POST/campaigns/:campaignId/versions/:versionId/rollbackשחזור לגרסה
GET/campaigns/:campaignId/historyהיסטוריית יומן ביקורת (limit, עד 200)
POST/campaigns/bulk-delete / bulk-duplicate / bulk-archive / bulk-unarchiveפעולות באצווה; גוף { "ids": [...] }, מחזיר { succeeded, failed }
POST/campaigns/bulk-tagתיוג באצווה; גוף { "ids": [...], "tags": [...] }
POST/campaigns/:campaignId/send-test-whatsapp / send-test-sms / send-test-push / send-test-in-appשליחות בדיקה לטלפון/משתמש לפני שיגור
GET/campaigns/:campaignId/sto-coverageכיסוי אופטימיזציית זמן שליחה עבור הקהל
GET/campaigns/:campaignId/recurring-statusסטטוס קמפיין מחזורי
POST/campaigns/:campaignId/retest-abאיפוס המנצח בבדיקת A/B בקמפיין מחזורי עם וריאנט מנצח
POST/campaigns/:campaignId/launch-rlשיגור במצב AI-optimized (RL)
GET/campaigns/:campaignId/rl-statsסטטיסטיקות לוח הבקרה לקמפיין AI-optimized
POST/campaigns/:campaignId/pause-rl / resume-rlהשהיה / חידוש של קמפיין AI-optimized
POST/campaigns/ml-path-warmthסטטוס חימום פרסונליזציה עבור מזהי נתיבים/וריאנטים

תגובות שגיאה

כל השגיאות משתמשות במבנה הסטנדרטי - ראו תגובת שגיאה בסקירת ה־API למבנה המלא ולרשימת קודי המצב.

{
"statusCode": 404,
"message": "Campaign not found",
"timestamp": "2026-07-12T09:00:00.000Z",
"path": "/campaigns/8f14e45f-ceea-467f-a11d-2f4b6a1c9e3b"
}
סטטוסמתי
400התיקוף נכשל (למשל channel לא חוקי או weight חסר בווריאנט) - הגוף כולל מערך errors עם הודעה לכל שדה שנכשל
401מפתח API חסר או לא תקין
403למפתח ה-API חסרה הרשאת campaigns:* הנדרשת
404הקמפיין לא נמצא בסביבת העבודה
409התנגשות במחזור החיים - למשל חידוש קמפיין שכבר אינו מושהה ("Campaign is no longer paused.") או שיגור קמפיין שכבר אינו במצב שניתן לשלוח ממנו

קישורים קשורים