Skip to content

משלוח אקספרס ​

ארבע נקודות קצה בקבוצת shipping מכסות שירותי אותו יום ואקספרס: הצעת מחיר, shipment promise של Wolt Drive, ושתי בדיקות זכאות ל-ZigZag Express 24.

אלה אינן workflow

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

נקודת קצהמיושמת על ידיהמתודה שהיא דורשת
same_day_delivery_quoteGet PackagegetSameDayDeliveryQuote()
create_shipping_promiseWolt DrivecreateShipmentPromise()
get_express_delivery_enabledZigZaggetExpressDeliveryenabled()
get_express_delivery_statusZigZaggetExpressDeliveryStatus()

רישיון שמחלקת שירות חברת השילוח שלו אינה מגדירה את המתודה של נקודת הקצה שאתם קוראים לה מקבל HTTP 400 ו-message: "Not supported for this provider" — ה-controller בודק עם method_exists() לפני כל דבר אחר, כולל לפני $request->validate(). לכן אין רצף של "בדיקת זמינות → הצעת מחיר → promise → סטטוס" שיש לעקוב אחריו: שתי בדיקות ה-ZigZag שייכות יחד, והצעת המחיר של Get Package וה-promise של Wolt Drive עומדות כל אחת בנפרד והן של חברות שילוח שונות.

ארבע אלה הן GET

בשונה משאר קבוצת ה-shipping של v1, שהיא POST עם גוף JSON, אלה מקבלות את כל הפרמטרים שלהן — כולל פרטי ההזדהות — כערכים במחרוזת השאילתה. שלחו אותם במחרוזת השאילתה — זו הצורה הנתמכת. גוף JSON נקרא גם הוא בנתיבי ה-GET האלה: שליחת כל הפרמטרים, כולל פרטי ההזדהות, כ-JSON עם Content-Type: application/json ועם מחרוזת שאילתה ריקה עובדת. גוף form-encoded אינו נקרא — הוא מחזיר 422.

אימות ​

כל הארבע יושבות מאחורי אותו middleware hasLicense כמו שאר הקבוצה, ולכן license_key ו-domain נדרשים בכל קריאה, כפרמטרי שאילתה. מפתח רישיון שלא ניתן לפענח מחזיר HTTP 403 עם המעטפת הסטנדרטית ועם message: "Invalid License Key" עוד לפני שה-handler רץ. ראו אימות.

שדהסוגחובהתיאור
license_keystringכןמפתח הרישיון של חשבון חברת השילוח.
domainstringכןהדומיין של החנות הקוראת. נדרש על ידי הוולידציה; הדומיין השמור של הרישיון עצמו אינו מושווה אליו כרגע.
tokenstringלאSanctum personal access token. HasLicense קורא ל-PersonalAccessToken::findToken() בכל בקשה; הוא משנה את התוצאה רק עבור רישיונות שהחברה שלהם מסומנת כפרימיום — בלי משתמש עם פרימיום פעיל הרישיונות האלה נדחים עם 403.

כשלים מגיעים תמיד בסדר קבוע: 403 של דחיית רישיון, אחר כך 400 של בדיקת הספק, ואחר כך 422 של ולידציית הפרמטרים. מכיוון שבדיקת ה-method_exists() רצה לפני $request->validate(), קריאה על חברת שילוח שאינה נתמכת לא תוכל להחזיר 422 לעולם — על רישיון של Cargo, בקשה שנושאת רק פרטי הזדהות ובלי שום פרמטר אחר עונה 400 עם "Not supported for this provider". ההשלכה מעשית: אי אפשר לגלות את חוזה הפרמטרים של נקודת קצה על ידי גישושים מרישיון שחברת השילוח שלו אינה מיישמת אותה.

