התראות SMS
הגדרת SMS ללקוחות: הגדרת הספק, אימות באמצעות שליחת בדיקה, הגדרת תבניות הודעה לפי שיטת משלוח, וביקורת של מה שנשלח בפועל. פרטי ה-endpoints נמצאים במסמך ההתראות.
ברמת חשבון לקוח — ללא license_key
בניגוד למשלוחים ול-webhooks, ה-endpoints של ההתראות פועלים על חשבון הסוחר שמאחורי ה-client credentials שלכם ומכסים את כל המשלוחים שלו בכל הרישיונות. הם אינם קוראים license_key.
שלב 1 — קריאת ההגדרות הנוכחיות
curl --location 'https://app.shipos.co.il/api/v2/notifications/sms-settings' \
--header 'X-Client-Id: {client_id}' \
--header 'X-Client-Secret: {client_secret}' \
--header 'Accept: application/json'// Node.js 18+ / דפדפנים — ללא תלויות
const response = await fetch('https://app.shipos.co.il/api/v2/notifications/sms-settings', {
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: settings } = await response.json()
console.log(settings.username, settings.has_token, settings.configured)<?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',
],
]);
$settings = json_decode(
$client->get('notifications/sms-settings')->getBody()->getContents(),
true,
)['data'];
echo $settings['configured'] ? 'sending is set up' : 'not configured', PHP_EOL;<?php
use Illuminate\Support\Facades\Http;
$settings = 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/notifications/sms-settings')
->throw()
->json('data');
logger()->info($settings['configured'] ? 'sending is set up' : 'not configured');# pip install httpx
import os
import httpx
response = httpx.get(
"https://app.shipos.co.il/api/v2/notifications/sms-settings",
headers={
"X-Client-Id": os.environ["SHIPOS_CLIENT_ID"],
"X-Client-Secret": os.environ["SHIPOS_CLIENT_SECRET"],
"Accept": "application/json",
},
)
response.raise_for_status()
settings = response.json()["data"]
print(settings["username"], settings["has_token"], settings["configured"])package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
)
type smsSettingsResponse struct {
Data struct {
Username string `json:"username"`
HasToken bool `json:"has_token"`
Configured bool `json:"configured"`
} `json:"data"`
}
func main() {
req, _ := http.NewRequest("GET",
"https://app.shipos.co.il/api/v2/notifications/sms-settings", 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 smsSettingsResponse
if err := json.NewDecoder(res.Body).Decode(&payload); err != nil {
panic(err)
}
fmt.Println(payload.Data.Username, payload.Data.HasToken, payload.Data.Configured)
}// 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 ShipOsSmsSettings {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://app.shipos.co.il/api/v2/notifications/sms-settings"))
.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":{"configured":true,...}}
}
}// .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>("notifications/sms-settings")
?? throw new InvalidOperationException("Empty response");
var settings = payload.RootElement.GetProperty("data");
Console.WriteLine(settings.GetProperty("username").GetString());
Console.WriteLine(settings.GetProperty("configured").GetBoolean());require "net/http"
require "json"
uri = URI("https://app.shipos.co.il/api/v2/notifications/sms-settings")
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)
settings = JSON.parse(response.body).fetch("data")
puts "#{settings["username"]} has_token=#{settings["has_token"]} configured=#{settings["configured"]}"// [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/notifications/sms-settings")
.header("X-Client-Id", std::env::var("SHIPOS_CLIENT_ID")?)
.header("X-Client-Secret", std::env::var("SHIPOS_CLIENT_SECRET")?)
.header("Accept", "application/json")
.send()
.await?
.error_for_status()?
.json()
.await?;
let settings = &payload["data"];
println!("{} configured={}", settings["username"], settings["configured"]);
Ok(())
}ההגדרות הן singleton — הקריאה תמיד מחזירה 200, גם לפני שהוגדר משהו:
{
"data": {
"id": 42,
"username": "shipos_store",
"sender_name": "MyStore",
"has_token": true,
"configured": true,
"created_at": "2026-01-01T00:00:00.000000Z",
"updated_at": "2026-07-20T12:30:00.000000Z"
}
}שימו לב לשני הדגלים הבוליאניים: ה-token של הספק הוא write-only ולעולם אינו מוחזר. has_token אומר לכם ש-token מאוחסן; configured הוא true רק כאשר גם username וגם token קיימים — כלומר השליחה באמת מוגדרת.
שלב 2 — הפעלה או עדכון של הספק
בצעו PUT של ההגדרות המלאות. כל שלושת השדות נדרשים בכל עדכון (זו החלפה מלאה, לא patch):
curl --location --request PUT 'https://app.shipos.co.il/api/v2/notifications/sms-settings' \
--header 'X-Client-Id: {client_id}' \
--header 'X-Client-Secret: {client_secret}' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"username": "shipos_store",
"token": "provider-api-token-value",
"sender_name": "MyStore"
}'const res = await fetch('https://app.shipos.co.il/api/v2/notifications/sms-settings', {
method: 'PUT',
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({
username: 'shipos_store',
token: 'provider-api-token-value', // לכתיבה בלבד: נשמר, לעולם לא מוחזר
sender_name: 'MyStore',
}),
});
const { data } = await res.json();
console.log(data.configured); // true כאשר השליחה מוגדרת<?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->put('notifications/sms-settings', [
'json' => [
'username' => 'shipos_store',
'token' => 'provider-api-token-value', // לכתיבה בלבד: נשמר, לעולם לא מוחזר
'sender_name' => 'MyStore',
],
]);
$settings = json_decode($response->getBody()->getContents(), true)['data'];
$configured = $settings['configured']; // true כאשר השליחה מוגדרת<?php
use Illuminate\Support\Facades\Http;
$response = Http::withHeaders([
'X-Client-Id' => config('services.shipos.client_id'),
'X-Client-Secret' => config('services.shipos.client_secret'),
])
->acceptJson()
->put('https://app.shipos.co.il/api/v2/notifications/sms-settings', [
'username' => 'shipos_store',
'token' => 'provider-api-token-value', // לכתיבה בלבד: נשמר, לעולם לא מוחזר
'sender_name' => 'MyStore',
])
->throw();
$configured = $response->json('data.configured'); // true כאשר השליחה מוגדרת# pip install httpx
import os
import httpx
response = httpx.put(
"https://app.shipos.co.il/api/v2/notifications/sms-settings",
headers={
"X-Client-Id": os.environ["SHIPOS_CLIENT_ID"],
"X-Client-Secret": os.environ["SHIPOS_CLIENT_SECRET"],
"Accept": "application/json",
},
json={
"username": "shipos_store",
"token": "provider-api-token-value", # לכתיבה בלבד: נשמר, לעולם לא מוחזר
"sender_name": "MyStore",
},
)
response.raise_for_status()
print(response.json()["data"]["configured"]) # True כאשר השליחה מוגדרתpackage main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
func main() {
body, _ := json.Marshal(map[string]string{
"username": "shipos_store",
"token": "provider-api-token-value", // לכתיבה בלבד: נשמר, לעולם לא מוחזר
"sender_name": "MyStore",
})
req, _ := http.NewRequest("PUT",
"https://app.shipos.co.il/api/v2/notifications/sms-settings", 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 {
Configured bool `json:"configured"`
} `json:"data"`
}
if err := json.NewDecoder(res.Body).Decode(&payload); err != nil {
panic(err)
}
fmt.Println(payload.Data.Configured) // true כאשר השליחה מוגדרת
}// Java 17+ — java.net.http, ללא תלויות
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class ShipOsUpdateSmsSettings {
public static void main(String[] args) throws Exception {
// ה-token הוא לכתיבה בלבד: נשמר, לעולם לא מוחזר
String body = """
{"username":"shipos_store","token":"provider-api-token-value","sender_name":"MyStore"}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://app.shipos.co.il/api/v2/notifications/sms-settings"))
.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")
.PUT(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body()); // {"data":{"configured":true,...}}
}
}// .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.PutAsJsonAsync("notifications/sms-settings", new
{
username = "shipos_store",
token = "provider-api-token-value", // לכתיבה בלבד: נשמר, לעולם לא מוחזר
sender_name = "MyStore",
});
response.EnsureSuccessStatusCode();
var payload = await response.Content.ReadFromJsonAsync<JsonDocument>();
Console.WriteLine(payload!.RootElement.GetProperty("data")
.GetProperty("configured").GetBoolean()); // true כאשר השליחה מוגדרתrequire "net/http"
require "json"
uri = URI("https://app.shipos.co.il/api/v2/notifications/sms-settings")
request = Net::HTTP::Put.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(
username: "shipos_store",
token: "provider-api-token-value", # לכתיבה בלבד: נשמר, לעולם לא מוחזר
sender_name: "MyStore",
)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body).dig("data", "configured") # true כאשר השליחה מוגדרת// [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()
.put("https://app.shipos.co.il/api/v2/notifications/sms-settings")
.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!({
"username": "shipos_store",
// לכתיבה בלבד: נשמר, לעולם לא מוחזר
"token": "provider-api-token-value",
"sender_name": "MyStore"
}))
.send()
.await?
.error_for_status()?
.json()
.await?;
println!("{}", payload["data"]["configured"]); // true כאשר השליחה מוגדרת
Ok(())
}| שדה body | חובה | הערות |
|---|---|---|
username | כן | שם המשתמש בחשבון הספק. עד 255 תווים. |
token | כן | token של ה-API של הספק. Write-only — התגובה משקפת אותו רק דרך has_token / configured. |
sender_name | כן | שם השולח המוצג לנמעני ה-SMS. עד 255 תווים. |
התגובה היא ה-singleton המעודכן (200), באותו מבנה כמו שלב 1.
שלב 3 — שליחת SMS בדיקה
ודאו שפרטי ההתחברות באמת עובדים על ידי שליחת הודעה חד-פעמית דרך הספק המוגדר:
curl --location 'https://app.shipos.co.il/api/v2/notifications/test-sms' \
--header 'X-Client-Id: {client_id}' \
--header 'X-Client-Secret: {client_secret}' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"phone": "0501234567",
"message": "הודעת בדיקה של ShipOS"
}'// Node.js 18+ / דפדפנים — ללא תלויות
const res = await fetch('https://app.shipos.co.il/api/v2/notifications/test-sms', {
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({
phone: '0501234567',
message: 'הודעת בדיקה של ShipOS',
}),
})
// גם 424 מחזיר payload של `data` — הסתעפו לפי data.sent, לא לפי `error`
const { data } = await res.json()
console.log(data.sent, data.provider_status, data.message)<?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',
],
'http_errors' => false, // דחייה של הספק היא 424 עם payload של data
]);
$result = json_decode($client->post('notifications/test-sms', [
'json' => [
'phone' => '0501234567',
'message' => 'הודעת בדיקה של ShipOS',
],
])->getBody()->getContents(), true)['data'];
echo $result['sent'] ? 'sent' : 'provider said no: '.$result['provider_status'], PHP_EOL;<?php
use Illuminate\Support\Facades\Http;
$result = 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/notifications/test-sms', [
'phone' => '0501234567',
'message' => 'הודעת בדיקה של ShipOS',
])
->json('data'); // בלי ->throw(): 424 נושא payload של data, לא מעטפת שגיאה
logger()->info($result['sent'] ? 'sent' : 'provider said no', $result);# pip install httpx
import os
import httpx
response = httpx.post(
"https://app.shipos.co.il/api/v2/notifications/test-sms",
headers={
"X-Client-Id": os.environ["SHIPOS_CLIENT_ID"],
"X-Client-Secret": os.environ["SHIPOS_CLIENT_SECRET"],
"Accept": "application/json",
},
json={"phone": "0501234567", "message": "הודעת בדיקה של ShipOS"},
)
# גם 424 מחזיר payload של data — הסתעפו לפי data["sent"]
result = response.json()["data"]
print(result["sent"], result["provider_status"], result["message"])package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
func main() {
body, _ := json.Marshal(map[string]string{
"phone": "0501234567",
"message": "הודעת בדיקה של ShipOS",
})
req, _ := http.NewRequest("POST",
"https://app.shipos.co.il/api/v2/notifications/test-sms", 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()
// גם 200 וגם 424 נושאים payload של data — הסתעפו לפי Sent
var payload struct {
Data struct {
Sent bool `json:"sent"`
ProviderStatus string `json:"provider_status"`
Message string `json:"message"`
} `json:"data"`
}
if err := json.NewDecoder(res.Body).Decode(&payload); err != nil {
panic(err)
}
fmt.Println(payload.Data.Sent, payload.Data.ProviderStatus, payload.Data.Message)
}// Java 17+ — java.net.http, ללא תלויות
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class ShipOsTestSms {
public static void main(String[] args) throws Exception {
String body = """
{"phone":"0501234567","message":"הודעת בדיקה של ShipOS"}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://app.shipos.co.il/api/v2/notifications/test-sms"))
.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());
// 424 = דחייה של הספק, עדיין payload של data — בדקו את data.sent
System.out.println(response.statusCode() + " " + response.body());
}
}// .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("notifications/test-sms", new
{
phone = "0501234567",
message = "הודעת בדיקה של ShipOS",
});
// גם 424 מחזיר payload של data — הסתעפו לפי data.sent, לא לפי מפתח error
var payload = await response.Content.ReadFromJsonAsync<JsonDocument>();
var result = payload!.RootElement.GetProperty("data");
Console.WriteLine($"{result.GetProperty("sent").GetBoolean()} " +
$"{result.GetProperty("provider_status").GetString()}");require "net/http"
require "json"
uri = URI("https://app.shipos.co.il/api/v2/notifications/test-sms")
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(phone: "0501234567", message: "הודעת בדיקה של ShipOS")
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
# גם 424 מחזיר payload של data — הסתעפו לפי data["sent"]
result = JSON.parse(response.body).fetch("data")
puts "#{result["sent"]} #{result["provider_status"]} #{result["message"]}"// [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>> {
// בלי error_for_status(): דחייה של הספק ב-424 עדיין נושאת payload של data
let payload: Value = reqwest::Client::new()
.post("https://app.shipos.co.il/api/v2/notifications/test-sms")
.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!({ "phone": "0501234567", "message": "הודעת בדיקה של ShipOS" }))
.send()
.await?
.json()
.await?;
let result = &payload["data"];
println!("{} {}", result["sent"], result["provider_status"]);
Ok(())
}phone (עד 20 תווים) ו-message (עד 1000 תווים) שניהם חובה.
בהצלחה תקבלו 200:
{
"data": {
"sent": true,
"provider_status": "OK",
"message": "..."
}
}דחייה של הספק היא 424 עם payload של data
כאשר ספק ה-SMS מסרב לשליחה (token שגוי, שם שולח חסום, יעד לא תקין), סטטוס התגובה הוא 424 — אבל הגוף הוא עדיין payload של data (sent: false בתוספת provider_status / message של הספק), לא מעטפת { "error": ... }. זה מבחין במכוון בין "ניסינו, הספק סירב" לבין שגיאת בקשה בצד שלכם. הסתעפו לפי סטטוס ה-HTTP או לפי data.sent, לא לפי קיומו של מפתח error. ראו את מדריך השגיאות למעטפת הרגילה.
שלב 4 — ניהול תבניות
תבניות מגדירות את ההודעה שנשלחת לפי שיטת משלוח. הציגו את מה שקיים:
curl --location 'https://app.shipos.co.il/api/v2/notifications/sms-templates' \
--header 'X-Client-Id: {client_id}' \
--header 'X-Client-Secret: {client_secret}' \
--header 'Accept: application/json'// Node.js 18+ / דפדפנים — ללא תלויות
const response = await fetch('https://app.shipos.co.il/api/v2/notifications/sms-templates', {
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: templates } = await response.json()
for (const template of templates) {
console.log(template.id, template.shipping_method, template.active)
}<?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',
],
]);
$templates = json_decode(
$client->get('notifications/sms-templates')->getBody()->getContents(),
true,
)['data'];
foreach ($templates as $template) {
echo $template['id'], ' ', $template['shipping_method'], PHP_EOL;
}<?php
use Illuminate\Support\Facades\Http;
$templates = 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/notifications/sms-templates')
->throw()
->json('data');
foreach ($templates as $template) {
logger()->info($template['shipping_method'].' → '.$template['message']);
}# pip install httpx
import os
import httpx
response = httpx.get(
"https://app.shipos.co.il/api/v2/notifications/sms-templates",
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 template in response.json()["data"]:
print(template["id"], template["shipping_method"], template["active"])package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
)
type smsTemplatesResponse struct {
Data []struct {
ID int `json:"id"`
ShippingMethod string `json:"shipping_method"`
Active bool `json:"active"`
} `json:"data"`
}
func main() {
req, _ := http.NewRequest("GET",
"https://app.shipos.co.il/api/v2/notifications/sms-templates", 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 smsTemplatesResponse
if err := json.NewDecoder(res.Body).Decode(&payload); err != nil {
panic(err)
}
for _, template := range payload.Data {
fmt.Println(template.ID, template.ShippingMethod, template.Active)
}
}// 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 ShipOsListSmsTemplates {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://app.shipos.co.il/api/v2/notifications/sms-templates"))
.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":[{"id":7,...}]}
}
}// .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>("notifications/sms-templates")
?? throw new InvalidOperationException("Empty response");
foreach (var template in payload.RootElement.GetProperty("data").EnumerateArray())
{
Console.WriteLine($"{template.GetProperty("id").GetInt32()} " +
$"{template.GetProperty("shipping_method").GetString()}");
}require "net/http"
require "json"
uri = URI("https://app.shipos.co.il/api/v2/notifications/sms-templates")
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 |template|
puts "#{template["id"]} #{template["shipping_method"]} active=#{template["active"]}"
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/notifications/sms-templates")
.header("X-Client-Id", std::env::var("SHIPOS_CLIENT_ID")?)
.header("X-Client-Secret", std::env::var("SHIPOS_CLIENT_SECRET")?)
.header("Accept", "application/json")
.send()
.await?
.error_for_status()?
.json()
.await?;
if let Some(templates) = payload["data"].as_array() {
for template in templates {
println!("{} {}", template["id"], template["shipping_method"]);
}
}
Ok(())
}צרו (או עדכנו — ה-API מבצע upsert לפי שיטת משלוח) תבנית. Body: shipping_method (string, עד 64) ו-message (string, עד 1000):
curl --location 'https://app.shipos.co.il/api/v2/notifications/sms-templates' \
--header 'X-Client-Id: {client_id}' \
--header 'X-Client-Secret: {client_secret}' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"shipping_method": "hfd",
"message": "ההזמנה שלך בדרך! ניתן לעקוב כאן: {tracking_url}"
}'const res = await fetch('https://app.shipos.co.il/api/v2/notifications/sms-templates', {
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({
shipping_method: 'hfd',
message: 'ההזמנה שלך בדרך! ניתן לעקוב כאן: {tracking_url}',
}),
});
const { data } = await res.json();
const templateId = data.id; // id מספרי — בשימוש בכתובות ה-toggle/delete<?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('notifications/sms-templates', [
'json' => [
'shipping_method' => 'hfd',
'message' => 'ההזמנה שלך בדרך! ניתן לעקוב כאן: {tracking_url}',
],
]);
$template = json_decode($response->getBody()->getContents(), true)['data'];
$templateId = $template['id']; // id מספרי — בשימוש בכתובות ה-toggle/delete<?php
use Illuminate\Support\Facades\Http;
$template = 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/notifications/sms-templates', [
'shipping_method' => 'hfd',
'message' => 'ההזמנה שלך בדרך! ניתן לעקוב כאן: {tracking_url}',
])
->throw()
->json('data');
$templateId = $template['id']; // id מספרי — בשימוש בכתובות ה-toggle/delete# pip install httpx
import os
import httpx
response = httpx.post(
"https://app.shipos.co.il/api/v2/notifications/sms-templates",
headers={
"X-Client-Id": os.environ["SHIPOS_CLIENT_ID"],
"X-Client-Secret": os.environ["SHIPOS_CLIENT_SECRET"],
"Accept": "application/json",
},
json={
"shipping_method": "hfd",
"message": "ההזמנה שלך בדרך! ניתן לעקוב כאן: {tracking_url}",
},
)
response.raise_for_status()
template_id = response.json()["data"]["id"] # id מספרי — בשימוש בכתובות ה-toggle/deletepackage main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
func main() {
body, _ := json.Marshal(map[string]string{
"shipping_method": "hfd",
"message": "ההזמנה שלך בדרך! ניתן לעקוב כאן: {tracking_url}",
})
req, _ := http.NewRequest("POST",
"https://app.shipos.co.il/api/v2/notifications/sms-templates", 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 int `json:"id"`
} `json:"data"`
}
if err := json.NewDecoder(res.Body).Decode(&payload); err != nil {
panic(err)
}
fmt.Println(payload.Data.ID) // id מספרי — בשימוש בכתובות ה-toggle/delete
}// Java 17+ — java.net.http, ללא תלויות
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class ShipOsUpsertSmsTemplate {
public static void main(String[] args) throws Exception {
// {tracking_url} הוא placeholder של ShipOS — השאירו אותו כמו שהוא, אל תעצבו אותו
String body = """
{"shipping_method":"hfd","message":"ההזמנה שלך בדרך! ניתן לעקוב כאן: {tracking_url}"}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://app.shipos.co.il/api/v2/notifications/sms-templates"))
.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());
// data.id הוא ה-id המספרי — בשימוש בכתובות ה-toggle/delete
System.out.println(response.body());
}
}// .NET 8+ — System.Net.Http.Json
using System.Net.Http.Json;
using System.Text.Json;
using var http = new HttpClient
{
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"));
// לא מחרוזת עם אינטרפולציה: {tracking_url} חייב להגיע ל-API כמו שהוא
var response = await http.PostAsJsonAsync("notifications/sms-templates", new
{
shipping_method = "hfd",
message = "ההזמנה שלך בדרך! ניתן לעקוב כאן: {tracking_url}",
});
response.EnsureSuccessStatusCode();
var payload = await response.Content.ReadFromJsonAsync<JsonDocument>();
var templateId = payload!.RootElement.GetProperty("data")
.GetProperty("id").GetInt32(); // id מספרי — בשימוש בכתובות ה-toggle/deleterequire "net/http"
require "json"
uri = URI("https://app.shipos.co.il/api/v2/notifications/sms-templates")
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(
shipping_method: "hfd",
# במרכאות בודדות: {tracking_url} הוא placeholder של ShipOS, לא אינטרפולציה של Ruby
message: 'ההזמנה שלך בדרך! ניתן לעקוב כאן: {tracking_url}',
)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
template_id = JSON.parse(response.body).dig("data", "id") # בשימוש בכתובות ה-toggle/delete// [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/notifications/sms-templates")
.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!({
"shipping_method": "hfd",
// {tracking_url} הוא placeholder של ShipOS — נשלח כמו שהוא
"message": "ההזמנה שלך בדרך! ניתן לעקוב כאן: {tracking_url}"
}))
.send()
.await?
.error_for_status()?
.json()
.await?;
// id מספרי — בשימוש בכתובות ה-toggle/delete
println!("{}", payload["data"]["id"]);
Ok(())
}תגובת ה-201 מחזירה את התבנית שנוצרה/עודכנה:
{
"data": {
"id": 7,
"shipping_method": "hfd",
"delivery_type": null,
"message": "ההזמנה שלך בדרך! ניתן לעקוב כאן: {tracking_url}",
"active": true,
"created_at": "2026-07-29T10:00:00.000000Z",
"updated_at": "2026-07-29T10:00:00.000000Z"
}
}החליפו את מצב ה-active של תבנית או מחקו אותה — {template} הוא ה-id המספרי מהמשאב, לא UUID:
# הפעלה/כיבוי
curl --location --request PUT 'https://app.shipos.co.il/api/v2/notifications/sms-templates/7/toggle' \
--header 'X-Client-Id: {client_id}' \
--header 'X-Client-Secret: {client_secret}' \
--header 'Accept: application/json'
# מחיקה
curl --location --request DELETE 'https://app.shipos.co.il/api/v2/notifications/sms-templates/7' \
--header 'X-Client-Id: {client_id}' \
--header 'X-Client-Secret: {client_secret}' \
--header 'Accept: application/json'const base = 'https://app.shipos.co.il/api/v2/notifications/sms-templates'
const headers = {
'X-Client-Id': process.env.SHIPOS_CLIENT_ID,
'X-Client-Secret': process.env.SHIPOS_CLIENT_SECRET,
Accept: 'application/json',
}
// הפעלה/כיבוי
const toggled = await fetch(`${base}/7/toggle`, { method: 'PUT', headers })
console.log((await toggled.json()).data.active)
// מחיקה
const deleted = await fetch(`${base}/7`, { method: 'DELETE', headers })
console.log((await deleted.json()).data.deleted) // true<?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',
],
]);
// הפעלה/כיבוי
$template = json_decode(
$client->put('notifications/sms-templates/7/toggle')->getBody()->getContents(),
true,
)['data'];
// מחיקה
$client->delete('notifications/sms-templates/7');<?php
use Illuminate\Support\Facades\Http;
$shipos = Http::withHeaders([
'X-Client-Id' => config('services.shipos.client_id'),
'X-Client-Secret' => config('services.shipos.client_secret'),
])->acceptJson();
// הפעלה/כיבוי
$template = $shipos
->put('https://app.shipos.co.il/api/v2/notifications/sms-templates/7/toggle')
->throw()
->json('data');
// מחיקה
$shipos->delete('https://app.shipos.co.il/api/v2/notifications/sms-templates/7')->throw();# pip install httpx
import os
import httpx
base = "https://app.shipos.co.il/api/v2/notifications/sms-templates"
headers = {
"X-Client-Id": os.environ["SHIPOS_CLIENT_ID"],
"X-Client-Secret": os.environ["SHIPOS_CLIENT_SECRET"],
"Accept": "application/json",
}
# הפעלה/כיבוי
toggled = httpx.put(f"{base}/7/toggle", headers=headers)
toggled.raise_for_status()
print(toggled.json()["data"]["active"])
# מחיקה
deleted = httpx.delete(f"{base}/7", headers=headers)
deleted.raise_for_status()
print(deleted.json()["data"]["deleted"]) # Truepackage main
import (
"fmt"
"net/http"
"os"
)
const base = "https://app.shipos.co.il/api/v2/notifications/sms-templates"
func call(method, url string) *http.Response {
req, _ := http.NewRequest(method, url, nil)
req.Header.Set("X-Client-Id", os.Getenv("SHIPOS_CLIENT_ID"))
req.Header.Set("X-Client-Secret", os.Getenv("SHIPOS_CLIENT_SECRET"))
req.Header.Set("Accept", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
return res
}
func main() {
toggled := call("PUT", base+"/7/toggle") // הפעלה/כיבוי
defer toggled.Body.Close()
deleted := call("DELETE", base+"/7") // מחיקה
defer deleted.Body.Close()
fmt.Println(toggled.StatusCode, deleted.StatusCode)
}// Java 17+ — java.net.http, ללא תלויות
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class ShipOsManageSmsTemplate {
static final String BASE =
"https://app.shipos.co.il/api/v2/notifications/sms-templates";
static HttpResponse<String> send(String method, String path) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(BASE + path))
.header("X-Client-Id", System.getenv("SHIPOS_CLIENT_ID"))
.header("X-Client-Secret", System.getenv("SHIPOS_CLIENT_SECRET"))
.header("Accept", "application/json")
.method(method, HttpRequest.BodyPublishers.noBody())
.build();
return HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
}
public static void main(String[] args) throws Exception {
System.out.println(send("PUT", "/7/toggle").body()); // הפעלה/כיבוי
System.out.println(send("DELETE", "/7").body()); // מחיקה
}
}// .NET 8+
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 toggled = await http.PutAsync("notifications/sms-templates/7/toggle", null);
toggled.EnsureSuccessStatusCode();
Console.WriteLine(await toggled.Content.ReadAsStringAsync());
// מחיקה
var deleted = await http.DeleteAsync("notifications/sms-templates/7");
deleted.EnsureSuccessStatusCode();
Console.WriteLine(await deleted.Content.ReadAsStringAsync()); // {"data":{"deleted":true}}require "net/http"
require "json"
BASE = URI("https://app.shipos.co.il/api/v2/notifications/sms-templates/")
def call(request)
request["X-Client-Id"] = ENV.fetch("SHIPOS_CLIENT_ID")
request["X-Client-Secret"] = ENV.fetch("SHIPOS_CLIENT_SECRET")
request["Accept"] = "application/json"
uri = request.uri
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
end
# הפעלה/כיבוי
toggled = call(Net::HTTP::Put.new(BASE + "7/toggle"))
puts JSON.parse(toggled.body).dig("data", "active")
# מחיקה
deleted = call(Net::HTTP::Delete.new(BASE + "7"))
puts JSON.parse(deleted.body).dig("data", "deleted") # true// [dependencies]
// reqwest = { version = "0.12", features = ["json"] }
// tokio = { version = "1", features = ["full"] }
// serde_json = "1"
use serde_json::Value;
const BASE: &str = "https://app.shipos.co.il/api/v2/notifications/sms-templates";
fn auth(req: reqwest::RequestBuilder) -> reqwest::RequestBuilder {
req.header("X-Client-Id", std::env::var("SHIPOS_CLIENT_ID").unwrap())
.header("X-Client-Secret", std::env::var("SHIPOS_CLIENT_SECRET").unwrap())
.header("Accept", "application/json")
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::Client::new();
// הפעלה/כיבוי
let toggled: Value = auth(client.put(format!("{BASE}/7/toggle")))
.send().await?.error_for_status()?.json().await?;
println!("{}", toggled["data"]["active"]);
// מחיקה
let deleted: Value = auth(client.delete(format!("{BASE}/7")))
.send().await?.error_for_status()?.json().await?;
println!("{}", deleted["data"]["deleted"]); // true
Ok(())
}Toggle מחזיר את התבנית המעודכנת; מחיקה מחזירה { "data": { "deleted": true } }. מזהה תבנית שאינו שייך לחשבונכם מחזיר 404 not_found.
שלב 5 — ביקורת עם יומן ה-SMS
כל ניסיון שליחה נרשם ביומן. שאילתו את היומן עם מסננים אופציונליים:
curl --location 'https://app.shipos.co.il/api/v2/notifications/sms-logs?filter[success]=false&per_page=50' \
--header 'X-Client-Id: {client_id}' \
--header 'X-Client-Secret: {client_secret}' \
--header 'Accept: application/json'const url = new URL('https://app.shipos.co.il/api/v2/notifications/sms-logs')
url.searchParams.set('filter[success]', 'false')
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',
},
})
const { data: logs } = await response.json()
for (const log of logs) {
console.log(log.phone, log.state, log.provider.message)
}<?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('notifications/sms-logs', [
'query' => ['filter[success]' => 'false', 'per_page' => 50],
]);
$logs = json_decode($response->getBody()->getContents(), true)['data'];
foreach ($logs as $log) {
echo $log['phone'], ' ', $log['state'], ' ', $log['provider']['message'], PHP_EOL;
}<?php
use Illuminate\Support\Facades\Http;
$logs = 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/notifications/sms-logs', [
'filter[success]' => 'false',
'per_page' => 50,
])
->throw()
->json('data');
foreach ($logs as $log) {
logger()->warning($log['phone'].' → '.data_get($log, 'provider.message'));
}# pip install httpx
import os
import httpx
response = httpx.get(
"https://app.shipos.co.il/api/v2/notifications/sms-logs",
headers={
"X-Client-Id": os.environ["SHIPOS_CLIENT_ID"],
"X-Client-Secret": os.environ["SHIPOS_CLIENT_SECRET"],
"Accept": "application/json",
},
params={"filter[success]": "false", "per_page": 50},
)
response.raise_for_status()
for log in response.json()["data"]:
print(log["phone"], log["state"], log["provider"]["message"])package main
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"os"
)
func main() {
query := url.Values{}
query.Set("filter[success]", "false")
query.Set("per_page", "50")
req, _ := http.NewRequest("GET",
"https://app.shipos.co.il/api/v2/notifications/sms-logs?"+query.Encode(), 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 {
Phone string `json:"phone"`
State string `json:"state"`
Success bool `json:"success"`
} `json:"data"`
}
if err := json.NewDecoder(res.Body).Decode(&payload); err != nil {
panic(err)
}
for _, log := range payload.Data {
fmt.Println(log.Phone, log.State, log.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 ShipOsSmsLogs {
public static void main(String[] args) throws Exception {
// סוגריים מרובעים חייבים להיות מקודדים באחוזים: filter[success] → filter%5Bsuccess%5D
String url = "https://app.shipos.co.il/api/v2/notifications/sms-logs"
+ "?filter%5Bsuccess%5D=false&per_page=50";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.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());
System.out.println(response.body()); // {"data":[{"id":1201,...}]}
}
}// .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"));
// סוגריים מרובעים מקודדים באחוזים: filter[success] → filter%5Bsuccess%5D
var payload = await http.GetFromJsonAsync<JsonDocument>(
"notifications/sms-logs?filter%5Bsuccess%5D=false&per_page=50")
?? throw new InvalidOperationException("Empty response");
foreach (var log in payload.RootElement.GetProperty("data").EnumerateArray())
{
Console.WriteLine($"{log.GetProperty("phone").GetString()} " +
$"{log.GetProperty("state").GetString()}");
}require "net/http"
require "json"
uri = URI("https://app.shipos.co.il/api/v2/notifications/sms-logs")
uri.query = URI.encode_www_form("filter[success]" => "false", "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
JSON.parse(response.body).fetch("data").each do |log|
puts "#{log["phone"]} #{log["state"]} #{log.dig("provider", "message")}"
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/notifications/sms-logs")
.query(&[("filter[success]", "false"), ("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?;
if let Some(logs) = payload["data"].as_array() {
for log in logs {
println!("{} {}", log["phone"], log["provider"]["message"]);
}
}
Ok(())
}| פרמטר query | תיאור |
|---|---|
filter[shipping_id] | רק יומנים של משלוח אחד. |
filter[success] | true / false — רק שליחות מוצלחות או כושלות. |
per_page | גודל עמוד, ברירת מחדל 25, מקסימום 100. |
כל רשומת יומן:
{
"data": [
{
"id": 1201,
"shipment_id": "b7e4c9d2-1a3f-4e5b-9c8d-2f1e0a9b8c7d",
"shipping_method": "hfd",
"phone": "0501234567",
"message": "ההזמנה שלך בדרך! ...",
"success": true,
"state": "sent",
"provider": { "status": "OK", "message": "..." },
"created_at": "2026-07-29T10:05:00.000000Z",
"updated_at": "2026-07-29T10:05:00.000000Z"
}
]
}filter[success]=false בשילוב השדות provider.status / provider.message הוא הדרך המהירה ביותר לענות על "למה הלקוח לא קיבל את ה-SMS?".
ראו גם
- מסמך ההתראות — טבלאות שדות מלאות ומקרי שגיאה לכל endpoint.
- מדריך השגיאות — מעטפת השגיאות שה-endpoints האלה חולקים עם שאר ה-API.