Skip to content

יצירת המשלוח הראשון שלכם

המדריך הזה מוביל אתכם מסט חדש של פרטי גישה ל-API ועד משלוח שנוצר, עם תווית מוכנה להדפסה ומעקב חי. הוא עובר מקצה לקצה על ארבעת ה-endpoints המרכזיים — חשבון, רישיונות, משלוחים ומעקב.

לפני שמתחילים

תצטרכו את פרטי הלקוח (client credentials) של ה-API — צמד client_id ו-client_secret. כל בקשה מאומתת שולחת אותם ככותרות (headers):

X-Client-Id: {client_id}
X-Client-Secret: {client_secret}
Accept: application/json

בקשות עם גוף (body) שולחות גם Content-Type: application/json. כל הדוגמאות משתמשות בכתובת הבסיס https://app.shipos.co.il/api/v2. לפרטים ראו את מדריך האימות.

שלב 1 — אימות פרטי הגישה

קראו ל-GET /account. הקריאה מחזירה את חשבון הסוחר שמאחורי פרטי הגישה שלכם, עם כל חשבונות המובילים (הרישיונות) מוטמעים בתשובה — תגובה מוצלחת מוכיחה שהכותרות שלכם תקינות.

bash
curl --location 'https://app.shipos.co.il/api/v2/account' \
--header 'X-Client-Id: {client_id}' \
--header 'X-Client-Secret: {client_secret}' \
--header 'Accept: application/json'
js
// Node.js 18+ / דפדפנים — ללא תלויות
const response = await fetch('https://app.shipos.co.il/api/v2/account', {
  headers: {
    'X-Client-Id': process.env.SHIPOS_CLIENT_ID,
    'X-Client-Secret': process.env.SHIPOS_CLIENT_SECRET,
    Accept: 'application/json',
  },
})

if (!response.ok) {
  const { error } = await response.json()
  throw new Error(`${error.code}: ${error.message}`)
}

const { data: account } = await response.json()

console.log(account.company_name, '—', account.licenses.length, 'license(s)')
php
<?php
// composer require guzzlehttp/guzzle

$client = new \GuzzleHttp\Client([
    'base_uri' => 'https://app.shipos.co.il/api/v2/',
    'headers' => [
        'X-Client-Id' => getenv('SHIPOS_CLIENT_ID'),
        'X-Client-Secret' => getenv('SHIPOS_CLIENT_SECRET'),
        'Accept' => 'application/json',
    ],
]);

$account = json_decode(
    $client->get('account')->getBody()->getContents(),
    true,
)['data'];

echo $account['company_name'], ' — ', count($account['licenses']), ' license(s)', PHP_EOL;
php
<?php

use Illuminate\Support\Facades\Http;

$account = Http::withHeaders([
    'X-Client-Id' => config('services.shipos.client_id'),
    'X-Client-Secret' => config('services.shipos.client_secret'),
])
    ->acceptJson()
    ->get('https://app.shipos.co.il/api/v2/account')
    ->throw()
    ->json('data');

logger()->info($account['company_name'], ['licenses' => count($account['licenses'])]);
python
# pip install httpx
import os

import httpx

response = httpx.get(
    "https://app.shipos.co.il/api/v2/account",
    headers={
        "X-Client-Id": os.environ["SHIPOS_CLIENT_ID"],
        "X-Client-Secret": os.environ["SHIPOS_CLIENT_SECRET"],
        "Accept": "application/json",
    },
)
response.raise_for_status()
account = response.json()["data"]

print(account["company_name"], "—", len(account["licenses"]), "license(s)")
go
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
)

type accountResponse struct {
	Data struct {
		CompanyName string            `json:"company_name"`
		Licenses    []json.RawMessage `json:"licenses"`
	} `json:"data"`
}

func main() {
	req, _ := http.NewRequest("GET", "https://app.shipos.co.il/api/v2/account", nil)
	req.Header.Set("X-Client-Id", os.Getenv("SHIPOS_CLIENT_ID"))
	req.Header.Set("X-Client-Secret", os.Getenv("SHIPOS_CLIENT_SECRET"))
	req.Header.Set("Accept", "application/json")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	var account accountResponse
	if err := json.NewDecoder(res.Body).Decode(&account); err != nil {
		panic(err)
	}

	fmt.Println(account.Data.CompanyName, "—", len(account.Data.Licenses), "license(s)")
}
java
// Java 17+ — java.net.http, ללא תלויות (פענוח עם Jackson/Gson)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class VerifyCredentials {
    public static void main(String[] args) throws Exception {
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://app.shipos.co.il/api/v2/account"))
            .header("X-Client-Id", System.getenv("SHIPOS_CLIENT_ID"))
            .header("X-Client-Secret", System.getenv("SHIPOS_CLIENT_SECRET"))
            .header("Accept", "application/json")
            .build();

        HttpResponse<String> response = HttpClient.newHttpClient()
            .send(request, HttpResponse.BodyHandlers.ofString());

        if (response.statusCode() != 200) {
            throw new RuntimeException("ShipOS error: " + response.body());
        }

        System.out.println(response.body()); // {"data":{...}} — מפו עם Jackson/Gson
    }
}
csharp
// .NET 8+ — System.Net.Http.Json
using System.Net.Http.Json;
using System.Text.Json;

using var http = new HttpClient
{
    BaseAddress = new Uri("https://app.shipos.co.il/api/v2/"),
};
http.DefaultRequestHeaders.Add("X-Client-Id",
    Environment.GetEnvironmentVariable("SHIPOS_CLIENT_ID"));
http.DefaultRequestHeaders.Add("X-Client-Secret",
    Environment.GetEnvironmentVariable("SHIPOS_CLIENT_SECRET"));

var payload = await http.GetFromJsonAsync<JsonDocument>("account")
    ?? throw new InvalidOperationException("Empty response");
var account = payload.RootElement.GetProperty("data");

Console.WriteLine($"{account.GetProperty("company_name").GetString()} — " +
    $"{account.GetProperty("licenses").GetArrayLength()} license(s)");
ruby
require "net/http"
require "json"

uri = URI("https://app.shipos.co.il/api/v2/account")
request = Net::HTTP::Get.new(uri)
request["X-Client-Id"] = ENV.fetch("SHIPOS_CLIENT_ID")
request["X-Client-Secret"] = ENV.fetch("SHIPOS_CLIENT_SECRET")
request["Accept"] = "application/json"

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end

raise "ShipOS error: #{response.body}" unless response.is_a?(Net::HTTPSuccess)

account = JSON.parse(response.body).fetch("data")

puts "#{account["company_name"]}#{account["licenses"].size} license(s)"
rust
// [dependencies]
// reqwest = { version = "0.12", features = ["json"] }
// tokio = { version = "1", features = ["full"] }
// serde_json = "1"
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let payload: Value = reqwest::Client::new()
        .get("https://app.shipos.co.il/api/v2/account")
        .header("X-Client-Id", std::env::var("SHIPOS_CLIENT_ID")?)
        .header("X-Client-Secret", std::env::var("SHIPOS_CLIENT_SECRET")?)
        .header("Accept", "application/json")
        .send()
        .await?
        .error_for_status()?
        .json()
        .await?;

    let account = &payload["data"];
    let licenses = account["licenses"].as_array().map_or(0, Vec::len);
    println!("{} — {} license(s)", account["company_name"], licenses);
    Ok(())
}

תגובת 200 חוזרת עם מעטפת { "data": ... } הסטנדרטית:

json
{
  "data": {
    "id": 1042,
    "name": "ישראל ישראלי",
    "email": "israel@example.co.il",
    "phone": "0521234567",
    "locale": "he",
    "company_name": "אופנת הרצל בע״מ",
    "enable_api": 1,
    "can_use_collection_points": true,
    "label_method": "A4",
    "label_type": null,
    "licenses": [ ... ]
  }
}

