News Malta Budget 2027 announced an eco tax of €10 per adult per night for short lets (capped at €80 per person) from 1 January 2027 — not yet law. Leer más
Guestbud

Desarrolladores · para Desarrolladores

Webhooks

Recibe eventos firmados en tiempo real (reservas, check-ins, pagos, estancias desbloqueadas, extras y mensajes) y verifica la firma HMAC-SHA256.

Los webhooks envían eventos a tu sistema en el momento en que se producen, así que no necesitas consultar la API periódicamente.

Eventos #

EventoCuándo
booking.createdSe ha creado una reserva (panel, importación desde un canal o API)
booking.updatedHan cambiado las fechas, los huéspedes, las horas de check-in/check-out o los datos de contacto
booking.cancelledSe ha cancelado una reserva
checkin.completedEl huésped ha completado (o actualizado) el check-in online
payment.completedTasa turística pagada o fianza retenida/pagada (también cuando el personal la marca como pagada)
booking.unlockedTodos los pasos están completados: la guía de la estancia está desbloqueada
extras.orderedEl huésped ha pagado extras, incluido un check-in anticipado o un check-out tardío
message.sentSe ha enviado un mensaje al huésped a través del canal de la reserva (Airbnb, Booking.com … vía Hostaway o Channex)
feedback.receivedEl huésped ha valorado la estancia (1–5) en la página de opiniones tras una solicitud de reseña
pingEvento de prueba del botón Test

Qué contiene data #

EventoCampos de data
booking.created, booking.updated, booking.cancelledbookingId, ref, source (importaciones desde canales); reason: "stay-times" cuando un check-in anticipado / check-out tardío comprado ha cambiado las horas
checkin.completedbookingId, ref
payment.completedbookingId, leg (eco o deposit), status (paid o held), manual: true cuando el personal lo marcó como pagado
booking.unlockedbookingId
extras.orderedbookingId, leg: "extras", status: "paid"
message.sentbookingId, ref, via (p. ej. Hostaway)
feedback.receivedbookingId, ref, rating (1–5)

La versión legible por máquina de cada evento (cabeceras, cuerpo y data) está en la sección webhooks del documento OpenAPI y en la referencia de la API.

Añadir un webhook #

Settings → Webhooks: introduce una URL https://, marca los eventos que quieres recibir (ninguno = todos) y haz clic en Add webhook. El secreto de firma se muestra una sola vez: guárdalo junto a tu receptor.

Settings → Webhooks
Settings → Webhooks

La solicitud #

POST con un cuerpo JSON:

{
  "id": "evt_…",
  "event": "payment.completed",
  "createdAt": "2026-11-18T14:03:11.000Z",
  "tenant": "t_…",
  "data": { "bookingId": "b_…", "leg": "eco", "status": "paid" }
}

Cabeceras:

CabeceraContenido
X-GP-Eventel nombre del evento
X-GP-DeliveryID único de la entrega
X-GP-TimestampTiempo Unix en segundos
X-GP-Signaturev1= + HMAC-SHA256 en hexadecimal de <timestamp>.<raw body> con tu secreto de firma

Verificar la firma (Node.js) #

const crypto = require('crypto');
function verify(rawBody, headers, secret) {
  const ts = headers['x-gp-timestamp'];
  const expected = 'v1=' + crypto.createHmac('sha256', secret).update(ts + '.' + rawBody).digest('hex');
  const given = String(headers['x-gp-signature'] || '');
  const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
  return fresh && given.length === expected.length && crypto.timingSafeEqual(Buffer.from(given), Buffer.from(expected));
}

Verifica siempre contra el cuerpo sin procesar de la solicitud y rechaza las marcas de tiempo antiguas para bloquear ataques de repetición.

Verificar la firma (C# / .NET) #

using System.Security.Cryptography; using System.Text;
static bool Verify(string rawBody, string ts, string signature, string secret) {
  if (!long.TryParse(ts, out var t) || Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - t) > 300) return false;
  using var h = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
  var hex = Convert.ToHexString(h.ComputeHash(Encoding.UTF8.GetBytes(ts + "." + rawBody))).ToLowerInvariant();
  return CryptographicOperations.FixedTimeEquals(Encoding.ASCII.GetBytes("v1=" + hex), Encoding.ASCII.GetBytes(signature ?? ""));
}

En .NET Framework, usa BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant() en lugar de Convert.ToHexString, y compara en tiempo constante con un bucle sencillo.

Verificar la firma (PHP) #

$expected = 'v1=' . hash_hmac('sha256', $_SERVER['HTTP_X_GP_TIMESTAMP'] . '.' . file_get_contents('php://input'), $secret);
$ok = abs(time() - (int)$_SERVER['HTTP_X_GP_TIMESTAMP']) < 300 && hash_equals($expected, $_SERVER['HTTP_X_GP_SIGNATURE'] ?? '');

Entrega y reintentos #

Responde con cualquier código de estado 2xx en un plazo de 10 segundos. Las entregas fallidas se reintentan a los 30 segundos y a los 5 minutos (tres intentos en total). Recent deliveries muestra los últimos 200 intentos con su resultado.

  • El id del cuerpo y la cabecera X-GP-Delivery son los mismos en cada reintento: guárdalos e ignora los duplicados.
  • Los eventos pueden llegar desordenados; usa createdAt y consulta la reserva para obtener su estado actual.
  • No se siguen las redirecciones y solo se llama a direcciones https:// públicas (no a redes privadas ni locales).
  • Las solicitudes llegan con Content-Type: application/json y User-Agent: GuestPortal-Webhooks/1.

Preguntas frecuentes #

¿Recibo la reserva completa en el evento? #

El evento incluye los ID y el cambio. Obtén la reserva completa con GET /api/v1/bookings/{id} usando una clave de API; así no viajan datos personales en el cuerpo de los webhooks.

¿Pueden los canales enviar webhooks a Guestbud? #

Sí, es la dirección contraria. Hostaway y Channex pueden avisar a Guestbud al instante de reservas nuevas y modificadas; consulta Hostaway y Channex. Esas direcciones entrantes son secretas para cada empresa y solo activan una nueva importación de esa reserva.

¿Se envían webhooks desde la cuenta de demostración? #

No.