תשובות 422 בעמוד הזה אינן מעטפת ארבעת המפתחות של v1. הן בצורת הוולידציה של Laravel, {"message": ..., "errors": {...}}, וההודעות שלהן מתורגמות — בעברית במופעים הישראליים. license_key או domain חסר הוא אחד מה-422 האלה, שנזרק על ידי hasLicense; רק מפתח שאינו נפתר לשום רישיון מחזיר 403 עם המעטפת ועם "Invalid License Key".

חברת פרימיום נדחית עם 403 ועם אחת משתי הודעות מדויקות: "Premium companies are not supported in this version of plugin" כאשר לא ניתן היה לפענח משתמש מה-token, ו-"You must be a premium member to use this company" כאשר משתמש כן נפענח אך אינו פרימיום פעיל.

כתובות איסוף אינן מטופלות באופן אחיד בארבע נקודות הקצה. רק same_day_delivery_quote משתמשת בכתובת איסוף בכלל, והיא קוראת collect_street, collect_street_number ו-collect_city מההגדרות השמורות של הרישיון — ולא collect_company, שאף אחת מהארבע אינה קוראת. create_shipping_promise משתמשת ב-venue_id של Wolt מהרישיון במקום בכתובת, ולשתי נקודות הקצה של ZigZag אין מושג של כתובת איסוף כלל. גם לא נכון שכתובת האיסוף היא תמיד זו של הרישיון: כאשר לרישיון אין הגדרות איסוף שמורות, License::getCollectionSettings() מחזירה null-ים וה-handler נופל אל shipment_settings[collect_*] שסופק על ידי הקורא בבקשה, וזה מה שקובע.


GET /shipping/same_day_delivery_quote ​

קבלת מחיר למשלוח באותו יום דרך Get Package, מכתובת האיסוף של הרישיון לכתובת שאתם מספקים. שום דבר אינו מוזמן.

פרמטרים ​

שאילתה ​

שדהסוגחובהתיאור
license_keystringכןראו אימות.
domainstringכןראו אימות.
citystringכןעיר היעד.
streetstringכןרחוב היעד.
street_numberintegerכןמספר הרחוב ביעד. עובר ולידציה כ-integer כאן (שלוש נקודות הקצה האחרות מקבלות מחרוזת).
namestringכןשם הנמען. נדרש על ידי הוולידציה.
phonestringכןטלפון הנמען. נדרש על ידי הוולידציה.
datestringכןהתאריך המבוקש, Y-m-d. נדרש על ידי הוולידציה.
package_sizestringכןאחד מ-0, 1, 2, 3, ENVELOPE, SMALL, MEDIUM, LARGE.

TIP

name, phone ו-date נאכפים על ידי הוולידטור אך אינם מועברים ל-Get Package במימוש הנוכחי, ששולח רק את שתי הכתובות ואת גודל החבילה. שלחו בכל זאת ערכים אמיתיים — הוולידציה היא מה שהיא, וה-payload עשוי להתרחב.

package_size הוא פרמטר אמיתי, אבל package_id אינו יכול להיקבע על ידי הקורא: ה-handler מעביר הלאה רק קלט שעבר ולידציה, ולכן $data['package_id'] ?? Str::random() בשכבת חברת השילוח בוחר תמיד בענף הרנדומלי. אין לנסות לספק אותו.

איך הצעת המחיר נדחית ​

לפני מתן ההצעה, השירות מביא את רשימת היישובים של Get Package לשירות אותו יום (נשלפת עבור תל אביב, נשמרת במטמון ל-24 שעות) ובודק מולה את עיר האיסוף של הרישיון. עיר איסוף שאינה ברשימה מחזירה success: false עם message: "City {city} is not in location list".

בקשה לדוגמה ​

