דלגו לתוכן

או התחילו מנקודה בטוחה: אינדקס הכלים המלא · מפת הטבלאות המרכזיות

מערכת חדשה — 14 יום חינם

קבצים ב‑REST

עודכן 30.08.2026

העלאת קובץ למערכת היא שתי פעולות נפרדות, לא אחת:

  1. העלאה — הבייטים עולים לאחסון והשרת מחזיר name ו‑url.
  2. שיוך — כותבים את הערך שחזר לתוך שדה מסוג File ברשומה.

בין שתי הפעולות אין קשר אוטומטי. זו הנקודה שממנה נובעות כמעט כל התקלות בעמוד הזה.

POST /parse/files/{fileName}

הגוף הוא בייטים גולמיים; כותרת Content-Type היא של הקובץ, לא application/json.

Bash
curl -sS -X POST "https://api.mbapps.co.il/parse/files/contract.pdf" \
-H "X-Parse-Application-Id: $APP_ID" \
-H "X-Parse-Master-Key: $MASTER_KEY" \
-H "Content-Type: application/pdf" \
--data-binary '@/path/to/contract.pdf'
JavaScript
const fs = require('fs');
const APP_ID = process.env.APP_ID, MASTER_KEY = process.env.MASTER_KEY;
const res = await fetch('https://api.mbapps.co.il/parse/files/contract.pdf', {
method: 'POST',
headers: {
'X-Parse-Application-Id': APP_ID,
'X-Parse-Master-Key': MASTER_KEY,
'Content-Type': 'application/pdf',
},
body: fs.readFileSync('/path/to/contract.pdf'),
});
const data = await res.json();
Python
import os, requests
APP_ID = os.environ["APP_ID"]
MASTER_KEY = os.environ["MASTER_KEY"]
with open("/path/to/contract.pdf", "rb") as fh:
res = requests.post(
"https://api.mbapps.co.il/parse/files/contract.pdf",
headers={
"X-Parse-Application-Id": APP_ID,
"X-Parse-Master-Key": MASTER_KEY,
"Content-Type": "application/pdf",
},
data=fh,
)
data = res.json()
PHP
<?php
$appId = getenv('APP_ID');
$masterKey = getenv('MASTER_KEY');
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => "https://api.mbapps.co.il/parse/files/contract.pdf",
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"X-Parse-Application-Id: $appId",
"X-Parse-Master-Key: $masterKey",
"Content-Type: application/pdf",
],
CURLOPT_POSTFIELDS => file_get_contents("/path/to/contract.pdf"),
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);

201 Created

