web2table — יצירת רשומה מקושרת
יוצר שורה בכל טבלת יעד (Sales, Cases, Orders, טבלה מותאמת) וגם איש קשר ב‑Accounts, אם הוא עדיין לא קיים. איש קשר קיים נמצא ומקושר, לא משוכפל.
גוף הבקשה
Section titled “גוף הבקשה”{ "table": "Sales", "phone": "0501234567", "email": "israel@example.co.il", "account_Name": "ישראל ישראלי", "account_City": "תל אביב", "table_Name": "פנייה מדף נחיתה", "table_Total": 1500, "table_Comment": "הגיע מדף הנחיתה"}חובה: table (שם המחלקה המדויק) וגם phone. בלי phone התשובה היא 400 {"error":"missing \"phone\""}.
שלוש קבוצות שמות השדות
Section titled “שלוש קבוצות שמות השדות”זו הנקודה שבה מתרחשות רוב הטעויות באינטגרציות. לכל קבוצה יש קידומת משלה, ולא מערבבים ביניהן.
| הקבוצה | קידומת | דוגמאות | מה השרת עושה |
|---|---|---|---|
| מפתחות איתור | אין | phone, phone2, email, email2, idnum, table |
מזינים את זיהוי הכפילויות. באיש קשר חדש: phone→PhoneNumber, email→Email, idnum→CompanyId |
שדות Accounts |
account_ |
account_Name, account_F_name, account_City, account_CompanyId |
מוחלים רק כשנוצר איש קשר חדש |
| שדות טבלת היעד | table_ |
table_Name, table_Total, table_Comment |
מוחלים על השורה החדשה, אחרי אימות מול הסכימה |
| תוספות ברמה העליונה | אין | Name, CampaignName, PageName, isExistsAccountCheck |
ראו “שדות שנקבעים אוטומטית” |
מפתחות האיתור במלואם
Section titled “מפתחות האיתור במלואם”חמישה מפתחות מזינים את זיהוי הכפילויות, וכולם בלי קידומת. שניים מהם — phone2 ו‑email2 — מפתחות משניים שקל לפספס, והם בדיוק מה שמונע כפילות אצל לקוח שיש לו שני מספרים או שתי כתובות:
| המפתח | מה הוא עושה בחיפוש | מה הוא ממלא באיש קשר חדש |
|---|---|---|
phone |
✔ חובה. נסרק בחמישה פורמטים שמורים בלבד (הרשימה) | Accounts.PhoneNumber |
phone2 |
מפתח משני — נסרק גם הוא | כלום — ראו למטה |
email |
השוואת שוויון, ב‑OR מול הטלפון | Accounts.Email |
email2 |
מפתח משני | כלום — ראו למטה |
idnum |
ח.פ. / ת.ז. — השוואה מדויקת, בלי נרמול | Accounts.CompanyId |
שדות שנקבעים אוטומטית בשורה החדשה
Section titled “שדות שנקבעים אוטומטית בשורה החדשה”| השדה | הערך |
|---|---|
AccountId |
Pointer לאיש הקשר שנמצא או נוצר |
IsFirst |
true לאיש קשר חדש; false רק כשאיש הקשר היה קיים וגם נשלח isExistsAccountCheck: true |
Name |
ה‑Name מהבקשה; אחרת "פניה ראשונה" (חדש) או "פניה חוזרת" (חוזר + isExistsAccountCheck) |
CampaignName / PageName |
הערך מהבקשה; אחרת "MainLandingPage" |
PhoneNumber, Email |
מועתקים מאיש הקשר |
AccountNotExist |
true — תמיד, ראו למטה |
זיהוי כפילויות
Section titled “זיהוי כפילויות”אותה שאילתה רב‑פורמטית של getlead — כל וריאציות הטלפון, ב‑OR עם האימייל — ובנוסף CompanyId (מ‑idnum) והמפתחות המשניים phone2 / email2. הפירוט המלא: זיהוי כפילויות — מה קורה בשרת.
תשובות
Section titled “תשובות”| סטטוס | הגוף |
|---|---|
200 |
{ "success": true, "accountId": "<objectId>", "Id": "<objectId של שורת היעד>" } |
400 |
missing "phone" · missing "table" in request body · missing "PhoneNumber" or "Email" (ולידציה) · AcceptWebToTable is Disabled |
400 |
{"code":103,"message":"Class X does not exist."} — שם מחלקה שאינו קיים |
400 |
{"code":111,"message":"schema mismatch for …"} — טיפוס שגוי: Pointer באורך לא נכון, תאריך לא מרופד ("2026-6-1"), מחרוזת ב‑account_IsAccount, מספר בשדה בוליאני, מחרוזת URL בשדה File. שורת היעד לא נוצרת; מה קורה לאיש הקשר תלוי בקבוצת השדה (ראו למטה) |
400 |
{"code":1} — אובייקט File של Parse בגוף. חוזר אחרי ~4 שניות, ובצד השרת נוצרו איש קשר ו‑5 שורות יעד כפולות (באג web-forms-10) |
400 |
{} (גוף ריק) — table או phone שאינם מחרוזת (למשל מספר) |
500 |
תקלת שרת |
שני מקרי שימוש
Section titled “שני מקרי שימוש”הרשמה לקורס
Section titled “הרשמה לקורס”const APP_ID = 'הדביקו-כאן';
const COURSE_MAP = { 'קורס יסודות CRM': 'aB3dEf9HiJ', 'סדנת אוטומציות': 'kLm4NoP7Qr',};
async function submitRegistration(f) { const data = { table: 'CourseRegistrations', // שם המחלקה המדויק phone: f.phone, // חובה, בלי קידומת email: f.email, idnum: f.idNumber, // → Accounts.CompanyId על איש קשר חדש
account_F_name: f.firstName, account_L_name: f.lastName, account_City: f.city,
table_CourseId: COURSE_MAP[f.course], // objectId חשוף table_StartDate: f.startDate, // ISO שטוח: "2026-09-01" table_Comment: f.notes, PageName: 'course-landing-2026', isExistsAccountCheck: true, // כדי ש-IsFirst יהיה אמין };
Object.keys(data).forEach((k) => { if (data[k] == null || data[k] === '') delete data[k]; });
const res = await fetch(`https://api.mbapps.co.il/functions/${APP_ID}/web2table`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Parse-Application-Id': APP_ID }, body: JSON.stringify(data), });
const body = await res.json().catch(() => ({})); if (!res.ok) { // כל שגיאה עסקית חוזרת כ-400 — ההבחנה היא לפי הגוף const e = body.error || body.message || ''; if (/Disabled/.test(e)) throw new Error('AcceptWebToTable כבוי במערכת'); if (/missing/.test(e)) throw new Error('חסר טלפון או שם טבלה'); throw new Error('שגיאת שרת: ' + e); } return body; // { success, accountId, Id }}לקוח (ולא ליד) + בחירה מרובה
Section titled “לקוח (ולא ליד) + בחירה מרובה”const data = { table: 'Orders', phone: '0501234567', account_Name: 'חברת דוגמה בע"מ', account_IsAccount: true, // בוליאני אמיתי! → נוצר כלקוח, לא כליד account_CompanyId: '514999999', table_Total: '2400', table_array_tags_Pointer_Tags: ['GGZUYqBjqT', 'io3Z6YsMcG'],};שדות בחירה מרובה (array_*_Pointer_*) מקבלים מערך של objectId חשופים, עם הקידומת המתאימה לקבוצה.
הפעלה — דגל נפרד משל עצמו
Section titled “הפעלה — דגל נפרד משל עצמו”| שדה | ערך |
|---|---|
Name |
AcceptWebToTable |
Value |
{ "AcceptWebToTable": true } |
מה עוד יושב בתוך Value
Section titled “מה עוד יושב בתוך Value”| המפתח | מה הוא עושה |
|---|---|
AcceptWebToTable |
המתג עצמו |
ValidatePhoneOrEmail |
אכיפה בצד השרת: 400 missing "PhoneNumber" or "Email" כשגם הטלפון (מסירים תווים שאינם ספרות, ואז 7–14 ספרות) וגם האימייל (6–80 תווים, מכיל @ ו‑.) אינם תקינים |
DefaultValues.Account |
ערכי ברירת מחדל לאיש הקשר שנוצר |
DefaultValues.Table |
ערכי ברירת מחדל לשורה שנוצרת בטבלת היעד — למשל סטטוס פתיחה או דגל “הגיע מהאתר”, בלי לחשוף מזהים בקוד הדף |
{ "Name": "AcceptWebToTable", "Value": { "AcceptWebToTable": true, "ValidatePhoneOrEmail": true, "DefaultValues": { "Account": { "LeadSourceId": "yOTdl4L99Q" }, "Table": { "SaleStatusId": "zrP1MSVBoq", "IsWeb": "true" } } }}שני כללים על DefaultValues — שניהם אומתו בפועל:
- הן מוחלות רק על שדות שהבקשה לא שלחה. ערך שנשלח בגוף הבקשה מנצח (נבדק על
account_Cityועלtable_Source). - הן כפופות לאותם טיפוסים של שכבת הטפסים: Pointer כמזהה חשוף בן 10 תווים, תאריך ISO שטוח. ראו מיפוי שדות.
מודל האבטחה — שלוש עובדות שקובעות ארכיטקטורה
Section titled “מודל האבטחה — שלוש עובדות שקובעות ארכיטקטורה”אומתו בפועל על מערכת חיה (08.2026):
- כתיבה אנונימית ישירה ל‑REST חסומה ב‑CAPTCHA — פתיחת CLP לא עוזרת.
POST /parse/classes/<Table>עם Application Id בלבד נדחה עםcode 119, גם אחרי הגדרתcreate: {"*": true}בפועל. שער ה‑CAPTCHA יושב לפני בדיקת ההרשאות. web2tableרץ בהרשאות מוגברות ועוקף CLP. באימות ה‑CLP שלSalesנסגר לחלוטין ({}לכל פעולה) — והפונקציה עדיין יצרה שורה והחזירה 200. המסקנה המעשית: השאירו את ההרשאות של טבלת היעד סגורות. פתיחתן היא חשיפה נטו בלי שום תועלת.web2tableהוא create‑only. אין לו סמנטיקת עדכון: שליחתobjectIdאוtable_objectIdלא פונה לשורה קיימת — מזהה חדש חוזר בתשובה וכל קריאה מוסיפה שורה.
מה עושים כשצריך בכל זאת “עדכון מקישור ציבורי”
Section titled “מה עושים כשצריך בכל זאת “עדכון מקישור ציבורי””התבנית: טבלת קליטה + טריגר השלכה. הדף הציבורי יוצר שורה בטבלת ביניים ייעודית, וטריגר data‑change על אותה טבלה משליך את הערכים על אובייקט העסק האמיתי (update-object עם connection: "source.<שדה Pointer>"). כך טבלת העסק נשארת סגורה לכתיבה אנונימית.
שלוש השלכות שכדאי לתעד מראש כדי שמישהו לא “יתקן” אותן שנה אחר כך:
- הקישור חייב לשאת
phone(שדה חובה), כלומר מספר טלפון של לקוח נוסע ב‑URL ונוחת בלוגים של שרתים. זו החלטת פרטיות שצריך להעלות מול הלקוח, לא להסתיר — החלופה היא טוקן אטום לכל רשומה שנפתר בצד שרת. - אינטראקציה דו‑שלבית (דירוג עכשיו, הערה כעבור רגע) מייצרת שתי שורות קליטה לתגובה אחת. זו התנהגות נכונה: טבלת הקליטה היא היומן הגולמי, ואובייקט העסק מחזיק את התשובה הסופית.
- טריגר שמגיב לקריאה הראשונה ירוץ לפני שהנתונים של השנייה קיימים. אל תרכיבו גוף הודעה או משימה משדה שמגיע בקריאה המאוחרת — הפנו את הקורא לרשומה.
הפירוט המלא של שלוש העובדות ושל תבנית טבלת הקליטה: מודל האבטחה של כתיבה אנונימית.
רשימת בדיקה
Section titled “רשימת בדיקה”-
tableהוא שם המחלקה המדויק (לא התווית בעברית — היא מחזירהcode 100, לאmissing "table") -
phoneנשלח, בלי קידומת - נשלפו סכימות
Accountsוגם טבלת היעד, וכל שדה אומת - Pointer כמחרוזת של 10 תווים בדיוק (אורך אחר → 400
code 111; אם השגיאה ב‑table_*נשאר איש קשר יתום) - תאריכים כ‑ISO מרופד (
2026-06-01); לא מרופד → 400code 111, ו‑dd/mm/yyyyנקרא כחודש/יום - אין שדה
Fileבגוף — 400 ובכל זאת נוצרות רשומות (עד 5 כפולות) -
account_IsAccount— אם נדרש, נשלח כבוליאני ולא כמחרוזת (מחרוזת → 400 לכל הבקשה) -
SaleStatusIdנקבע דרךDefaultValues.Tableולא דרךtable_SaleStatusId -
isExistsAccountCheck: trueאםIsFirstמשמעותי לדיווח — ו‑AccountNotExistלא משמש לשום הבחנה -
AcceptWebToTableדלוק — שורה אחת בלבד - טיפול השגיאות בקוד מסתעף על גוף התשובה ולא על 403/422
- ה‑CLP של טבלת היעד נשאר סגור
- הבנתם ותיעדתם שכל קריאה מוסיפה שורה
- getlead — כשצריך רק איש קשר
- דגלי Config —
AcceptWebToTable, וכללי השורה היחידה - מיפוי שדות · זיהוי כפילויות · מודל האבטחה
- הטמעה בפועל — WordPress, Wix, HTML ושרת ביניים
- אבחון תקלות בטפסים · שגיאות ופתרון תקלות
- דוגמאות קוד — PHP, Python, Node, C#