אם קיבלתם 401 במקום — פרטי הגישה שגויים או חסרים; ראו שגיאות.

שלב 2 — איתור ה-license_key שלכם

כל משלוח נוצר תחת רישיון אחד (חשבון מוביל). endpoints של כתיבה בוחרים אותו באמצעות השדה license_key בגוף הבקשה; endpoints מסוג GET משתמשים בפרמטר שאילתה license_key. הערך הוא השדה key שמוחזר מ-GET /licenses:

bash
curl --location 'https://app.shipos.co.il/api/v2/licenses' \
--header 'X-Client-Id: {client_id}' \
--header 'X-Client-Secret: {client_secret}' \
--header 'Accept: application/json'
js
// Node.js 18+ / דפדפנים — ללא תלויות
const response = await fetch('https://app.shipos.co.il/api/v2/licenses', {
  headers: {
    'X-Client-Id': process.env.SHIPOS_CLIENT_ID,
    'X-Client-Secret': process.env.SHIPOS_CLIENT_SECRET,
    Accept: 'application/json',
  },
})

if (!response.ok) {
  const { error } = await response.json()
  throw new Error(`${error.code}: ${error.message}`)
}

const { data: licenses } = await response.json()

for (const license of licenses) {
  console.log(license.key, '→', license.company.carrier.name, license.is_active)
}
php
<?php
// composer require guzzlehttp/guzzle

$client = new \GuzzleHttp\Client([
    'base_uri' => 'https://app.shipos.co.il/api/v2/',
    'headers' => [
        'X-Client-Id' => getenv('SHIPOS_CLIENT_ID'),
        'X-Client-Secret' => getenv('SHIPOS_CLIENT_SECRET'),
        'Accept' => 'application/json',
    ],
]);

$licenses = json_decode(
    $client->get('licenses')->getBody()->getContents(),
    true,
)['data'];

foreach ($licenses as $license) {
    echo $license['key'], ' → ', $license['company']['carrier']['name'], PHP_EOL;
}
php
<?php

use Illuminate\Support\Facades\Http;

$licenses = Http::withHeaders([
    'X-Client-Id' => config('services.shipos.client_id'),
    'X-Client-Secret' => config('services.shipos.client_secret'),
])
    ->acceptJson()
    ->get('https://app.shipos.co.il/api/v2/licenses')
    ->throw()
    ->json('data');

foreach ($licenses as $license) {
    logger()->info($license['key'].' → '.$license['company']['carrier']['name']);
}
python
# pip install httpx
import os

import httpx

response = httpx.get(
    "https://app.shipos.co.il/api/v2/licenses",
    headers={
        "X-Client-Id": os.environ["SHIPOS_CLIENT_ID"],
        "X-Client-Secret": os.environ["SHIPOS_CLIENT_SECRET"],
        "Accept": "application/json",
    },
)
response.raise_for_status()

for lic in response.json()["data"]:
    print(lic["key"], "→", lic["company"]["carrier"]["name"], lic["is_active"])
go
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
)

type licensesResponse struct {
	Data []struct {
		Key      string `json:"key"`
		IsActive bool   `json:"is_active"`
		Company  struct {
			Carrier struct {
				Name string `json:"name"`
			} `json:"carrier"`
		} `json:"company"`
	} `json:"data"`
}

func main() {
	req, _ := http.NewRequest("GET", "https://app.shipos.co.il/api/v2/licenses", nil)
	req.Header.Set("X-Client-Id", os.Getenv("SHIPOS_CLIENT_ID"))
	req.Header.Set("X-Client-Secret", os.Getenv("SHIPOS_CLIENT_SECRET"))
	req.Header.Set("Accept", "application/json")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	var payload licensesResponse
	if err := json.NewDecoder(res.Body).Decode(&payload); err != nil {
		panic(err)
	}

	for _, license := range payload.Data {
		fmt.Println(license.Key, "→", license.Company.Carrier.Name, license.IsActive)
	}
}
java
// Java 17+ — java.net.http, ללא תלויות (פענוח עם Jackson/Gson)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class ListLicenses {
    public static void main(String[] args) throws Exception {
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://app.shipos.co.il/api/v2/licenses"))
            .header("X-Client-Id", System.getenv("SHIPOS_CLIENT_ID"))
            .header("X-Client-Secret", System.getenv("SHIPOS_CLIENT_SECRET"))
            .header("Accept", "application/json")
            .build();

        HttpResponse<String> response = HttpClient.newHttpClient()
            .send(request, HttpResponse.BodyHandlers.ofString());

        if (response.statusCode() != 200) {
            throw new RuntimeException("ShipOS error: " + response.body());
        }

        System.out.println(response.body()); // {"data":[{"key":"a1b2c3d4e5f6",...}]}
    }
}
csharp
// .NET 8+ — System.Net.Http.Json
using System.Net.Http.Json;
using System.Text.Json;

using var http = new HttpClient
{
    BaseAddress = new Uri("https://app.shipos.co.il/api/v2/"),
};
http.DefaultRequestHeaders.Add("X-Client-Id",
    Environment.GetEnvironmentVariable("SHIPOS_CLIENT_ID"));
http.DefaultRequestHeaders.Add("X-Client-Secret",
    Environment.GetEnvironmentVariable("SHIPOS_CLIENT_SECRET"));

var payload = await http.GetFromJsonAsync<JsonDocument>("licenses")
    ?? throw new InvalidOperationException("Empty response");

foreach (var license in payload.RootElement.GetProperty("data").EnumerateArray())
{
    var carrier = license.GetProperty("company").GetProperty("carrier");
    Console.WriteLine(
        $"{license.GetProperty("key").GetString()} → {carrier.GetProperty("name").GetString()}");
}
ruby
require "net/http"
require "json"

uri = URI("https://app.shipos.co.il/api/v2/licenses")
request = Net::HTTP::Get.new(uri)
request["X-Client-Id"] = ENV.fetch("SHIPOS_CLIENT_ID")
request["X-Client-Secret"] = ENV.fetch("SHIPOS_CLIENT_SECRET")
request["Accept"] = "application/json"

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end

raise "ShipOS error: #{response.body}" unless response.is_a?(Net::HTTPSuccess)

JSON.parse(response.body).fetch("data").each do |license|
  puts "#{license["key"]}#{license.dig("company", "carrier", "name")}"
end
rust
// [dependencies]
// reqwest = { version = "0.12", features = ["json"] }
// tokio = { version = "1", features = ["full"] }
// serde_json = "1"
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let payload: Value = reqwest::Client::new()
        .get("https://app.shipos.co.il/api/v2/licenses")
        .header("X-Client-Id", std::env::var("SHIPOS_CLIENT_ID")?)
        .header("X-Client-Secret", std::env::var("SHIPOS_CLIENT_SECRET")?)
        .header("Accept", "application/json")
        .send()
        .await?
        .error_for_status()?
        .json()
        .await?;

    if let Some(licenses) = payload["data"].as_array() {
        for license in licenses {
            println!(
                "{} → {}",
                license["key"], license["company"]["carrier"]["name"]
            );
        }
    }
    Ok(())
}
json
{
  "data": [
    {
      "id": 812,
      "key": "a1b2c3d4e5f6",            // ← זהו ה-license_key שלכם
      "name": "חשבון HFD ראשי",
      "company": {
        "id": 3391,
        "name": "בלדר לוגיסטיקה בע״מ",
        "carrier": { "id": 4, "name": "HFD" }
      },
      "commitment_day": 3,
      "multiple_shipment": true,
      "is_active": true,
      "is_expired": false,
      "expires_at": "2027-01-31T00:00:00.000000Z",
      "settings": [ ... ]
    }
  ]
}

מתי אפשר להשמיט את license_key?