bash
curl --location --get 'https://app.shipos.co.il/api/shipping/same_day_delivery_quote' \
--header 'Accept: application/json' \
--data-urlencode 'license_key={license_key}' \
--data-urlencode 'domain=your-store.example.com' \
--data-urlencode 'city=תל אביב' \
--data-urlencode 'street=הרצל' \
--data-urlencode 'street_number=10' \
--data-urlencode 'name=ישראל ישראלי' \
--data-urlencode 'phone=0501234567' \
--data-urlencode 'date=2026-09-01' \
--data-urlencode 'package_size=SMALL'
js
// Node.js 18+ / דפדפנים — בלי תלויות
const query = new URLSearchParams({
  license_key: process.env.SHIPOS_LICENSE_KEY,
  domain: process.env.SHIPOS_DOMAIN,
  city: 'תל אביב',
  street: 'הרצל',
  street_number: '10',
  name: 'ישראל ישראלי',
  phone: '0501234567',
  date: '2026-09-01',
  package_size: 'SMALL',
})

const response = await fetch(
  `https://app.shipos.co.il/api/shipping/same_day_delivery_quote?${query}`,
  { headers: { Accept: 'application/json' } },
)

const body = await response.json()

if (!body.success) {
  throw new Error(`ShipOS v1: ${body.message}`)
}

console.log(body.data)
php
<?php

use Illuminate\Support\Facades\Http;

$body = Http::acceptJson()
    ->get('https://app.shipos.co.il/api/shipping/same_day_delivery_quote', [
        'license_key' => config('services.shipos.license_key'),
        'domain' => config('services.shipos.domain'),
        'city' => 'תל אביב',
        'street' => 'הרצל',
        'street_number' => 10,
        'name' => 'ישראל ישראלי',
        'phone' => '0501234567',
        'date' => '2026-09-01',
        'package_size' => 'SMALL',
    ])
    ->json();

if (! ($body['success'] ?? false)) {
    throw new RuntimeException('ShipOS v1: '.$body['message']);
}

תשובה לדוגמה ​

data הוא גוף ההצעה של Get Package עצמה, מועבר כפי שהוא — התיעוד הזה אינו חוזר על הסכמה של חברת השילוח.

json
{
  "data": { "...": "..." },
  "message": "",
  "success": true,
  "warning": ""
}

עיר איסוף שמחוץ לרשימת אותו יום:

json
{
  "data": [],
  "message": "City חוות זוהר המדבר is not in location list",
  "success": false,
  "warning": ""
}

העיר שמופיעה בהודעה הזו היא עיר האיסוף של הרישיון, ולא עיר היעד שהבקשה ביקשה — הדוגמה שלמעלה שולחת city=תל אביב ונדחית בגלל שם מקום אחר לגמרי.

שגיאות ​

סטטוסמתי
400חברת השילוח של הרישיון אינה מיישמת הצעת מחיר לאותו יום (Not supported for this provider), עיר האיסוף אינה ברשימה של Get Package, או ש-Get Package ענתה בשגיאת HTTP. בשגיאת HTTP של חברת השילוח message הוא Error Retrieving Quote וגוף השגיאה של חברת השילוח נמצא ב-data; כאשר לא ניתן היה לבצע את הקריאה כלל (DNS, timeout) message הוא שגיאת התעבורה כפי שהיא.
403לא ניתן לפענח את הרישיון, הוא הושבת, או שהוא חברת פרימיום ללא משתמש עם פרימיום פעיל.
422ולידציית הפרמטרים נכשלה, או ש-license_key/domain חסר (זה מגיע מ-hasLicense). נגיש רק לאחר שבדיקת הספק עברה. בצורת {"message", "errors"} של Laravel, ולא במעטפת של v1.

GET /shipping/create_shipping_promise ​

בקשת shipment promise מ-Wolt Drive — הצעה מתומחרת ומוגבלת בזמן למשלוח מהמקום (venue) של הרישיון לכתובת שאתם מספקים.

promise כאן הוא לידיעה בלבד

נקודת קצה זו מחזירה את ה-promise של Wolt כדי שחנות תוכל להציג מחיר וחלון זמן. הוא אינו מועבר ליצירת משלוח: open_new_order יוצרת promise משל עצמה בפנים ומשתמשת ב-shipment_promise_id שלו. שום דבר שאתם מקבלים כאן אינו צריך להישמר או להישלח מחדש.

