דלגו לתוכן

אינטגרציית Webhook

Webhooks מאפשרים למערכות שלך לקבל התראות בזמן אמת כאשר אירועים מתרחשים בחשבון Wink שלך — הזמנות חדשות, ביטולים, עדכוני תשלום ועוד. מדריך זה מלווה אותך בהגדרה ובשיטות עבודה מומלצות.

מדריך זה מיועד למפתחים המשלבים את Wink עם מערכות חיצוניות כגון מערכות ניהול נכסים (PMS), מנהלי ערוצים, CRM או לוחות בקרה מותאמים אישית.

  1. אתה רושם כתובת URL של webhook ב-Wink.
  2. כאשר אירוע מתרחש (למשל, הזמנה חדשה), Wink שולח בקשת HTTP POST לכתובת ה-URL שלך.
  3. השרת שלך מעבד את המטען ומחזיר תגובה עם 200 OK.
  1. היכנס לחשבונך (Extranet, Studio או TripPay — כולם תומכים ב-webhooks).
  2. עבור אל Applications ואז Webhooks. ראה Webhooks.
  3. לחץ על Create webhook.
  4. הזן שם (למשל, “סנכרון הזמנות PMS”).
  5. הזן את כתובת ה-URL של ה-webhook — נקודת הקצה HTTPS בשרת שלך.
  6. בחר אירועים — בחר אירועים ספציפיים למנוי, או השאר ריק כדי לקבל את כל האירועים.
  7. הפעל את המתג Enabled.
  8. לחץ על Save — התגובה מציגה את סוד החתימה שלך פעם אחת; שמור אותו כעת.

Wink מפרסם כיום 70 סוגי אירועי webhook בתחומי הזמנות, נכסים, חשבונות (ישויות ניהול) ומלאי (סוגי חדרים, תוכניות תעריפים, תעריפים ראשיים, תוספות, מתקנים, ערוצי מכירה, מבצעים). הנפוצים:

קטגוריהדוגמאות
הזמנהbooking.create, booking.cancelled, booking.refund.partial, booking.refund.full, booking.review.created
נכסproperty.created, property.status.updated, property.policy.updated
מלאיroom_type.updated, rate_plan.created, master_rate.updated, special_rate.created, sales_channel.created
חשבוןmanaging_entity.created, managing_entity.status.updated, managing_entity.manager.added

הרשימה המלאה, הכוללת תיאור, מי מקבל אותה וקישור לעמוד ההפניה של כל אירוע — היא קטלוג אירועי Webhook. עמוד ההפניה לכל אירוע (גוף JSON, כותרות, מדיניות ניסיון חוזר) נמצא ב-Webhooks API.

הצג את כל סוגי האירועים

כל משלוח הוא HTTP POST לכתובת ה-URL של ה-webhook שלך עם Content-Type: application/json והעטיפה הבאה:

{
"id": "0198a4f2-6b0e-7c1d-9a3e-2f4b8c6d1e0a",
"type": "booking.create",
"occurredAt": "2026-08-15T09:30:00Z",
"ownerIdentifier": "3c6b1a5d-8e2f-4a0b-9c7d-6e4f0a8b2c51",
"recipientRole": "SUPPLIER",
"schemaVersion": 2,
"object": { "...": "event-specific payload, e.g. BookingWebhookPayload" }
}
  • id — מזהה האירוע; זהה לכל נקודת קצה בחשבונך שמקבלת את האירוע ולכל ניסיון חוזר. השתמש בו כמפתח idempotency.
  • type — מפתח סוג האירוע (נשלח גם בכותרת Wink-Event-Type). בצע סניף לפי type ו-schemaVersion כדי לפרש את object.
  • object — סיכום מעובד של המשאב שהאירוע עוסק בו (מזהים, סטטוס, השדות שאתה פועל עליהם) בנוסף ל-links.self, כתובת REST קנונית בצד הספק של המשאב המלא. שלוף אותה עם אישורי ה-API שלך כשאתה צריך יותר מהסיכום; אם אתה מקבל את האירוע כסוכן נסיעות או משווק, השתמש בנקודת הקצה המתאימה של ממשק ה-API שלך עבור אותו מזהה.

כל סכמת מטען מתועדת לפי אירוע ב-Webhooks API ההפניה.

כותרתמשמעות
Wink-Versionגרסת חוזה התקשורת, 2.0.
Wink-Event-Idזהה ל-id בגוף — מפתח ה-idempotency שלך.
Wink-Delivery-Idייחודי לכל נקודת קצה לכל אירוע; משתנה רק אם אתה מבצע משלוח חוזר.
Wink-Event-Typeזהה ל-type בגוף.
Wink-Delivery-Attemptמספר ניסיון מבוסס 1 למשלוח זה.
Wink-Signatureחתימת HMAC — ראה למטה.

לכל webhook יש סוד חתימה (whsec_…) ש-Wink מציג פעם אחת, כאשר אתה יוצר את ה-webhook או מסובב את הסוד שלו. שמור אותו כסיסמה. כל משלוח נושא

Wink-Signature: t=1755250200,v1=5d41402abc4b2a76b9719d911017c592…

