Shipnest

חיפוש בתיעוד

חפשו לפי נושא, endpoint, או מונח

API Reference

API ציבורי של Shipnest

REST API לפי scopes, פורמט תשובה אחיד, ו-Outbound Webhooks חתומים ב-HMAC. כל הדוגמאות כאן הן curl — אפשר להשתמש בכל שפה / כלי שמדבר HTTP.

Updated: 17 ביוני 2026

התחלה

Base URL#

ה-Base URL של ה-API שלכם הוא הדומיין של פורטל הלקוחות שלכם (אותו דומיין שעליו רץ ה-Tenant). למשל:

http
https://app.shipnest.example

את ה-Base URL המדויק שלכם תמצאו בכרטיס הגדרות → API ו-Webhooks בפורטל. כל הנתיבים כאן יחסיים ל-Base URL הזה.

זמנים, מטבע, ושיטת הקידוד

תאריכים ב-payloads נכתבים תמיד ב-ISO 8601 עם Z בסוף (UTC), גם אם המערכת מציגה ללקוח בשעון ישראל. סכומי כסף ב-API נשלחים בשקלים (decimal) — המערכת ממירה אגורות (integer) פנימית, כך שלא צריך לדאוג לכך מצדכם.
אבטחה

אימות#

כל בקשה ל-/api/v1/* חייבת לכלול שני headers:

http
Authorization: Bearer ship_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
X-Timestamp: 1714838400
  • Authorization — מפתח API בפורמט ship_live_…. מפתחות נוצרים ומבוטלים ב-self-service מתוך הפורטל, באותו דפוס של Stripe / GitHub / Vercel.
  • X-Timestamp — Unix time (שניות או מילישניות) של רגע הבקשה. הסטייה המותרת מול שעון השרת היא ±5 דקות. ההגבלה מצמצמת את חלון התקיפות מסוג Replay.

מחזור חיים של טוקן#

  1. יצירה ב-/portal/settings/api — בוחרים שם, רשימת scopes, ותאריך תפוגה אופציונלי (ללא תפוגה / 30 / 90 / 365 ימים).
  2. הטוקן הגולמי מוצג פעם אחת בלבד בדיאלוג אחרי היצירה. שומרים אותו מיד ב-secret manager (1Password, AWS Secrets Manager, Vercel env, וכו'). המערכת שומרת רק SHA-256 hash — לא נוכל לשחזר.
  3. אם הטוקן אבד או דלף — מבטלים אותו בקליק ויוצרים חדש. הביטול תקף מיידית. כל בקשה עם טוקן מבוטל מקבלת 401 Unauthorized.

הטוקן מוצג פעם אחת בלבד

זה לא baggy — זה דרישה של SOC 2 / ISO 27001. דליפת DB לא חושפת מפתחות חיים, ו-session hijack לא מקבל את הטוקן "תמיד גלוי" בממשק. במקום זה — ביטול-ויצירה-מחדש בקליק.

מגבלות חשבון#

  • עד 10 מפתחות פעילים בו-זמנית לכל Tenant.
  • מפתחות שפג תוקפם או בוטלו לא נמחקים — הם נשמרים ל-audit (מי יצר, מתי, מי ביטל), אבל לא נספרים במכסה.
  • פעולות יצירה/ביטול נכתבות ב-audit log של ה-Tenant ומופיעות בכרטיס "המפתחות שלי" עם זמני שימוש אחרון.
הרשאות

Scopes#

לכל מפתח מצורפת רשימה סגורה של scopes — מינימום ההרשאות שהוא צריך. בקשה ל-endpoint שדורש scope שאינו במפתח נדחית ב-403 Forbidden.

Scopes זמינים
shipments:readקריאת משלוחים, פרטי משלוח בודד, היסטוריית visits.
shipments:writeיצירה ועדכון של משלוחים, וביטול דרך POST /shipments/[barcode]/cancel.
customers:readקריאת רשימת לקוחות ופרטי לקוח בודד.
customers:writeיצירה ועדכון של לקוחות.
webhooks:manageניהול subscriptions של webhooks — יצירה, עדכון, מחיקה, ושליחת test event.

עקרון הרשאה מינימלית

תנו לכל מפתח רק את ה-scopes שהוא באמת צריך. למשל — סקריפט שמייצא משלוחים לדוח חודשי צריך רק shipments:read. כך, אם המפתח דלף, ההיקף הנזק מוגבל.
פורמט תשובה

Response Envelope#

כל תשובה — הצלחה או כישלון — עוטפת את התוכן באובייקט אחיד:

json
// הצלחה
{
  "success": true,
  "data": { ... },
  "meta": { "count": 25, "nextCursor": "shp_5f3a...", "hasMore": true }
}

// שגיאה
{
  "success": false,
  "error": "Missing required scope: shipments:write"
}
  • data מכיל את התוכן — אובייקט בודד, או מערך בעמודי list. בקריאה ל-endpoint יחיד, יהיה אובייקט; בקריאה ל-list, יהיה מערך.
  • meta מופיע רק בקריאות list ומכיל את count (מספר הפריטים בעמוד הנוכחי), nextCursor (cursor לעמוד הבא) ו-hasMore. hasMore: false או nextCursor ריק = הגעתם לסוף.
  • error בקבועי שגיאה תמיד מחרוזת אחת מובנת. אין רמות (warning / info) — מה שלא success: true זה כישלון.

Rate limiting#

כל endpoint מוגבל ל-60 בקשות לדקה לכל מפתח, לכל נתיב. כשהמכסה מוצתה — 429 Too Many Requests עם headers שמסבירים מתי לנסות שוב:

http
HTTP/1.1 429 Too Many Requests
Retry-After: 17
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1714838460
  • Retry-After — מספר שניות עד שהחלון מתאפס. כבדו אותו, אל תעשו spam.
  • צריכים קצב גבוה יותר? פנו אלינו ונגדיל מכסה ספציפית למפתח.

קודי HTTP#

קודי תשובה נפוצים
200 / 201הצלחה. 201 נשלח אחרי POST שיצר משאב חדש.
400קלט לא תקין — ולידציה נכשלה. השדה הספציפי בדרך כלל מצוין ב-error.
401חסר / לא תקף Bearer token, או X-Timestamp מחוץ לחלון הסטייה.
403המפתח קיים ותקף, אבל לא כולל את ה-scope הנדרש ל-endpoint.
404המשאב לא נמצא ב-Tenant הזה. שימו לב — לא חושפים אם המשאב קיים ב-Tenant אחר.
409קונפליקט — למשל ניסיון ליצור משלוח עם barcode שכבר קיים.
429חריגה ממכסת הבקשות. ראו Retry-After.
500תקלת שרת אצלנו. אם זה חוזר — צרו קשר עם הפרטים מה-response.

כל ה-endpoints נמצאים תחת /api/v1/. הכותרת של כל endpoint מציינת את ה-scope הנדרש.

משלוחים (Shipments)#

GET/api/v1/shipmentsshipments:read

רשימת משלוחים, ממויינת מהחדש לישן. פגינציה דרך cursor.

Query parameters
limit
number
מספר תוצאות. ברירת מחדל 50, מקסימום 100.
cursor
string
id של המשלוח האחרון בעמוד הקודם (מתוך meta.nextCursor).
status
string
סינון לפי sendStatus: PENDING / SUCCESS / FAILURE.
createdFrom
ISO date
סינון תחתון לפי createdAt.
createdTo
ISO date
סינון עליון לפי createdAt.
bash
curl 'https://app.shipnest.example/api/v1/shipments?limit=20&status=SUCCESS' \
  -H 'Authorization: Bearer ship_live_…' \
  -H 'X-Timestamp: 1714838400'
GET/api/v1/shipments/{barcode}shipments:read

פרטי משלוח יחיד לפי ברקוד, כולל עד 20 ה-visits האחרונים שלו.

bash
curl 'https://app.shipnest.example/api/v1/shipments/ABC-1001' \
  -H 'Authorization: Bearer ship_live_…' \
  -H 'X-Timestamp: 1714838400'
POST/api/v1/shipmentsshipments:write

יצירת משלוח חדש במערכת המקומית בלבד — המשלוח לא יישלח אוטומטית ל-Lionwheel. עבור Tenants מסונכרנים מול Lionwheel, יש ליצור את המשלוח דרך API של Lionwheel וה-webhook יביא אותו אלינו.

שדות חובה
barcode
string
חובה
ייחודי גלובלית לכל Tenant.
phone
string
חובה
מספר טלפון של הנמען (פורמט בינלאומי או ישראלי).
customerName
string
חובה
שם הנמען.
sourceName
string
חובה
שם השולח (העסק שלכם).
destinationCity
string
חובה
עיר היעד.
destinationStreet
string
חובה
רחוב היעד.
destinationNumber
string
חובה
מספר בית.
שדות אופציונליים
destinationFloor / destinationApartment / destinationNotes / destinationEmailפרטי מסירה נוספים. destinationNotes נראית לשליח.
sourceCity / sourceStreet / sourceNumber / sourcePhoneכתובת איסוף — אם משלוח לאיסוף ולא ממחסן ברירת המחדל.
message
string
ההודעה שתישלח אוטומטית ללקוח (אם הוגדרה תבנית).
packages
number
מספר חבילות (ברירת מחדל 1).
price
number
ערך הגוביינא בשקלים. 0 או חסר = ללא COD.
weight
number
משקל בק"ג.
urgency
string
REGULAR / EXPRESS / URGENT.
leaveNextToDoor
boolean
להשאיר ליד הדלת אם הלקוח לא ענה.
shipmentNote / orgNoteהערות פנימיות (לא נשלחות ללקוח).
customerId / externalOrderIdקישור ללקוח קיים, או ID של ההזמנה במערכת המקור.
regionCodeקוד אזור (לסיווג ידני / דוחות).

ברירות מחדל בעת יצירה: sendStatus = "PENDING", sourceProvider = "api".
תגובה: 201 עם המשלוח שנוצר; 409 אם הברקוד כבר קיים ב-Tenant.

bash
curl -X POST 'https://app.shipnest.example/api/v1/shipments' \
  -H 'Authorization: Bearer ship_live_…' \
  -H 'X-Timestamp: 1714838400' \
  -H 'Content-Type: application/json' \
  -d '{
    "barcode": "ABC-1001",
    "phone": "+972501234567",
    "customerName": "ישראל ישראלי",
    "sourceName": "החנות שלי",
    "destinationCity": "תל אביב",
    "destinationStreet": "אבן גבירול",
    "destinationNumber": "10",
    "packages": 2,
    "price": 35,
    "urgency": "REGULAR"
  }'
PATCH/api/v1/shipments/{barcode}shipments:write

עדכון שדות של משלוח קיים. שדות שלא נשלחו יישארו ללא שינוי. שדות פנימיים (id, tenantId, barcode, נתוני AI, ערכים שמגיעים מ-Lionwheel) אינם ניתנים לעדכון דרך ה-API.

שדות נתמכים
phone / customerName / sourceNameפרטי שולח/נמען.
destinationCity / destinationStreet / destinationNumber / destinationFloor / destinationApartment / destinationNotes / destinationEmailכתובת ופרטי מסירה.
sourceCity / sourceStreet / sourceNumber / sourcePhoneכתובת איסוף.
message / packages / price / weight / urgency / leaveNextToDoorפרטי המשלוח.
shipmentNote / orgNote / customerId / externalOrderIdהערות וקישורים.
sendStatus / errorMessageסטטוס שליחה (יישומים שמנהלים שליחה מבחוץ).
bash
curl -X PATCH 'https://app.shipnest.example/api/v1/shipments/ABC-1001' \
  -H 'Authorization: Bearer ship_live_…' \
  -H 'X-Timestamp: 1714838400' \
  -H 'Content-Type: application/json' \
  -d '{ "destinationNotes": "פעמון 3", "urgency": "EXPRESS" }'
POST/api/v1/shipments/{barcode}/cancelshipments:write

ביטול משלוח. אצל משלוחים מסונכרנים מ-Lionwheel — הביטול נשלח גם לשם. הביטול מעדכן את הסטטוס ל-CANCELLED ופולט אירוע shipment.status_changed.

Body (אופציונלי)
reason
string
סיבת הביטול — נשמרת ב-audit ונשלחת ל-webhook.
bash
curl -X POST 'https://app.shipnest.example/api/v1/shipments/ABC-1001/cancel' \
  -H 'Authorization: Bearer ship_live_…' \
  -H 'X-Timestamp: 1714838400' \
  -H 'Content-Type: application/json' \
  -d '{ "reason": "הלקוח ביטל את ההזמנה" }'

לקוחות (Customers)#

GET/api/v1/customerscustomers:read

רשימת לקוחות, פגינציה לפי cursor.

Query parameters
limit
number
ברירת מחדל 100, מקסימום 200.
cursor
string
id של הלקוח האחרון בעמוד הקודם.
isActive
boolean
סינון לפי סטטוס פעיל.
search
string
חיפוש חופשי לפי שם, טלפון או דוא"ל.
GET/api/v1/customers/{id}customers:read

פרטי לקוח יחיד. id הוא ה-id הפנימי של Shipnest (נוצר ביצירה).

POST/api/v1/customerscustomers:write

יצירת לקוח חדש.

שדות
name
string
חובה
שם הלקוח (חברה / אדם).
email
string
דוא"ל לקשר.
phone
string
טלפון לקשר.
address
string
כתובת חופשית.
isActive
boolean
ברירת מחדל true.
bash
curl -X POST 'https://app.shipnest.example/api/v1/customers' \
  -H 'Authorization: Bearer ship_live_…' \
  -H 'X-Timestamp: 1714838400' \
  -H 'Content-Type: application/json' \
  -d '{ "name": "חברה לדוגמה בעמ", "phone": "03-1234567" }'
PATCH/api/v1/customers/{id}customers:write

עדכון לקוח קיים. שדות שלא נשלחו יישארו ללא שינוי.

ניהול subscriptions של Webhooks#

ה-endpoints כאן מנהלים את ה-subscriptions של ה-webhooks — היכן Shipnest שולח אירועים. הם לא ה-webhooks עצמם (אלו נשלחים מ-Shipnest אליכם, ראו סעיף Webhooks).

GET/api/v1/webhookswebhooks:manage

רשימת כל ה-subscriptions של ה-Tenant.

POST/api/v1/webhookswebhooks:manage

יצירת subscription חדש.

שדות
url
string
חובה
ה-URL שאליו נשלח את ה-payloads. חייב להיות HTTPS בפרודקשן.
events
string[]
חובה
רשימת אירועים — ראו קטלוג האירועים. אפשר ["*"] לקבל הכל.
description
string
תיאור חופשי לזיהוי ב-UI.
isActive
boolean
ברירת מחדל true.

התגובה כוללת secret שנוצר ביצירה — שמרו אותו, הוא הסוד שמשמש לחתימת ה-HMAC. הוא מוצג פעם אחת בלבד.

GET/api/v1/webhooks/{id}webhooks:manage

פרטי subscription יחיד (ללא ה-secret).

PATCH/api/v1/webhooks/{id}webhooks:manage

עדכון של subscription — שינוי URL, רשימת events, או הפעלה/השבתה.

DELETE/api/v1/webhooks/{id}webhooks:manage

מחיקת subscription. הפעולה idempotent — מחיקה של ID שכבר נמחק מחזירה 200.

POST/api/v1/webhooks/{id}/testwebhooks:manage

שליחת אירוע test ל-subscription. שימושי כדי לוודא שה-URL שלכם מקבל בקשות, מאמת חתימות נכון, ומחזיר 2xx בזמן.

אירועים יוצאים

Outbound Webhooks#

Shipnest שולחת POST ל-URLs שהגדרתם כשמתרחש אירוע מתאים. ה-payload חתום ב-HMAC-SHA256 כדי שתוכלו לוודא שהבקשה הגיעה מאיתנו.

קטלוג האירועים#

אירועים נתמכים
shipment.createdמשלוח חדש נכנס למערכת (UI / API / Lionwheel webhook).
shipment.status_changedסטטוס המשלוח השתנה. כולל ביטול דרך POST /shipments/[barcode]/cancel.
shipment.assignedמשלוח שויך לשליח. ה-payload כולל action: "assigned" (שיוך ראשון) או "transferred" (העברה משליח לשליח).
shipment.deliveredהמשלוח נמסר (סטטוס COMPLETED או ROUNDTRIP_DELIVERED). נפלט גם מאפליקציית הנהג וגם מ-Lionwheel webhook.
shipment.failedשליח סימן את הביקור ככשל. ה-payload כולל reasonCode (no_answer / wrong_address / refused / closed / other) ו-reason טקסטואלי.
visit.completedביקור הושלם (נמסר בהצלחה). מקביל ל-shipment.delivered אבל ברמת ה-Visit.
cod.collectedגוביינא נגבתה לראשונה (מעבר מ-PENDING לסטטוס שאינו PENDING).
customer.createdלקוח חדש נוצר (דרך API ציבורי או UI ניהול).

Headers בכל delivery#

http
Content-Type: application/json
User-Agent: Shipnest-Webhooks/1.0
X-Webhook-Event: shipment.created
X-Webhook-Delivery-Id: a1b2c3d4e5f6...
X-Webhook-Signature: t=1714838400,v1=hex-digest...
X-Webhook-Timestamp: 1714838400

מבנה ה-payload#

json
{
  "event": "shipment.created",
  "tenantId": "shipping-001",
  "occurredAt": "2026-05-04T12:00:00.000Z",
  "data": {
    "shipmentId": 42,
    "barcode": "ABC-1001",
    "customerName": "חברה לדוגמה",
    "phone": "+972501234567",
    "destinationCity": "תל אביב",
    "destinationStreet": "אבן גבירול",
    "status": "UNASSIGNED"
  }
}

אימות חתימה#

ה-signature הוא בפורמט t=<unix>,v1=<hex>. לאימות, חשבו מחדש HMAC-SHA256 על המחרוזת `${t}.${rawBody}` והשוו ב-constant-time (כדי למנוע timing attacks).

ts
import crypto from "crypto";

export function verify(rawBody: string, headerSig: string, secret: string): boolean {
  const parts = Object.fromEntries(
    headerSig.split(",").map((p) => p.split("="))
  );
  const t = parts.t;
  const sent = Buffer.from(parts.v1, "hex");
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${t}.${rawBody}`)
    .digest();

  if (sent.length !== expected.length) return false;
  return crypto.timingSafeEqual(sent, expected);
}

מאמתים על ה-raw body

חתימת ה-HMAC מחושבת על ה-body כמחרוזת raw, לא על אובייקט JSON מפוענח. אם ה-framework שלכם (Express, Hono, Next.js route handler) מפענח JSON אוטומטית — קראו את ה-body כ-string לפני, או אחרת תקבלו חתימה לא תואמת.

ניסיונות חוזרים#

תגובה עם status ב-2xx נחשבת להצלחה. כל תגובה אחרת או timeout (10 שניות) נחשבים לכישלון ומפעילים backoff מעריכי:

  • ניסיון 1 → 1 דקה
  • ניסיון 2 → 5 דקות
  • ניסיון 3 → 30 דקות
  • ניסיון 4 → שעתיים
  • ניסיון 5 → 12 שעות

לאחר 6 כישלונות סך הכל, ה-delivery יסומן exhausted ולא יישלח שוב. לוג המסירות זמין בלוח הבקרה של ה-Tenant.

Idempotency חובה

ייתכן ואותו אירוע יישלח יותר מפעם אחת (retry שהצליח מצד שני אבל לא הצלחנו לרשום זאת). השתמשו ב-X-Webhook-Delivery-Id כ-key למניעת עיבוד כפול. לעולם אל תזהו אירוע ייחודי לפי occurredAt או תוכן ה-payload בלבד.
שיטות עבודה

המלצות#

ניהול secrets#

  • שמרו את הטוקן (ship_live_…) וה-webhook secret ב-secret manager. לעולם אל תכניסו ב-Git.
  • מפתח לכל סקריפט / שירות — לא לחלוק. אם דליפה תקרה, ביטול נקודתי לא יפיל את כל החיבורים שלכם.
  • סבבו (rotate) טוקנים פעם בשנה לפחות. צרו חדש → בדקו → בטלו את הישן.

Polling או Webhooks?#

  • Webhooks — עדיפים. תגובה בזמן אמת, ללא עומס מיותר. השקיעו ב-idempotency וב-queue אצלכם.
  • Polling — רלוונטי רק לסנכרון חוזר של מצב מלא (למשל דוח יומי). אל תעשו polling כדי "לדעת אם משהו השתנה" — זה לא יעיל ולא יציב.

טיפול בשגיאות#

  • 5xx ו-429 — תמיד retry עם exponential backoff (בערך כמו ה-backoff של ה-webhooks שלנו).
  • 4xx (חוץ מ-429) — לא לחזור על אותה בקשה. אלו שגיאות לוגיות (ולידציה, scope חסר, משאב לא קיים). תקנו את הקלט.
  • תיעדו כל בקשה שנכשלה ב-X-Webhook-Delivery-Id / response body שלנו — זה מאפשר תמיכה לסייע במהירות.
כלים נלווים

כלים#

  • /openapi.yaml — ספק OpenAPI 3.1 סטטי לייבוא ב-Postman / Insomnia / n8n / Make.
  • /portal/settings/api — ניהול מפתחות, רשימת endpoints מותאמת ל-Base URL שלכם, ופרומפט AI מוכן ל-Claude / ChatGPT / Cursor.
  • /docs/changelog — שינויים אחרונים, כולל הרחבות של קטלוג ה-events ושינויי scopes.