אם לחשבון שלכם יש בדיוק רישיון פעיל אחד, הוא משמש כברירת מחדל ואפשר להשמיט את license_key. עם יותר מרישיון פעיל אחד, השמטה מחזירה 422; מפתח לא פעיל, שפג תוקפו או שאינו בבעלותכם מחזיר 403. הכללים המלאים ברישיונות ו-license_key.

שלב 3 — יצירת המשלוח

POST /shipments מקבל מעטפת {ship_data, order}:

  • ship_data — המטען שמופנה למוביל: למי לשלוח, לאן ואיך. השדות contact_name, contact_phone, type, return ו-packages הם חובה; street ו-city הם חובה אלא אם הגדרתם ship_data.pickup (משלוח לנקודת איסוף).
  • order — תמונת ההזמנה שנשמרת לצד המשלוח, כולל בלוק נמען order.shipping (חובה) ו-order_items אופציונליים.

עבור ship_data.type, ‏1 = משלוח רגיל ו-2 = איסוף (החזרה); עבור ship_data.return, ‏1 = כיוון אחד ו-2 = הלוך ושוב. למשלוח רגיל עד הבית השתמשו ב-type: "1", ‏return: "1".

שלחו כותרת Idempotency-Key — כל מחרוזת ייחודית לכל משלוח לוגי (UUID עובד מצוין). אם הבקשה מסתיימת ב-timeout או שהתהליך שלכם קורס, ניסיון חוזר עם אותו מפתח מחזיר בבטחה את המשלוח שכבר נוצר, במקום ליצור (ולשלם על) כפילות. ראו אידמפוטנטיות.

bash
curl --location 'https://app.shipos.co.il/api/v2/shipments' \
--header 'X-Client-Id: {client_id}' \
--header 'X-Client-Secret: {client_secret}' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: 4f9d2c6a-7b1e-4e3a-9c5d-8a0b1c2d3e4f' \
--data '{
  "license_key": "a1b2c3d4e5f6",
  "ship_data": {
    "contact_name": "ישראל ישראלי",
    "contact_phone": "0521234567",
    "contact_mail": "israel@example.co.il",
    "street": "הרצל",
    "number": "10",
    "city": "תל אביב",
    "entrance": "ב",
    "floor": "3",
    "apartment": "12",
    "type": "1",
    "return": "1",
    "packages": 1,
    "note": "להשאיר אצל השומר אם אין איש בבית"
  },
  "order": {
    "id": "1042",
    "number": "1042",
    "status": "processing",
    "currency": "ILS",
    "total": 249.90,
    "source": "api",
    "shipping": {
      "first_name": "ישראל",
      "last_name": "ישראלי",
      "phone": "0521234567",
      "email": "israel@example.co.il",
      "address_1": "הרצל",
      "address_2": "10",
      "city": "תל אביב",
      "postcode": "6688312",
      "country": "IL"
    },
    "order_items": [
      {
        "sku": "TSHIRT-M-BLK",
        "name": "חולצת טי כותנה (M, שחור)",
        "quantity": 2,
        "price": 89.95,
        "total": 179.90
      },
      {
        "sku": "SOCKS-3PK",
        "name": "שלישיית גרביים",
        "quantity": 1,
        "price": 70.00,
        "total": 70.00
      }
    ]
  }
}'
js
// Node.js 18+ / דפדפנים — ללא תלויות
const res = await fetch('https://app.shipos.co.il/api/v2/shipments', {
  method: 'POST',
  headers: {
    'X-Client-Id': process.env.SHIPOS_CLIENT_ID,
    'X-Client-Secret': process.env.SHIPOS_CLIENT_SECRET,
    Accept: 'application/json',
    'Content-Type': 'application/json',
    'Idempotency-Key': '4f9d2c6a-7b1e-4e3a-9c5d-8a0b1c2d3e4f',
  },
  body: JSON.stringify({
    license_key: 'a1b2c3d4e5f6',
    ship_data: {
      contact_name: 'ישראל ישראלי',
      contact_phone: '0521234567',
      contact_mail: 'israel@example.co.il',
      street: 'הרצל',
      number: '10',
      city: 'תל אביב',
      entrance: 'ב',
      floor: '3',
      apartment: '12',
      type: '1',
      return: '1',
      packages: 1,
      note: 'להשאיר אצל השומר אם אין איש בבית',
    },
    order: {
      id: '1042',
      number: '1042',
      status: 'processing',
      currency: 'ILS',
      total: 249.9,
      source: 'api',
      shipping: {
        first_name: 'ישראל',
        last_name: 'ישראלי',
        phone: '0521234567',
        email: 'israel@example.co.il',
        address_1: 'הרצל',
        address_2: '10',
        city: 'תל אביב',
        postcode: '6688312',
        country: 'IL',
      },
      order_items: [
        { sku: 'TSHIRT-M-BLK', name: 'חולצת טי כותנה (M, שחור)', quantity: 2, price: 89.95, total: 179.9 },
        { sku: 'SOCKS-3PK', name: 'שלישיית גרביים', quantity: 1, price: 70.0, total: 70.0 },
      ],
    },
  }),
})

const { data: shipment } = await res.json() // res.status === 201
php
<?php
// composer require guzzlehttp/guzzle

$client = new \GuzzleHttp\Client(['base_uri' => 'https://app.shipos.co.il/api/v2/']);

$response = $client->post('shipments', [
    'headers' => [
        'X-Client-Id' => getenv('SHIPOS_CLIENT_ID'),
        'X-Client-Secret' => getenv('SHIPOS_CLIENT_SECRET'),
        'Accept' => 'application/json',
        'Idempotency-Key' => '4f9d2c6a-7b1e-4e3a-9c5d-8a0b1c2d3e4f',
    ],
    'json' => [
        'license_key' => 'a1b2c3d4e5f6',
        'ship_data' => [
            'contact_name' => 'ישראל ישראלי',
            'contact_phone' => '0521234567',
            'contact_mail' => 'israel@example.co.il',
            'street' => 'הרצל',
            'number' => '10',
            'city' => 'תל אביב',
            'entrance' => 'ב',
            'floor' => '3',
            'apartment' => '12',
            'type' => '1',
            'return' => '1',
            'packages' => 1,
            'note' => 'להשאיר אצל השומר אם אין איש בבית',
        ],
        'order' => [
            'id' => '1042',
            'number' => '1042',
            'status' => 'processing',
            'currency' => 'ILS',
            'total' => 249.90,
            'source' => 'api',
            'shipping' => [
                'first_name' => 'ישראל',
                'last_name' => 'ישראלי',
                'phone' => '0521234567',
                'email' => 'israel@example.co.il',
                'address_1' => 'הרצל',
                'address_2' => '10',
                'city' => 'תל אביב',
                'postcode' => '6688312',
                'country' => 'IL',
            ],
            'order_items' => [
                ['sku' => 'TSHIRT-M-BLK', 'name' => 'חולצת טי כותנה (M, שחור)', 'quantity' => 2, 'price' => 89.95, 'total' => 179.90],
                ['sku' => 'SOCKS-3PK', 'name' => 'שלישיית גרביים', 'quantity' => 1, 'price' => 70.00, 'total' => 70.00],
            ],
        ],
    ],
]);

$shipment = json_decode((string) $response->getBody(), true)['data'];
php
<?php

use Illuminate\Support\Facades\Http;

