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

Imports API

טעינה מרוכזת של אנשי קשר, אירועים או רשומות ישות מותאמת מתוך קובץ CSV או JSON.

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

סקירה​

ייבוא הוא שלוש קריאות, לא אחת. אתם מבקשים מיקום העלאה, מעלים את הקובץ ישירות לאחסון, ורק אז מבקשים מ־Joryio לעבד אותו:

  1. POST /users/import/upload-url - מחזיר כתובת חתומה מראש ואת ה־fileKey שמזהה את ההעלאה.
  2. PUT של הקובץ לכתובת הזו - ישירות לאחסון, כך שקובץ של 200MB לא עובר דרך ה־API.
  3. POST /users/import - יוצר את העבודה. חוזר מיד; הקובץ מעובד ברקע.
  4. GET /users/import - תשאול להתקדמות ולמספרים הסופיים.

הצלחה בשלב 2 לא אומרת דבר על שלב 3. ההעלאה היא רק קובץ שנחת בדלי; הוולידציה מתרחשת ביצירת העבודה ושוב לכל שורה בזמן הריצה.

אימות​

Authorization: Bearer YOUR_API_KEY

כל נקודת קצה כאן דורשת users:write. הגדרת overrideConsent דורשת בנוסף compliance:write - הרשאת users:write לבדה מקבלת 403, והייבוא לא מתחיל.

1. בקשת כתובת העלאה​

POST /users/import/upload-url
Content-Type: application/json

{
"filename": "customers-2026-08.csv"
}
{
"success": true,
"fileKey": "imports/<organizationId>/<workspaceId>/customers-2026-08.csv",
"uploadUrl": "https://storage.example.com/..."
}

ה־fileKey מוגבל לארגון ולסביבת העבודה שלכם. החזירו אותו כמות שהוא בשלב 3 - מפתח מחוץ לקידומת שלכם נדחה ב־400.

2. העלאת הקובץ​

curl -X PUT --upload-file customers-2026-08.csv "$UPLOAD_URL"

תשובת 200 כאן אומרת שהבתים נשמרו. היא לא אומרת שהייבוא יצליח.

3. יצירת עבודת הייבוא​

POST /users/import
Content-Type: application/json

{
"format": "csv",
"fileKey": "imports/<organizationId>/<workspaceId>/customers-2026-08.csv",
"importType": "users",
"originalFilename": "customers-2026-08.csv",
"fieldMapping": {
"Email Address": "email",
"First Name": "firstName",
"Loyalty Tier": "attributes.loyaltyTier"
}
}
שדהטיפוסהערות
formatcsv | jsonחובה
fileKeystringחובה. בדיוק מה ששלב 1 החזיר
importTypeusers | events | entitiesברירת מחדל users
originalFilenamestring?מוצג בהיסטוריית הייבוא
fieldMappingobject?עמודת מקור ← נתיב שדה יעד. השמיטו לזיהוי אוטומטי משורת הכותרות
overrideConsentboolean?ראו למטה. דורש compliance:write
smsAlreadyConfirmedboolean?רק לאישור הרשמה כפול ב־SMS. ראו למטה. דורש compliance:write
maxBackdatingDaysint?1-3650. עד כמה אחורה מותר לתארך אירוע מיובא
entityNamestring?חובה כאשר importType הוא entities

שדות לא מוכרים נדחים ב־400 במקום להתעלם מהם, כך שטעות כתיב בשם שדה נכשלת בקול רם במקום לא לעשות כלום בשקט.

fieldMapping מכיל עמודות, ורק עמודות​

כל מפתח ב־fieldMapping הוא שם עמודה שלכם. אפשרויות הייבוא הן שדות נפרדים ומוגדרים - overrideConsent,‏ entityName,‏ maxBackdatingDays - ולעולם לא מפתחות במפה הזו.

זה חשוב אם יש לכם עמודה ששמה ממש _overrideConsent: היא עמודה, היא ממופה כמו כל אחרת, והיא לא מפעילה עקיפת הסכמה. רק השדה המוגדר עושה זאת.

השמיטו את fieldMapping לגמרי והעמודות יותאמו משורת הכותרות של הקובץ. ספקו אותו והוא ייסמך בדיוק כפי שנמסר - כל מה שלא מופה מתעלמים ממנו.

