אירועים בזמן אמת ואימות חתימה

פתח ב-Claudeפתח ב-ChatGPT.md

Webhooks

קבלו עדכונים בזמן אמת במקום polling. כל אירוע נשלח כ-POST JSON לכתובת HTTPS שלכם.

הגדרה

bash
curl -X POST https://smsprovider-web.vercel.app/api/v1/webhooks \
  -H "Authorization: Bearer $BATLER_API_KEY" -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/hooks/batler", "events": ["message.delivered", "message.failed", "inbound.received"]}'

התשובה כוללת secret (whsec_…) — הוא מוצג פעם אחת בלבד. שמרו אותו לאימות החתימות.

אירועים

אירועמתי
message.sentההודעה נמסרה לרשת הסלולרית
message.deliveredאישור מסירה למכשיר
message.failedכישלון, עם reason (למשל blocked, no_coverage, kosher_phone)
message.expiredלא התקבל אישור מסירה בזמן
inbound.receivedתשובה נכנסת למספר השולח שלכם
otp.verified / otp.failedתוצאת אימות קוד
wallet.low_balance / wallet.creditedיתרה נמוכה / רכישת קרדיטים
blacklist.addedנמען ביקש הסרה
link.clickedלחיצה על קישור מעוקב

מבנה:

json
{
  "id": "4f0c7c1e-1c2b-4a0e-9d7b-2e3f4a5b6c7d",
  "type": "message.delivered",
  "created_at": "2026-11-02T18:00:05Z",
  "data": { "message_id": "0e9b2f0a-6c1d-4f43-8c33-6f3b3f0d9a11", "to": "+972501234567", "ref": "order-123", "status": "delivered", "reason": null, "operator": "Partner", "occurred_at": "2026-11-02T18:00:04Z" }
}

אימות חתימה

כל בקשה נושאת X-Batler-Signature: t=<unix seconds>,v1=<hex> כאשר v1 = HMAC-SHA256(secret, "<t>.<raw body>"), ו-X-Batler-Event-Id לזיהוי כפילויות. חשבו את החתימה על הגוף הגולמי ודחו חותמות זמן ישנות מ-5 דקות.

Node.js

ts
import { verifyWebhookSignature } from "@batler/sms";

app.post("/hooks/batler", express.raw({ type: "application/json" }), async (req, res) => {
  const raw = req.body.toString("utf8");
  if (!(await verifyWebhookSignature(process.env.BATLER_WEBHOOK_SECRET!, req.get("X-Batler-Signature"), raw))) return res.sendStatus(401);
  const event = JSON.parse(raw);
  // dedupe by req.get("X-Batler-Event-Id"), then handle event.type
  res.sendStatus(200);
});

PHP

php
$raw = file_get_contents('php://input');
$header = $_SERVER['HTTP_X_BATLER_SIGNATURE'] ?? '';
parse_str(str_replace(',', '&', $header), $p);
$expected = hash_hmac('sha256', $p['t'] . '.' . $raw, getenv('BATLER_WEBHOOK_SECRET'));
if (!isset($p['v1']) || !hash_equals($expected, $p['v1']) || abs(time() - (int)$p['t']) > 300) {
    http_response_code(401); exit;
}
$event = json_decode($raw, true);
http_response_code(200);

Python

python
import hmac, hashlib, time

def verify(secret: str, header: str, raw: bytes) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    t, v1 = parts.get("t", ""), parts.get("v1", "")
    if not t.isdigit() or abs(time.time() - int(t)) > 300:
        return False
    expected = hmac.new(secret.encode(), f"{t}.".encode() + raw, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, v1)

Retry

החזירו 2xx תוך 10 שניות. אחרת ננסה שוב אחרי 1 דק', 5 דק', 30 דק', 2 שעות, 6 שעות ו-24 שעות. אחרי 10 כשלונות רצופים הכתובת מושבתת ונשלח מייל. לוג המשלוחים ושליחה חוזרת: GET https://smsprovider-web.vercel.app/api/v1/webhooks/{id}/deliveries ו-…/replay.

☰