$shipment = Http::withHeaders([
    'X-Client-Id' => config('services.shipos.client_id'),
    'X-Client-Secret' => config('services.shipos.client_secret'),
    'Idempotency-Key' => '4f9d2c6a-7b1e-4e3a-9c5d-8a0b1c2d3e4f',
])
    ->acceptJson()
    ->post('https://app.shipos.co.il/api/v2/shipments', [
        'license_key' => 'a1b2c3d4e5f6',
        'ship_data' => [
            'contact_name' => 'ישראל ישראלי',
            'contact_phone' => '0521234567',
            'contact_mail' => 'israel@example.co.il',
            'street' => 'הרצל',
            'number' => '10',
            'city' => 'תל אביב',
            'entrance' => 'ב',
            'floor' => '3',
            'apartment' => '12',
            'type' => '1',
            'return' => '1',
            'packages' => 1,
            'note' => 'להשאיר אצל השומר אם אין איש בבית',
        ],
        'order' => [
            'id' => '1042',
            'number' => '1042',
            'status' => 'processing',
            'currency' => 'ILS',
            'total' => 249.90,
            'source' => 'api',
            'shipping' => [
                'first_name' => 'ישראל',
                'last_name' => 'ישראלי',
                'phone' => '0521234567',
                'email' => 'israel@example.co.il',
                'address_1' => 'הרצל',
                'address_2' => '10',
                'city' => 'תל אביב',
                'postcode' => '6688312',
                'country' => 'IL',
            ],
            'order_items' => [
                ['sku' => 'TSHIRT-M-BLK', 'name' => 'חולצת טי כותנה (M, שחור)', 'quantity' => 2, 'price' => 89.95, 'total' => 179.90],
                ['sku' => 'SOCKS-3PK', 'name' => 'שלישיית גרביים', 'quantity' => 1, 'price' => 70.00, 'total' => 70.00],
            ],
        ],
    ])
    ->throw()
    ->json('data');
python
# pip install httpx
import os

import httpx

payload = {
    "license_key": "a1b2c3d4e5f6",
    "ship_data": {
        "contact_name": "ישראל ישראלי",
        "contact_phone": "0521234567",
        "contact_mail": "israel@example.co.il",
        "street": "הרצל",
        "number": "10",
        "city": "תל אביב",
        "entrance": "ב",
        "floor": "3",
        "apartment": "12",
        "type": "1",
        "return": "1",
        "packages": 1,
        "note": "להשאיר אצל השומר אם אין איש בבית",
    },
    "order": {
        "id": "1042",
        "number": "1042",
        "status": "processing",
        "currency": "ILS",
        "total": 249.90,
        "source": "api",
        "shipping": {
            "first_name": "ישראל",
            "last_name": "ישראלי",
            "phone": "0521234567",
            "email": "israel@example.co.il",
            "address_1": "הרצל",
            "address_2": "10",
            "city": "תל אביב",
            "postcode": "6688312",
            "country": "IL",
        },
        "order_items": [
            {"sku": "TSHIRT-M-BLK", "name": "חולצת טי כותנה (M, שחור)", "quantity": 2, "price": 89.95, "total": 179.90},
            {"sku": "SOCKS-3PK", "name": "שלישיית גרביים", "quantity": 1, "price": 70.00, "total": 70.00},
        ],
    },
}

response = httpx.post(
    "https://app.shipos.co.il/api/v2/shipments",
    json=payload,
    headers={
        "X-Client-Id": os.environ["SHIPOS_CLIENT_ID"],
        "X-Client-Secret": os.environ["SHIPOS_CLIENT_SECRET"],
        "Accept": "application/json",
        "Idempotency-Key": "4f9d2c6a-7b1e-4e3a-9c5d-8a0b1c2d3e4f",
    },
    timeout=60.0,
)
response.raise_for_status()  # 201
shipment = response.json()["data"]

print(shipment["uuid"], shipment["tracking_code"])
go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
)

func main() {
	payload := map[string]any{
		"license_key": "a1b2c3d4e5f6",
		"ship_data": map[string]any{
			"contact_name":  "ישראל ישראלי",
			"contact_phone": "0521234567",
			"contact_mail":  "israel@example.co.il",
			"street":        "הרצל",
			"number":        "10",
			"city":          "תל אביב",
			"entrance":      "ב",
			"floor":         "3",
			"apartment":     "12",
			"type":          "1",
			"return":        "1",
			"packages":      1,
			"note":          "להשאיר אצל השומר אם אין איש בבית",
		},
		"order": map[string]any{
			"id":       "1042",
			"number":   "1042",
			"status":   "processing",
			"currency": "ILS",
			"total":    249.90,
			"source":   "api",
			"shipping": map[string]any{
				"first_name": "ישראל",
				"last_name":  "ישראלי",
				"phone":      "0521234567",
				"email":      "israel@example.co.il",
				"address_1":  "הרצל",
				"address_2":  "10",
				"city":       "תל אביב",
				"postcode":   "6688312",
				"country":    "IL",
			},
			"order_items": []map[string]any{
				{"sku": "TSHIRT-M-BLK", "name": "חולצת טי כותנה (M, שחור)", "quantity": 2, "price": 89.95, "total": 179.90},
				{"sku": "SOCKS-3PK", "name": "שלישיית גרביים", "quantity": 1, "price": 70.00, "total": 70.00},
			},
		},
	}

	body, _ := json.Marshal(payload)
	req, _ := http.NewRequest("POST", "https://app.shipos.co.il/api/v2/shipments", bytes.NewReader(body))
	req.Header.Set("X-Client-Id", os.Getenv("SHIPOS_CLIENT_ID"))
	req.Header.Set("X-Client-Secret", os.Getenv("SHIPOS_CLIENT_SECRET"))
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Idempotency-Key", "4f9d2c6a-7b1e-4e3a-9c5d-8a0b1c2d3e4f")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	var payloadOut struct {
		Data struct {
			UUID         string `json:"uuid"`
			TrackingCode string `json:"tracking_code"`
		} `json:"data"`
	}
	if err := json.NewDecoder(res.Body).Decode(&payloadOut); err != nil {
		panic(err)
	}

	fmt.Println(res.StatusCode, payloadOut.Data.UUID, payloadOut.Data.TrackingCode)
}
java
// Java 17+ — java.net.http, ללא תלויות (בקוד אמיתי בנו את ה-JSON עם Jackson/Gson)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class CreateShipment {
    public static void main(String[] args) throws Exception {
        String body = """
            {
              "license_key": "a1b2c3d4e5f6",
              "ship_data": {
                "contact_name": "ישראל ישראלי",
                "contact_phone": "0521234567",
                "contact_mail": "israel@example.co.il",
                "street": "הרצל",
                "number": "10",
                "city": "תל אביב",
                "entrance": "ב",
                "floor": "3",
                "apartment": "12",
                "type": "1",
                "return": "1",
                "packages": 1,
                "note": "להשאיר אצל השומר אם אין איש בבית"
              },
              "order": {
                "id": "1042",
                "number": "1042",
                "status": "processing",
                "currency": "ILS",
                "total": 249.90,
                "source": "api",
                "shipping": {
                  "first_name": "ישראל",
                  "last_name": "ישראלי",
                  "phone": "0521234567",
                  "email": "israel@example.co.il",
                  "address_1": "הרצל",
                  "address_2": "10",
                  "city": "תל אביב",
                  "postcode": "6688312",
                  "country": "IL"
                },
                "order_items": [
                  {"sku": "TSHIRT-M-BLK", "name": "חולצת טי כותנה (M, שחור)", "quantity": 2, "price": 89.95, "total": 179.90},
                  {"sku": "SOCKS-3PK", "name": "שלישיית גרביים", "quantity": 1, "price": 70.00, "total": 70.00}
                ]
              }
            }
            """;

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://app.shipos.co.il/api/v2/shipments"))
            .header("X-Client-Id", System.getenv("SHIPOS_CLIENT_ID"))
            .header("X-Client-Secret", System.getenv("SHIPOS_CLIENT_SECRET"))
            .header("Accept", "application/json")
            .header("Content-Type", "application/json")
            .header("Idempotency-Key", "4f9d2c6a-7b1e-4e3a-9c5d-8a0b1c2d3e4f")
            .POST(HttpRequest.BodyPublishers.ofString(body))
            .build();

        HttpResponse<String> response = HttpClient.newHttpClient()
            .send(request, HttpResponse.BodyHandlers.ofString());

        if (response.statusCode() != 201) {
            throw new RuntimeException("ShipOS error: " + response.body());
        }

        System.out.println(response.body()); // {"data":{"uuid":...,"tracking_code":...}}
    }
}
csharp
// .NET 8+ — System.Net.Http.Json
using System.Net.Http.Json;
using System.Text.Json;

