Ir al artículo
Aniq-UI

HollinaReservas y pagos

Reservas y pagos

Cómo se hace, se paga, se confirma y se cancela una reserva: tarjeta con Stripe, PayPal, pago a la llegada, el simulador incluido, los webhooks que confirman un pago, los reembolsos y los pasos que da el anfitrión en el panel.

Para el paquete Full Stack

Tres formas de pagar

MétodoSe ofrece cuandoDónde paga el huésped
TarjetaCon Stripe cuando STRIPE_SECRET_KEY está definida; con el simulador incluido mientras no haya ningún procesador configuradoLa página de Checkout alojada de Stripe, así que ningún número de tarjeta llega a esta aplicación; con el simulador, un formulario de tarjeta en el pago
PayPalCon PayPal cuando PAYPAL_CLIENT_ID y PAYPAL_CLIENT_SECRET están definidas; con el simulador mientras no haya ningún procesador configuradoLa página de aprobación de PayPal
Pago a la llegadaMientras el ajuste allow_pay_on_arrival esté activado (Ajustes, Pagos)Nada en línea: el anfitrión lo cobra en la puerta
Configurado en la APISe ofrece en líneaRechazado
Ni Stripe ni PayPalTarjeta y PayPal, ambos liquidados por el simuladorNada
Solo StripeTarjeta, con StripePayPal
Solo PayPalPayPal, con PayPalTarjeta
AmbosTarjeta con Stripe, PayPal con PayPalNada

El pago a la llegada se ofrece junto a cualquiera de estos mientras su ajuste esté activado, y se rechaza mientras esté desactivado. El pago lee la lista de GET /api/payments/methods, así que nunca ofrece un método que la API no pueda aceptar, y un método alojado no pide datos de tarjeta en el sitio web. Una reserva enviada con un método rechazado recibe la respuesta "Ese método de pago no está disponible. Elige otra forma de pagar." antes de que se escriba nada, así que no retiene noches. El dinero va a tu propia cuenta de Stripe o PayPal; el producto nunca lo retiene.

El simulador incluido

Una instalación nueva no tiene procesador, así que el simulador liquida todas las reservas con tarjeta y PayPal al instante sin contactar con nadie. Todo el proceso se puede recorrer en un portátil sin claves, sin cuenta de comercio y sin red, y la reserva, la confirmación, el calendario y las cifras de ingresos son filas reales escritas por el proceso real. Un número de tarjeta que termina en 0 es rechazado, para que se vea el camino del fallo.

Mientras se ejecuta, el formulario de tarjeta del pago dice "Modo de prueba: no se cobra ninguna tarjeta.", GET /api/payments/methods responde simulated: true, y la API escribe una línea en su registro al iniciarse:

El registro de la API
[Payments] Payment simulator active: card and PayPal bookings are confirmed without payment until a processor is configured (STRIPE_SECRET_KEY, or PAYPAL_CLIENT_ID and PAYPAL_CLIENT_SECRET).

No cobra nada

Una reserva que confirma el simulador nunca se pagó, así que solo se ejecuta mientras ni Stripe ni PayPal estén configurados. Configura el procesador con el que pagarán tus huéspedes antes de abrirles el sitio web: desde entonces el simulador queda apagado, y el pago ofrece solo los métodos que aceptan tus procesadores, más el pago a la llegada mientras esté activado. La pestaña Pagos de los ajustes del panel indica cuándo se usa el simulador.

El ciclo de vida de una reserva