בלי fieldMapping, איותים נפוצים של כותרות ממופים לשדות הסטנדרטיים - למשל first_name, ‏First Name או given_name ל-attributes.firstName, ‏surname או last_name ל-attributes.lastName, ‏e-mail ל-email ו-mobile ל-phone; כל עמודה אחרת הופכת למאפיין מותאם אישית בשמה. הרשימה המלאה בייבוא מרוכז. full_name אינו מפוצל. קובצי CSV יכולים להיות מופרדים בפסיקים, בנקודה-פסיק או בטאבים - המפריד נקבע לפי שורת הכותרות.

קבצי JSON​

שני המבנים מתקבלים:

[ { "email": "[email protected]" }, { "email": "[email protected]" } ]
{ "users": [ { "email": "[email protected]" } ] }

overrideConsent​

כברירת מחדל ייבוא יכול לחסום אך לא להעניק: שורת unsubscribed בקובץ שלכם מסירה את איש הקשר מרשימת התפוצה, בעוד ששורת subscribed לא מחזירה למנוי מישהו שביטל קודם.

הערך overrideConsent: true מתייחס לקובץ כסמכותי בשני הכיוונים. זו פעולת ציות, ולכן היא דורשת compliance:write מעבר ל־users:write.

שימו לב לאי־הסימטריה: ביטולי מנוי חלים כך או כך. אינכם צריכים את הדגל הזה כדי לסנכרן ביטולים מתוך CRM - רק כדי להחזיר למנוי אנשים שביטלו.

הערך חייב להיות בוליאני של JSON. מחרוזת, ‏1 או "yes" נדחים ב־400 במקום להיקרא בשקט כ־false - עדיף לדעת מאשר להאמין שעקיפה רצה כשהיא לא.

גם עם overrideConsent: true, הרשמה מחדש חלה רק על איש הקשר שבשורה - אנשי קשר אחרים עם אותו אימייל או טלפון נשארים מבוטלים - ביטול STOP נעקף רק עם הדגל (ונרשם בהיסטוריית איש הקשר עם משימת הייבוא), וייבוא לעולם אינו מסיר החזרה קשה, תלונת ספאם או חסימה ברמת הארגון. בלעדיו, ערך subscribed לאיש קשר חסום מתעלם. ערך unsubscribed מגיע לכל איש קשר בסביבת העבודה עם אותו אימייל או טלפון. אנשי קשר שחולקים אימייל או טלפון.

המשימה שהסתיימה נושאת consentSummary:

{ "overridden": 12, "overriddenSmsStop": 3, "keptUnsubscribed": 40, "keptDeliverability": 1, "keptOrganization": 0 }

overridden סופר הרשמות מחדש שנעשו עם overrideConsent, ו־overriddenSmsStop כמה מהן היו אנשי קשר SMS ששלחו STOP (ספק ה־SMS שלהם עשוי להמשיך לחסום הודעות עד שישלחו START); keptUnsubscribed סופר ערכי subscribed שהתעלמו מהם כי הדגל היה כבוי; keptDeliverability ו־keptOrganization סופרים את אלו שאף ייבוא אינו רשאי להסיר. consentSummary הוא null בייבואים שהסתיימו לפני שהשדה נוסף.

smsAlreadyConfirmed​

רלוונטי רק כשאישור הרשמה כפול ב־SMS של סביבת העבודה מופעל. אז כל הרשמה חדשה ל־SMS בקובץ (איש קשר ללא סטטוס SMS) נשמרת כ־pending ומקבלת הודעת "Reply YES" אחת, שנשלחת בתוך כדקה; consentSummary.awaitingSmsConfirmation סופר אותן. smsAlreadyConfirmed: true מצהיר שיש בידכם הוכחה שהאנשים האלה כבר אישרו את ההרשמה ל־SMS: הם נשמרים כ־subscribed בלי הודעה. זו הצהרת ציות, ולכן היא דורשת compliance:write כמו overrideConsent.

