Aggiornato il
I webhook sono il modo più rapido per restare sincronizzato con Nowistay. Invece di interrogare l’API ogni pochi minuti per rilevare prenotazioni nuove o modificate, indichi a Nowistay dove inviare gli eventi e il tuo servizio li riceve non appena accadono. Questo articolo ti mostra come creare un webhook, verificare la firma e gestire i nuovi tentativi.
L’API REST pubblica di Nowistay permette ai tuoi strumenti e ai tuoi partner di leggere e scrivere i dati di Nowistay tramite HTTPS. Ti autentichi con OAuth2 (authorization code + PKCE), ricevi un token di accesso e chiami gli endpoint sotto /public/v1/*. I webhook sono il corrispettivo push: stessi dati, stessa struttura di GET /public/v1/bookings/{id}, ma è Nowistay a inviarteli quando qualcosa cambia.
Se non hai ancora configurato OAuth, parti dalla guida principale: Usare l’API REST pubblica di Nowistay. Copre la registrazione, il flusso di consenso, gli scope e come testare le chiamate dal playground della documentazione.
booking.created e booking.updated.GET /public/v1/bookings/{id}, comprensivo di date, canale, stato, importi, campi rilevanti per le missioni e i tuoi parametri personalizzati della prenotazione.webhooks.write. POST /public/v1/webhooks richiede anche bookings.read, perché il payload è il dettaglio completo di una prenotazione.2xx.curl -X POST https://api.nowistay.com/public/v1/webhooks \
-H "Authorization: Bearer nis_access_token_example" \
-H "Content-Type: application/json" \
-d '{
"propertyId": 101,
"url": "https://partner.example.com/nowistay/webhooks",
"events": ["booking.created", "booking.updated"],
"description": "PMS sync"
}'
Risposta:
{
"id": 801,
"propertyId": 101,
"url": "https://partner.example.com/nowistay/webhooks",
"events": ["booking.created", "booking.updated"],
"description": "PMS sync",
"status": "active",
"createdAt": "2026-05-27T16:40:00Z",
"updatedAt": "2026-05-27T16:40:00Z",
"signingSecret": "whsec_9npwH6J8QyZp1L8U3xqG7sN2"
}
Salva subito il signingSecret. Viene restituito una sola volta, alla creazione. Non è possibile leggerlo di nuovo dall’API. Se lo perdi, elimina il webhook e creane uno nuovo.
Ogni consegna è una richiesta HTTP POST al tuo URL, con questi header:
Content-Type: application/jsonUser-Agent: Nowistay-Webhooks/1.0Nowistay-Webhook-Id: 801Nowistay-Webhook-Event-Id: evt_LkP2sxR9zV8QyW... (univoco per evento)Nowistay-Webhook-Event-Type: booking.updatedNowistay-Webhook-Timestamp: 1779292800 (secondi Unix)Nowistay-Webhook-Signature: v1=3a7b...e1c (HMAC-SHA256 in esadecimale)E un corpo JSON strutturato così:
{
"id": "evt_LkP2sxR9zV8QyW...",
"type": "booking.updated",
"createdAt": "2026-05-27T16:40:00Z",
"apiVersion": "2026-05-27",
"propertyId": 101,
"bookingId": 9001,
"data": {
"booking": {
"id": 9001,
"propertyId": 101,
"arrival": "2026-07-14",
"departure": "2026-07-18",
"status": "confirmed",
"channel": "airbnb",
"reservationNumber": "HMABCDE",
"guest": { "firstName": "Maya", "lastName": "M." },
"amounts": { "amount": "620.00", "currency": "EUR" },
"identity": { "status": "verified" }
}
}
}
Il tuo endpoint deve rispondere con uno stato 2xx qualsiasi (200 o 204 sono i più comuni). Qualsiasi altra risposta, o una risposta che impiega più di 10 secondi, conta come errore e fa scattare un nuovo tentativo.
Verifica sempre la firma prima di fidarti del corpo. Senza verifica, chiunque indovini il tuo URL potrebbe inviare eventi falsi al tuo servizio.
Nowistay calcola la firma così:
signature = "v1=" + HMAC_SHA256(
signing_secret,
timestamp + "." + event_id + "." + raw_request_body
).hex()
Ricalcolala dal tuo lato usando gli header Nowistay-Webhook-Timestamp e Nowistay-Webhook-Event-Id e il corpo grezzo esatto della richiesta (non analizzare e riserializzare il JSON prima della verifica, o rischi differenze a livello di byte).
import crypto from "node:crypto";
function verify(req, signingSecret) {
const timestamp = req.headers["nowistay-webhook-timestamp"];
const eventId = req.headers["nowistay-webhook-event-id"];
const signature = req.headers["nowistay-webhook-signature"];
const rawBody = req.rawBody; // Buffer of the raw HTTP body
const signed = Buffer.concat([
Buffer.from(`${timestamp}.${eventId}.`, "utf8"),
rawBody,
]);
const expected = "v1=" + crypto
.createHmac("sha256", signingSecret)
.update(signed)
.digest("hex");
const a = Buffer.from(signature);
const b = Buffer.from(expected);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
import hmac, hashlib
def verify(request, signing_secret: str) -> bool:
timestamp = request.headers["Nowistay-Webhook-Timestamp"]
event_id = request.headers["Nowistay-Webhook-Event-Id"]
signature = request.headers["Nowistay-Webhook-Signature"]
raw_body = request.body # bytes
signed = f"{timestamp}.{event_id}.".encode("utf-8") + raw_body
expected = "v1=" + hmac.new(
signing_secret.encode("utf-8"),
signed,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(signature, expected)
Controlla anche che il timestamp sia recente (ad esempio entro gli ultimi 5 minuti) per proteggerti dagli attacchi di replay.
L’oggetto data.booking rispecchia ciò che restituisce GET /public/v1/bookings/{id} quando viene chiamato senza lo scope bookings.sensitive.read. Questo significa che:
Quando il tuo strumento ha bisogno di uno di questi campi sensibili, recupera il dettaglio della prenotazione dall’API con un token che ha lo scope bookings.sensitive.read. Il bookingId nell’envelope del webhook è l’input giusto per quella chiamata.
curl https://api.nowistay.com/public/v1/bookings/9001 \
-H "Authorization: Bearer nis_access_token_with_sensitive_scope"
Se il tuo endpoint restituisce uno stato diverso da 2xx, va in timeout o fallisce per qualsiasi altro motivo, Nowistay non scarta l’evento. Programma un nuovo tentativo, con backoff esponenziale e un po’ di jitter:
Si continua finché il tuo endpoint non accetta l’evento, oppure finché il webhook non fallisce da più di 72 ore consecutive. A quel punto Nowistay imposta lo stato del webhook su disabled e smette di inviargli nuovi eventi. I contatori degli errori si azzerano a ogni consegna riuscita, quindi un incidente isolato non fa mai scattare la disattivazione automatica.
I record delle consegne vengono conservati per 30 giorni, poi eliminati.
Un webhook disattivato può essere riattivato dall’API quando il tuo endpoint è di nuovo in salute. Invia un PATCH con status: "active":
curl -X PATCH https://api.nowistay.com/public/v1/webhooks/801 \
-H "Authorization: Bearer nis_access_token_example" \
-H "Content-Type: application/json" \
-d '{"status": "active"}'
Nowistay non rinvia gli eventi scattati mentre il webhook era disattivato. Se ne hai persi alcuni, esegui un recupero una tantum con GET /public/v1/bookings usando un filtro per data, poi riprendi il tuo flusso basato sui webhook.
Puoi sospendere temporaneamente le consegne (durante una finestra di manutenzione, ad esempio) senza perdere la configurazione del webhook:
# Pause
curl -X PATCH https://api.nowistay.com/public/v1/webhooks/801 \
-H "Authorization: Bearer nis_access_token_example" \
-H "Content-Type: application/json" \
-d '{"status": "paused"}'
# Resume
curl -X PATCH https://api.nowistay.com/public/v1/webhooks/801 \
-H "Authorization: Bearer nis_access_token_example" \
-H "Content-Type: application/json" \
-d '{"status": "active"}'
# Delete permanently
curl -X DELETE https://api.nowistay.com/public/v1/webhooks/801 \
-H "Authorization: Bearer nis_access_token_example"
Nella stessa chiamata puoi anche modificare url, l’elenco events o description. Cambiare l’URL non ruota il segreto di firma.
# List all webhooks (optionally filtered by property)
curl "https://api.nowistay.com/public/v1/webhooks?propertyId=101" \
-H "Authorization: Bearer nis_access_token_example"
# Read one webhook
curl https://api.nowistay.com/public/v1/webhooks/801 \
-H "Authorization: Bearer nis_access_token_example"
La risposta dell’elenco mostra gli stessi campi della risposta di creazione, tranne il segreto di firma (viene restituito solo alla creazione).
https://user:pass@... viene rifiutato).localhost, nessun intervallo IP privato o riservato. Nowistay risolve inoltre il nome host al momento della consegna e blocca le chiamate che risolvono verso indirizzi privati.id del corpo e salta l’evento se l’hai già elaborato.2xx subito ed elabora l’evento in un job in background se è oneroso.Nowistay-Webhook-Event-Id e l’id della richiesta nei tuoi log. Velocizza l’assistenza.GET /public/v1/bookings/{id} dopo aver ricevuto l’evento.Guide per gli host: leggi il blog.
Pronto a mettere la tua casa vacanza in pilota automatico?