JSON
{
"url": "https://api.mbapps.co.il/parse/files/aaaaaaa…/9f2c1b7e-contract.pdf",
"name": "9f2c1b7e-contract.pdf"
}
פרט ערך
גודל מרבי אין תקרה נאכפת. נבדקו העלאות של 11MB ו‑15MB — שתיהן נשמרו
סוג הקובץ יש ולידציה בצד השרת — לפי התוכן (magic bytes) — ראו האזהרה למטה
Content-Type אינו נבדק. PNG תקין שנשלח עם Content-Type: text/plain נשמר (201). שלחו את הטיפוס הנכון בכל זאת — הוא מה שהדפדפן יקבל בהורדה
שם הקובץ בנתיב כל שם מתקבל — גם רווחים, סוגריים ועברית (בקידוד URL). השרת מוסיף קידומת ומקודד את השם ב‑url שחוזר
אימות אינו נדרש להעלאה — X-Parse-Application-Id בלבד מספיק. ראו core-api-05
Bash
curl -sS -X PUT "https://api.mbapps.co.il/parse/classes/Cases/aB3dEf9HiJ" \
-H "X-Parse-Application-Id: $APP_ID" \
-H "X-Parse-Master-Key: $MASTER_KEY" \
-H "Content-Type: application/json" \
-d '{"Attachment":{"__type":"File","name":"9f2c1b7e-contract.pdf","url":"https://api.mbapps.co.il/parse/files/aaaaaaa…/9f2c1b7e-contract.pdf"}}'
JavaScript
const APP_ID = process.env.APP_ID, MASTER_KEY = process.env.MASTER_KEY;
const res = await fetch('https://api.mbapps.co.il/parse/classes/Cases/aB3dEf9HiJ', {
method: 'PUT',
headers: {
'X-Parse-Application-Id': APP_ID,
'X-Parse-Master-Key': MASTER_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
Attachment: {
__type: 'File',
name: '9f2c1b7e-contract.pdf',
url: 'https://api.mbapps.co.il/parse/files/aaaaaaa…/9f2c1b7e-contract.pdf',
},
}),
});
const data = await res.json();
Python
import os, requests
APP_ID = os.environ["APP_ID"]
MASTER_KEY = os.environ["MASTER_KEY"]
res = requests.put(
"https://api.mbapps.co.il/parse/classes/Cases/aB3dEf9HiJ",
headers={
"X-Parse-Application-Id": APP_ID,
"X-Parse-Master-Key": MASTER_KEY,
"Content-Type": "application/json",
},
json={
"Attachment": {
"__type": "File",
"name": "9f2c1b7e-contract.pdf",
"url": "https://api.mbapps.co.il/parse/files/aaaaaaa…/9f2c1b7e-contract.pdf",
},
},
)
data = res.json()
PHP
<?php
$appId = getenv('APP_ID');
$masterKey = getenv('MASTER_KEY');
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => "https://api.mbapps.co.il/parse/classes/Cases/aB3dEf9HiJ",
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"X-Parse-Application-Id: $appId",
"X-Parse-Master-Key: $masterKey",
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"Attachment" => [
"__type" => "File",
"name" => "9f2c1b7e-contract.pdf",
"url" => "https://api.mbapps.co.il/parse/files/aaaaaaa…/9f2c1b7e-contract.pdf",
],
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);

לפני זה — ודאו שהשדה קיים ושהוא באמת מטיפוס File או PrivateFile:

Bash
curl -sS "https://api.mbapps.co.il/parse/schemas/Cases" \
-H "X-Parse-Application-Id: $APP_ID" -H "X-Parse-API-Key: $API_KEY"
JavaScript
const APP_ID = process.env.APP_ID, API_KEY = process.env.API_KEY;
const res = await fetch('https://api.mbapps.co.il/parse/schemas/Cases', {
headers: {
'X-Parse-Application-Id': APP_ID,
'X-Parse-API-Key': API_KEY,
},
});
const data = await res.json();
Python
import os, requests
APP_ID = os.environ["APP_ID"]
API_KEY = os.environ["API_KEY"]
res = requests.get(
"https://api.mbapps.co.il/parse/schemas/Cases",
headers={
"X-Parse-Application-Id": APP_ID,
"X-Parse-API-Key": API_KEY,
},
)
data = res.json()
PHP
<?php
$appId = getenv('APP_ID');
$apiKey = getenv('API_KEY');
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => "https://api.mbapps.co.il/parse/schemas/Cases",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"X-Parse-Application-Id: $appId",
"X-Parse-API-Key: $apiKey",
],
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);

ראו סכימות.

File PrivateFile
מה קורה בשיוך ה‑URL נכתב מחדש לכתובת ציבורית: https://db-static.mbapps.co.il/<APP_ID>/<name>, והערך מקבל "public": true ה‑URL נכתב מחדש ל‑…/parse/files/<APP_ID>/<name>/<Table>/<objectId>/<Field>, והערך מקבל "private": true
הגישה פתוחה לכל מי שמחזיק את הכתובת200 בלי שום כותרת (S3 + CDN, Cache-Control: public, max-age=86400) מתווכת דרך הרשומה והשדה: Master Key, או Session Token של משתמש עם הרשאה על הרשומה. כל השאר — 302 לשער ההתחברות
מתאים ל לוגו, תמונת מוצר, נכס שיווקי חוזים, מסמכים חתומים, מסמכים חשבונאיים, כל דבר עם מידע אישי
דוגמאות במוצר _User.profile_image, Products.PreviewImage, Products.Image1/Image2, Files.PublicFile PriceQuotes.SignedPdf, PriceQuotes.Signature, AccountingHeaders.File, Notes.File, Files.File, ConversationMessages.File
1 · POST /parse/files/{name}  ──>  { name, url }
                               │
              crash here │  ──>  orphan file
                               ▼