כאשר t הוא חותמת זמן יוניקס (בשניות) ו-v1 הוא ה-HMAC-SHA256 הקסדצימלי הקטן של המחרוזת t + "." + rawBody, עם מפתח הסוד שלך, ו-rawBody הוא בדיוק בתים של גוף הבקשה כפי שהתקבל — אל תבצע סריאליזציה מחדש של ה-JSON לפני האימות. במשך 24 שעות לאחר סיבוב סוד, הכותרת נושאת ערך v1= שני חתום עם הסוד הקודם; קבל את המשלוח אם כל אחד מ-v1 תואם.

אמת בארבעה שלבים: פרש את t ואת כל v1; חשב מחדש את ה-HMAC על t.rawBody עם הסוד שלך; השווה עם השוואה בזמן קבוע; דחה אם |now − t| חורג מהסובלנות שלך (מומלץ 5 דקות).

// Node.js (סגנון Express; ודא שיש לך את גוף ה-RAW, לא אובייקט מפורש)
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verifyWinkSignature(header, rawBody, secret, toleranceSeconds = 300) {
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=').map((s) => s.trim())));
const t = Number(parts.t);
if (!Number.isFinite(t) || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false;
const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
return header
.split(',')
.filter((p) => p.trim().startsWith('v1='))
.map((p) => p.trim().slice(3))
.some((v1) => v1.length === expected.length && timingSafeEqual(Buffer.from(v1, 'utf8'), Buffer.from(expected, 'utf8')));
}
// Java
static boolean verify(String header, String rawBody, String secret, long nowSeconds, long toleranceSeconds) throws Exception {
long t = Long.MIN_VALUE;
List<String> signatures = new ArrayList<>();
for (String part : header.split(",")) {
String[] kv = part.trim().split("=", 2);
if (kv[0].equals("t")) t = Long.parseLong(kv[1]);
else if (kv[0].equals("v1")) signatures.add(kv[1]);
}
if (t == Long.MIN_VALUE || Math.abs(nowSeconds - t) > toleranceSeconds) return false;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] expected = HexFormat.of().formatHex(mac.doFinal((t + "." + rawBody).getBytes(StandardCharsets.UTF_8))).getBytes(StandardCharsets.US_ASCII);
return signatures.stream().anyMatch(v1 -> MessageDigest.isEqual(expected, v1.toLowerCase().getBytes(StandardCharsets.US_ASCII)));
}

סובב את הסוד מהפורטל או עם POST /api/managing-entity/{id}/webhook/{webhookId}/rotate-secret; התגובה מציגה את הסוד החדש פעם אחת, והישן ממשיך לאמת במשך 24 שעות בזמן שאתה מפיץ אותו.

ניסיונות חוזרים ומשלוחים חוזרים

Section titled “ניסיונות חוזרים ומשלוחים חוזרים”
  • הגיב עם כל 2xx תוך 10 שניות לאישור. בצע את העבודה הכבדה באופן אסינכרוני.
  • 5xx, תזמון, 408 או 429 ינסו שוב עם רווחי זמן: אחרי דקה, 5 דקות, 30 דקות, שעתיים, 6 שעות, 12 שעות, ואז יומי — 10 ניסיונות במשך כ-3 ימים — לאחר מכן המשלוח מסומן כ-**מת.
  • כל 4xx אחר מטופל כ”סירבת במשלוח זה” ואינו מנסה שוב.
  • כל אירוע, משלוח וניסיון (סטטוס, קטע תגובה) גלויים תחת Applications > Webhooks ובאמצעות ה-API (…/webhook/event/grid, …/webhook/delivery/grid). ניתן לשלוח מחדש כל משלוח (POST …/webhook/delivery/{deliveryId}/redeliver, שמתחיל סדרת ניסיונות חדשה), לשלוח מחדש את כל המשלוחים המתים של webhook בבת אחת (POST …/webhook/{webhookId}/redeliver-dead), או לבטל אחד.
  • משלוחים נשמרים למשך 30 יום.

שלח לעצמך אירוע webhook.test סינתטי מהפורטל או עם POST /api/managing-entity/{id}/webhook/{webhookId}/test. הוא חתום ונשלח בדיוק כמו אירוע אמיתי, כך שתוכל לאמת את נקודת הקצה שלך, את בדיקת החתימה ואת טיפול ה-idempotency לפני המנוי לאירועים חיים.

  • השתמש ב-HTTPS — Wink שולח מטענים רק לנקודות קצה HTTPS.
  • הגיב במהירות — החזר 200 OK ברגע שאתה מקבל את המטען. בצע כל עיבוד כבד באופן אסינכרוני.
  • Idempotency — המטפל שלך צריך להיות idempotent; הסר כפילויות לפי Wink-Event-Id. Wink מנסה שוב כאשר אינו מקבל תגובת 2xx.
  • אמת את המקור — אמת את כותרת Wink-Signature (ראה אימות חתימות) לפני העיבוד; דחה כל דבר שנכשל.
  • רישום — רשום כל מטען webhook שאתה מקבל. זה מקל על איתור תקלות באינטגרציה.

ניתן לנטרל webhook מבלי למחוק אותו. זה עוצר את המשלוח כדי שתוכל לפתור בעיות מבלי לאבד את ההגדרות שלך. כשתהיה מוכן, הפעל אותו שוב.

מחיקת webhook מסירה אותו לצמיתות. כל אינטגרציה שתלויה ב-webhook זה תפסיק לקבל התראות.