פרמטרים ​

שאילתה ​

שדהסוגחובהתיאור
license_keystringכןראו אימות.
domainstringכןראו אימות.
citystringכןעיר המסירה.
streetstringכןרחוב המסירה.
street_numberstringלאמספר הרחוב במסירה. משורשר ל-street לפני שהוא נשלח ל-Wolt.

ה-venue של Wolt, אסטרטגיית זמן ההכנה ושעות הפעילות מגיעים כולם מההגדרות של הרישיון (venue_id, time_type, min_preparation_time_minutes או time_slot, opening_time, closing_time), ולא מהבקשה.

שעות סגירה ​

כאשר לרישיון מוגדרים גם opening_time וגם closing_time והשעה הנוכחית ב-Asia/Jerusalem נמצאת מחוץ לחלון הזה, לא נעשית קריאה ל-Wolt והתשובה היא כישלון שנושא data.details: "Delivery area will be closed at the requested delivery time.".

איך המחיר נכתב מחדש ​

Wolt מחזירה את price.amount ביחידות משנה. ה-handler מחלק אותו ב-100 ומעגל לשתי ספרות אחרי הנקודה, ואז מיישם את ה-price_type של הרישיון:

price_typeההשפעה על data.price.amount
לא מוגדר / כל דבר אחרהסכום המומר של חברת השילוח.
fixמוחלף ב-fix_price של הרישיון.
markupהסכום המומר של חברת השילוח בתוספת ה-markup_price של הרישיון, מעוגל לשתי ספרות אחרי הנקודה.

בקשה לדוגמה ​

bash
curl --location --get 'https://app.shipos.co.il/api/shipping/create_shipping_promise' \
--header 'Accept: application/json' \
--data-urlencode 'license_key={license_key}' \
--data-urlencode 'domain=your-store.example.com' \
--data-urlencode 'city=תל אביב' \
--data-urlencode 'street=הרצל' \
--data-urlencode 'street_number=10'
js
// Node.js 18+ / דפדפנים — בלי תלויות
const query = new URLSearchParams({
  license_key: process.env.SHIPOS_LICENSE_KEY,
  domain: process.env.SHIPOS_DOMAIN,
  city: 'תל אביב',
  street: 'הרצל',
  street_number: '10',
})

const response = await fetch(
  `https://app.shipos.co.il/api/shipping/create_shipping_promise?${query}`,
  { headers: { Accept: 'application/json' } },
)

const body = await response.json()

if (!body.success) {
  // למשל מחוץ לשעות הפעילות של ה-venue
  throw new Error(`ShipOS v1: ${body.data.details ?? body.message}`)
}

console.log(body.data.price.amount)
php
<?php

use Illuminate\Support\Facades\Http;

$body = Http::acceptJson()
    ->get('https://app.shipos.co.il/api/shipping/create_shipping_promise', [
        'license_key' => config('services.shipos.license_key'),
        'domain' => config('services.shipos.domain'),
        'city' => 'תל אביב',
        'street' => 'הרצל',
        'street_number' => '10',
    ])
    ->json();

if (! ($body['success'] ?? false)) {
    throw new RuntimeException('ShipOS v1: '.($body['data']['details'] ?? $body['message']));
}

logger()->info('Wolt promise', ['amount' => $body['data']['price']['amount']]);

תשובה לדוגמה ​

data הוא אובייקט ה-shipment promise של Wolt כאשר price.amount נכתב מחדש כמתואר למעלה. המפתחות שהאפליקציה הזו עצמה קוראת ממנו הם id, pickup.options, dropoff.location.coordinates, dropoff.location.formatted_address, dropoff.options ו-price; שאר האובייקט הוא של Wolt ומועבר כפי שהוא.