עם overrideConsent: true (ואישור הרשמה כפול ב־SMS מופעל), איש קשר בקובץ שביקש הסרה מ־SMS מטופל כמו הרשמה חדשה: pending, הודעת אישור אחת, בלי תזכורת, רישום רק אחרי YES, וחזרה ל־unsubscribed ללא מענה. בלעדיו, אנשי קשר שביקשו הסרה נשארים ללא שינוי ולא מקבלים הודעה. smsAlreadyConfirmed: true רושם אותם במקום זאת (יחד עם overrideConsent). איש קשר שכבר pending לעולם לא מאושר על ידי קובץ.

4. תשאול להתקדמות​

GET /users/import

מחזיר את היסטוריית הייבוא של סביבת העבודה, מהחדש לישן, עם status,‏ totalRows,‏ processedRows,‏ createdCount,‏ updatedCount,‏ skippedCount,‏ failedCount, וכאשר שורות נכשלו - מדגם חסום של השגיאות עם מספרי השורות במקור. matchedSeveralCount סופר שורות עם אימייל בלי externalId כשכמה אנשי קשר חולקים את האימייל הזה: כל שורה כזו עדכנה רק את איש הקשר שהיה פעיל לאחרונה מביניהם, ביטול הרשמה בה הגיע לכולם, ודוח השגיאות מפרט אותה כ-notice. ראו כשכמה אנשי קשר חולקים אימייל; הוסיפו externalId לשורות כדי להתאים איש קשר אחד במדויק.

השדה status נע pending ← processing ← completed או failed.

5. רשימת ייבואים שסגמנט יכול לכוון אליהם​

GET /users/import/sources?limit=100

דורש users:read. מחזיר את ייבואי אנשי הקשר (users) שהסתיימו בסביבת העבודה, מהחדש לישן - הרשימה שממנה בוחר תנאי הסגמנט הגיע מייבוא:

{
"imports": [
{
"id": "6f1c2a9e-4b7d-4c1e-9a53-2f0d8e7b1c44",
"fileName": "customers-2026-08.csv",
"status": "completed",
"createdAt": "2026-10-08T09:00:00.000Z",
"completedAt": "2026-10-08T09:05:12.000Z",
"rowCount": 1200,
"createdCount": 1000,
"updatedCount": 150
}
]
}

ברירת המחדל של limit היא 100, והמקסימום 200. ids (מופרדים בפסיקים, עד 100) מחזיר בדיוק את הייבואים האלה, בלי קשר לגילם - כדי לתת שם לייבואים שתנאי שמור מצביע עליהם. status הוא completed, expired (הסתיים; דוח השגיאות שלו נוקה) או failed - ייבוא שנכשל מוצג רק אם הספיק לעבד שורות, כי אנשי הקשר שהגיע אליהם מסומנים. ייבואי אירועים וישויות אינם מוצגים.

כל איש קשר שייבוא אנשי קשר יוצר או מעדכן מסומן ב-id של הייבוא, כך שסגמנט יכול לכוון אל הייבוא:

{ "type": "contact_import", "operator": "any_of", "value": ["6f1c2a9e-4b7d-4c1e-9a53-2f0d8e7b1c44"] }

ראו את המסנן contact_import ב-Segments API. אנשי קשר שיובאו לפני שהיכולת הזו שוחררה אינם נושאים סימון.

ייבוא אחד בכל רגע​

לסביבת עבודה מותר ייבוא אחד במצב pending או processing. בקשה שנייה בזמן שאחת פעילה מחזירה:

{ "statusCode": 400, "message": "An import is already in progress for this workspace. Please wait for it to complete." }

תשאלו את שלב 4 עד שהראשון מסתיים במקום לנסות שוב מיד.

שגיאות​

סטטוסמשמעות
400שדה לא מוכר, ערך overrideConsent שגוי, fileKey מחוץ לקידומת שלכם, ייבוא entities ללא entityName, או ייבוא שכבר רץ
403התבקשה overrideConsent ללא compliance:write
403התבקש smsAlreadyConfirmed ללא compliance:write
404ה־fileKey לא מצביע על אובייקט שהועלה - העבודה נוצרת ואז נכשלת עם "The specified key does not exist"

שורות שנכשלות בנפרד לא מפילות את העבודה. הן נספרות ב־failedCount ומדוגמות בדוח השגיאות, כך שקובץ עם שלוש שורות פגומות מתוך חמישים אלף עדיין מייבא את 49,997 האחרות.