Webhooks
ניהול מנויי ה-webhook של חשבון חברת שילוח (רישיון). ShipOS שולחת POST עם payload JSON חתום ל-url שלכם בכל פעם שאירוע שנרשמתם אליו מופעל, מתעדת כל ניסיון כ-delivery, ומאפשרת לשלוח "ping" לבדיקה. כל ה-endpoints של webhooks הם ברמת רישיון: הם פועלים תחת רישיון (License) אחד בדיוק, שנבחר באמצעות license_key.
חתימת ה-payload
כל delivery חתום. ShipOS שולחת שני headers עם כל POST:
X-ShipOS-Event— שם האירוע (למשלshipment.created).X-ShipOS-Signature—t={timestamp},v1={hmac}, כאשר{hmac}הואHMAC-SHA256("{timestamp}.{body}")עם מפתח שהוא סוד החתימה של המנוי (ערך ה-whsec_…שמוחזר פעם אחת בעת היצירה). חשבו אותו מחדש על גוף הבקשה הגולמי כדי לאמת אותנטיות.
הגוף הנשלח הוא { "event": "...", "created_at": {unix_timestamp}, "data": { ... } }. משלוחים מנוסים מחדש עד 5 פעמים עם המתנה של 30 שניות על כל תגובה שאינה 2xx או שגיאת תעבורה.
אירועים זמינים למנוי
| אירוע | מופעל כאשר |
|---|---|
shipment.created | משלוח נוצר. |
shipment.status_changed | סטטוס של משלוח משתנה. |
shipment.delivered | משלוח נמסר. |
shipment.cancelled | משלוח בוטל. |
ping נשלח גם הוא על ידי ה-endpoint של ping כאירוע בדיקה, אך הוא אינו ערך אירוע שניתן להירשם אליו.
GET /webhooks
מציג את כל מנויי ה-webhook שבבעלות הרישיון של הקורא. אימות: client credentials. רישיון: חובה.
פרמטרים
Query
| שדה | סוג | חובה | תיאור |
|---|---|---|---|
license_key | string | מותנה | ה-licenses.key שבוחר את חשבון חברת השילוח. חובה כאשר לחשבון יש יותר מרישיון פעיל אחד. |
בקשה לדוגמה
curl --location 'https://app.shipos.co.il/api/v2/webhooks?license_key={license_key}' \
--header 'X-Client-Id: {client_id}' \
--header 'X-Client-Secret: {client_secret}' \
--header 'Accept: application/json'// Node.js 18+ / דפדפנים — ללא תלויות
const url = new URL('https://app.shipos.co.il/api/v2/webhooks')
url.searchParams.set('license_key', '{license_key}')
const response = await fetch(url, {
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: webhooks } = await response.json()
for (const hook of webhooks) {
console.log(hook.id, hook.url, hook.events.join(', '))
}<?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',
],
]);
$response = $client->get('webhooks', [
'query' => ['license_key' => '{license_key}'],
]);
$webhooks = json_decode($response->getBody()->getContents(), true)['data'];
foreach ($webhooks as $hook) {
echo $hook['id'], ' ', $hook['url'], ' ', implode(', ', $hook['events']), PHP_EOL;
}<?php
use Illuminate\Support\Facades\Http;
$webhooks = 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/webhooks', [
'license_key' => '{license_key}',
])
->throw()
->json('data');
foreach ($webhooks as $hook) {
logger()->info($hook['id'].' '.$hook['url'].' '.implode(', ', $hook['events']));
}# pip install httpx
import os
import httpx
response = httpx.get(
"https://app.shipos.co.il/api/v2/webhooks",
params={"license_key": "{license_key}"},
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 hook in response.json()["data"]:
print(hook["id"], hook["url"], ", ".join(hook["events"]))package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
)
type webhookList struct {
Data []struct {
ID string `json:"id"`
URL string `json:"url"`
Events []string `json:"events"`
} `json:"data"`
}
func main() {
req, _ := http.NewRequest("GET",
"https://app.shipos.co.il/api/v2/webhooks?license_key={license_key}", 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 list webhookList
if err := json.NewDecoder(res.Body).Decode(&list); err != nil {
panic(err)
}
for _, hook := range list.Data {
fmt.Println(hook.ID, hook.URL, hook.Events)
}
}// 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 ShipOsListWebhooks {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(
"https://app.shipos.co.il/api/v2/webhooks?license_key={license_key}"))
.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
}
}// .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>(
"webhooks?license_key={license_key}")
?? throw new InvalidOperationException("Empty response");
foreach (var hook in payload.RootElement.GetProperty("data").EnumerateArray())
{
Console.WriteLine(
$"{hook.GetProperty("id").GetString()} {hook.GetProperty("url").GetString()}");
}require "net/http"
require "json"
uri = URI("https://app.shipos.co.il/api/v2/webhooks")
uri.query = URI.encode_www_form(license_key: "{license_key}")
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 |hook|
puts "#{hook["id"]} #{hook["url"]} #{hook["events"].join(", ")}"
end// [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/webhooks")
.query(&[("license_key", "{license_key}")])
.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?;
for hook in payload["data"].as_array().unwrap_or(&Vec::new()) {
println!("{} {} {}", hook["id"], hook["url"], hook["events"]);
}
Ok(())
}תגובה 200
{
"data": [
{
"id": "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f",
"url": "https://example.com/hooks/shipos",
"events": ["shipment.created", "shipment.delivered"],
"is_active": true,
"created_at": "2026-07-01T09:00:00.000000Z",
"updated_at": "2026-07-20T12:30:00.000000Z"
}
]
}ה-secret לחתימה אינו נכלל ברשימה — הוא מוחזר פעם אחת בלבד, בעת היצירה.
שגיאות
| סטטוס | קוד | מתי |
|---|---|---|
| 401 | unauthenticated | client credentials חסרים או שגויים. |
| 403 | forbidden | לחשבון אין רישיון פעיל, או שה-license_key שסופק אינו בבעלותכם / אינו פעיל / פג תוקף. |
| 422 | validation_failed | לחשבון כמה רישיונות פעילים ו-license_key הושמט. |
POST /webhooks
יוצר מנוי webhook ומחזיר אותו יחד עם סוד החתימה החד-פעמי שלו. אימות: client credentials. רישיון: חובה.
פרמטרים
Body
| שדה | סוג | חובה | תיאור |
|---|---|---|---|
license_key | string | מותנה | ה-licenses.key שבוחר את חשבון חברת השילוח (חובה כאשר לחשבון יש יותר מרישיון פעיל אחד). |
url | string (URL) | כן | כתובת היעד שמקבלת את ה-POST החתום. עד 2048 תווים. |
events | string[] | כן | לפחות אירוע אחד להירשם אליו. כל אחד חייב להיות אחד מהאירועים הזמינים למנוי. |
events.* | string | כן | ערך אירוע בודד. |
סוד החתימה נוצר בצד השרת (whsec_ + 40 תווים אקראיים); לא ניתן לספק אותו מצד הלקוח.
בקשה לדוגמה
curl --location --request POST 'https://app.shipos.co.il/api/v2/webhooks' \
--header 'X-Client-Id: {client_id}' \
--header 'X-Client-Secret: {client_secret}' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"license_key": "{license_key}",
"url": "https://example.com/hooks/shipos",
"events": ["shipment.created", "shipment.delivered"]
}'// Node.js 18+ / דפדפנים — ללא תלויות
const response = await fetch('https://app.shipos.co.il/api/v2/webhooks', {
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',
},
body: JSON.stringify({
license_key: '{license_key}',
url: 'https://example.com/hooks/shipos',
events: ['shipment.created', 'shipment.delivered'],
}),
})
if (!response.ok) {
const { error } = await response.json()
throw new Error(`${error.code}: ${error.message}`)
}
const { data: webhook } = await response.json()
// שמרו את webhook.secret עכשיו — הוא מוחזר פעם אחת בלבד.
console.log(webhook.id, webhook.secret)<?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',
],
]);
$response = $client->post('webhooks', [
'json' => [
'license_key' => '{license_key}',
'url' => 'https://example.com/hooks/shipos',
'events' => ['shipment.created', 'shipment.delivered'],
],
]);
$webhook = json_decode($response->getBody()->getContents(), true)['data'];
// שמרו את $webhook['secret'] עכשיו — הוא מוחזר פעם אחת בלבד.
echo $webhook['id'], ' ', $webhook['secret'], PHP_EOL;<?php
use Illuminate\Support\Facades\Http;
$webhook = Http::withHeaders([
'X-Client-Id' => config('services.shipos.client_id'),
'X-Client-Secret' => config('services.shipos.client_secret'),
])
->acceptJson()
->post('https://app.shipos.co.il/api/v2/webhooks', [
'license_key' => '{license_key}',
'url' => 'https://example.com/hooks/shipos',
'events' => ['shipment.created', 'shipment.delivered'],
])
->throw()
->json('data');
// שמרו את $webhook['secret'] עכשיו — הוא מוחזר פעם אחת בלבד.
logger()->info($webhook['id'].' '.$webhook['secret']);# pip install httpx
import os
import httpx
response = httpx.post(
"https://app.shipos.co.il/api/v2/webhooks",
headers={
"X-Client-Id": os.environ["SHIPOS_CLIENT_ID"],
"X-Client-Secret": os.environ["SHIPOS_CLIENT_SECRET"],
"Accept": "application/json",
},
json={
"license_key": "{license_key}",
"url": "https://example.com/hooks/shipos",
"events": ["shipment.created", "shipment.delivered"],
},
)
response.raise_for_status()
webhook = response.json()["data"]
# שמרו את webhook["secret"] עכשיו — הוא מוחזר פעם אחת בלבד.
print(webhook["id"], webhook["secret"])package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
func main() {
body, _ := json.Marshal(map[string]any{
"license_key": "{license_key}",
"url": "https://example.com/hooks/shipos",
"events": []string{"shipment.created", "shipment.delivered"},
})
req, _ := http.NewRequest("POST",
"https://app.shipos.co.il/api/v2/webhooks", 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")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
var payload struct {
Data struct {
ID string `json:"id"`
Secret string `json:"secret"`
} `json:"data"`
}
if err := json.NewDecoder(res.Body).Decode(&payload); err != nil {
panic(err)
}
// שמרו את הסוד עכשיו — הוא מוחזר פעם אחת בלבד.
fmt.Println(payload.Data.ID, payload.Data.Secret)
}// 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 ShipOsCreateWebhook {
public static void main(String[] args) throws Exception {
String body = """
{
"license_key": "{license_key}",
"url": "https://example.com/hooks/shipos",
"events": ["shipment.created", "shipment.delivered"]
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://app.shipos.co.il/api/v2/webhooks"))
.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")
.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()); // מכיל את ה-"secret" החד-פעמי
}
}// .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 response = await http.PostAsJsonAsync("webhooks", new
{
license_key = "{license_key}",
url = "https://example.com/hooks/shipos",
events = new[] { "shipment.created", "shipment.delivered" },
});
response.EnsureSuccessStatusCode();
var payload = await response.Content.ReadFromJsonAsync<JsonDocument>()
?? throw new InvalidOperationException("Empty response");
var webhook = payload.RootElement.GetProperty("data");
// שמרו את הסוד עכשיו — הוא מוחזר פעם אחת בלבד.
Console.WriteLine(
$"{webhook.GetProperty("id").GetString()} {webhook.GetProperty("secret").GetString()}");require "net/http"
require "json"
uri = URI("https://app.shipos.co.il/api/v2/webhooks")
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.body = JSON.dump(
license_key: "{license_key}",
url: "https://example.com/hooks/shipos",
events: ["shipment.created", "shipment.delivered"]
)
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)
webhook = JSON.parse(response.body).fetch("data")
# שמרו את webhook["secret"] עכשיו — הוא מוחזר פעם אחת בלבד.
puts "#{webhook["id"]} #{webhook["secret"]}"// [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: Value = reqwest::Client::new()
.post("https://app.shipos.co.il/api/v2/webhooks")
.header("X-Client-Id", std::env::var("SHIPOS_CLIENT_ID")?)
.header("X-Client-Secret", std::env::var("SHIPOS_CLIENT_SECRET")?)
.header("Accept", "application/json")
.json(&json!({
"license_key": "{license_key}",
"url": "https://example.com/hooks/shipos",
"events": ["shipment.created", "shipment.delivered"]
}))
.send()
.await?
.error_for_status()?
.json()
.await?;
// שמרו את הסוד עכשיו — הוא מוחזר פעם אחת בלבד.
println!("{} {}", payload["data"]["id"], payload["data"]["secret"]);
Ok(())
}תגובה 201
{
"data": {
"id": "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f",
"url": "https://example.com/hooks/shipos",
"events": ["shipment.created", "shipment.delivered"],
"is_active": true,
"secret": "whsec_S0meRandom40CharSigningSecretValueHere00",
"created_at": "2026-07-29T10:00:00.000000Z",
"updated_at": "2026-07-29T10:00:00.000000Z"
}
}שמרו את הסוד עכשיו
secret מוחזר רק בתגובת היצירה הזו. לאחר מכן הוא write-only ולעולם לא יופיע שוב ב-GET /webhooks, בעדכונים או בכל תגובה אחרת. שמרו אותו בצורה מאובטחת כדי לאמת את ה-header X-ShipOS-Signature.
שגיאות
| סטטוס | קוד | מתי |
|---|---|---|
| 401 | unauthenticated | client credentials חסרים או שגויים. |
| 403 | forbidden | אין רישיון פעיל, או שה-license_key שסופק אינו בבעלותכם / אינו פעיל / פג תוקף. |
| 422 | validation_failed | url חסר/שגוי/ארוך מדי, events ריק או מכיל אירוע לא מוכר, או כמה רישיונות עם license_key שהושמט. |
PATCH /webhooks/
מעדכן מנוי webhook שבבעלות הרישיון של הקורא. סמנטיקה חלקית (PATCH) — שלחו רק את השדות שברצונכם לשנות. אימות: client credentials. רישיון: חובה.
פרמטרים
Path
| שדה | סוג | חובה | תיאור |
|---|---|---|---|
uuid | string | כן | ה-id של מנוי ה-webhook (UUID). |
Body (הכול אופציונלי; סוד החתימה לעולם לא ניתן לשינוי)
| שדה | סוג | חובה | תיאור |
|---|---|---|---|
license_key | string | מותנה | בוחר את חשבון חברת השילוח (חובה עם כמה רישיונות פעילים). |
url | string (URL) | לא | כתובת יעד חדשה. עד 2048 תווים. |
events | string[] | לא | סט אירועים חלופי (מינימום 1, ללא כפילויות). כל אחד חייב להיות ערך אירוע תקין. |
events.* | string | חובה עם events | ערך אירוע בודד. |
is_active | boolean | לא | הפעלה או השבתה של המנוי. |
בקשה לדוגמה
curl --location --request PATCH 'https://app.shipos.co.il/api/v2/webhooks/9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f' \
--header 'X-Client-Id: {client_id}' \
--header 'X-Client-Secret: {client_secret}' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"license_key": "{license_key}",
"events": ["shipment.created", "shipment.status_changed"],
"is_active": false
}'// Node.js 18+ / דפדפנים — ללא תלויות
const uuid = '9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f'
const response = await fetch(`https://app.shipos.co.il/api/v2/webhooks/${uuid}`, {
method: 'PATCH',
headers: {
'X-Client-Id': process.env.SHIPOS_CLIENT_ID,
'X-Client-Secret': process.env.SHIPOS_CLIENT_SECRET,
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
license_key: '{license_key}',
events: ['shipment.created', 'shipment.status_changed'],
is_active: false,
}),
})
if (!response.ok) {
const { error } = await response.json()
throw new Error(`${error.code}: ${error.message}`)
}
const { data: webhook } = await response.json()
console.log(webhook.id, webhook.is_active, webhook.events.join(', '))<?php
// composer require guzzlehttp/guzzle
$uuid = '9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f';
$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',
],
]);
$response = $client->patch("webhooks/{$uuid}", [
'json' => [
'license_key' => '{license_key}',
'events' => ['shipment.created', 'shipment.status_changed'],
'is_active' => false,
],
]);
$webhook = json_decode($response->getBody()->getContents(), true)['data'];
echo $webhook['id'], ' ', implode(', ', $webhook['events']), PHP_EOL;<?php
use Illuminate\Support\Facades\Http;
$uuid = '9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f';
$webhook = Http::withHeaders([
'X-Client-Id' => config('services.shipos.client_id'),
'X-Client-Secret' => config('services.shipos.client_secret'),
])
->acceptJson()
->patch("https://app.shipos.co.il/api/v2/webhooks/{$uuid}", [
'license_key' => '{license_key}',
'events' => ['shipment.created', 'shipment.status_changed'],
'is_active' => false,
])
->throw()
->json('data');
logger()->info($webhook['id'].' '.implode(', ', $webhook['events']));# pip install httpx
import os
import httpx
uuid = "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f"
response = httpx.patch(
f"https://app.shipos.co.il/api/v2/webhooks/{uuid}",
headers={
"X-Client-Id": os.environ["SHIPOS_CLIENT_ID"],
"X-Client-Secret": os.environ["SHIPOS_CLIENT_SECRET"],
"Accept": "application/json",
},
json={
"license_key": "{license_key}",
"events": ["shipment.created", "shipment.status_changed"],
"is_active": False,
},
)
response.raise_for_status()
webhook = response.json()["data"]
print(webhook["id"], webhook["is_active"], ", ".join(webhook["events"]))package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
func main() {
uuid := "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f"
body, _ := json.Marshal(map[string]any{
"license_key": "{license_key}",
"events": []string{"shipment.created", "shipment.status_changed"},
"is_active": false,
})
req, _ := http.NewRequest("PATCH",
"https://app.shipos.co.il/api/v2/webhooks/"+uuid, 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")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
var payload struct {
Data struct {
ID string `json:"id"`
Events []string `json:"events"`
IsActive bool `json:"is_active"`
} `json:"data"`
}
if err := json.NewDecoder(res.Body).Decode(&payload); err != nil {
panic(err)
}
fmt.Println(payload.Data.ID, payload.Data.IsActive, payload.Data.Events)
}// 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 ShipOsUpdateWebhook {
public static void main(String[] args) throws Exception {
String uuid = "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f";
String body = """
{
"license_key": "{license_key}",
"events": ["shipment.created", "shipment.status_changed"],
"is_active": false
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://app.shipos.co.il/api/v2/webhooks/" + uuid))
.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")
.method("PATCH", HttpRequest.BodyPublishers.ofString(body))
.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
}
}// .NET 8+ — System.Net.Http.Json
using System.Net.Http.Json;
using System.Text.Json;
var uuid = "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f";
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 response = await http.PatchAsJsonAsync($"webhooks/{uuid}", new
{
license_key = "{license_key}",
events = new[] { "shipment.created", "shipment.status_changed" },
is_active = false,
});
response.EnsureSuccessStatusCode();
var payload = await response.Content.ReadFromJsonAsync<JsonDocument>()
?? throw new InvalidOperationException("Empty response");
var webhook = payload.RootElement.GetProperty("data");
Console.WriteLine(
$"{webhook.GetProperty("id").GetString()} {webhook.GetProperty("is_active").GetBoolean()}");require "net/http"
require "json"
uuid = "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f"
uri = URI("https://app.shipos.co.il/api/v2/webhooks/#{uuid}")
request = Net::HTTP::Patch.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.body = JSON.dump(
license_key: "{license_key}",
events: ["shipment.created", "shipment.status_changed"],
is_active: false
)
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)
webhook = JSON.parse(response.body).fetch("data")
puts "#{webhook["id"]} #{webhook["is_active"]} #{webhook["events"].join(", ")}"// [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 uuid = "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f";
let payload: Value = reqwest::Client::new()
.patch(format!("https://app.shipos.co.il/api/v2/webhooks/{uuid}"))
.header("X-Client-Id", std::env::var("SHIPOS_CLIENT_ID")?)
.header("X-Client-Secret", std::env::var("SHIPOS_CLIENT_SECRET")?)
.header("Accept", "application/json")
.json(&json!({
"license_key": "{license_key}",
"events": ["shipment.created", "shipment.status_changed"],
"is_active": false
}))
.send()
.await?
.error_for_status()?
.json()
.await?;
let webhook = &payload["data"];
println!("{} {} {}", webhook["id"], webhook["is_active"], webhook["events"]);
Ok(())
}תגובה 200
{
"data": {
"id": "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f",
"url": "https://example.com/hooks/shipos",
"events": ["shipment.created", "shipment.status_changed"],
"is_active": false,
"created_at": "2026-07-01T09:00:00.000000Z",
"updated_at": "2026-07-29T10:05:00.000000Z"
}
}שגיאות
| סטטוס | קוד | מתי |
|---|---|---|
| 401 | unauthenticated | client credentials חסרים או שגויים. |
| 403 | forbidden | אין רישיון פעיל, או ש-license_key אינו בבעלותכם / אינו פעיל / פג תוקף. |
| 404 | not_found | אין webhook עם ה-uuid הזה השייך לרישיון של הקורא. |
| 422 | validation_failed | url שגוי, events ריק/שגוי, או כמה רישיונות עם license_key שהושמט. |
POST /webhooks/{uuid}/ping
מכניס לתור delivery של אירוע בדיקה ping לכתובת ה-URL של המנוי. שימושי לאימות ה-endpoint שלכם ובדיקת החתימה. אימות: client credentials. רישיון: חובה.
הגוף הנשלח הוא { "event": "ping", "created_at": {timestamp}, "data": { "message": "This is a test event from ShipOS." } }, חתום בדיוק כמו אירוע אמיתי.
פרמטרים
Path
| שדה | סוג | חובה | תיאור |
|---|---|---|---|
uuid | string | כן | ה-id של מנוי ה-webhook (UUID). |
Query / Body
| שדה | סוג | חובה | תיאור |
|---|---|---|---|
license_key | string | מותנה | בוחר את חשבון חברת השילוח (חובה עם כמה רישיונות פעילים). |
בקשה לדוגמה
curl --location --request POST 'https://app.shipos.co.il/api/v2/webhooks/9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f/ping' \
--header 'X-Client-Id: {client_id}' \
--header 'X-Client-Secret: {client_secret}' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{ "license_key": "{license_key}" }'// Node.js 18+ / דפדפנים — ללא תלויות
const uuid = '9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f'
const response = await fetch(
`https://app.shipos.co.il/api/v2/webhooks/${uuid}/ping`,
{
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',
},
body: JSON.stringify({ license_key: '{license_key}' }),
},
)
if (!response.ok) {
const { error } = await response.json()
throw new Error(`${error.code}: ${error.message}`)
}
const { data } = await response.json()
console.log(data.queued) // true — נכנס לתור, לא שהמקבל קיבל אותו<?php
// composer require guzzlehttp/guzzle
$uuid = '9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f';
$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',
],
]);
$response = $client->post("webhooks/{$uuid}/ping", [
'json' => ['license_key' => '{license_key}'],
]);
$data = json_decode($response->getBody()->getContents(), true)['data'];
var_dump($data['queued']);<?php
use Illuminate\Support\Facades\Http;
$uuid = '9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f';
$queued = Http::withHeaders([
'X-Client-Id' => config('services.shipos.client_id'),
'X-Client-Secret' => config('services.shipos.client_secret'),
])
->acceptJson()
->post("https://app.shipos.co.il/api/v2/webhooks/{$uuid}/ping", [
'license_key' => '{license_key}',
])
->throw()
->json('data.queued');
logger()->info('ping queued: '.var_export($queued, true));# pip install httpx
import os
import httpx
uuid = "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f"
response = httpx.post(
f"https://app.shipos.co.il/api/v2/webhooks/{uuid}/ping",
headers={
"X-Client-Id": os.environ["SHIPOS_CLIENT_ID"],
"X-Client-Secret": os.environ["SHIPOS_CLIENT_SECRET"],
"Accept": "application/json",
},
json={"license_key": "{license_key}"},
)
response.raise_for_status()
print(response.json()["data"]["queued"])package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
func main() {
uuid := "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f"
body, _ := json.Marshal(map[string]string{"license_key": "{license_key}"})
req, _ := http.NewRequest("POST",
"https://app.shipos.co.il/api/v2/webhooks/"+uuid+"/ping",
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")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
var payload struct {
Data struct {
Queued bool `json:"queued"`
} `json:"data"`
}
if err := json.NewDecoder(res.Body).Decode(&payload); err != nil {
panic(err)
}
fmt.Println(payload.Data.Queued)
}// 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 ShipOsPingWebhook {
public static void main(String[] args) throws Exception {
String uuid = "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f";
String body = "{\"license_key\": \"{license_key}\"}";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(
"https://app.shipos.co.il/api/v2/webhooks/" + uuid + "/ping"))
.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")
.POST(HttpRequest.BodyPublishers.ofString(body))
.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":{"queued":true}}
}
}// .NET 8+ — System.Net.Http.Json
using System.Net.Http.Json;
using System.Text.Json;
var uuid = "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f";
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 response = await http.PostAsJsonAsync($"webhooks/{uuid}/ping", new
{
license_key = "{license_key}",
});
response.EnsureSuccessStatusCode();
var payload = await response.Content.ReadFromJsonAsync<JsonDocument>()
?? throw new InvalidOperationException("Empty response");
Console.WriteLine(
payload.RootElement.GetProperty("data").GetProperty("queued").GetBoolean());require "net/http"
require "json"
uuid = "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f"
uri = URI("https://app.shipos.co.il/api/v2/webhooks/#{uuid}/ping")
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.body = JSON.dump(license_key: "{license_key}")
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)
puts JSON.parse(response.body).dig("data", "queued")// [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 uuid = "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f";
let payload: Value = reqwest::Client::new()
.post(format!("https://app.shipos.co.il/api/v2/webhooks/{uuid}/ping"))
.header("X-Client-Id", std::env::var("SHIPOS_CLIENT_ID")?)
.header("X-Client-Secret", std::env::var("SHIPOS_CLIENT_SECRET")?)
.header("Accept", "application/json")
.json(&json!({ "license_key": "{license_key}" }))
.send()
.await?
.error_for_status()?
.json()
.await?;
println!("{}", payload["data"]["queued"]);
Ok(())
}תגובה 200
{ "data": { "queued": true } }המשלוח נשלח באופן אסינכרוני; queued: true מאשר שהוא נכנס לתור, לא שהמקבל קיבל אותו. בדקו את GET /webhooks/{uuid}/deliveries לתוצאה.
שגיאות
| סטטוס | קוד | מתי |
|---|---|---|
| 401 | unauthenticated | client credentials חסרים או שגויים. |
| 403 | forbidden | אין רישיון פעיל, או ש-license_key אינו בבעלותכם / אינו פעיל / פג תוקף. |
| 404 | not_found | אין webhook עם ה-uuid הזה השייך לרישיון של הקורא. |
GET /webhooks/{uuid}/deliveries
מציג את ניסיונות ה-delivery של מנוי webhook עם עימוד (החדשים ביותר לפי סדר המאגר). אימות: client credentials. רישיון: חובה.
פרמטרים
Path
| שדה | סוג | חובה | תיאור |
|---|---|---|---|
uuid | string | כן | ה-id של מנוי ה-webhook (UUID). |
Query
| שדה | סוג | חובה | תיאור |
|---|---|---|---|
license_key | string | מותנה | בוחר את חשבון חברת השילוח (חובה עם כמה רישיונות פעילים). |
per_page | int | לא | פריטים לעמוד. ברירת מחדל 25, מקסימום 100. |
בקשה לדוגמה
curl --location 'https://app.shipos.co.il/api/v2/webhooks/9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f/deliveries?license_key={license_key}&per_page=50' \
--header 'X-Client-Id: {client_id}' \
--header 'X-Client-Secret: {client_secret}' \
--header 'Accept: application/json'// Node.js 18+ / דפדפנים — ללא תלויות
const uuid = '9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f'
const url = new URL(
`https://app.shipos.co.il/api/v2/webhooks/${uuid}/deliveries`,
)
url.searchParams.set('license_key', '{license_key}')
url.searchParams.set('per_page', '50')
const response = await fetch(url, {
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: deliveries } = await response.json()
for (const attempt of deliveries) {
console.log(attempt.event, attempt.attempt, attempt.status_code, attempt.success)
}<?php
// composer require guzzlehttp/guzzle
$uuid = '9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f';
$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',
],
]);
$response = $client->get("webhooks/{$uuid}/deliveries", [
'query' => ['license_key' => '{license_key}', 'per_page' => 50],
]);
$deliveries = json_decode($response->getBody()->getContents(), true)['data'];
foreach ($deliveries as $attempt) {
echo $attempt['event'], ' #', $attempt['attempt'], ' ', $attempt['status_code'], PHP_EOL;
}<?php
use Illuminate\Support\Facades\Http;
$uuid = '9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f';
$deliveries = 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/webhooks/{$uuid}/deliveries", [
'license_key' => '{license_key}',
'per_page' => 50,
])
->throw()
->json('data');
foreach ($deliveries as $attempt) {
logger()->info($attempt['event'].' #'.$attempt['attempt'].' '.$attempt['status_code']);
}# pip install httpx
import os
import httpx
uuid = "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f"
response = httpx.get(
f"https://app.shipos.co.il/api/v2/webhooks/{uuid}/deliveries",
params={"license_key": "{license_key}", "per_page": 50},
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 attempt in response.json()["data"]:
print(attempt["event"], attempt["attempt"], attempt["status_code"], attempt["success"])package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
)
type deliveryList struct {
Data []struct {
Event string `json:"event"`
Attempt int `json:"attempt"`
StatusCode *int `json:"status_code"`
Success bool `json:"success"`
} `json:"data"`
}
func main() {
uuid := "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f"
req, _ := http.NewRequest("GET",
"https://app.shipos.co.il/api/v2/webhooks/"+uuid+
"/deliveries?license_key={license_key}&per_page=50", 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 list deliveryList
if err := json.NewDecoder(res.Body).Decode(&list); err != nil {
panic(err)
}
for _, attempt := range list.Data {
fmt.Println(attempt.Event, attempt.Attempt, attempt.Success)
}
}// 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 ShipOsWebhookDeliveries {
public static void main(String[] args) throws Exception {
String uuid = "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://app.shipos.co.il/api/v2/webhooks/" + uuid
+ "/deliveries?license_key={license_key}&per_page=50"))
.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
}
}// .NET 8+ — System.Net.Http.Json
using System.Net.Http.Json;
using System.Text.Json;
var uuid = "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f";
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>(
$"webhooks/{uuid}/deliveries?license_key={{license_key}}&per_page=50")
?? throw new InvalidOperationException("Empty response");
foreach (var attempt in payload.RootElement.GetProperty("data").EnumerateArray())
{
Console.WriteLine(
$"{attempt.GetProperty("event").GetString()} #{attempt.GetProperty("attempt").GetInt32()} {attempt.GetProperty("success").GetBoolean()}");
}require "net/http"
require "json"
uuid = "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f"
uri = URI("https://app.shipos.co.il/api/v2/webhooks/#{uuid}/deliveries")
uri.query = URI.encode_www_form(license_key: "{license_key}", per_page: 50)
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 |attempt|
puts "#{attempt["event"]} ##{attempt["attempt"]} #{attempt["status_code"]} #{attempt["success"]}"
end// [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 = "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f";
let payload: Value = reqwest::Client::new()
.get(format!("https://app.shipos.co.il/api/v2/webhooks/{uuid}/deliveries"))
.query(&[("license_key", "{license_key}"), ("per_page", "50")])
.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?;
for attempt in payload["data"].as_array().unwrap_or(&Vec::new()) {
println!("{} {} {}", attempt["event"], attempt["attempt"], attempt["success"]);
}
Ok(())
}תגובה 200
{
"data": [
{
"id": 4821,
"event": "shipment.created",
"attempt": 1,
"status_code": 200,
"success": true,
"error": null,
"created_at": "2026-07-29T10:00:01.000000Z",
"updated_at": "2026-07-29T10:00:01.000000Z"
},
{
"id": 4822,
"event": "shipment.delivered",
"attempt": 2,
"status_code": 500,
"success": false,
"error": "HTTP 500",
"created_at": "2026-07-29T11:00:31.000000Z",
"updated_at": "2026-07-29T11:00:31.000000Z"
}
],
"links": { "first": "...", "last": "...", "prev": null, "next": "..." },
"meta": { "current_page": 1, "per_page": 50, "total": 2 }
}שדות delivery
| שדה | סוג | תיאור |
|---|---|---|
id | int | מזהה ניסיון ה-delivery. |
event | string | שם האירוע שנשלח (כולל ping). |
attempt | int | מספר הניסיון (ניסיונות חוזרים מגדילים אותו). |
status_code | int | null | סטטוס HTTP שהוחזר על ידי ה-endpoint שלכם, או null בכשל תעבורה. |
success | bool | האם הניסיון הצליח (2xx). |
error | string | null | סיבת הכשל (למשל HTTP 500 או הודעת חריגה), או null בהצלחה. |
created_at | string | חותמת זמן של הניסיון. |
updated_at | string | חותמת זמן עדכון הרשומה. |
links/meta של עימוד Laravel סטנדרטי מצורפים לאוסף.
שגיאות
| סטטוס | קוד | מתי |
|---|---|---|
| 401 | unauthenticated | client credentials חסרים או שגויים. |
| 403 | forbidden | אין רישיון פעיל, או ש-license_key אינו בבעלותכם / אינו פעיל / פג תוקף. |
| 404 | not_found | אין webhook עם ה-uuid הזה השייך לרישיון של הקורא. |
DELETE /webhooks/
מוחק מנוי webhook שבבעלות הרישיון של הקורא. אימות: client credentials. רישיון: חובה.
פרמטרים
Path
| שדה | סוג | חובה | תיאור |
|---|---|---|---|
uuid | string | כן | ה-id של מנוי ה-webhook (UUID). |
Query / Body
| שדה | סוג | חובה | תיאור |
|---|---|---|---|
license_key | string | מותנה | בוחר את חשבון חברת השילוח (חובה עם כמה רישיונות פעילים). |
בקשה לדוגמה
curl --location --request DELETE 'https://app.shipos.co.il/api/v2/webhooks/9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f?license_key={license_key}' \
--header 'X-Client-Id: {client_id}' \
--header 'X-Client-Secret: {client_secret}' \
--header 'Accept: application/json'// Node.js 18+ / דפדפנים — ללא תלויות
const uuid = '9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f'
const url = new URL(`https://app.shipos.co.il/api/v2/webhooks/${uuid}`)
url.searchParams.set('license_key', '{license_key}')
const response = await fetch(url, {
method: 'DELETE',
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 } = await response.json()
console.log(data.deleted) // true — 200, לא 204<?php
// composer require guzzlehttp/guzzle
$uuid = '9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f';
$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',
],
]);
$response = $client->delete("webhooks/{$uuid}", [
'query' => ['license_key' => '{license_key}'],
]);
$data = json_decode($response->getBody()->getContents(), true)['data'];
var_dump($data['deleted']);<?php
use Illuminate\Support\Facades\Http;
$uuid = '9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f';
$deleted = Http::withHeaders([
'X-Client-Id' => config('services.shipos.client_id'),
'X-Client-Secret' => config('services.shipos.client_secret'),
])
->acceptJson()
->delete("https://app.shipos.co.il/api/v2/webhooks/{$uuid}?license_key={license_key}")
->throw()
->json('data.deleted');
logger()->info('deleted: '.var_export($deleted, true));# pip install httpx
import os
import httpx
uuid = "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f"
response = httpx.request(
"DELETE",
f"https://app.shipos.co.il/api/v2/webhooks/{uuid}",
params={"license_key": "{license_key}"},
headers={
"X-Client-Id": os.environ["SHIPOS_CLIENT_ID"],
"X-Client-Secret": os.environ["SHIPOS_CLIENT_SECRET"],
"Accept": "application/json",
},
)
response.raise_for_status()
print(response.json()["data"]["deleted"])package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
)
func main() {
uuid := "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f"
req, _ := http.NewRequest("DELETE",
"https://app.shipos.co.il/api/v2/webhooks/"+uuid+
"?license_key={license_key}", 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 struct {
Data struct {
Deleted bool `json:"deleted"`
} `json:"data"`
}
if err := json.NewDecoder(res.Body).Decode(&payload); err != nil {
panic(err)
}
fmt.Println(payload.Data.Deleted)
}// 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 ShipOsDeleteWebhook {
public static void main(String[] args) throws Exception {
String uuid = "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://app.shipos.co.il/api/v2/webhooks/" + uuid
+ "?license_key={license_key}"))
.header("X-Client-Id", System.getenv("SHIPOS_CLIENT_ID"))
.header("X-Client-Secret", System.getenv("SHIPOS_CLIENT_SECRET"))
.header("Accept", "application/json")
.DELETE()
.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":{"deleted":true}}
}
}// .NET 8+ — System.Net.Http.Json
using System.Net.Http.Json;
using System.Text.Json;
var uuid = "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f";
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 response = await http.DeleteAsync(
$"webhooks/{uuid}?license_key={{license_key}}");
response.EnsureSuccessStatusCode();
var payload = await response.Content.ReadFromJsonAsync<JsonDocument>()
?? throw new InvalidOperationException("Empty response");
Console.WriteLine(
payload.RootElement.GetProperty("data").GetProperty("deleted").GetBoolean());require "net/http"
require "json"
uuid = "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f"
uri = URI("https://app.shipos.co.il/api/v2/webhooks/#{uuid}")
uri.query = URI.encode_www_form(license_key: "{license_key}")
request = Net::HTTP::Delete.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)
puts JSON.parse(response.body).dig("data", "deleted")// [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 = "9f2c1a7e-6b4d-4c2a-8e1f-7d3b2a1c0e9f";
let payload: Value = reqwest::Client::new()
.delete(format!("https://app.shipos.co.il/api/v2/webhooks/{uuid}"))
.query(&[("license_key", "{license_key}")])
.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?;
println!("{}", payload["data"]["deleted"]);
Ok(())
}תגובה 200
מחיקה מחזירה אישור JSON עם סטטוס 200 (לא 204):
{ "data": { "deleted": true } }שגיאות
| סטטוס | קוד | מתי |
|---|---|---|
| 401 | unauthenticated | client credentials חסרים או שגויים. |
| 403 | forbidden | אין רישיון פעיל, או ש-license_key אינו בבעלותכם / אינו פעיל / פג תוקף. |
| 404 | not_found | אין webhook עם ה-uuid הזה השייך לרישיון של הקורא. |