json
{
  "data": {
    "id": "...",
    "price": { "amount": 24.9, "...": "..." },
    "pickup": { "options": [] },
    "dropoff": { "location": { "coordinates": {}, "formatted_address": "..." }, "options": [] }
  },
  "message": "",
  "success": true,
  "warning": ""
}

מחוץ לשעות הפעילות:

json
{
  "data": { "details": "Delivery area will be closed at the requested delivery time." },
  "message": "Error Retrieving Quote",
  "success": false,
  "warning": ""
}

שגיאות ​

סטטוסמתי
400חברת השילוח של הרישיון אינה Wolt Drive (Not supported for this provider), ה-venue מחוץ לשעות הפעילות שלו, או ש-Wolt לא ענתה 201. message נופל בברירת מחדל ל-Error Retrieving Quote.
403לא ניתן לפענח את הרישיון, הוא הושבת, או שהוא חברת פרימיום ללא משתמש עם פרימיום פעיל.
422ולידציית הפרמטרים נכשלה, או ש-license_key/domain חסר (זה מגיע מ-hasLicense). נגיש רק לאחר שבדיקת הספק עברה. בצורת {"message", "errors"} של Laravel, ולא במעטפת של v1.

GET /shipping/get_express_delivery_enabled ​

דיווח אם ZigZag Express 24 מופעל עבור הרישיון הזה. זה קורא את הגדרת ה-enable_express_delivery של הרישיון עצמו; אין קריאה ל-ZigZag ואין שאלה לגבי כתובת.

פרמטרים ​

שאילתה ​

שדהסוגחובהתיאור
license_keystringכןראו אימות.
domainstringכןראו אימות.

אין פרמטרים אחרים. ה-handler אינו מבצע ולידציה על שום דבר מעבר למה ש-hasLicense דורש.

בקשה לדוגמה ​

bash
curl --location --get 'https://app.shipos.co.il/api/shipping/get_express_delivery_enabled' \
--header 'Accept: application/json' \
--data-urlencode 'license_key={license_key}' \
--data-urlencode 'domain=your-store.example.com'
js
// Node.js 18+ / דפדפנים — בלי תלויות
const query = new URLSearchParams({
  license_key: process.env.SHIPOS_LICENSE_KEY,
  domain: process.env.SHIPOS_DOMAIN,
})

const response = await fetch(
  `https://app.shipos.co.il/api/shipping/get_express_delivery_enabled?${query}`,
  { headers: { Accept: 'application/json' } },
)

const body = await response.json()

// "לא מופעל" מגיע כ-HTTP 400 עם success: false
console.log(body.success ? 'express on' : body.message)
php
<?php

use Illuminate\Support\Facades\Http;

$body = Http::acceptJson()
    ->get('https://app.shipos.co.il/api/shipping/get_express_delivery_enabled', [
        'license_key' => config('services.shipos.license_key'),
        'domain' => config('services.shipos.domain'),
    ])
    ->json();

logger()->info($body['success'] ? 'express on' : $body['message']);

תשובה לדוגמה ​

צמד ה-{ success, message } של שירות חברת השילוח עצמו ממוקם בתוך data, וה-message שלו מועתק ל-message של המעטפת, כך שהשניים מסכימים ביניהם.

json
{
  "data": { "success": true, "message": "Express Delivery service is enabled" },
  "message": "Express Delivery service is enabled",
  "success": true,
  "warning": ""
}

לא מופעל — שימו לב שזה HTTP 400, ולא 200 שנושא false:

json
{
  "data": { "success": false, "message": "Express Delivery service is not enabled" },
  "message": "Express Delivery service is not enabled",
  "success": false,
  "warning": ""
}

שגיאות ​

סטטוסמתי
400חברת השילוח של הרישיון אינה ZigZag (Not supported for this provider), או שהגדרת ה-enable_express_delivery של הרישיון כבויה.
403לא ניתן לפענח את הרישיון, הוא הושבת, או שהוא חברת פרימיום ללא משתמש עם פרימיום פעיל.
422license_key או domain הושמט — נזרק על ידי hasLicense עוד לפני שה-handler רץ. בצורת {"message", "errors"} של Laravel, ולא במעטפת של v1.

