Skip to content

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-Signaturet={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_keystringמותנהה-licenses.key שבוחר את חשבון חברת השילוח. חובה כאשר לחשבון יש יותר מרישיון פעיל אחד.

בקשה לדוגמה

bash
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'
js
// 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
<?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
<?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']));
}
python
# 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"]))
go
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
// 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
    }
}
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>(
    "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()}");
}
ruby
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
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/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

json
{
  "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 לחתימה אינו נכלל ברשימה — הוא מוחזר פעם אחת בלבד, בעת היצירה.

שגיאות

סטטוסקודמתי
401unauthenticatedclient credentials חסרים או שגויים.
403forbiddenלחשבון אין רישיון פעיל, או שה-license_key שסופק אינו בבעלותכם / אינו פעיל / פג תוקף.
422validation_failedלחשבון כמה רישיונות פעילים ו-license_key הושמט.

POST /webhooks

יוצר מנוי webhook ומחזיר אותו יחד עם סוד החתימה החד-פעמי שלו. אימות: client credentials. רישיון: חובה.

פרמטרים

Body

שדהסוגחובהתיאור
license_keystringמותנהה-licenses.key שבוחר את חשבון חברת השילוח (חובה כאשר לחשבון יש יותר מרישיון פעיל אחד).
urlstring (URL)כןכתובת היעד שמקבלת את ה-POST החתום. עד 2048 תווים.
eventsstring[]כןלפחות אירוע אחד להירשם אליו. כל אחד חייב להיות אחד מהאירועים הזמינים למנוי.
events.*stringכןערך אירוע בודד.

סוד החתימה נוצר בצד השרת (whsec_ + 40 תווים אקראיים); לא ניתן לספק אותו מצד הלקוח.

בקשה לדוגמה

bash
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"]
}'
js
// 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
<?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
<?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']);
python
# 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"])
go
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
// 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" החד-פעמי
    }
}
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 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()}");
ruby
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"]}"
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: 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

json
{
  "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.

שגיאות

סטטוסקודמתי
401unauthenticatedclient credentials חסרים או שגויים.
403forbiddenאין רישיון פעיל, או שה-license_key שסופק אינו בבעלותכם / אינו פעיל / פג תוקף.
422validation_failedurl חסר/שגוי/ארוך מדי, events ריק או מכיל אירוע לא מוכר, או כמה רישיונות עם license_key שהושמט.

PATCH /webhooks/

מעדכן מנוי webhook שבבעלות הרישיון של הקורא. סמנטיקה חלקית (PATCH) — שלחו רק את השדות שברצונכם לשנות. אימות: client credentials. רישיון: חובה.

פרמטרים

Path

שדהסוגחובהתיאור
uuidstringכןה-id של מנוי ה-webhook (UUID).

Body (הכול אופציונלי; סוד החתימה לעולם לא ניתן לשינוי)

שדהסוגחובהתיאור
license_keystringמותנהבוחר את חשבון חברת השילוח (חובה עם כמה רישיונות פעילים).
urlstring (URL)לאכתובת יעד חדשה. עד 2048 תווים.
eventsstring[]לאסט אירועים חלופי (מינימום 1, ללא כפילויות). כל אחד חייב להיות ערך אירוע תקין.
events.*stringחובה עם eventsערך אירוע בודד.
is_activebooleanלאהפעלה או השבתה של המנוי.

בקשה לדוגמה

bash
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
}'
js
// 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
<?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
<?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']));
python
# 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"]))
go
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
// 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
    }
}
csharp
// .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()}");
ruby
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(", ")}"
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 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

json
{
  "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"
  }
}

שגיאות

סטטוסקודמתי
401unauthenticatedclient credentials חסרים או שגויים.
403forbiddenאין רישיון פעיל, או ש-license_key אינו בבעלותכם / אינו פעיל / פג תוקף.
404not_foundאין webhook עם ה-uuid הזה השייך לרישיון של הקורא.
422validation_failedurl שגוי, 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

