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
גוף הבקשה
| שדה | סוג | חובה | תיאור |
|---|---|---|---|
name | string | כן | שם הקמפיין (עד 255 תווים) |
description | string | לא | תיאור (עד 1000 תווים) |
channel | string | כן | email, sms, push, webhook, whatsapp, in_app או ai_optimized |
variants | array | כן* | וריאנטים של ההודעה (חובה לכל ערוץ מלבד in_app) |
targeting | object | לא | קהל: userIds, filterGroups, excludeFilterGroups, filterOperator, subscriptionPreference |
sendType | string | לא | immediate, scheduled, triggered, intelligent, recurring או ai_optimized |
scheduledAt | string | לא | תאריך ISO 8601 עבור sendType: "scheduled" |
scheduledTimezone | string | לא | אזור זמן IANA שבו מתפרש מועד התזמון |
triggerConfig | object | לא | כלל טריגר עבור sendType: "triggered" - type, eventName, conditions, reEntry, cooldownHours |
recurringSchedule | object | לא | עבור sendType: "recurring" - frequency (daily/weekly/monthly/custom), cron, dayOfWeek, dayOfMonth, timeOfDay, timezone, endDate, maxOccurrences |
conversionTracking | object | לא | primaryConversion / secondaryConversions (שם אירוע + תנאי מאפיינים), conversionWindowHours, attributionModel (first_touch/last_touch/linear) |
emailConfigId | string | לא | זהות שולח אימייל שמורה (לערוץ האימייל) |
subscriptionCategoryId | string | לא | קטגוריית הסכמה (רשימת מנויים) שתחתיה הקמפיין נשלח |
sendVolumeLimit | object | לא | enabled, maxSends, cadence (lifetime/per_send) |
תוכן הודעת In-App
כל וריאנט של In-App נושא את התוכן שנכתב עבורו ב־customContent. השדה mode קובע אילו שדות רלוונטיים:
mode | שדות | מוצג כ־ |
|---|---|---|
native | title, body, imageUrl, buttons, closeButton, backdropDismissible, style | הרכיבים של האפליקציה עצמה - ללא WebView |
html (ברירת מחדל) | html, css | קוד שנכתב על ידי המחבר בתוך WebView |
drag_drop | html, 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, לכן שלחו שדה רק כשהקמפיין באמת זקוק לו.
| שדה | טיפוס | חל על | משמעות |
|---|---|---|---|
backgroundColor | string | web, iOS, Android | רקע הכרטיס |
textColor | string | web, iOS, Android | כותרת וגוף ההודעה (הגוף מעט מרוכך) |
primaryButtonColor | string | web, iOS, Android | צבע הכפתור הראשון |
primaryButtonTextColor | string | web, iOS, Android | הטקסט שעליו. אם לא נשלח, נבחר שחור או לבן לפי הניגודיות מול צבע הכפתור |
cornerRadius | number | web, iOS, Android | 0-48. לא חל על fullscreen, שם פינות מעוגלות היו חושפות את האפליקציה בפינות |
fontSize | number | web, iOS, Android | 10-32. גודל גוף ההודעה; הכותרת נגזרת ממנו. בנייד עדיין מוחלת גם הגדרת גודל הטקסט של המשתמש |
titleWeight | string | web, iOS, Android | regular, medium, semibold, bold. לכותרת בלבד - גוף ההודעה נשאר רגיל לקריאוּת |
textAlign | string | web, iOS, Android | auto (ברירת מחדל), start, center, end. auto הולך לפי שפת ההודעה עצמה, כך שעברית וערבית נקראות מימין לשמאל גם באפליקציה באנגלית |
fontFamily | string | web; בנייד מיטבי | בנייד חל רק אם האפליקציה ארזה את הגופן (iOS: רשום באפליקציה; Android: res/font או משפחה מערכתית). אם הוא חסר, נשמר הגופן של האפליקציה במקום תחליף |
customCss | string | web בלבד | 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:
| שדה | סוג | חובה | תיאור |
|---|---|---|---|
id | string | כן | מזהה הווריאנט |
name | string | כן | שם הווריאנט |
weight | number | כן | נתח תעבורה, 0–100 (סכום המשקלים חייב להתאים לכללי הערוץ) |
message | object | לא | הודעת הערוץ. אימייל: 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 |
isControlGroup | boolean | לא | מסמן את הווריאנט כקבוצת ביקורת שאינה נכללת בשליחה (ומאפשר למדוד שיפור יחסי) |
דוגמת בקשה
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
פרמטרי שאילתה
| פרמטר | סוג | ברירת מחדל | תיאור |
|---|---|---|---|
status | string | - | סינון לפי סטטוס (מופרד בפסיקים לריבוי ערכים) |
channel | string | - | סינון לפי ערוץ (מופרד בפסיקים) |
tags | string | - | סינון לפי תגיות (מופרד בפסיקים) |
q | string | - | חיפוש טקסט חופשי |
createdBy / editedBy | string | - | סינון לפי יוצר / עורך אחרון (מזהי משתמשים מופרדים בפסיקים) |
createdFrom | string | - | רק קמפיינים שנוצרו בתאריך ISO זה או אחריו |
page | number | 1 | מספר עמוד |
limit | number | 20 | תוצאות לעמוד (לכל היותר 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
גוף הבקשה
| שדה | סוג | חובה | תיאור |
|---|---|---|---|
userId | string | כן | מזהה המשתמש היעד |
channel | string | כן | email, sms או push |
message | object | כן | subject (אימייל), body (טקסט), html (אימייל) |
triggerData | object | לא | הקשר זמין לפרסונליזציה (type, name, properties, metadata) |
idempotencyKey | string | לא | מפתח למניעת כפילויות שסיפק הקורא - ניסיון חוזר עם אותו מפתח אינו נשלח פעמיים |
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.") או שיגור קמפיין שכבר אינו במצב שניתן לשלוח ממנו |
קישורים קשורים
- יצירת קמפיינים
- ניתוח נתוני קמפיינים
- API של סגמנטים - בניית הקהלים שאליהם הקמפיינים פונים
- API של מסעות - מסעות רב-שלביים