1סקירה
אפליקציית המסעדה של RazGaz היא לקוח ולא שרת: היא פותחת הזמנות, קוראת את לוח ההזמנות ומעדכנת אותן דרך ממשק ציבורי, ולאותו ממשק בדיוק יכולה לפנות מערכת הניהול של המסעדה. אינטגרציה לפי המסמך הזה מחליפה את האפליקציה במלואה — אין פעולה שהאפליקציה יכולה לבצע ומערכת המסעדה אינה יכולה.
| הזדהות | חשבון המסעדה — דואר אלקטרוני וסיסמה, מומרים לאסימון |
| קריאות RazGaz | https://api.raz-gaz.com |
| קריאת ועדכון הזמנות | https://firestore.googleapis.com/v1/projects/razgaz-f7295/databases/(default)/documents |
| תעבורה | HTTPS בלבד. Content-Type: application/json, UTF-8 |
שני המאחזים הם חלק אחד מהממשק. פתיחת הזמנה ומענה על זמן הכנה הן קריאות ל‑RazGaz; קריאת לוח ההזמנות והפעולות על הזמנה קיימת נעשות ישירות מול מסד הנתונים, כשההרשאה נגזרת מאותו אסימון עצמו. מסעדה רואה ומעדכנת את ההזמנות שלה בלבד — ההגבלה נאכפת בצד השרת, לא בצד הלקוח.
אין ערוץ חוזר יזום. RazGaz אינה קוראת חזרה למערכת המסעדה ואינה שולחת webhook. כדי לדעת מה קרה להזמנה — מי אסף אותה, איפה השליח, האם נמסרה — יש לתשאל, §6.
2מה RazGaz מנפיקה לכם
שלושה דברים, כולם מ‑RazGaz, לפני ההזמנה הראשונה:
| מה זה | |
|---|---|
| דואר אלקטרוני וסיסמה | חשבון המסעדה. חשבון אחד לכל סניף — אין חשבון אחד שמנהל כמה סניפים, ולכן מערכת שמשרתת שני סניפים מחזיקה שני חשבונות ומזדהה בנפרד לכל אחד |
| מפתח Web API | מזהה הפרויקט הציבורי הדרוש להמרת הסיסמה לאסימון (§3). אינו סוד ואינו מעניק דבר בלעדיו — הסיסמה היא הסוד |
| שם הסניף | השם הקנוני של הסניף אצל RazGaz, בדיוק כפי שהוא רשום. זהו הערך שההזמנות שלכם נושאות בשדה restaurantName, והוא מה שמסננים לפיו ב‑§6 |
אין צורך בקוד סניף ואין צורך במפתח API כמו שיש למערכת קופה: בממשק הזה הזהות
היא החשבון, וממנו נגזר הסניף. סניף לא פעיל — מסומן כך על ידי RazGaz — אינו יכול
לפתוח הזמנות (403), אך הזמנות שכבר קיימות ממשיכות להיות קריאות ועדכניות.
3הזדהות
3.1קבלת אסימון
POST https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=<WEB_API_KEY>
{
"email": "branch@example.com",
"password": "…",
"returnSecureToken": true
}
בתשובה, שלושת השדות שיש לשמור:
| שדה | מה לעשות בו |
|---|---|
idToken | האסימון עצמו. נשלח בכל בקשה, §3.3 |
refreshToken | מחליף אסימון שפג, §3.2. אינו פג מעצמו |
expiresIn | תוחלת החיים בשניות — 3600, שעה אחת |
3.2רענון
POST https://securetoken.googleapis.com/v1/token?key=<WEB_API_KEY>
עם grant_type=refresh_token&refresh_token=<refreshToken>, בקידוד
application/x-www-form-urlencoded. התשובה מכילה id_token חדש.
אין להזדהות מחדש בסיסמה לכל בקשה. יש להחזיק את האסימון בזיכרון ולרענן אותו
לפני שהוא פג — כדקה מראש הוא מרווח סביר. אסימון שפג נענה ב‑401, ופנייה חוזרת
עם אותו אסימון תיענה באותו אופן בלי סוף.
3.3שימוש
בכל בקשה, לשני המאחזים גם יחד:
Authorization: Bearer <idToken>
בקשה בלי אסימון, עם אסימון שפג או עם אסימון של חשבון אחר נענית ב‑401 או
ב‑403 ודבר אינו נרשם — לא נפתחת הזמנה ולא מתעדכן דבר. שגיאה כזו בייצור
פירושה שהאינטגרציה שקטה, ויש להסלים אותה, לא לחזור על הבקשה.
4פתיחת הזמנה
POST /createRestaurantOrder
פותחת הזמנת משלוח מהסניף שאליו החשבון משויך. נקודת האיסוף אינה נשלחת ואינה נשלטת: היא המיקום השמור של הסניף אצל RazGaz. RazGaz מחשבת את שכר השליח, משדרת את ההזמנה לשליחים באזור ומנהלת את השליח משלב השיוך ועד המסירה.
4.1בקשה — השדה היחיד שהוא חובה
| שדה | טיפוס | תיאור |
|---|---|---|
deliveryAddress | מחרוזת | כתובת המסירה בשורה אחת קריאה: רחוב, מספר בית ועיר. אינה משמשת לניווט — הקואורדינטות משמשות לכך — אבל זה מה שהשליח קורא. פרטי הכניסה — קומה, דירה, כניסה — אינם שייכים לשורה הזו אלא לשדות שלהם ב‑§4.3: כשאין קואורדינטות, השורה הזו היא מה שנשלח לאיתור על המפה, וקומה בתוכה פוגעת בדיוק האיתור. קוד שער וכיוצא בזה — ב‑notes |
זה השדה היחיד שהוא חובה. כתובת היא כל מה שנקודת הקצה צריכה; כל שאר פרטי ההזמנה, ובכללם רשימת הפריטים והקואורדינטות, אופציונליים.
4.2בקשה — נקודת המסירה על המפה
| שדה | טיפוס | תיאור |
|---|---|---|
deliveryLocation | אובייקט | נקודת המסירה על המפה. { "latitude": number, "longitude": number }, שני הערכים מספרים ב‑JSON ולא מחרוזות |
מומלץ לשלוח, אך אינו חובה. אם המערכת שלכם מחזיקה קואורדינטות — שלחו אותן, ואנחנו נשתמש בהן כפי שהן. זו התוצאה הטובה ביותר: נקודה שהמערכת שלכם אישרה עדיפה על נקודה שאנחנו מסיקים.
בלעדיהן אנחנו מאתרים את הכתובת אצלנו, וממלאים את העיר של הסניף כשהכתובת לא ציינה עיר — "הרצל 5" מסניף ברעננה הוא הרצל שברעננה. הכתובת שתישמר על ההזמנה תכלול את שם העיר שנוסף (המילים שלכם נשמרות, שם העיר מתווסף בסופן), כדי שהשליח יראה כתובת שלמה.
שני דברים שכדאי לתכנן סביבם:
- כתובת שאי אפשר לאתר בכלל נדחית ב‑
400עם הודעה בעברית. - כתובת שאותרה רק ברמת העיר תקבל נקודה במרכז העיר ולא בבניין, וההזמנה תיפתח כרגיל. אין בתשובה שדה שמבדיל בין השניים — אם הדיוק חשוב לכם, שלחו קואורדינטות.
4.3בקשה — שדות אופציונליים
| שדה | טיפוס | תיאור |
|---|---|---|
items | מערך | פריטי ההזמנה, כל אחד { "name": string, "qty": number }. יש לשלוח כאשר הם ידועים — השליח רואה את הרשימה והיא מה שנבדק מולו באיסוף מהדלפק. אינו חובה: הזמנה שנשלחה בלעדיהם, או עם מערך ריק, נפתחת כרגיל ומוצגת בלי רשימת פריטים — כך מגיעות ממילא הזמנות ממערכות קופה שאינן שולחות רשימה. ערך שאינו מערך נדחה ב‑400 |
estimatedReadyMinutes | מספר שלם | דקות מעכשיו ועד שהאוכל יהיה מוכן. גדול מ‑0 ולא יותר מ‑240. יש לשלוח בכל מקרה שבו המערכת יודעת את הזמן — ראו §5. בהזמנה מתוזמנת (scheduledFor שלהלן) יש לשלוח תמיד: ההזמנה משוחררת ישירות לשידור ואיש אינו נשאל שוב, כך שהזמנה מתוזמנת בלעדיו יוצאת בהצהרה שהאוכל כבר מוכן. הוא אינו משפיע על מועד השידור — הוא קבוע, 20 דקות לפני מועד האיסוף |
scheduledFor | מספר | מחרוזת | הזמנה מתוזמנת. המועד שבו השליח יגיע למסעדה לאסוף את ההזמנה — אלפיות שנייה מ‑epoch, או ISO‑8601. ההזמנה מוחזקת ומשוחררת בזמן שמאפשר להכין אותה עד שהשליח בדלפק, ואינה מוצעת לאף שליח לפני כן. חייב להיות בעתיד ולא יותר מ‑7 ימים מראש, אחרת הקריאה נדחית ב‑400 |
customerName | מחרוזת | שם הלקוח, כפי שהשליח צריך לבקש אותו |
customerPhone | מחרוזת | מספר שניתן להתקשר אליו. השליח מתקשר בהגעה |
floor | מחרוזת | קומה. מוצגת לשליח בדלת, בנפרד משורת הכתובת |
apartment | מחרוזת | דירה |
entrance | מחרוזת | כניסה |
notes | מחרוזת | טקסט חופשי שמוצג לשליח. הוראות מסירה, "להשאיר בדלת" |
orderAmount | מספר | הסכום שהלקוח משלם על ההזמנה, בשקלים |
paymentMethod | מחרוזת | "cash" כאשר על השליח לגבות תשלום מהלקוח. כל ערך אחר, וכן היעדר השדה, נרשמים כ‑"card" — כלומר השליח אינו גובה דבר |
items נשמר כפי שנשלח, וכל המסכים — של השליח, של המוקד — קוראים בדיוק את שני
המפתחות name ו‑qty. פריט שקורא לכמות שלו בשם אחר יוצג בכמות 1.
שלושת שדות הכניסה (floor, apartment, entrance) נשמרים בנפרד משורת הכתובת
ומוצגים לשליח כשהוא מגיע לבניין. ערך "0" נקרא כ"לא נמסר" ואינו מוצג — כך
מגיעות הזמנות ממערכות קופה ששולחות "0" לבית פרטי, ואי אפשר להבחין בין השתיים.
קומת קרקע שחשוב שתוצג — לכתוב במילים ("קרקע").
4.4שדות שמורים — אין לשלוח
נקודת האיסוף, שכר השליח, רדיוס השידור, אזור התמחור ומספר ההזמנה האנושי כולם נקבעים בצד RazGaz ואינם מתקבלים מהבקשה.
4.5תשובה
| HTTP | גוף | משמעות |
|---|---|---|
201 | { "success": true, "orderId": "…" } | ההזמנה נפתחה |
orderId הוא מזהה ההזמנה בצד RazGaz, והוא הערך שכל שאר המסמך הזה מקבל: §5, §6.2
ו‑§8 כולם מזוהים לפיו. יש לשמור אותו לצד ההזמנה במערכת המסעדה — אין דרך אחרת
להצביע על הזמנה, ואין חיפוש לפי מזהה שלכם.
4.6שגיאות
| HTTP | מתי |
|---|---|
400 | חסר deliveryAddress, items נשלח כערך שאינו מערך, או estimatedReadyMinutes מחוץ לתחום |
400 (עברית) | נשלחה כתובת בלי קואורדינטות ולא הצלחנו לאתר אותה על המפה בכלל (§4.2) |
400 | לסניף אין מיקום איסוף שמור אצל RazGaz — תקלת הגדרה, יש לפנות אלינו |
401 | אסימון חסר, פג או פסול (§3) |
403 | לחשבון לא משויך סניף, או שהסניף מסומן כלא פעיל |
405 | לא POST |
4.7שליחה חוזרת פותחת הזמנה נוספת
בקריאה הזו אין idempotency. מזהה ההזמנה נוצר בצד RazGaz בכל קריאה, ואין שדה שבו נשלח המזהה שלכם, ולכן אין ל‑RazGaz דרך לזהות ששתי בקשות מתארות את אותה הזמנה. שליחה חוזרת אחרי timeout שבו הבקשה הראשונה כן הגיעה פותחת משלוח שני, ושני שליחים יגיעו לאותו סניף.
לכן: ניסיון חוזר אוטומטי על קריאה זו הוא באחריות מערכת המסעדה, ותנאי לו הוא לדעת שהראשון לא נכתב. הדרך לבדוק היא §6.1 — תשאול ההזמנות הפעילות וחיפוש הזמנה שמתאימה לכתובת, לטלפון ולזמן. הזמנה שנפתחה בטעות פעמיים מבוטלת לפי §8.3.
5זמן הכנה
זמן ההכנה הוא מה שמאפשר ל‑RazGaz לתזמן את השליח כך שיגיע לאוכל מוכן ולא לפניו. לכל סניף רשום אצלנו זמן הכנה ממוצע, או סימון שאומר שהוא נותן זמן לכל הזמנה בנפרד. שני מצבים אפשריים לכן להזמנה חדשה:
- נשלח
estimatedReadyMinutesב‑§4.1, או שלסניף יש ממוצע רשום — ההזמנה יוצאת לשידור מיד, וזה המסלול הרצוי. - לא נשלח, והסניף מסומן כמי שנותן זמן לכל הזמנה — ההזמנה מוחזקת בסטטוס
awaiting_prep_timeואינה משודרת לאף שליח עד שנענית לפי §5.1 או §5.2. הזמנה שאינה נענית נשארת מוחזקת: אין שחרור אוטומטי, כי שידור על סמך ניחוש גרוע יותר מהמתנה. RazGaz מקבלת התראה פנימית על הזמנה שאיש אינו עונה עליה, אבל היא אינה משחררת אותה.
הדרך הפשוטה להימנע מהמצב השני היא לשלוח estimatedReadyMinutes תמיד.
5.1"מוכן בעוד N דקות"
POST /submitPrepTime
{ "orderId": "…", "minutes": 20 }
minutes — מספר דקות מעכשיו, גדול מ‑0 ולא יותר מ‑240.
הקריאה עושה אחד משני דברים, לפי מצב ההזמנה, ואין צורך לבחור ביניהם:
| מצב ההזמנה | מה קורה |
|---|---|
awaiting_prep_time | משחרר את ההזמנה: הסטטוס עובר ל‑pending ושעון ההכנה מתחיל מעכשיו. אם מנהל RazGaz הקפיא את פרסום הסניף, ההזמנה עוברת ל‑held במקום, ומוקדן מפרסם אותה — אין מה לעשות מצדכם |
| כל מצב פעיל אחר | עדכון זמן ההכנה. הסטטוס אינו נוגע; זה המסלול של "האוכל יתאחר בעוד עשר דקות", והשליח שכבר שויך מקבל על כך הודעה |
delivered / cancelled | 409 — ההזמנה נגמרה |
תשובה: { "success": true, "orderId": "…", "minutes": 20, "released": true, "readyAt": 1755513600000 }.
released אומר אם זו הייתה השחרור או העדכון; readyAt — אלפיות שנייה מ‑epoch —
מגיע רק בשחרור.
5.2הזמנה למועד מאוחר
אם המועד ידוע כבר בפתיחת ההזמנה, שלחו scheduledFor ב‑createRestaurantOrder
(§4.3) וזה הכול — ההזמנה מתוזמנת מלכתחילה ואין צורך בקריאה הזו. מה שלהלן נוגע
להזמנה שכבר פתוחה: אחת שנשלחה בלי מועד, או אחת שממתינה לזמן הכנה.
POST /scheduleRestaurantOrder
{ "orderId": "…", "scheduledFor": "2026-08-18T20:30:00+03:00", "minutes": 25 }
התשובה השנייה לאותה שאלה: לא כמה זמן האוכל לוקח מעכשיו אלא מתי שהשליח יבוא
לאסוף אותו. RazGaz מחזיקה את ההזמנה ומשחררת אותה לשידור בעצמה, בזמן שמחושב
אחורה מהמועד — דרך זמן ההכנה, כך שהאוכל מוכן כשהשליח בדלפק. לכן minutes נדרש
כאן גם הוא: זמן ההכנה הוא חלק מהחשבון, ובלעדיו המועד אינו ניתן לחישוב.
| שדה | טיפוס | תיאור |
|---|---|---|
orderId | מחרוזת | ההזמנה. חייבת להיות ב‑awaiting_prep_time |
scheduledFor | מספר | מחרוזת | מועד האיסוף המבוקש — השעה שבה השליח יגיע למסעדה: אלפיות שנייה מ‑epoch, או ISO‑8601. חייב להיות בעתיד ולא יותר מ‑7 ימים מראש |
minutes | מספר שלם | זמן ההכנה, 1–240 |
תשובה: { "success": true, "orderId": "…", "scheduledFor": …, "releaseAt": …, "minutes": 25 }
— שתי החותמות באלפיות שנייה. releaseAt הוא הרגע שבו ההזמנה תצא לשידור, ועד אז
היא בסטטוס scheduled ואינה מוצעת לאף שליח.
| HTTP | מתי |
|---|---|
400 | מועד בעבר, מועד רחוק מ‑7 ימים, או minutes מחוץ לתחום |
404 | הזמנה לא מוכרת |
403 | ההזמנה אינה של הסניף הזה |
409 | ההזמנה אינה ב‑awaiting_prep_time — כלומר היא כבר שוחררה, ותזמון אחורה אינו אפשרי מכאן |
הזמנה שכבר יצאה לשידור אינה ניתנת לתזמון מהממשק הזה. אם לקוח הזיז מועד לאחר שההזמנה שוחררה — יש לבטל (§8.3) ולפתוח חדשה בזמנה.
6קריאת ההזמנות
כאן נקרא כל מה שהאפליקציה מציגה: הסטטוס, השליח, מקומו על המפה, זמני הדרך. הקריאה
היא מול המאחז השני, firestore.googleapis.com, עם אותו אסימון מ‑§3.3. הבסיס
לכל הקריאות בפרק הזה:
https://firestore.googleapis.com/v1/projects/razgaz-f7295/databases/(default)/documents
מגבלות התשאול הן חלק מהחוזה. התשאול הוא הדרך היחידה לדעת מה קרה להזמנה, ולכן הקצב שלו אינו עניין של נימוס:
| קצב מותר | בקשה אחת ל‑דקה לכל סניף, לכל היותר |
| כשאין הזמנה פעילה | לא לתשאל כלל |
| מספר המתשאלים | אחד לכל סניף — לא אחד לכל קופה או מסך |
שלושת אלה נאמרים במפורש מפני שכל אחד מהם כבר נשבר אצלנו בייצור, באינטגרציה אחרת: מערכת קופה אחת מתשאלת נקודת קצה אחרת שלנו פעם ב‑0.37 שניות — פי 54 מהקצב שנמסר לה — סביב השעון, כולל בשעות שבהן המטבח סגור, ומכמה עמדות במקביל שכל אחת מחזיקה שעון משלה. היא עשתה זאת בעבור מסעדה אחת ששלחה שמונה הזמנות.
שום דבר אינו אוכף את הקצב הזה בכל בקשה. אף קריאה שלכם לא תידחה בגלל חריגה — נתיב הקריאה הוא שירות של Google ואין בינו לביניכם שום רכיב שלנו. מה שאנחנו רואים ביומיום הוא נפח הקריאות הכולל מכל הסניפים; ייחוס של קפיצה לסניף מסוים הוא דבר שאנחנו מפעילים כשקפיצה כזו כבר מולנו, והוא נוקב בשמכם. חריגה מתמשכת פירושה פנייה אליכם, ואם היא נמשכת, השבתת חשבון הסניף: זה הכלי היחיד שיש לנו כאן, והוא גם מפסיק את פתיחת ההזמנות. עדיף להימנע מהשיחה הזו — ובוודאי שעדיף לא להיזקק לתשאול כלל, שזה בדיוק מה שמאזין (§6.6) עושה.
6.1ההזמנות הפעילות
POST …/documents:runQuery
{
"structuredQuery": {
"from": [{ "collectionId": "orders" }],
"where": { "compositeFilter": { "op": "AND", "filters": [
{ "fieldFilter": {
"field": { "fieldPath": "restaurantName" },
"op": "EQUAL",
"value": { "stringValue": "שם הסניף" } } },
{ "fieldFilter": {
"field": { "fieldPath": "status" },
"op": "IN",
"value": { "arrayValue": { "values": [
{ "stringValue": "scheduled" },
{ "stringValue": "awaiting_prep_time" },
{ "stringValue": "held" },
{ "stringValue": "pending" },
{ "stringValue": "broadcasting" },
{ "stringValue": "accepted" },
{ "stringValue": "arrived_at_pickup" },
{ "stringValue": "picked_up" },
{ "stringValue": "arrived_at_delivery" }
] } } } }
] } }
}
}
שם הסניף הוא השם הקנוני מ‑§2, זהות מלאה תו בתו. שם שאינו זהה מחזיר קבוצה ריקה
ולא שגיאה — זו התקלה השקטה היחידה בפרק הזה, ולכן כדאי לוודא את השם מול הזמנה
אחת אמיתית לפני העלייה לאוויר.
6.2הזמנה אחת
GET …/documents/orders/<orderId> — עם האסימון בכותרת. 404 להזמנה לא מוכרת,
403 להזמנה של סניף אחר.
זו הדרך לעקוב אחרי הזמנה מסוימת בלי לתשאל את כל הלוח, ובפרט הדרך לוודא שקריאה מ‑§4 או §5 שאין ממנה תשובה אכן נכתבה.
6.3היסטוריה
אותה שאילתה כמו §6.1 עם "stringValue": "delivered" ו‑"cancelled" ברשימת
הסטטוסים. אין מחיקה של הזמנות: הזמנה שנמסרה או בוטלה נשארת קריאה.
6.4השדות שחוזרים
התשובה היא מסמך Firestore, כלומר כל ערך עטוף בטיפוס שלו
(stringValue, integerValue, doubleValue, timestampValue, nullValue,
geoPointValue, mapValue, arrayValue). אלה השדות שיש בהם עניין למערכת
המסעדה; יש בהזמנה שדות נוספים, כולם תפעול פנימי של RazGaz:
| שדה | מה זה |
|---|---|
status | מצב ההזמנה, §7 |
platformOrderRef | מספר ההזמנה האנושי — מה שאומרים בטלפון |
estimatedReadyMinutes | זמן ההכנה שנרשם, בדקות |
readyAt | הרגע שבו האוכל צפוי להיות מוכן, לפי זמן ההכנה |
markedReadyAt | הרגע שבו נאמר שהאוכל מוכן. ריק כל עוד לא נאמר — §8.1 |
carrierId | מזהה השליח, או null כל עוד לא שויך. המפתח ל‑§6.5 |
estimatedArrival | הערכת RazGaz לזמן ההגעה של השליח |
scheduledFor | מועד האיסוף בהזמנה מתוזמנת — השעה שבה השליח יגיע למסעדה, §5.2 |
cancelledAt, cancellationReason | ביטול: מתי, ומה נכתב עליו |
deliveredAt | רגע המסירה ללקוח |
deliveryAddress, customerName, customerPhone, items, orderAmount, paymentMethod, notes | כפי שנשלחו ב‑§4 |
6.5מעקב אחר השליח
GET …/documents/carriers/<carrierId> — כאשר ההזמנה כבר נושאת carrierId.
| שדה | מה זה |
|---|---|
displayName | שם השליח |
phone | הטלפון שלו — למי שרוצה כפתור התקשרות |
currentLocation | מקומו על המפה, geoPointValue, מתעדכן כל עוד הוא בפעילות |
vehicleType | סוג הרכב |
זהו המידע שהאפליקציה מציירת על המפה. מסמך השליח נקרא במלואו, וכל מה שאינו בטבלה הזו הוא תפעול פנימי של RazGaz ואינו חלק מהחוזה הזה — אין להסתמך עליו.
6.6לא לתשאל בכלל — הדרך המומלצת
ל‑Firestore יש ערוץ הקשבה: פותחים חיבור אחד, ומקבלים כל שינוי ברגע שהוא קורה. זו הדרך שאפליקציית המסעדה עצמה עובדת, וזו הדרך המומלצת כאן — היא מגיעה מיד במקום בתוך דקה, ואין לה שום עלות בזמן שדבר אינו קורה, כך שגם המגבלות שלמעלה פשוט אינן חלות.
היא דורשת את ה‑SDK של Firebase, כי ערוץ ההקשבה הוא gRPC ואינו קיים ב‑REST. ב‑Node:
const { initializeApp } = require('firebase/app');
const { getAuth, signInWithEmailAndPassword } = require('firebase/auth');
const { getFirestore, collection, query, where, onSnapshot } = require('firebase/firestore');
const app = initializeApp({ apiKey: '<WEB_API_KEY>', projectId: 'razgaz-f7295' });
await signInWithEmailAndPassword(getAuth(app), 'branch@example.com', '…');
onSnapshot(
query(
collection(getFirestore(app), 'orders'),
where('restaurantName', '==', 'שם הסניף'),
where('status', 'in', ['scheduled', 'awaiting_prep_time', 'held', 'pending', 'broadcasting',
'accepted', 'arrived_at_pickup', 'picked_up', 'arrived_at_delivery']),
),
(snap) => {
for (const change of snap.docChanges()) {
// 'added' — הזמנה נכנסה ללוח · 'modified' — סטטוס, שליח או ETA השתנו
console.log(change.type, change.doc.id, change.doc.data().status);
}
},
);
השאילתה זהה לזו של §6.1, וכך גם ההרשאות. signInWithEmailAndPassword מחזיק את
האסימון בעצמו ומרענן אותו — §3.2 אינו נחוץ במסלול הזה. השדות שחוזרים הם אותם
שדות של §6.4, אלא שהם מגיעים כערכים רגילים ולא עטופים בטיפוסי Firestore.
מה שמגיע הוא כל שינוי במסמך, לא רק שינוי סטטוס — גם עדכוני זמן ההגעה של השליח, שנכתבים כל שתי דקות כל עוד ההזמנה בדרך. זה מה שמאפשר להציג ETA שזז על המסך, וזה גם מה שקובע את העלות: כמה עשרות שינויים לכל הזמנה, ואפס בין הזמנות.
מתי בכל זאת לתשאל. כשאין SDK — מערכת ב‑PHP או ב‑.NET ישן שאינה יכולה להחזיק חיבור — התשאול של §6.1 הוא המסלול, בכפוף למגבלות שבראש §6.
7סטטוסים
status | משמעות |
|---|---|
awaiting_prep_time | מוחזקת: RazGaz מחכה לזמן הכנה. אינה משודרת לאף שליח — §5 |
held | מוחזקת אצל מוקדן RazGaz: הסניף מוגדר לפרסום ידני, ומוקדן משחרר כל הזמנה. אינה משודרת לאף שליח; אין מה לעשות מצד הסניף — מבשלים כרגיל |
scheduled | נקבעה למועד מאוחר, ממתינה לשחרור אוטומטי — §5.2 |
pending | שוחררה, טרם החל שידור |
broadcasting | מוצעת לשליחים באזור |
accepted | שליח לקח אותה על עצמו ובדרך לסניף |
arrived_at_pickup | השליח בסניף |
picked_up | האוכל אצל השליח, בדרך ללקוח |
arrived_at_delivery | השליח אצל הלקוח |
delivered | נמסרה. סופי |
cancelled | בוטלה. סופי |
הסטטוס מתקדם בסדר הזה, אבל לא כל מצב מופיע בהכרח בתשאול: שני מצבים סמוכים יכולים להתחלף בין שתי דגימות. יש להתייחס לסטטוס כמצב נוכחי ולא כאירוע, ולא לבנות לוגיקה שדורשת לראות כל מצב.
8פעולות על הזמנה קיימת
שלוש הפעולות שהאפליקציה מציעה על כרטיס הזמנה. כולן POST …/documents:commit
מול המאחז של §6, עם אותו אסימון, ובצורה מדויקת: הצורות שלהלן הן מה שמותר,
וכתיבה אחרת על הזמנה נדחית בצד השרת — שדה שאינו ברשימה, או הזמנה של סניף אחר,
מוחזרים כשגיאת הרשאה ולא כתיבה חלקית.
בכל הבקשות <orderId> הוא המזהה מ‑§4.5, ו‑name הוא הנתיב המלא
projects/razgaz-f7295/databases/(default)/documents/orders/<orderId>.
8.1האוכל מוכן
{ "writes": [ {
"update": {
"name": "projects/razgaz-f7295/databases/(default)/documents/orders/<orderId>",
"fields": { "readySource": { "nullValue": null } }
},
"updateMask": { "fieldPaths": ["markedReadyAt", "readySource"] },
"updateTransforms": [
{ "fieldPath": "markedReadyAt", "setToServerValue": "REQUEST_TIME" }
]
} ] }
זו ההודעה לשליח שאין טעם להמתין. markedReadyAt נכתב כזמן השרת — לא כשעון של
מערכת המסעדה — כי כל הצד השני קורא אותו כזמן RazGaz, ושעון שנמצא כמה דקות
מהמקום מזיז את ההודעה. readySource: null נשלח באותה כתיבה; השדה מתעד מי אמר
שהאוכל מוכן, ומ-19 באוגוסט 2026 התשובה היא תמיד אדם.
שום דבר אחר לא כותב את השדה הזה. זמן הכנה הוא הערכה, ולתת להערכה שפגה לסמן "מוכן" פירושו לומר לשליח שהאוכל מוכן בלי שאיש הסתכל עליו. לכן הערכה שנגמרה אינה משנה דבר בהזמנה: אם הקריאה הזו לא נעשית, פשוט לא נאמר לשליח דבר, לאורך כל חיי ההזמנה. ההזמנה עדיין משודרת, נלקחת ונמסרת כרגיל. לשלוח כשהשקית על הדלפק, לא לפני.
לקרוא פעם אחת. קריאה שנייה כותבת חותמת חדשה על הראשונה ואינה מוסיפה דבר.
8.2עדכון זמן הכנה
לא כאן — §5.1. submitPrepTime נכון לשני המצבים, כותב את אותו השדה, וגם מודיע
לשליח שכבר שויך. כתיבה ישירה של estimatedReadyMinutes אפשרית ואינה מודיעה
לאיש; אין סיבה להעדיף אותה.
8.3ביטול
{ "writes": [ {
"update": {
"name": "projects/razgaz-f7295/databases/(default)/documents/orders/<orderId>",
"fields": {
"status": { "stringValue": "cancelled" },
"cancellationReason": { "stringValue": "בוטל על ידי המסעדה" }
}
},
"updateMask": { "fieldPaths": ["status", "cancelledAt", "cancellationReason"] },
"updateTransforms": [
{ "fieldPath": "cancelledAt", "setToServerValue": "REQUEST_TIME" }
]
} ] }
"cancelled" הוא הערך היחיד הנתמך ב‑status מהממשק הזה. שאר הסטטוסים הם תיאור
של מה שקורה לשליח, ו‑RazGaz היא שכותבת אותם; הזמנה שסומנה מבחוץ במצב שאינו מתאים
למה שקורה בפועל מתנתקת ממה שהמוקד והשליח רואים.
cancellationReason נקרא בידי אדם ולכן כדאי שיהיה קונקרטי — "הלקוח ביטל",
"הסניף סגר" — ולא ריק.
ביטול הוא סופי ואינו מבטל את עצמו. הזמנה מבוטלת אינה חוזרת לשידור ואין דרך
להחיות אותה; מה שנדרש אחריה הוא הזמנה חדשה לפי §4. ביטול הזמנה שהשליח כבר אסף
אינו מחזיר את האוכל — במצב picked_up ואחריו יש להתקשר למוקד ולא להסתמך על
הקריאה הזו לבד.
9מה שאין בממשק הזה
מה שכדאי לדעת לפני התכנון, כדי שלא יתוכנן סביבו:
| קריאה חוזרת ל‑RazGaz | אין. אין webhook ואין הודעת דחיפה למערכת המסעדה; המידע מגיע בתשאול, §6 |
| תרגום כתובת לקואורדינטות | מ‑2026‑08‑25 יש: שלחו כתובת בלי קואורדינטות ואנחנו נאתר אותה, וגם נמלא את העיר של הסניף כשהכתובת לא ציינה עיר (§4.2). שליחת קואורדינטות עדיין מדויקת יותר, והיא הדרך היחידה שמבטיחה בניין ולא מרכז עיר |
| מזהה הזמנה משלכם | אין. המזהה הוא של RazGaz, ואין חיפוש לפי המזהה שלכם — §4.5, §4.7 |
| שינוי כתובת או פרטי לקוח לאחר הפתיחה | אין. הזמנה שנפתחה עם כתובת שגויה מבוטלת ונפתחת מחדש |
| בחירת שליח, או שינוי אזור ותמחור | אין. שיוך שליח, שכרו ורדיוס השידור הם של RazGaz |
| תזמון הזמנה שכבר שוחררה | אין. התזמון אפשרי רק מ‑awaiting_prep_time — §5.2 |
| חשבון אחד לכמה סניפים | אין. חשבון לכל סניף, §2 |
10לפני עלייה לאוויר
בסדר הזה, ועל סניף אחד אמיתי:
- הזדהות מחזירה אסימון, והרענון עובד. לא רק ההזדהות — גם המסלול שאחרי שעה, כי בייצור הוא זה שנתקל בו כל הזמן.
- הזמנת בדיקה נפתחת ומחזירה
201ו‑orderId, וה‑orderIdנשמר אצלכם לצד ההזמנה. - תשאול §6.1 מחזיר בדיוק את ההזמנה הזאת. אם הוא מחזיר קבוצה ריקה — שם הסניף אינו זהה לשם הקנוני. זו התקלה השכיחה.
- הסטטוס זז. מ‑
pendingל‑broadcastingומשם ל‑acceptedכששליח לוקח את ההזמנה, ואזcarrierIdמתמלא ו‑§6.5 מחזיר את מקומו. - "האוכל מוכן" (§8.1) נכתב —
markedReadyAtמתמלא בתשאול הבא. - ביטול (§8.3) עובד על ההזמנה שנפתחה לבדיקה, וסוגר אותה. לסיים בה כדי לא להשאיר משלוח בדיקה פתוח בשידור.
estimatedReadyMinutesנשלח על כל הזמנה — או שאושר מול RazGaz שלסניף יש זמן הכנה ממוצע רשום. אחרת ההזמנה הראשונה בייצור תיתקע מוחזקת, §5.
לשאלות ולתקלות אינטגרציה — הכתובת היא מי שמסר לכם את המסמך הזה. שגיאה שחוזרת
בייצור, ובפרט 401, 403 או תשאול שמחזיר ריק, היא אינטגרציה שאינה מספקת דבר
בשקט; יש להסלים אותה מיד ולא להמתין להזמנה הבאה.