2 · PUT /parse/classes/{Table}/{objectId}

תהליך שקרס אחרי ההעלאה ולפני השיוך משאיר קובץ יתום: הוא קיים, הוא צורך מכסת אחסון, ואף רשומה אינה מצביעה עליו. אין דרך למצוא אותו דרך ה‑API — הוא אינו מופיע בשום שאילתת נתונים.

הדפוס העמיד: רשמו את ה‑url שחזר לפני ניסיון השיוך, כדי שיהיה מה לשייך או מה לנקות אחר כך.

Python
import logging, requests
API = "https://api.mbapps.co.il/parse"
H_BIN = {"X-Parse-Application-Id": APP_ID, "X-Parse-Master-Key": MASTER_KEY}
H_JSON = {**H_BIN, "Content-Type": "application/json"}
def upload_and_attach(path: str, mime: str, table: str, object_id: str, field: str) -> dict:
filename = path.rsplit("/", 1)[-1]
# 1 · העלאה
with open(path, "rb") as fh:
up = requests.post(f"{API}/files/{filename}", headers={**H_BIN, "Content-Type": mime},
data=fh, timeout=120)
up.raise_for_status()
stored = up.json() # {"name": "...", "url": "..."}
# תיעוד לפני השיוך — כדי שקובץ יתום לא ייעלם מהעין
logging.info("uploaded %s -> %s", filename, stored["url"])
# 2 · שיוך
body = {field: {"__type": "File", "name": stored["name"], "url": stored["url"]}}
at = requests.put(f"{API}/classes/{table}/{object_id}", headers=H_JSON, json=body, timeout=30)
if not at.ok:
logging.error("attach failed for %s — orphan file remains at %s", object_id, stored["url"])
at.raise_for_status()
return stored
השכבה ההתנהגות
web2table / web2case לא תומכות בהעלאת קבצים — ושדה מסוג File בבקשה אינו “נזרק בשקט” אלא מפיל את כל הבקשה ב‑400, ומשאיר אחריו נזק: איש הקשר כן נוצר, ואם שלחתם אובייקט File (ולא מחרוזת) גם נוצרות עד 5 שורות יעד כפולות בגלל retry פנימי (web-forms-10, עדיין משתחזר ל‑28.08.2026). העלו בנפרד ושייכו אחר כך, או קבלו את הקובץ בשרת ביניים משלכם. הכלל חל גם על getlead
WhatsApp תחבורה משלו — base64 עם קידומת Data‑URI, או שם קובץ שכבר שמור במערכת. שימו לב לאסימטריה: העלאה רגילה מקבלת base64 בלי קידומת
שדה String שנראה כמו URL לפעמים עמוד מצפה ל‑URL גולמי במחרוזת ולא לאובייקט File. בדקו סכימה
DELETE /parse/files/{fileName}

הפעולה קיימת ועובדת, ודורשת Master Key או API Key:

Bash
curl -sS -X DELETE "https://api.mbapps.co.il/parse/files/9f2c1b7e-contract.pdf" \
-H "X-Parse-Application-Id: $APP_ID" \
-H "X-Parse-Master-Key: $MASTER_KEY"
JavaScript
const APP_ID = process.env.APP_ID, MASTER_KEY = process.env.MASTER_KEY;
const res = await fetch('https://api.mbapps.co.il/parse/files/9f2c1b7e-contract.pdf', {
method: 'DELETE',
headers: {
'X-Parse-Application-Id': APP_ID,
'X-Parse-Master-Key': MASTER_KEY,
},
});
Python
import os, requests
APP_ID = os.environ["APP_ID"]
MASTER_KEY = os.environ["MASTER_KEY"]
res = requests.delete(
"https://api.mbapps.co.il/parse/files/9f2c1b7e-contract.pdf",
headers={
"X-Parse-Application-Id": APP_ID,
"X-Parse-Master-Key": MASTER_KEY,
},
)
PHP
<?php
$appId = getenv('APP_ID');
$masterKey = getenv('MASTER_KEY');
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => "https://api.mbapps.co.il/parse/files/9f2c1b7e-contract.pdf",
CURLOPT_CUSTOMREQUEST => "DELETE",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"X-Parse-Application-Id: $appId",
"X-Parse-Master-Key: $masterKey",
],
]);
$response = curl_exec($ch);
curl_close($ch);
  • הצלחה: 200 עם גוף ריק — לא {}, לא הודעה.
  • אחרי המחיקה, קריאה ל‑URL של הקובץ תחת /parse/files/ מחזירה 404 File not found.
  • שם קובץ שאינו קיים מוחזר גם הוא ב‑200. הפעולה אידמפוטנטית ואינה מבחינה בין “נמחק” ל“לא היה”.
  • עם X-Parse-Application-Id בלבד: 403 {"error":"unauthorized: master key is required"}.
  • אין כלי מחיקת קבצים בשכבת ה‑MCP — שם קיימים רק Upload-Public-File ו‑Get-File-Content.

השם למחיקה הוא ה‑name שחזר מהשרת (עם הקידומת), לא שם הקובץ המקומי שלכם. שמרו אותו.

מכאן נובע כלל תכנון: תכננו לא לייצר קבצים יתומים — לא כי אי אפשר למחוק, אלא כי אי אפשר למצוא אותם: אין נקודת קצה שמחזירה רשימת קבצים, והם אינם מופיעים בשום שאילתת נתונים.

האחסון נמדד לכל מערכת ומוצג בסביבת הפיתוח, במסך הפרויקט (“Storage used · X GB remaining”). לכל מערכת יש גם דגל outOfStorage. קריאת מצב האחסון ושינוי הדגל הן פעולות תפעוליות מצד הספק — הן אינן חשופות ב‑API הזה, ולכן גם אי אפשר לבדוק מהקוד כמה מקום נשאר. תכננו בהתאם: אם המערכת מעלה קבצים בקצב, בקשו מהצוות ניטור.

התבנית ההקשר
https://api.mbapps.co.il/parse/files/<APP_ID>/<FILE_NAME> URL קובץ כפי שחוזר מההעלאה — סגור מאחורי שער ההתחברות
https://db-static.mbapps.co.il/<APP_ID>/<FILE_NAME> File אחרי שיוך — עותק ציבורי ב‑CDN, מצורף לו "public": true
…/parse/files/<APP_ID>/<FILE_NAME>/<Table>/<objectId>/<Field> PrivateFile אחרי שיוך — הנתיב נכתב מחדש ומצורף לו "private": true
https://siteadmin.mbapps.co.il/uploads/… נכסי אתר — לוגואים, קבצי עמוד
  1. השדה קיים בסכימה, והוא File או PrivateFile — לא String.
  2. התוכן תואם לסיומת — אחרת 403 Invalid file type (ה‑Content-Type עצמו אינו נבדק, אבל שלחו אותו נכון).
  3. השיוך משתמש ב‑name ו‑url שחזרו מהשרת — שיוך עם השם המקומי מתקבל ב‑200, וההורדה מהכתובת שנכתבה מחדש מחזירה 404 File not found.
  4. מידע רגיש → PrivateFile, לא File — שדה File הופך את הקובץ לציבורי. מחיקה מסירה אותו מעתה (403), אך ה‑CDN עשוי לשמור עותק עד כ‑24 שעות (api-b-01).
  5. רשמתם את ה‑URL לפני השיוך, כדי שקריסה לא תשאיר קובץ אבוד ובלתי נראה.
  6. אם ההעלאה היא מקוד שרץ בדפדפן — זכרו שהיא עוברת גם בלי מפתח, כלומר גם לתוקף.