Salta ai contenuti

Integrazione Webhook

I webhook permettono ai tuoi sistemi di ricevere notifiche in tempo reale quando si verificano eventi sul tuo account Wink — nuove prenotazioni, cancellazioni, aggiornamenti di pagamento e altro. Questa guida ti accompagna nella configurazione e nelle migliori pratiche.

Questa guida è rivolta agli sviluppatori che integrano Wink con sistemi esterni come property management system (PMS), channel manager, CRM o dashboard personalizzate.

  1. Registri un URL webhook su Wink.
  2. Quando si verifica un evento (es. una nuova prenotazione), Wink invia un HTTP POST al tuo URL.
  3. Il tuo server elabora il payload e risponde con un 200 OK.
  1. Accedi al tuo account (Extranet, Studio o TripPay — tutti supportano i webhook).
  2. Vai su Applications e poi su Webhooks. Vedi Webhooks.
  3. Clicca su Create webhook.
  4. Inserisci un nome (es. “Sincronizzazione Prenotazioni PMS”).
  5. Inserisci il tuo webhook URL — l’endpoint HTTPS sul tuo server.
  6. Seleziona eventi — scegli eventi specifici a cui iscriverti, oppure lascia vuoto per ricevere tutti gli eventi.
  7. Attiva l’opzione Enabled.
  8. Clicca su Save — la risposta mostra il tuo signing secret una sola volta; salvalo subito.

Wink pubblica oggi 70 tipi di eventi webhook tra prenotazioni, proprietà, account (entità gestenti) e inventario (tipi di camera, piani tariffari, tariffe master, extra, servizi, canali di vendita, promozioni). I più comuni:

CategoriaEsempi
Prenotazionebooking.create, booking.cancelled, booking.refund.partial, booking.refund.full, booking.review.created
Proprietàproperty.created, property.status.updated, property.policy.updated
Inventarioroom_type.updated, rate_plan.created, master_rate.updated, special_rate.created, sales_channel.created
Accountmanaging_entity.created, managing_entity.status.updated, managing_entity.manager.added

L’elenco completo e generato — con descrizione, destinatari e link alla pagina di riferimento di ogni evento — è il Catalogo Eventi Webhook. La pagina di riferimento per ogni evento (corpo JSON, header, politica di retry) si trova nella Webhooks API.

Visualizza tutti i tipi di evento

Ogni consegna è un HTTP POST al tuo URL webhook con Content-Type: application/json e questo involucro:

{
"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": { "...": "payload specifico dell'evento, es. BookingWebhookPayload" }
}
  • id — identificatore dell’evento; identico per ogni endpoint del tuo account che riceve questo evento e per ogni retry. Usalo come tua chiave di idempotenza.
  • type — chiave del tipo di evento (inviata anche come header Wink-Event-Type). Gestisci in base a type e schemaVersion per interpretare object.
  • object — un riassunto curato della risorsa a cui si riferisce l’evento (identificatori, stato, campi su cui agisci) più links.self, l’URL REST canonico lato fornitore della risorsa completa. Recuperalo con le tue credenziali API quando ti serve più del riassunto; se ricevi l’evento come rivenditore o agente di viaggio, usa l’endpoint corrispondente della tua API per lo stesso identificatore.

Ogni schema payload è documentato per evento nella Webhooks API di riferimento.

HeaderSignificato
Wink-VersionVersione del contratto wire, 2.0.
Wink-Event-IdUguale a id nel corpo — la tua chiave di idempotenza.
Wink-Delivery-IdUnico per endpoint per evento; cambia solo se ridistribuisci.
Wink-Event-TypeUguale a type nel corpo.
Wink-Delivery-AttemptNumero di tentativo 1-based per questa consegna.
Wink-SignatureFirma HMAC — vedi sotto.

Ogni webhook ha un signing secret (whsec_…) che Wink mostra una sola volta, quando crei il webhook o ruoti il suo segreto. Salvalo come una password. Ogni consegna porta

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

dove t è un timestamp Unix (secondi) e v1 è l’HMAC-SHA256 in esadecimale minuscolo della stringa t + "." + rawBody, firmata con il tuo segreto, e rawBody è il corpo esatto della richiesta ricevuta — non rieseguire la serializzazione JSON prima di verificare. Per 24 ore dopo una rotazione del segreto l’header porta un secondo valore v1= firmato con il segreto precedente; accetta la consegna se qualunque v1 corrisponde.

Verifica in quattro passaggi: analizza t e ogni v1; ricalcola l’HMAC su t.rawBody con il tuo segreto; confronta con un confronto a tempo costante; rifiuta se |now − t| supera la tua tolleranza (consigliati 5 minuti).

// Node.js (stile Express; assicurati di avere il corpo RAW, non un oggetto parsato)
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)));
}

Ruota il segreto dal portale o con POST /api/managing-entity/{id}/webhook/{webhookId}/rotate-secret; la risposta mostra il nuovo segreto una sola volta, e quello vecchio continua a essere valido per 24 ore mentre lo distribuisci.

  • Rispondi con qualsiasi 2xx entro 10 secondi per confermare. Esegui il lavoro pesante in modo asincrono.
  • Un 5xx, timeout, 408 o 429 viene ritentato con backoff: dopo 1 minuto, 5 minuti, 30 minuti, 2 ore, 6 ore, 12 ore, poi giornalmente — 10 tentativi in circa 3 giorni — dopo i quali la consegna è marcata dead.
  • Qualsiasi altro 4xx è trattato come “hai rifiutato questa consegna” e non viene ritentato.
  • Ogni evento, consegna e tentativo (stato, snippet di risposta) è visibile sotto Applications > Webhooks e tramite API (…/webhook/event/grid, …/webhook/delivery/grid). Puoi ridistribuire qualsiasi consegna (POST …/webhook/delivery/{deliveryId}/redeliver, che avvia una nuova serie di tentativi), ridistribuire tutte le consegne dead di un webhook in una volta (POST …/webhook/{webhookId}/redeliver-dead), o annullarne una.
  • Le consegne sono conservate per 30 giorni.

Invia a te stesso un evento sintetico webhook.test dal portale o con POST /api/managing-entity/{id}/webhook/{webhookId}/test. È firmato e consegnato esattamente come un evento reale, così puoi verificare il tuo endpoint, il controllo della firma e la gestione dell’idempotenza prima di iscriverti agli eventi live.

  • Usa HTTPS — Wink invia payload solo a endpoint HTTPS.
  • Rispondi rapidamente — Restituisci un 200 OK appena ricevi il payload. Esegui qualsiasi elaborazione pesante in modo asincrono.
  • Idempotenza — Il tuo handler deve essere idempotente; deduplica su Wink-Event-Id. Wink ritenta se non riceve una risposta 2xx.
  • Valida la fonte — Verifica l’header Wink-Signature (vedi Verifica delle firme) prima di elaborare; rifiuta tutto ciò che fallisce.
  • Logging — Registra ogni payload webhook che ricevi. Questo facilita molto il debug delle integrazioni.

Puoi disabilitare un webhook senza cancellarlo. Questo mette in pausa la consegna così puoi risolvere problemi senza perdere la configurazione. Quando sei pronto, riattivalo.

Cancellare un webhook lo rimuove definitivamente. Qualsiasi integrazione che si basa su quel webhook smetterà di ricevere notifiche.