EstadoSignificadoSiguiente
PendienteHecha en el sitio web, a la espera de su pago o del anfitriónConfirmada o cancelada
ConfirmadoPagada, o aceptada por el anfitrión para el pago a la llegadaCon check-in realizado o cancelada
Check-in realizadoEl huésped ha llegado. Una reserva con pago a la llegada se marca como pagada aquíCompletada o cancelada (una estancia interrumpida)
CompletadaLa estancia ha terminado, y el huésped puede reseñarlaNinguno
CanceladaPor el huésped, por el anfitrión, o porque una retención sin pagar caducóNinguno
  • Una reserva con tarjeta o PayPal se confirma con su pago, nunca a mano: el Confirmar del anfitrión se rechaza con "Esta reserva no se puede confirmar hasta que llegue el pago." hasta que se pague. Una reserva con pago a la llegada espera a que el anfitrión la confirme.
  • El anfitrión avanza una reserva en su página del panel con Confirmar, Registrar entrada, Completar y Cancelar, y guarda una nota interna que el huésped nunca ve. Un paso que la reserva no puede dar ahora se muestra desactivado con su motivo.
  • Una reserva solo avanza, y completada y cancelada son finales.
  • Cada reserva tiene una referencia asignada en orden (B0001, B0002 y así sucesivamente), y conserva la tarifa por noche, la tarifa de limpieza y el total con los que se hizo.
  • La campana del panel avisa a todos los administradores que pueden ver reservas cuando se paga una reserva (por el webhook, la captura de PayPal o el simulador), cuando una reserva con pago a la llegada espera al anfitrión, y cuando se cancela una reserva, indicando si la terminó el huésped, el equipo o una retención sin pagar que caducó.

Lo que confirma un pago

El webhook del procesador, nunca que el huésped vuelva al sitio. Un huésped enviado a Stripe o PayPal vuelve a su propia página de reserva, en SITE_URL, que dice que el pago se está confirmando hasta que llega el webhook. Un pago que falla deja la reserva pendiente, así que el huésped puede intentarlo de nuevo hasta que se agote la retención de 30 minutos.

  • PayPal necesita un paso más que Stripe: aprobar deja el pedido aprobado y no cobra nada, así que la página de retorno lo captura, y el propio resultado de la captura o el webhook liquida la reserva.
  • Un pago que llega tarde para una reserva ya cancelada se registra como pagado y se deja para que el anfitrión lo reembolse: las noches pueden pertenecer ya a otra persona.
  • Todos los proveedores reintentan sus webhooks, y un evento que llega dos veces confirma la reserva una sola vez.

Configura Stripe

En el .env de la API, con una clave de prueba mientras lo pruebas (una clave sk_live_ mueve dinero real, y el registro de la API lo indica al iniciarse):

El .env de la API
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
EventoQué hace
checkout.session.completedConfirma la reserva. Es el único evento que lo hace, porque es el único que significa que la sesión se pagó
payment_intent.payment_failedMarca el pago como fallido y deja la reserva pendiente, para que el huésped pueda pagar de nuevo
charge.refundedMarca el pago como reembolsado
charge.dispute.createdUna devolución de cargo, tratada como un reembolso

En un servidor, crea un endpoint de webhook en Stripe con la dirección pública de tu API seguida de /api/webhooks/payments/stripe, para esos cuatro eventos, y pon su secreto de firma en STRIPE_WEBHOOK_SECRET. En local, reenvía los eventos con la CLI de Stripe y pon el secreto que imprime en .env:

Terminal
stripe listen --forward-to localhost:8000/api/webhooks/payments/stripe

Luego completa un pago de prueba real en el navegador con la tarjeta 4242 4242 4242 4242. stripe trigger checkout.session.completed no sirve aquí: un evento provocado no lleva referencia de reserva, así que se ignora. Sin STRIPE_WEBHOOK_SECRET se rechaza todo webhook de Stripe y una reserva con tarjeta nunca se liquida.

Configura PayPal

