מבוא
ה-ShipOS API v2 הוא REST API עצמאי ומתוּעד גרסה ליצירה וניהול של משלוחים בכל חברות השליחויות ש-ShipOS תומכת בהן. הוא אגנוסטי לחברת השליחויות: אותם מבני בקשה ותגובה עובדים בין אם חברת השליחויות שמתחת היא Cargo, HFD, Run Software או כל אחת אחרת — אף שדה ייחודי לחברת שליחויות אינו מופיע בחוזה.
כתובת בסיס (Base URL)
https://app.shipos.co.il/api/v2כל הנתיבים במדריך זה יחסיים לכתובת הבסיס הזו. ה-API רשום תחת ה-prefix של api/v2 והוא נפרד לחלוטין מה-API הישן (v1).
מוסכמות
פורמט — JSON בלבד. שלחו
Accept: application/json, ובבקשות עם גוף (body) גםContent-Type: application/json.מעטפת הצלחה — כל תגובת משאב עטופה במפתח
dataברמה העליונה: אובייקט עבור משאב יחיד, מערך עבור אוסף.json{ "data": { "id": 1, "...": "..." } }מעטפת שגיאה — כשלים מחזירים אובייקט
errorברמה העליונה עםcodeקריא-מכונה,messageקריא-אנוש ו-statusשל HTTP. ראו שגיאות.json{ "error": { "code": "forbidden", "message": "This license is inactive.", "status": 403 } }מזהים — משלוחים מזוהים לפי ה-
uuidשלהם. חשבון חברת שליחויות מזוהה לפי ה-license_keyשלו.
אימות בשורה אחת
שלחו את פרטי הלקוח שלכם בכל בקשה שאינה ציבורית:
X-Client-Id: {client_id}
X-Client-Secret: {client_secret}הפרטים המלאים, כולל איך משיגים ומחליפים פרטי גישה, נמצאים בעמוד אימות. איך לבחור חשבון חברת שליחויות ספציפי מוסבר בעמוד רישיונות ו-license_key.
התחלה מהירה
בדקו שה-API זמין (ללא צורך באימות):
curl --location 'https://app.shipos.co.il/api/v2/ping' \
--header 'Accept: application/json'// Node.js 18+ / דפדפנים — בלי תלויות, בלי פרטי הזדהות
const response = await fetch('https://app.shipos.co.il/api/v2/ping', {
headers: { Accept: 'application/json' },
})
if (!response.ok) {
throw new Error(`ShipOS unreachable: HTTP ${response.status}`)
}
console.log(await response.json())<?php
// composer require guzzlehttp/guzzle
$client = new \GuzzleHttp\Client();
$response = $client->get('https://app.shipos.co.il/api/v2/ping', [
'headers' => ['Accept' => 'application/json'],
]);
print_r(json_decode($response->getBody()->getContents(), true));<?php
use Illuminate\Support\Facades\Http;
$ping = Http::acceptJson()
->get('https://app.shipos.co.il/api/v2/ping')
->throw()
->json();
logger()->info('ShipOS ping', $ping);# pip install httpx
import httpx
response = httpx.get(
"https://app.shipos.co.il/api/v2/ping",
headers={"Accept": "application/json"},
)
response.raise_for_status()
print(response.json())package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://app.shipos.co.il/api/v2/ping", nil)
req.Header.Set("Accept", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
panic(fmt.Sprintf("ShipOS unreachable: HTTP %d", res.StatusCode))
}
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}// Java 17+ — java.net.http, בלי תלויות
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class ShipOsPing {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://app.shipos.co.il/api/v2/ping"))
.header("Accept", "application/json")
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
throw new RuntimeException("ShipOS unreachable: HTTP " + response.statusCode());
}
System.out.println(response.body());
}
}// .NET 8+ — System.Net.Http.Json
using System.Net.Http.Json;
using System.Text.Json;
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("Accept", "application/json");
var ping = await http.GetFromJsonAsync<JsonDocument>(
"https://app.shipos.co.il/api/v2/ping")
?? throw new InvalidOperationException("Empty response");
Console.WriteLine(ping.RootElement.ToString());require "net/http"
require "json"
uri = URI("https://app.shipos.co.il/api/v2/ping")
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 unreachable: #{response.code}" unless response.is_a?(Net::HTTPSuccess)
puts JSON.parse(response.body)// [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 ping: Value = reqwest::Client::new()
.get("https://app.shipos.co.il/api/v2/ping")
.header("Accept", "application/json")
.send()
.await?
.error_for_status()?
.json()
.await?;
println!("{ping}");
Ok(())
}לאחר מכן ודאו שפרטי הגישה שלכם תקינים על ידי שליפת החשבון:
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'// 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
// composer require guzzlehttp/guzzle
$client = new \GuzzleHttp\Client();
$response = $client->get('https://app.shipos.co.il/api/v2/account', [
'headers' => [
'X-Client-Id' => getenv('SHIPOS_CLIENT_ID'),
'X-Client-Secret' => getenv('SHIPOS_CLIENT_SECRET'),
'Accept' => 'application/json',
],
]);
$account = json_decode($response->getBody()->getContents(), true)['data'];
echo $account['company_name'], ' — ', count($account['licenses']), ' license(s)', PHP_EOL;<?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'].' — '.count($account['licenses']).' license(s)');# 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)")package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
)
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()
if res.StatusCode != http.StatusOK {
panic(fmt.Sprintf("ShipOS error: HTTP %d", res.StatusCode))
}
var payload struct {
Data struct {
CompanyName string `json:"company_name"`
Licenses []json.RawMessage `json:"licenses"`
} `json:"data"`
}
if err := json.NewDecoder(res.Body).Decode(&payload); err != nil {
panic(err)
}
fmt.Println(payload.Data.CompanyName, "—", len(payload.Data.Licenses), "license(s)")
}// 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 ShipOsAccount {
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":{...}}
}
}// .NET 8+ — System.Net.Http.Json
using System.Net.Http.Json;
using System.Text.Json;
using var http = new HttpClient();
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("Accept", "application/json");
var payload = await http.GetFromJsonAsync<JsonDocument>(
"https://app.shipos.co.il/api/v2/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)");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)"// [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(())
}משם, עקבו אחר המדריך המפורט צרו את המשלוח הראשון שלכם, או עברו ישירות אל מדריך המשלוחים.
איך להתמצא
- תרחישי שימוש — מדריכים ממוקדי-משימה עם דוגמאות להעתקה ב-cURL, PHP ו-Node.js: משלוח ראשון, נקודות איסוף, החזרות, batches מרוכזים, עימוד (pagination), webhooks, טיפול בשגיאות ו-SMS.
- Endpoints — התיעוד המלא, עמוד לכל משאב, עם סקירה מרוכזת של כל הנתיבים.
- מדריך — המושגים הרוחביים: אימות, בחירת רישיון, אידמפוטנטיות ושגיאות.