using var http = new HttpClient
{
    BaseAddress = new Uri("https://app.shipos.co.il/api/v2/"),
};
http.DefaultRequestHeaders.Add("X-Client-Id",
    Environment.GetEnvironmentVariable("SHIPOS_CLIENT_ID"));
http.DefaultRequestHeaders.Add("X-Client-Secret",
    Environment.GetEnvironmentVariable("SHIPOS_CLIENT_SECRET"));
http.DefaultRequestHeaders.Add("Idempotency-Key",
    "4f9d2c6a-7b1e-4e3a-9c5d-8a0b1c2d3e4f");

var payload = new
{
    license_key = "a1b2c3d4e5f6",
    ship_data = new
    {
        contact_name = "ישראל ישראלי",
        contact_phone = "0521234567",
        contact_mail = "israel@example.co.il",
        street = "הרצל",
        number = "10",
        city = "תל אביב",
        entrance = "ב",
        floor = "3",
        apartment = "12",
        type = "1",
        @return = "1", // עובר סריאליזציה כ-"return"
        packages = 1,
        note = "להשאיר אצל השומר אם אין איש בבית",
    },
    order = new
    {
        id = "1042",
        number = "1042",
        status = "processing",
        currency = "ILS",
        total = 249.90m,
        source = "api",
        shipping = new
        {
            first_name = "ישראל",
            last_name = "ישראלי",
            phone = "0521234567",
            email = "israel@example.co.il",
            address_1 = "הרצל",
            address_2 = "10",
            city = "תל אביב",
            postcode = "6688312",
            country = "IL",
        },
        order_items = new object[]
        {
            new { sku = "TSHIRT-M-BLK", name = "חולצת טי כותנה (M, שחור)", quantity = 2, price = 89.95m, total = 179.90m },
            new { sku = "SOCKS-3PK", name = "שלישיית גרביים", quantity = 1, price = 70.00m, total = 70.00m },
        },
    },
};

var response = await http.PostAsJsonAsync("shipments", payload);
response.EnsureSuccessStatusCode(); // 201

var created = (await response.Content.ReadFromJsonAsync<JsonDocument>())!
    .RootElement.GetProperty("data");

Console.WriteLine($"{created.GetProperty("uuid").GetString()} " +
    $"{created.GetProperty("tracking_code").GetString()}");
ruby
require "net/http"
require "json"

payload = {
  license_key: "a1b2c3d4e5f6",
  ship_data: {
    contact_name: "ישראל ישראלי",
    contact_phone: "0521234567",
    contact_mail: "israel@example.co.il",
    street: "הרצל",
    number: "10",
    city: "תל אביב",
    entrance: "ב",
    floor: "3",
    apartment: "12",
    type: "1",
    return: "1",
    packages: 1,
    note: "להשאיר אצל השומר אם אין איש בבית"
  },
  order: {
    id: "1042",
    number: "1042",
    status: "processing",
    currency: "ILS",
    total: 249.90,
    source: "api",
    shipping: {
      first_name: "ישראל",
      last_name: "ישראלי",
      phone: "0521234567",
      email: "israel@example.co.il",
      address_1: "הרצל",
      address_2: "10",
      city: "תל אביב",
      postcode: "6688312",
      country: "IL"
    },
    order_items: [
      { sku: "TSHIRT-M-BLK", name: "חולצת טי כותנה (M, שחור)", quantity: 2, price: 89.95, total: 179.90 },
      { sku: "SOCKS-3PK", name: "שלישיית גרביים", quantity: 1, price: 70.00, total: 70.00 }
    ]
  }
}

uri = URI("https://app.shipos.co.il/api/v2/shipments")
request = Net::HTTP::Post.new(uri)
request["X-Client-Id"] = ENV.fetch("SHIPOS_CLIENT_ID")
request["X-Client-Secret"] = ENV.fetch("SHIPOS_CLIENT_SECRET")
request["Accept"] = "application/json"
request["Content-Type"] = "application/json"
request["Idempotency-Key"] = "4f9d2c6a-7b1e-4e3a-9c5d-8a0b1c2d3e4f"
request.body = JSON.dump(payload)

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end

raise "ShipOS error: #{response.body}" unless response.code == "201"

shipment = JSON.parse(response.body).fetch("data")
puts shipment["uuid"], shipment["tracking_code"]
rust
// [dependencies]
// reqwest = { version = "0.12", features = ["json"] }
// tokio = { version = "1", features = ["full"] }
// serde_json = "1"
use serde_json::{json, Value};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let payload = json!({
        "license_key": "a1b2c3d4e5f6",
        "ship_data": {
            "contact_name": "ישראל ישראלי",
            "contact_phone": "0521234567",
            "contact_mail": "israel@example.co.il",
            "street": "הרצל",
            "number": "10",
            "city": "תל אביב",
            "entrance": "ב",
            "floor": "3",
            "apartment": "12",
            "type": "1",
            "return": "1",
            "packages": 1,
            "note": "להשאיר אצל השומר אם אין איש בבית"
        },
        "order": {
            "id": "1042",
            "number": "1042",
            "status": "processing",
            "currency": "ILS",
            "total": 249.90,
            "source": "api",
            "shipping": {
                "first_name": "ישראל",
                "last_name": "ישראלי",
                "phone": "0521234567",
                "email": "israel@example.co.il",
                "address_1": "הרצל",
                "address_2": "10",
                "city": "תל אביב",
                "postcode": "6688312",
                "country": "IL"
            },
            "order_items": [
                {"sku": "TSHIRT-M-BLK", "name": "חולצת טי כותנה (M, שחור)", "quantity": 2, "price": 89.95, "total": 179.90},
                {"sku": "SOCKS-3PK", "name": "שלישיית גרביים", "quantity": 1, "price": 70.00, "total": 70.00}
            ]
        }
    });

    let created: Value = reqwest::Client::new()
        .post("https://app.shipos.co.il/api/v2/shipments")
        .header("X-Client-Id", std::env::var("SHIPOS_CLIENT_ID")?)
        .header("X-Client-Secret", std::env::var("SHIPOS_CLIENT_SECRET")?)
        .header("Accept", "application/json")
        .header("Idempotency-Key", "4f9d2c6a-7b1e-4e3a-9c5d-8a0b1c2d3e4f")
        .json(&payload)
        .send()
        .await?
        .error_for_status()?
        .json()
        .await?;

    let shipment = &created["data"];
    println!("{} {}", shipment["uuid"], shipment["tracking_code"]);
    Ok(())
}

תגובת 201 Created מחזירה את אובייקט המשלוח המלא:

json
{
  "data": {
    "uuid": "9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88",
    "tracking_code": "66747921",
    "carrier": { "id": 4, "name": "HFD" },
    "status": null,
    "service_type": "1",
    "is_active": true,
    "recipient": {
      "name": "ישראל ישראלי",
      "phone": "0521234567",
      "company": null,
      "address": {
        "street": "הרצל",
        "number": "10",
        "city": "תל אביב",
        "state": null,
        "zip": "6688312",
        "country": "IL"
      }
    },
    "pickup_point_id": null,
    "packages": 1,
    "cod": null,
    "order": { "id": "1042", "number": "1042" },
    "references": { "external_id": null },
    "short_tracking_code": null,
    "label_generated": false,
    "collection_status": null,
    "collected_at": null,
    "ready_at": null,
    "created_at": "2026-07-29T09:14:00.000000Z",
    "updated_at": "2026-07-29T09:14:00.000000Z"
  }
}