El .env de la API
PAYPAL_CLIENT_ID=...
PAYPAL_CLIENT_SECRET=...
PAYPAL_WEBHOOK_ID=...
PAYPAL_ENV=sandbox
  • PayPal se ofrece cuando el id de cliente y el secreto están definidos. PAYPAL_ENV es sandbox salvo que definas live, así que un despliegue mal configurado no cobra dinero real.
  • Suscribe un webhook a PAYMENT.CAPTURE.COMPLETED (confirma la reserva), PAYMENT.CAPTURE.DENIED (el pago falló, la reserva sigue pendiente), PAYMENT.CAPTURE.REFUNDED y PAYMENT.CAPTURE.REVERSED (marcados como reembolsados) en la dirección de tu API seguida de /api/webhooks/payments/paypal, y pon el id de la suscripción en PAYPAL_WEBHOOK_ID: es lo que verifica la firma de PayPal.
  • CHECKOUT.ORDER.APPROVED se ignora a propósito: confirmar ahí retendría noches por dinero que no se ha movido.

La ruta del webhook

POST /api/webhooks/payments/:provider, con stripe o paypal como proveedor. No necesita inicio de sesión: cada petición se comprueba con la propia firma del proveedor sobre el cuerpo en bruto y una marca de tiempo, así que no se puede ni editar ni repetir. Una firma incorrecta responde 401 y un proveedor desconocido 404; todo evento verificado responde 200, incluso los que tratan de otra cosa, para que el proveedor no los reintente durante días.

La API debe ser accesible desde internet en esa dirección. Detrás de un proxy, reenvía el cuerpo de la petición sin tocar: un cuerpo reserializado ya no coincide con su firma.

Cancelaciones y reembolsos

  • Un huésped cancela desde la página de su reserva, gratis, mientras la reserva está pendiente o confirmada y la hora local de check-in está al menos a siete días. Dentro de ese plazo, la página indica que contacte con el anfitrión. El texto de la política que leen los huéspedes es el ajuste cancellation_policy; los siete días son una constante de la API.
  • El anfitrión cancela desde el panel en cualquier momento antes de que la reserva se complete.
  • El producto nunca devuelve dinero. Cancelar una reserva pagada marca su pago como refund_pending; el anfitrión la reembolsa en el propio panel de Stripe o PayPal, y el webhook de reembolso es lo que escribe refunded. Una reserva pagada a la llegada la reembolsa directamente el anfitrión.
  • Cancelar libera las noches al instante y avisa a todos los administradores que pueden ver reservas.

Quién puede hacer qué

PermisoPermite
bookings.viewLeer reservas, y recibir avisos de pagos, solicitudes de pago a la llegada y cancelaciones
bookings.editConfirmar, Registrar entrada, Completar y Cancelar, y la nota interna
settings.view, settings.editVer y cambiar la pestaña Pagos: el pago a la llegada y la política de cancelación

Los dos roles de la carga inicial tienen bookings.view y bookings.edit; solo el Super Admin tiene los permisos de ajustes.

Las rutas que hay detrás

GET /api/payments/methods responde { methods: [{ method, hosted }], allowPayOnArrival, simulated }. POST /api/bookings es público y responde con la referencia de la reserva, su access_token privado, su estado y estado de pago, el total y un redirect_url a la página del procesador para un método alojado; un método que la lista no contiene responde 422 con payment_method_unavailable. Las rutas propias del huésped aceptan ese token, o el correo electrónico con el que se hizo la reserva: GET /api/bookings/:reference, POST /api/bookings/:reference/settle (la captura de la página de retorno), /cancel y /review. El panel lee y mueve las reservas con GET y PATCH /api/bookings/manage/:reference, esta última con { "action": "confirm" }, check_in, complete o cancel, y admin_notes.

Cómo encajan las pasarelas de pago

Incluido con tu compra. Inicia sesión para leerlo o ábrelo en tu descarga.

La interfaz de la pasarela, cómo un método encuentra su procesador y cómo añadir el tuyo.

¿Te atascaste en un paso?

Busca una solución antes de empezar de nuevo.

Solución de problemas

Preferencias de Cookies

Utilizamos cookies para mejorar tu experiencia de navegación, analizar el tráfico del sitio y personalizar el contenido. Al hacer clic en "Aceptar Todo", consientes nuestro uso de cookies para análisis y publicidad personalizada.