שדהסוגחובהתיאור
uuidstringכןה-id של מנוי ה-webhook (UUID).

Query / Body

שדהסוגחובהתיאור
license_keystringמותנהבוחר את חשבון חברת השילוח (חובה עם כמה רישיונות פעילים).

בקשה לדוגמה

bash
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}" }'
js
// 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
<?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
<?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));
python
# 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"])
go
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
// 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}}
    }
}
csharp
// .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());
ruby
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")
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 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

json
{ "data": { "queued": true } }

המשלוח נשלח באופן אסינכרוני; queued: true מאשר שהוא נכנס לתור, לא שהמקבל קיבל אותו. בדקו את GET /webhooks/{uuid}/deliveries לתוצאה.

שגיאות

סטטוסקודמתי
401unauthenticatedclient credentials חסרים או שגויים.
403forbiddenאין רישיון פעיל, או ש-license_key אינו בבעלותכם / אינו פעיל / פג תוקף.
404not_foundאין webhook עם ה-uuid הזה השייך לרישיון של הקורא.

GET /webhooks/{uuid}/deliveries

מציג את ניסיונות ה-delivery של מנוי webhook עם עימוד (החדשים ביותר לפי סדר המאגר). אימות: client credentials. רישיון: חובה.

פרמטרים

Path

שדהסוגחובהתיאור
uuidstringכןה-id של מנוי ה-webhook (UUID).

Query

שדהסוגחובהתיאור
license_keystringמותנהבוחר את חשבון חברת השילוח (חובה עם כמה רישיונות פעילים).
per_pageintלאפריטים לעמוד. ברירת מחדל 25, מקסימום 100.

בקשה לדוגמה

bash
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'
js
// 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
<?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
<?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']);
}
python
# 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"])
go
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
// 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
    }
}
csharp
// .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()}");
}
ruby
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
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 = "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

json
{
  "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

שדהסוגתיאור
idintמזהה ניסיון ה-delivery.
eventstringשם האירוע שנשלח (כולל ping).
attemptintמספר הניסיון (ניסיונות חוזרים מגדילים אותו).
status_codeint | nullסטטוס HTTP שהוחזר על ידי ה-endpoint שלכם, או null בכשל תעבורה.
successboolהאם הניסיון הצליח (2xx).
errorstring | nullסיבת הכשל (למשל HTTP 500 או הודעת חריגה), או null בהצלחה.
created_atstringחותמת זמן של הניסיון.
updated_atstringחותמת זמן עדכון הרשומה.

links/meta של עימוד Laravel סטנדרטי מצורפים לאוסף.

שגיאות

סטטוסקודמתי
401unauthenticatedclient credentials חסרים או שגויים.
403forbiddenאין רישיון פעיל, או ש-license_key אינו בבעלותכם / אינו פעיל / פג תוקף.
404not_foundאין webhook עם ה-uuid הזה השייך לרישיון של הקורא.

DELETE /webhooks/

מוחק מנוי webhook שבבעלות הרישיון של הקורא. אימות: client credentials. רישיון: חובה.

פרמטרים

Path

שדהסוגחובהתיאור
uuidstringכןה-id של מנוי ה-webhook (UUID).

Query / Body

שדהסוגחובהתיאור
license_keystringמותנהבוחר את חשבון חברת השילוח (חובה עם כמה רישיונות פעילים).

בקשה לדוגמה

bash
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'
js
// 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
<?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
<?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));
python
# 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"])
go
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
// 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}}
    }
}
csharp
// .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());
ruby
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")
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 = "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):

json
{ "data": { "deleted": true } }

שגיאות

סטטוסקודמתי
401unauthenticatedclient credentials חסרים או שגויים.
403forbiddenאין רישיון פעיל, או ש-license_key אינו בבעלותכם / אינו פעיל / פג תוקף.
404not_foundאין webhook עם ה-uuid הזה השייך לרישיון של הקורא.