GET /shipping/get_express_delivery_status ​

בדיקה אם כתובת אחת זכאית ל-ZigZag Express 24. הכתובת מחוברת ל-"{city}, {street} {street_number}" ומועברת לפעולת IsRemoteArea של ZigZag, בשימוש ה-express_username / express_password מהגדרות הרישיון; אזור מרוחק אינו זכאי.

פרמטרים ​

שאילתה ​

שדהסוגחובהתיאור
license_keystringכןראו אימות.
domainstringכןראו אימות.
citystringכןעיר היעד.
streetstringכןרחוב היעד.
street_numberstringלאמספר הרחוב ביעד.

בקשה לדוגמה ​

bash
curl --location --get 'https://app.shipos.co.il/api/shipping/get_express_delivery_status' \
--header 'Accept: application/json' \
--data-urlencode 'license_key={license_key}' \
--data-urlencode 'domain=your-store.example.com' \
--data-urlencode 'city=תל אביב' \
--data-urlencode 'street=הרצל' \
--data-urlencode 'street_number=10'
js
// Node.js 18+ / דפדפנים — בלי תלויות
const query = new URLSearchParams({
  license_key: process.env.SHIPOS_LICENSE_KEY,
  domain: process.env.SHIPOS_DOMAIN,
  city: 'תל אביב',
  street: 'הרצל',
  street_number: '10',
})

const response = await fetch(
  `https://app.shipos.co.il/api/shipping/get_express_delivery_status?${query}`,
  { headers: { Accept: 'application/json' } },
)

const body = await response.json()

// כתובת שאינה זכאית היא 400, לא 200 עם דגל false
const eligible = body.success

console.log(eligible ? 'express available' : body.message)
php
<?php

use Illuminate\Support\Facades\Http;

$body = Http::acceptJson()
    ->get('https://app.shipos.co.il/api/shipping/get_express_delivery_status', [
        'license_key' => config('services.shipos.license_key'),
        'domain' => config('services.shipos.domain'),
        'city' => 'תל אביב',
        'street' => 'הרצל',
        'street_number' => '10',
    ])
    ->json();

logger()->info($body['success'] ? 'express available' : $body['message']);

תשובה לדוגמה ​

זכאית:

json
{
  "data": { "success": true, "message": "This area is eligible for Express Delivery" },
  "message": "This area is eligible for Express Delivery",
  "success": true,
  "warning": ""
}

אינה זכאית — HTTP 400:

json
{
  "data": { "success": false, "message": "This area is not eligible for Express Delivery" },
  "message": "This area is not eligible for Express Delivery",
  "success": false,
  "warning": ""
}

שגיאות ​

סטטוסמתי
400חברת השילוח של הרישיון אינה ZigZag (Not supported for this provider), הגדרת ה-enable_express_delivery של הרישיון כבויה, או שהכתובת נמצאת באזור מרוחק ולכן אינה זכאית.
403לא ניתן לפענח את הרישיון, הוא הושבת, או שהוא חברת פרימיום ללא משתמש עם פרימיום פעיל.
422ולידציית הפרמטרים נכשלה, או ש-license_key/domain חסר (זה מגיע מ-hasLicense). נגיש רק לאחר שבדיקת הספק עברה. בצורת {"message", "errors"} של Laravel, ולא במעטפת של v1.

המקבילה ב-v2 ​

אין. ל-API v2 אין נקודת קצה להצעת מחיר לאותו יום, ל-shipment promise או לזכאות אקספרס — המשטח שלו הוא משלוחים, אצוות, תוויות, הזמנות, מעקב, נקודות איסוף, רישיונות, נתוני עזר, webhooks והתראות. אם אתם צריכים את שירותי חברות השילוח האלה, אתם נשארים ב-v1 בשבילם.