שמרו את השדות הבאים בצד שלכם:

שדהלמה
uuidמזהה ה-API של המשלוח — נדרש לכל קריאת המשך (/shipments/{shipment}, /status, /label, /cancel).
tracking_codeקוד המעקב של המוביל. משמש גם עבור ה-endpoint הציבורי למעקב, וזה מה שהלקוח שלכם רואה.
short_tracking_codeקוד קצר שמשמש בתהליכי נקודות איסוף (עשוי להיות null במשלוחים עד הבית).
label_generatedהאם כבר הופקה תווית — משתלב עם שלב 4.

שלב 4 — קבלת התווית

GET /shipments/{shipment}/label מחזיר מטא-נתוני תווית עם קישור הורדה — לא את בייטי ה-PDF עצמם:

bash
curl --location 'https://app.shipos.co.il/api/v2/shipments/9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88/label' \
--header 'X-Client-Id: {client_id}' \
--header 'X-Client-Secret: {client_secret}' \
--header 'Accept: application/json'
js
// Node.js 18+ / דפדפנים — ללא תלויות
const uuid = '9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88'

const response = await fetch(
  `https://app.shipos.co.il/api/v2/shipments/${uuid}/label`,
  {
    headers: {
      'X-Client-Id': process.env.SHIPOS_CLIENT_ID,
      'X-Client-Secret': process.env.SHIPOS_CLIENT_SECRET,
      Accept: 'application/json',
    },
  },
)

if (!response.ok) {
  const { error } = await response.json()
  throw new Error(`${error.code}: ${error.message}`)
}

const { data: label } = await response.json()

console.log(label.format, label.url) // גשו ל-label.url כדי להוריד את ה-PDF
php
<?php
// composer require guzzlehttp/guzzle

$uuid = '9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88';

$client = new \GuzzleHttp\Client([
    'base_uri' => 'https://app.shipos.co.il/api/v2/',
    'headers' => [
        'X-Client-Id' => getenv('SHIPOS_CLIENT_ID'),
        'X-Client-Secret' => getenv('SHIPOS_CLIENT_SECRET'),
        'Accept' => 'application/json',
    ],
]);

$label = json_decode(
    $client->get("shipments/{$uuid}/label")->getBody()->getContents(),
    true,
)['data'];

echo $label['format'], ' ', $label['url'], PHP_EOL;
php
<?php

use Illuminate\Support\Facades\Http;

$uuid = '9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88';

$label = Http::withHeaders([
    'X-Client-Id' => config('services.shipos.client_id'),
    'X-Client-Secret' => config('services.shipos.client_secret'),
])
    ->acceptJson()
    ->get("https://app.shipos.co.il/api/v2/shipments/{$uuid}/label")
    ->throw()
    ->json('data');

// הורדת בייטי ה-PDF — כתובת התווית אינה דורשת פרטי גישה
$pdf = Http::get($label['url'])->throw()->body();
python
# pip install httpx
import os

import httpx

uuid = "9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88"

response = httpx.get(
    f"https://app.shipos.co.il/api/v2/shipments/{shipment}/label",
    headers={
        "X-Client-Id": os.environ["SHIPOS_CLIENT_ID"],
        "X-Client-Secret": os.environ["SHIPOS_CLIENT_SECRET"],
        "Accept": "application/json",
    },
)
response.raise_for_status()
label = response.json()["data"]

pdf = httpx.get(label["url"], follow_redirects=True).content
print(label["format"], len(pdf), "bytes")
go
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
)

type labelResponse struct {
	Data struct {
		ShipmentID string `json:"shipment_id"`
		Format     string `json:"format"`
		URL        string `json:"url"`
	} `json:"data"`
}

func main() {
	uuid := "9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88"
	url := fmt.Sprintf("https://app.shipos.co.il/api/v2/shipments/%s/label", uuid)

	req, _ := http.NewRequest("GET", url, nil)
	req.Header.Set("X-Client-Id", os.Getenv("SHIPOS_CLIENT_ID"))
	req.Header.Set("X-Client-Secret", os.Getenv("SHIPOS_CLIENT_SECRET"))
	req.Header.Set("Accept", "application/json")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	var label labelResponse
	if err := json.NewDecoder(res.Body).Decode(&label); err != nil {
		panic(err)
	}

	fmt.Println(label.Data.Format, label.Data.URL)
}
java
// Java 17+ — java.net.http, ללא תלויות (פענוח עם Jackson/Gson)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class GetLabel {
    public static void main(String[] args) throws Exception {
        String uuid = "9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88";

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://app.shipos.co.il/api/v2/shipments/" + uuid + "/label"))
            .header("X-Client-Id", System.getenv("SHIPOS_CLIENT_ID"))
            .header("X-Client-Secret", System.getenv("SHIPOS_CLIENT_SECRET"))
            .header("Accept", "application/json")
            .build();

        HttpResponse<String> response = HttpClient.newHttpClient()
            .send(request, HttpResponse.BodyHandlers.ofString());

        if (response.statusCode() != 200) {
            throw new RuntimeException("ShipOS error: " + response.body());
        }

        System.out.println(response.body()); // {"data":{"format":"pdf","url":...}}
    }
}
csharp
// .NET 8+ — System.Net.Http.Json
using System.Net.Http.Json;
using System.Text.Json;

var uuid = "9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88";

using var http = new HttpClient
{
    BaseAddress = new Uri("https://app.shipos.co.il/api/v2/"),
};
http.DefaultRequestHeaders.Add("X-Client-Id",
    Environment.GetEnvironmentVariable("SHIPOS_CLIENT_ID"));
http.DefaultRequestHeaders.Add("X-Client-Secret",
    Environment.GetEnvironmentVariable("SHIPOS_CLIENT_SECRET"));

var payload = await http.GetFromJsonAsync<JsonDocument>($"shipments/{shipment}/label")
    ?? throw new InvalidOperationException("Empty response");
var label = payload.RootElement.GetProperty("data");

Console.WriteLine($"{label.GetProperty("format").GetString()} " +
    $"{label.GetProperty("url").GetString()}");
ruby
require "net/http"
require "json"

uuid = "9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88"

uri = URI("https://app.shipos.co.il/api/v2/shipments/#{uuid}/label")
request = Net::HTTP::Get.new(uri)
request["X-Client-Id"] = ENV.fetch("SHIPOS_CLIENT_ID")
request["X-Client-Secret"] = ENV.fetch("SHIPOS_CLIENT_SECRET")
request["Accept"] = "application/json"

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end

raise "ShipOS error: #{response.body}" unless response.is_a?(Net::HTTPSuccess)

label = JSON.parse(response.body).fetch("data")
puts label["format"], label["url"]
rust
// [dependencies]
// reqwest = { version = "0.12", features = ["json"] }
// tokio = { version = "1", features = ["full"] }
// serde_json = "1"
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let uuid = "9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88";

    let payload: Value = reqwest::Client::new()
        .get(format!(
            "https://app.shipos.co.il/api/v2/shipments/{shipment}/label"
        ))
        .header("X-Client-Id", std::env::var("SHIPOS_CLIENT_ID")?)
        .header("X-Client-Secret", std::env::var("SHIPOS_CLIENT_SECRET")?)
        .header("Accept", "application/json")
        .send()
        .await?
        .error_for_status()?
        .json()
        .await?;

    let label = &payload["data"];
    println!("{} {}", label["format"], label["url"]);
    Ok(())
}
json
{
  "data": {
    "shipment_id": "9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88",
    "format": "pdf",
    "url": "https://app.shipos.co.il/shipping/label/9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88"
  }
}

גשו אל ה-url כדי להוריד את תווית ה-PDF. שימו לב שהכתובת נמצאת מחוץ ל-/api/v2 ואינה דורשת את כותרות פרטי הלקוח — היכולת היא הידיעה של ה-uuid של המשלוח, לכן התייחסו לקישור עצמו כאל מידע רגיש.

