אימות
ה-API של v1 מאמת באמצעות מפתח רישיון שנשלח בגוף הבקשה. אין כותרות פרטי גישה, אין החלפת token ואין session: כל קריאה לנקודת קצה shipping/* נושאת שדה license_key ושדה domain, וה-middleware מפענח אותם לרישיון (License) שהבקשה פועלת תחתיו.
כך זה לא עובד ב-v2
v2 מאמתת את החשבון באמצעות הכותרות X-Client-Id / X-Client-Secret ובוחרת את הרישיון בנפרד באמצעות פרמטר license_key. v1 ממזגת את השניים: מפתח הרישיון הוא פרטי הגישה. אם אתם בונים משהו חדש, השתמשו באימות של v2 במקום.
שדות חובה
שלחו את שני השדות בכל בקשה ל-shipping/*. בנקודות הקצה מסוג POST הם שייכים לגוף ה-JSON; בנקודות הקצה מסוג GET (same_day_delivery_quote, create_shipping_promise, get_express_delivery_enabled, get_express_delivery_status, user-by-license) הם נשלחים ב-query string.
| שדה | סוג | חובה | תיאור |
|---|---|---|---|
license_key | string | כן | ה-key של הרישיון. מזהה גם את הקורא וגם את חשבון חברת השילוח שהפעולה מתבצעת מולו. |
domain | string | כן | הדומיין של החנות הקוראת, למשל your-store.example.com. נדרש על ידי הוולידציה — ראו על domain למה שנבדק ומה שלא. |
token | string | לא | token אישי של Sanctum שמשתמש ShipOS שבבעלותו הרישיון. נבדק רק עבור רישיונות של חברות פרימיום (למטה). |
ה-license_key נוצר ב-ShipOS ומועתק להגדרות התוסף בחנות; אין נקודת קצה ב-v1 שמנפיקה אותו.
אל תשלחו שדה license
ה-middleware ממזג את מודל הרישיון שפוענח אל תוך הבקשה תחת המפתח license. כל ערך license שתשלחו נדרס, ולכן אי אפשר להשתמש בו כדי להשפיע על החשבון שהבקשה פועלת תחתיו — אבל גם אל תסתמכו על כך שהוא ישרוד.
מה נבדק
ה-middleware hasLicense רץ לפני הוולידציה של נקודת הקצה עצמה, בסדר הזה:
- ולידציה של גוף הבקשה —
license_keyו-domainחייבים שניהם להיות קיימים, מחרוזות שאינן ריקות. חוסר הוא שגיאת ולידציה422, לא403. - פענוח ה-token — אם קיים שדה
token, הוא נבדק כ-token אישי של Sanctum והבעלים שלו הופך למשתמש הפועל. בלי token, המשתמש הפועל הוא מי שה-session מאמת — ובעבור קורא API חיצוני, זה אף אחד.tokenשאינו מפוענח אינו שגיאה בפני עצמו; הוא פשוט משאיר את המשתמש הפועל כ-null. - חיפוש הרישיון — שורת הרישיון נמצאת לפי
key. מפתח לא מוכר → כשל. - בדיקת פעילות — הדגל
is_activeשל הרישיון חייב להיות true. רישיון שבוטל → כשל. - שער פרימיום — אם החברה של הרישיון מסומנת
is_premium, הבקשה דורשת בנוסף משתמש פועל (שלב 2) וגם שהחברות בפרימיום של אותו משתמש תהיה פעילה. חוסר באחד מהם → כשל.
בהצלחה הרישיון מוצמד לבקשה ונקודת הקצה ממשיכה תחתיו. כל מה שנקודת הקצה נוגעת בו לאחר מכן — הלקוח, החברה, ספק חברת השילוח וההגדרות שלו — נגזר מאותו רישיון, ולכן מפתח הרישיון לבדו קובע איזה חשבון של חברת שילוח מחויב.
אין בדיקת תוקף במסלול הזה: רישיון שתוקפו לא פג אך אינו פעיל נדחה בשלב 4, ותוקף מבוסס-זמן אינו נבדק כאן.
על domain
domain הוא שדה חובה, אבל הבדיקה שהשוותה אותו ל-domain המאוחסן של הרישיון מסומנת כהערה בקוד הנוכחי — הערך שלו נבדק לקיום ואז אינו בשימוש להרשאה. המשיכו לשלוח את הדומיין האמיתי של החנות (השדה נדרש, הוא נרשם ביומן הבקשות, והבדיקה עשויה לחזור), אבל אל תתייחסו לדומיין תואם כגבול אבטחה.
עמודת ה-domain של הרישיון עצמו מאוכלסת בפעם הראשונה שחנות קוראת ל-GET /api/license/activate_license, ורק אם היא עדיין ריקה.
תגובות כשל
כל כשל רישיון מוחזר על ידי ה-middleware כ-HTTP 403 במעטפת v1 הסטנדרטית, כאשר data הוא מערך ריק והסיבה נמצאת ב-message:
{
"data": [],
"message": "License key has been deactivated",
"success": false,
"warning": ""
}| תנאי | Status | message |
|---|---|---|
license_key או domain חסרים | 422 | גוף ולידציה של Laravel — ראו שגיאות |
אין רישיון עם ה-key הזה | 403 | Invalid License Key |
is_active של הרישיון הוא false | 403 | License key has been deactivated |
| חברת פרימיום, לא פוענח משתמש פועל | 403 | Premium companies are not supported in this version of plugin |
| חברת פרימיום, הפרימיום של המשתמש הפועל אינו פעיל | 403 | You must be a premium member to use this company |
שתי הערות על הסטטוסים:
- המקרה של מפתח לא מוכר מסווג פנימית כ-
404, אבל ה-middleware מחזיר403עבור כל כשלי הרישיון. אל תצפו ל-404כאן. - הודעות הפרימיום עוברות דרך תרגום, ולכן הן עשויות לחזור מתורגמות. הסתעפו לפי סטטוס ה-HTTP ו-
success, לעולם לא לפיmessage.
דוגמה מלאה
קריאת הפרטים המאוחסנים של משלוח לא דורשת דבר מלבד פרטי הגישה בתוספת קוד המעקב:
curl --location 'https://app.shipos.co.il/api/shipping/get_order_details' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"license_key": "{license_key}",
"domain": "your-store.example.com",
"shipping_id": "66747921"
}'// Node.js 18+ / דפדפנים — בלי תלויות
const response = await fetch('https://app.shipos.co.il/api/shipping/get_order_details', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({
license_key: process.env.SHIPOS_LICENSE_KEY,
domain: process.env.SHIPOS_DOMAIN,
shipping_id: '66747921',
}),
})
const body = await response.json()
if (response.status === 403) {
// הרישיון נדחה: מפתח לא מוכר, רישיון שבוטל, או שער פרימיום.
throw new Error(`ShipOS license rejected: ${body.message}`)
}
if (!response.ok || !body.success) {
throw new Error(`ShipOS v1: ${body.message}`)
}
console.log(body.data)<?php
use Illuminate\Support\Facades\Http;
$response = Http::acceptJson()
->post('https://app.shipos.co.il/api/shipping/get_order_details', [
'license_key' => config('services.shipos.license_key'),
'domain' => config('services.shipos.domain'),
'shipping_id' => '66747921',
]);
$body = $response->json();
if ($response->forbidden()) {
throw new RuntimeException('ShipOS license rejected: '.$body['message']);
}
if (! ($body['success'] ?? false)) {
throw new RuntimeException('ShipOS v1: '.$body['message']);
}
logger()->info('Shipment details', $body['data']);רישיון שמפוענח בהצלחה אומר שהשלב הבא הוא חיפוש המשלוח עצמו: v1 מצמצמת כל שאילתת משלוח לרישיון הקורא, ולכן קוד מעקב ששייך לחשבון אחר מתנהג בדיוק כמו קוד שאינו קיים.
ריבוי רישיונות
אין ב-v1 תצוגה ברמת החשבון. בקשה אחת פועלת תחת רישיון אחד בדיוק, שנבחר לפי ה-license_key שאתם שולחים, ולקוח שמחזיק כמה רישיונות של חברות שילוח בוחר את חברת השילוח על ידי בחירת המפתח. שום דבר ב-v1 אינו מציג את המפתחות שבבעלות חשבון.
קוראים פנימיים (First-party)
ה-middleware מזהה גם שדה secret השווה למפתח האפליקציה, שמדלג על ולידציית הדומיין ועל בדיקות הרישיון שלמעלה וטוען את הרישיון לפי המפתח ישירות. המסלול הזה קיים עבור השירותים הפנימיים של ShipOS עצמה; הוא אינו זמין לאינטגרטורים ומתועד כאן רק כדי שנוכחותו ביומני הבקשות לא תיתפס בטעות כדרך פנימה.