פונקציות צד שרת
שתי דרכי הפעלה
Section titled “שתי דרכי הפעלה”| הכיוון | מי מפעיל | איך |
|---|---|---|
| מהחוץ פנימה | דף נחיתה, מערכת חיצונית, שרת ביניים | POST /functions/{appId}/{fn} |
| מבפנים | טריגר על שינוי נתונים | פעולה מסוג server-side-code עם functionName |
ובשני המקרים הפונקציה יכולה לגעת בנתוני המערכת (עם master key מוזרק), לקרוא למערכות חיצוניות (סליקה, SMS, מרכזייה), ולהשאיר עקבות ב‑_syslogTriggers וב‑_Timeline.
מהחוץ פנימה — קריאת HTTP ישירה. זה המסלול של טפסים ואינטגרציות.
מבפנים — פעולת טריגר מסוג server-side-code, שמעבירה לפונקציה את הרשומה שהפעילה אותה כהקשר:
{ "actionType": "server-side-code", "actionData": { "server-side-code": { "functionName": "calculateCommission", "useQueue": true } }}מתי בכלל צריך פונקציה
Section titled “מתי בכלל צריך פונקציה”התשובה הזו היא גם התשובה ל“האם זו הגדרה או פיתוח”:
| הצורך | למה קונפיגורציה לא מספיקה |
|---|---|
| חישובים חוצי‑רשומות, סכומי גלגול, עמלות מדורגות | טריגר פועל על רשומה אחת; אין שדות מחושבים ואין אגרגציה מובנית |
| חישוב זמן לפי ימי עסקים וחגים (SLA, חלונות שליחה) | הפרשי הזמן בטריגר הם דקות לוח שנה בלבד |
| קריאות לשער סליקה — חיוב, טוקנים, זיכויים | API חיצוני + סודות |
| טלפוניה — קליטת CDR, חיוג מהמערכת, מסך קופץ | דורש receiver לוובהוקים של ספק המרכזייה |
| מיזוג כפילויות, ולידציה מורכבת | אין מנוע דה‑דופליקציה מובנה |
| סנכרון עם מערכות חיצוניות (הנהלת חשבונות, יומנים, מרשמים) | API חיצוני, מיפוי, ניסיונות חוזרים |
| זרימות אימות לפורטל (OTP, הרשמה עצמית עם קישור לרשומה) | יצירת משתמש + שיוך תפקיד + הנפקת סשן |
פונקציות מותאמות מפותחות ונפרסות על ידי צוות MyBusiness. אי אפשר להעלות קוד צד שרת דרך ה‑API או דרך MCP (אין כלי כזה ברשימת הכלים), וגם בסביבת הפיתוח פריט הניווט Server Side Code מוסתר לחשבונות לקוח.
בתכנון פרויקט, כל דרישה שנוחתת בטבלה שלמעלה היא פריט פיתוח — עם זמן אספקה, עלות ובעל תפקיד — ולא פריט קונפיגורציה שמיישם סוגר תוך שעה. סווגו אותה ככזו כבר בשלב האפיון.
לעבוד מול פונקציה קיימת
Section titled “לעבוד מול פונקציה קיימת”1 · השיגו את החוזה. לכל פונקציה מבנה קלט משלה. אין מפרט גנרי: קבלו אותו מהצוות שפיתח אותה, או קראו את הטריגר שקורא לה.
2 · בדקו קריאה בודדת לפני שאתם משלבים:
curl -sS -i -X POST "https://api.mbapps.co.il/functions/${APP_ID}/${FN}" \ -H "Content-Type: application/json" \ -H "X-Parse-Application-Id: ${APP_ID}" \ -d '{"exampleKey":"exampleValue"}'const APP_ID = process.env.APP_ID, FN = process.env.FN;
const res = await fetch(`https://api.mbapps.co.il/functions/${APP_ID}/${FN}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Parse-Application-Id': APP_ID, }, body: JSON.stringify({ exampleKey: 'exampleValue' }),});console.log(res.status);const data = await res.json();import os, requests
APP_ID = os.environ["APP_ID"]FN = os.environ["FN"]
res = requests.post( f"https://api.mbapps.co.il/functions/{APP_ID}/{FN}", headers={ "Content-Type": "application/json", "X-Parse-Application-Id": APP_ID, }, json={"exampleKey": "exampleValue"},)print(res.status_code)data = res.json()<?php$appId = getenv('APP_ID');$fn = getenv('FN');
$ch = curl_init();curl_setopt_array($ch, [ CURLOPT_URL => "https://api.mbapps.co.il/functions/$appId/$fn", CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Content-Type: application/json", "X-Parse-Application-Id: $appId", ], CURLOPT_POSTFIELDS => json_encode(["exampleKey" => "exampleValue"]),]);$response = curl_exec($ch);$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);curl_close($ch);$data = json_decode($response, true);3 · חפשו את הראיות אחרי הריצה:
| מה לבדוק | איפה |
|---|---|
| האם הפונקציה רצה בכלל, והאם נכשלה | _syslogTriggers — כשהופעלה מטריגר; שדה error |
| מה השתנה בנתונים | _Timeline — אם הטבלה מנוטרת. שורה שנכתבה מפונקציה נושאת Referer: "server-side-code:<functionName>", וזו הדרך הטובה ביותר לזהות שהפונקציה נגעה ברשומה |
| האם הקריאה בכלל הגיעה מבחוץ | _RequestLog (path, method, statusCode, usingMK, ip, duration…) — מתמלא באיחור: כשעה אחרי הקמת מערכת חדשה המחלקה עדיין לא הייתה מוגדרת (core-api-07), ובמדידה הבאה, כארבע שעות אחרי ההקמה, היא כבר הכילה אלפי שורות מתוארכות מרגע ההקמה. מתי בדיוק בין שתי הנקודות היא הופיעה לא נמדד. אל תסיקו “הקריאה לא הגיעה” מיומן ריק. ראו יומנים |
פירוט: יומנים וראיות.
טבלת Config — מאיפה הפונקציה קוראת הגדרות
Section titled “טבלת Config — מאיפה הפונקציה קוראת הגדרות”פונקציות קוראות מפתחות ספקים ודגלי תכונה מטבלת Config (Name → Value כאובייקט):
{ "Name": "AcceptWebLeads", "Value": { "AcceptWebLeads": true } }{ "Name": "AcceptWebToTable","Value": { "AcceptWebToTable": true } }במערכת חדשה קיימות מהקופסה רק AcceptWebLeads (דלוקה) ו‑Payment; את AcceptWebToTable ו‑AcceptWebToCaseLeads יוצרים בעצמכם — בלי השורה, הפונקציה מחזירה 400 {"error":"AcceptWebToTable is Disabled"}. ראו דגלי הפעלה.
- בשרת מלפני 25.08.2026 הטבלה חסומה מכלי ה‑MCP (
Get-Data→Error: Table is restricted); מאז 25.08.2026 היא נגישה גם מ‑MCP בחיבור Master Key (אומת 2026-08-25;web-forms-07). - ב‑REST היא נגישה לכל אישור עם הרשאת קריאה — Master Key, API Key וגם Session Token של משתמש מורשה. מי בדיוק עובר תלוי ב‑CLP של
Configבטננט: בטננט הדמוfind/getמוגדרים כרגעrequiresAuthentication: true, כלומר כל משתמש מחובר קורא את הטבלה, לא רק בעל תפקיד. קריאה אנונימית נחסמת: בבדיקה חיה בדמו היא חזרה404עםcode 101(user needs to be authenticated), ובטננט עם CLP אחר אפשר לקבל400עםcode 119. בדקו את ה‑CLP אצלכם ואל תסתמכו על קוד שגיאה מסוים. - בדיוק שורה אחת לכל דגל. כשקיימות כמה שורות עם אותו
Name— וזה קורה בשטח — הקוד לוקח תמיד את השורה שנוצרה ראשונה. הבדיקה הייעודית (web-forms-09) הראתה התנהגות דטרמיניסטית: שורה ישנה עםfalseחוסמת שורה חדשה עםtrueבכל הריצות, וכל התסמין הוא400 … is Disabledבטופס.
# בדיקת דגל — Master Key, API Key, או Session Token של משתמש מורשהcurl -sS -G "https://api.mbapps.co.il/parse/classes/Config" \ -H "X-Parse-Application-Id: $APP_ID" \ -H "X-Parse-Master-Key: $MASTER_KEY" \ --data-urlencode 'where={"Name":"AcceptWebToTable"}'const APP_ID = process.env.APP_ID, MASTER_KEY = process.env.MASTER_KEY;
const params = new URLSearchParams({ where: '{"Name":"AcceptWebToTable"}',});
const res = await fetch(`https://api.mbapps.co.il/parse/classes/Config?${params}`, { headers: { 'X-Parse-Application-Id': APP_ID, 'X-Parse-Master-Key': MASTER_KEY, },});const data = await res.json();import os, requests
APP_ID = os.environ["APP_ID"]MASTER_KEY = os.environ["MASTER_KEY"]
res = requests.get( "https://api.mbapps.co.il/parse/classes/Config", headers={ "X-Parse-Application-Id": APP_ID, "X-Parse-Master-Key": MASTER_KEY, }, params={ "where": '{"Name":"AcceptWebToTable"}', },)data = res.json()<?php$appId = getenv('APP_ID');$masterKey = getenv('MASTER_KEY');
$query = http_build_query([ 'where' => '{"Name":"AcceptWebToTable"}',]);
$ch = curl_init();curl_setopt_array($ch, [ CURLOPT_URL => "https://api.mbapps.co.il/parse/classes/Config?$query", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "X-Parse-Application-Id: $appId", "X-Parse-Master-Key: $masterKey", ],]);$response = curl_exec($ch);curl_close($ch);$data = json_decode($response, true);הנתיב הסטנדרטי של Parse
Section titled “הנתיב הסטנדרטי של Parse”Parse הגנרי מגדיר גם POST /parse/functions/<name>. הנתיב הזה קיים בפריסה — אבל אין בו אף פונקציה: כל שם מוחזר עם {"code":141,"error":"function not found"}.
כל פונקציות המוצר רשומות אך ורק בדפוס /functions/{appId}/{name}. בנו על הדפוס של המוצר.
שלוש אזהרות
Section titled “שלוש אזהרות”- הפונקציה עוקפת הרשאות. היא רצה עם Master Key, ולכן CLP אינו מגביל אותה. פונקציה באגית יכולה לגעת בכל דבר — קריטריון קבלה ובדיקת יומנים אינם מותרות.
- הכתיבות שלה מפעילות טריגרים כמו כל כתיבה אחרת. פונקציה שכותבת 500 רשומות מפעילה 500 שרשראות. עומק שרשרת מרבי: 3 רמות — הרמה הרביעית נחסמת ונרשמת ב‑
_syslogTriggersעםerror: "blocked! trigger step is to deep -3. source trigger: <id>". - התאמת טלפון לפי הספרות האחרונות היא דפוס נפוץ באינטגרציות טלפוניה — ומייצרת התנגשויות בקווים משותפים. הגדירו את כלל ההתאמה במפורש במפרט.
המשך מכאן
Section titled “המשך מכאן”- getlead · web2table — הפונקציות שכל מערכת מגיעה איתן
- שגיאות ופתרון תקלות — 403 בטופס, 119 בכתיבה אנונימית
- יומנים וראיות — האם רץ, ומה קרה
- סביבות וגישה — הדומיינים והמזהים