הדפסת תוויות רבות בבת אחת

POST /shipments/labels עם רשימת uuids מחזיר כתובת אחת ל-PDF מאוחד של כולן — ראו את מדריך העזר למשלוחים.

שלב 5 — מעקב

שתי אפשרויות, בהתאם למי ששואל.

מאומת (ה-backend שלכם): GET /shipments/{shipment}/status שולף מחדש את הסטטוס מהמוביל ומחזיר את אובייקט המשלוח המלא והמעודכן (אותו מבנה כמו התגובה בשלב 3, עם status מלא):

bash
curl --location 'https://app.shipos.co.il/api/v2/shipments/9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88/status' \
--header 'X-Client-Id: {client_id}' \
--header 'X-Client-Secret: {client_secret}' \
--header 'Accept: application/json'
js
// Node.js 18+ / דפדפנים — ללא תלויות
const uuid = '9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88'

const response = await fetch(
  `https://app.shipos.co.il/api/v2/shipments/${uuid}/status`,
  {
    headers: {
      'X-Client-Id': process.env.SHIPOS_CLIENT_ID,
      'X-Client-Secret': process.env.SHIPOS_CLIENT_SECRET,
      Accept: 'application/json',
    },
  },
)

if (!response.ok) {
  const { error } = await response.json()
  throw new Error(`${error.code}: ${error.message}`)
}

const { data: shipment } = await response.json()

console.log(shipment.status?.description, shipment.status?.is_delivered)
php
<?php
// composer require guzzlehttp/guzzle

$uuid = '9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88';

$client = new \GuzzleHttp\Client([
    'base_uri' => 'https://app.shipos.co.il/api/v2/',
    'headers' => [
        'X-Client-Id' => getenv('SHIPOS_CLIENT_ID'),
        'X-Client-Secret' => getenv('SHIPOS_CLIENT_SECRET'),
        'Accept' => 'application/json',
    ],
]);

$shipment = json_decode(
    $client->get("shipments/{$uuid}/status")->getBody()->getContents(),
    true,
)['data'];

echo $shipment['status']['description'] ?? 'no status yet', PHP_EOL;
php
<?php

use Illuminate\Support\Facades\Http;

$uuid = '9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88';

$shipment = Http::withHeaders([
    'X-Client-Id' => config('services.shipos.client_id'),
    'X-Client-Secret' => config('services.shipos.client_secret'),
])
    ->acceptJson()
    ->get("https://app.shipos.co.il/api/v2/shipments/{$uuid}/status")
    ->throw()
    ->json('data');

logger()->info('Shipment status', [
    'code' => data_get($shipment, 'status.code'),
    'delivered' => data_get($shipment, 'status.is_delivered'),
]);
python
# pip install httpx
import os

import httpx

uuid = "9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88"

response = httpx.get(
    f"https://app.shipos.co.il/api/v2/shipments/{shipment}/status",
    headers={
        "X-Client-Id": os.environ["SHIPOS_CLIENT_ID"],
        "X-Client-Secret": os.environ["SHIPOS_CLIENT_SECRET"],
        "Accept": "application/json",
    },
    timeout=60.0,
)
response.raise_for_status()
shipment = response.json()["data"]

status = shipment.get("status") or {}
print(status.get("description"), status.get("is_delivered"))
go
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
)

type statusResponse struct {
	Data struct {
		TrackingCode string `json:"tracking_code"`
		Status       *struct {
			Code        string `json:"code"`
			Description string `json:"description"`
			IsDelivered bool   `json:"is_delivered"`
		} `json:"status"`
	} `json:"data"`
}

func main() {
	uuid := "9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88"
	url := fmt.Sprintf("https://app.shipos.co.il/api/v2/shipments/%s/status", uuid)

	req, _ := http.NewRequest("GET", url, nil)
	req.Header.Set("X-Client-Id", os.Getenv("SHIPOS_CLIENT_ID"))
	req.Header.Set("X-Client-Secret", os.Getenv("SHIPOS_CLIENT_SECRET"))
	req.Header.Set("Accept", "application/json")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	var payload statusResponse
	if err := json.NewDecoder(res.Body).Decode(&payload); err != nil {
		panic(err)
	}

	if payload.Data.Status != nil {
		fmt.Println(payload.Data.Status.Description, payload.Data.Status.IsDelivered)
	}
}
java
// Java 17+ — java.net.http, ללא תלויות (פענוח עם Jackson/Gson)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class RefreshStatus {
    public static void main(String[] args) throws Exception {
        String uuid = "9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88";

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://app.shipos.co.il/api/v2/shipments/" + uuid + "/status"))
            .header("X-Client-Id", System.getenv("SHIPOS_CLIENT_ID"))
            .header("X-Client-Secret", System.getenv("SHIPOS_CLIENT_SECRET"))
            .header("Accept", "application/json")
            .build();

        HttpResponse<String> response = HttpClient.newHttpClient()
            .send(request, HttpResponse.BodyHandlers.ofString());

        if (response.statusCode() != 200) {
            throw new RuntimeException("ShipOS error: " + response.body());
        }

        System.out.println(response.body()); // {"data":{...,"status":{...}}}
    }
}
csharp
// .NET 8+ — System.Net.Http.Json
using System.Net.Http.Json;
using System.Text.Json;

var uuid = "9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88";

using var http = new HttpClient
{
    BaseAddress = new Uri("https://app.shipos.co.il/api/v2/"),
};
http.DefaultRequestHeaders.Add("X-Client-Id",
    Environment.GetEnvironmentVariable("SHIPOS_CLIENT_ID"));
http.DefaultRequestHeaders.Add("X-Client-Secret",
    Environment.GetEnvironmentVariable("SHIPOS_CLIENT_SECRET"));

var payload = await http.GetFromJsonAsync<JsonDocument>($"shipments/{shipment}/status")
    ?? throw new InvalidOperationException("Empty response");
var shipment = payload.RootElement.GetProperty("data");

if (shipment.TryGetProperty("status", out var status) &&
    status.ValueKind == JsonValueKind.Object)
{
    Console.WriteLine($"{status.GetProperty("description").GetString()} " +
        $"{status.GetProperty("is_delivered").GetBoolean()}");
}
ruby
require "net/http"
require "json"

uuid = "9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88"

uri = URI("https://app.shipos.co.il/api/v2/shipments/#{uuid}/status")
request = Net::HTTP::Get.new(uri)
request["X-Client-Id"] = ENV.fetch("SHIPOS_CLIENT_ID")
request["X-Client-Secret"] = ENV.fetch("SHIPOS_CLIENT_SECRET")
request["Accept"] = "application/json"

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end

raise "ShipOS error: #{response.body}" unless response.is_a?(Net::HTTPSuccess)

shipment = JSON.parse(response.body).fetch("data")
puts shipment.dig("status", "description"), shipment.dig("status", "is_delivered")
rust
// [dependencies]
// reqwest = { version = "0.12", features = ["json"] }
// tokio = { version = "1", features = ["full"] }
// serde_json = "1"
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let uuid = "9b2c7f1e-3a4d-4c88-9f21-2f0d5a6b7c88";

    let payload: Value = reqwest::Client::new()
        .get(format!(
            "https://app.shipos.co.il/api/v2/shipments/{shipment}/status"
        ))
        .header("X-Client-Id", std::env::var("SHIPOS_CLIENT_ID")?)
        .header("X-Client-Secret", std::env::var("SHIPOS_CLIENT_SECRET")?)
        .header("Accept", "application/json")
        .send()
        .await?
        .error_for_status()?
        .json()
        .await?;

    let status = &payload["data"]["status"];
    println!("{} {}", status["description"], status["is_delivered"]);
    Ok(())
}

סטטוס ללא פרטים אישיים: GET /tracking/{shipping_code} מקבל את ה-tracking_code ומחזיר תצוגת סטטוס ללא פרטי נמען. הוא דורש את פרטי ההזדהות שלכם, ולכן יש לקרוא לו מהשרת — לעולם לא מדפדפן, שם הסוד ייחשף. כדי להציג ללקוחות מעקב, הפיקו אותו מהשרת שלכם או הפנו אותם לקישור שנשלח ב-SMS האיסוף:

bash
curl --location 'https://app.shipos.co.il/api/v2/tracking/66747921' \
--header 'Accept: application/json'
js
// Node.js 18+ / דפדפנים — ללא תלויות, ללא פרטי גישה
const trackingCode = '66747921'

const response = await fetch(
  `https://app.shipos.co.il/api/v2/tracking/${trackingCode}`,
  { headers: { Accept: 'application/json' } },
)

if (!response.ok) {
  const { error } = await response.json()
  throw new Error(`${error.code}: ${error.message}`)
}

const { data: tracking } = await response.json()

console.log(tracking.status.description, tracking.status.is_delivered)
php
<?php
// composer require guzzlehttp/guzzle — endpoint ציבורי, ללא פרטי גישה

$trackingCode = '66747921';

$client = new \GuzzleHttp\Client([
    'base_uri' => 'https://app.shipos.co.il/api/v2/',
    'headers' => ['Accept' => 'application/json'],
]);

$tracking = json_decode(
    $client->get("tracking/{$trackingCode}")->getBody()->getContents(),
    true,
)['data'];

echo $tracking['status']['description'], PHP_EOL;
php
<?php

use Illuminate\Support\Facades\Http;

$trackingCode = '66747921';

// endpoint ציבורי — ללא פרטי לקוח
$tracking = Http::acceptJson()
    ->get("https://app.shipos.co.il/api/v2/tracking/{$trackingCode}")
    ->throw()
    ->json('data');

logger()->info('Tracking', [
    'code' => data_get($tracking, 'status.code'),
    'delivered' => data_get($tracking, 'status.is_delivered'),
]);
python
# pip install httpx — endpoint ציבורי, ללא פרטי גישה
import httpx

tracking_code = "66747921"

response = httpx.get(
    f"https://app.shipos.co.il/api/v2/tracking/{tracking_code}",
    headers={"Accept": "application/json"},
)
response.raise_for_status()
tracking = response.json()["data"]

print(tracking["status"]["description"], tracking["status"]["is_delivered"])
go
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
)

type trackingResponse struct {
	Data struct {
		TrackingCode string `json:"tracking_code"`
		Status       struct {
			Code        string `json:"code"`
			Description string `json:"description"`
			IsDelivered bool   `json:"is_delivered"`
		} `json:"status"`
	} `json:"data"`
}

func main() {
	trackingCode := "66747921"
	url := fmt.Sprintf("https://app.shipos.co.il/api/v2/tracking/%s", trackingCode)

	// endpoint ציבורי — ללא כותרות פרטי גישה
	req, _ := http.NewRequest("GET", url, nil)
	req.Header.Set("Accept", "application/json")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	var payload trackingResponse
	if err := json.NewDecoder(res.Body).Decode(&payload); err != nil {
		panic(err)
	}

	fmt.Println(payload.Data.Status.Description, payload.Data.Status.IsDelivered)
}
java
// Java 17+ — java.net.http, endpoint ציבורי, ללא פרטי גישה
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class PublicTracking {
    public static void main(String[] args) throws Exception {
        String trackingCode = "66747921";

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://app.shipos.co.il/api/v2/tracking/" + trackingCode))
            .header("Accept", "application/json")
            .build();

        HttpResponse<String> response = HttpClient.newHttpClient()
            .send(request, HttpResponse.BodyHandlers.ofString());

        if (response.statusCode() != 200) {
            throw new RuntimeException("ShipOS error: " + response.body());
        }

        System.out.println(response.body()); // {"data":{"tracking_code":...,"status":{...}}}
    }
}
csharp
// .NET 8+ — System.Net.Http.Json, endpoint ציבורי, ללא פרטי גישה
using System.Net.Http.Json;
using System.Text.Json;

var trackingCode = "66747921";

using var http = new HttpClient
{
    BaseAddress = new Uri("https://app.shipos.co.il/api/v2/"),
};

var payload = await http.GetFromJsonAsync<JsonDocument>($"tracking/{trackingCode}")
    ?? throw new InvalidOperationException("Empty response");
var status = payload.RootElement.GetProperty("data").GetProperty("status");

Console.WriteLine($"{status.GetProperty("description").GetString()} " +
    $"{status.GetProperty("is_delivered").GetBoolean()}");
ruby
require "net/http"
require "json"

tracking_code = "66747921"

# endpoint ציבורי — ללא כותרות פרטי גישה
uri = URI("https://app.shipos.co.il/api/v2/tracking/#{tracking_code}")
request = Net::HTTP::Get.new(uri)
request["Accept"] = "application/json"

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end

raise "ShipOS error: #{response.body}" unless response.is_a?(Net::HTTPSuccess)

tracking = JSON.parse(response.body).fetch("data")
puts tracking.dig("status", "description"), tracking.dig("status", "is_delivered")
rust
// [dependencies]
// reqwest = { version = "0.12", features = ["json"] }
// tokio = { version = "1", features = ["full"] }
// serde_json = "1"
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let tracking_code = "66747921";

    // endpoint ציבורי — ללא כותרות פרטי גישה
    let payload: Value = reqwest::Client::new()
        .get(format!(
            "https://app.shipos.co.il/api/v2/tracking/{tracking_code}"
        ))
        .header("Accept", "application/json")
        .send()
        .await?
        .error_for_status()?
        .json()
        .await?;

    let status = &payload["data"]["status"];
    println!("{} {}", status["description"], status["is_delivered"]);
    Ok(())
}
json
{
  "data": {
    "tracking_code": "66747921",
    "carrier": { "id": 4, "name": "HFD" },
    "status": {
      "code": "3",
      "description": "יצא לחלוקה",
      "is_delivered": false
    },
    "is_active": true,
    "updated_at": "2026-07-30T07:41:12.000000Z"
  }
}

לפרטים ראו את מדריך העזר למעקב.

מה יכול להשתבש

כל השגיאות משתמשות במעטפת { "error": { "code", "message", "status", "details" } }. אלו שתפגשו בתהליך הזה:

HTTPerror.codeמשמעותמה לעשות
422validation_failedהגוף נכשל בוולידציה — שדה חובה של ship_data/order חסר או פגום, או ש-license_key הושמט כשלחשבון יש כמה רישיונות פעילים.תקנו את השדות המפורטים ב-error.details ושלחו מחדש.
403package_limit_reachedמכסת המשלוחים של המנוי שלכם נוצלה במלואה. המוביל לא נקרא.שדרגו את החבילה / פנו לתמיכה; ניסיון חוזר לא יעזור.
424carrier_errorהמוביל דחה את המשלוח (כתובת שגויה, תקלה בצד המוביל, ...). דבר לא נשמר.בדקו את error.message, תקנו את הנתונים ונסו שוב — עם Idempotency-Key חדש אם הגוף השתנה.
409idempotency_key_conflictאותו Idempotency-Key שימש שוב עם גוף בקשה שונה.השתמשו במפתח אחד לכל משלוח לוגי; צרו מפתח חדש למשלוח חדש באמת.
409duplicate_requestמשלוח עבור בדיוק אותה בקשה כבר נמצא בתהליך יצירה במקביל.המתינו רגע ונסו שוב עם אותו מפתח — תקבלו בחזרה את המשלוח שהושלם.

הקטלוג המלא במדריך השגיאות; סמנטיקת האידמפוטנטיות באידמפוטנטיות.