Aller à l'article
Aniq-UI

HollinaRéservations et paiements

Réservations et paiements

Comment une réservation est faite, payée, confirmée et annulée : carte via Stripe, PayPal, paiement à l'arrivée, le simulateur fourni, les webhooks qui confirment un paiement, les remboursements, et les étapes que l'hôte franchit dans le tableau de bord.

Pour le pack Full Stack

Trois façons de payer

MéthodeProposé quandOù le voyageur paie
CarteVia Stripe quand STRIPE_SECRET_KEY est défini ; via le simulateur fourni tant qu'aucun processeur n'est configuré du toutLa page Checkout hébergée de Stripe, donc aucun numéro de carte n'atteint cette application ; avec le simulateur, un formulaire de carte sur le paiement
PayPalVia PayPal quand PAYPAL_CLIENT_ID et PAYPAL_CLIENT_SECRET sont définis ; via le simulateur tant qu'aucun processeur n'est configuré du toutLa page d'approbation de PayPal
Paiement à l'arrivéeTant que le paramètre allow_pay_on_arrival est activé (Paramètres, Paiements)Rien en ligne : l'hôte encaisse à la porte
Configuré sur l'APIProposé en ligneRefusé
Ni Stripe ni PayPalCarte et PayPal, tous deux réglés par le simulateurRien
Stripe seulCarte, via StripePayPal
PayPal seulPayPal, via PayPalCarte
Les deuxCarte via Stripe, PayPal via PayPalRien

Le paiement à l'arrivée est proposé à côté de n'importe lequel de ces cas tant que son paramètre est activé, et refusé quand il est désactivé. Le paiement lit la liste depuis GET /api/payments/methods, il ne propose donc jamais un moyen que l'API ne peut pas accepter, et un moyen hébergé ne demande aucune donnée de carte sur le site. Une réservation envoyée avec un moyen refusé reçoit la réponse « That payment method is not available. Choose another way to pay. » avant que quoi que ce soit soit écrit, elle ne retient donc aucune nuit. L'argent va sur votre propre compte Stripe ou PayPal ; le produit ne le détient jamais.

Le simulateur fourni

Une installation neuve n'a aucun processeur, donc le simulateur règle aussitôt chaque réservation par carte et PayPal sans contacter personne. Tout le parcours est cliquable sur un portable sans clés, sans compte marchand et sans réseau, et la réservation, la confirmation, le calendrier et les chiffres de revenu sont de vraies lignes écrites par le vrai parcours. Un numéro de carte se terminant par 0 est refusé, pour que le cas d'échec soit visible.

Tant qu'il tourne, le formulaire de carte du paiement affiche « Test mode: no card is charged. », GET /api/payments/methods répond simulated: true, et l'API écrit une ligne dans son journal au démarrage :

Le journal de l'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).

Il ne prend aucun argent

Une réservation que confirme le simulateur n'a jamais été payée, il ne tourne donc que tant que ni Stripe ni PayPal n'est configuré. Configurez le processeur avec lequel vos voyageurs paieront avant d'ouvrir le site au public : à partir de là, le simulateur est désactivé, et le paiement ne propose que les moyens que vos processeurs acceptent, plus le paiement à l'arrivée tant qu'il est activé. L'onglet Paiements des paramètres du tableau de bord indique quand le simulateur est utilisé.

Le cycle de vie d'une réservation

StatutSignificationÉtapes suivantes
En attenteFaite sur le site, en attente de son paiement ou de l'hôteConfirmée ou annulée
ConfirméePayée, ou acceptée par l'hôte pour un paiement à l'arrivéeArrivée enregistrée ou annulée
Arrivée enregistréeLe voyageur est arrivé. Une réservation à payer à l'arrivée est marquée payée iciTerminée ou annulée (un séjour écourté)
TerminéeLe séjour est terminé, et le voyageur peut le noterAucune
AnnuléePar le voyageur, par l'hôte, ou parce qu'une retenue impayée a expiréAucune
  • Une réservation par carte ou PayPal est confirmée par son paiement, jamais à la main : le Confirm de l'hôte est refusé avec « This booking cannot be confirmed until the payment arrives. » tant qu'elle n'est pas payée. Une réservation à payer à l'arrivée attend que l'hôte la confirme.
  • L'hôte fait avancer une réservation sur sa page dans le tableau de bord avec Confirm, Check in, Complete et Cancel, et garde une note interne que le voyageur ne voit jamais. Une étape que la réservation ne peut pas franchir maintenant s'affiche désactivée avec sa raison.
  • Une réservation ne fait qu'avancer, et terminée et annulée sont définitives.
  • Chaque réservation a une référence attribuée dans l'ordre (B0001, B0002 et ainsi de suite), et garde le tarif par nuit, les frais de ménage et le total avec lesquels elle a été faite.
  • La cloche du tableau de bord prévient chaque admin qui peut voir les réservations quand une réservation est payée (par le webhook, la capture PayPal ou le simulateur), quand une réservation à payer à l'arrivée attend l'hôte, et quand une réservation est annulée, en disant si c'est le voyageur, l'équipe ou une retenue impayée expirée qui y a mis fin.

Ce qui confirme un paiement

Le webhook du processeur, jamais le retour du voyageur sur le site. Un voyageur envoyé vers Stripe ou PayPal revient sur sa propre page de réservation, à SITE_URL, qui dit que le paiement est en cours de confirmation tant que le webhook n'est pas arrivé. Un paiement qui échoue laisse la réservation en attente, donc le voyageur peut réessayer jusqu'à la fin de la retenue de 30 minutes.

  • PayPal demande une étape de plus que Stripe : l'approbation laisse la commande approuvée sans rien prélever, donc la page de retour la capture, et le résultat de la capture ou le webhook règle la réservation.
  • Un paiement qui arrive en retard pour une réservation déjà annulée est enregistré comme payé et laissé à l'hôte pour remboursement : les nuits peuvent déjà appartenir à quelqu'un d'autre.
  • Chaque fournisseur renvoie ses webhooks, et un événement qui arrive deux fois confirme la réservation une seule fois.

Configurer Stripe

Dans le .env de l'API, avec une clé de test pendant vos essais (une clé sk_live_ déplace de l'argent réel, et le journal de l'API le dit au démarrage) :

Le .env de l'API
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
ÉvénementRôle
checkout.session.completedConfirme la réservation. Le seul événement qui le fait, car c'est le seul qui signifie que la session a été payée
payment_intent.payment_failedMarque le paiement comme échoué et laisse la réservation en attente, pour que le voyageur puisse payer de nouveau
charge.refundedMarque le paiement comme remboursé
charge.dispute.createdUne rétrofacturation, traitée comme un remboursement

Sur un serveur, créez un endpoint de webhook dans Stripe à l'adresse publique de votre API suivie de /api/webhooks/payments/stripe, pour ces quatre événements, et placez son secret de signature dans STRIPE_WEBHOOK_SECRET. En local, transférez les événements avec le CLI Stripe et placez le secret qu'il affiche dans .env :

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

Terminez ensuite un vrai paiement de test dans le navigateur avec la carte 4242 4242 4242 4242. stripe trigger checkout.session.completed n'est pas utile ici : un événement déclenché ne porte aucune référence de réservation, il est donc ignoré. Sans STRIPE_WEBHOOK_SECRET, chaque webhook Stripe est refusé et une réservation par carte n'est jamais réglée.

Configurer PayPal

Le .env de l'API
PAYPAL_CLIENT_ID=...
PAYPAL_CLIENT_SECRET=...
PAYPAL_WEBHOOK_ID=...
PAYPAL_ENV=sandbox
  • PayPal est proposé dès que l'identifiant client et le secret sont tous deux définis. PAYPAL_ENV vaut sandbox sauf si vous définissez live, donc un déploiement mal configuré ne prend aucun argent réel.
  • Abonnez un webhook à PAYMENT.CAPTURE.COMPLETED (confirme la réservation), PAYMENT.CAPTURE.DENIED (paiement échoué, la réservation reste en attente), PAYMENT.CAPTURE.REFUNDED et PAYMENT.CAPTURE.REVERSED (marquée remboursée) à l'adresse de votre API suivie de /api/webhooks/payments/paypal, et placez l'identifiant de l'abonnement dans PAYPAL_WEBHOOK_ID : c'est ce qui vérifie la signature de PayPal.
  • CHECKOUT.ORDER.APPROVED est ignoré exprès : confirmer à ce moment retiendrait des nuits pour de l'argent qui n'a pas bougé.

La route des webhooks

POST /api/webhooks/payments/:provider, avec stripe ou paypal comme fournisseur. Elle ne demande aucune connexion : chaque requête est vérifiée par la signature du fournisseur sur le corps brut et un horodatage, si bien qu'elle ne peut être ni modifiée ni rejouée. Une mauvaise signature répond 401 et un fournisseur inconnu 404 ; chaque événement vérifié répond 200, y compris ceux qui concernent autre chose, pour que le fournisseur ne les renvoie pas pendant des jours.

L'API doit être joignable depuis internet à cette adresse. Derrière un proxy, transmettez le corps de la requête intact : un corps resérialisé ne correspond plus à sa signature.

Annulations et remboursements

  • Un voyageur annule depuis sa page de réservation, gratuitement, tant que la réservation est en attente ou confirmée et que l'heure locale d'arrivée est dans au moins sept jours. Dans cette fenêtre, la page dit de contacter l'hôte. Le texte de la politique que lisent les voyageurs est le paramètre cancellation_policy ; les sept jours sont une constante de l'API.
  • L'hôte annule depuis le tableau de bord à tout moment avant que la réservation soit terminée.
  • Le produit ne rend jamais d'argent. Annuler une réservation payée marque son paiement refund_pending ; l'hôte la rembourse dans le tableau de bord de Stripe ou de PayPal, et c'est le webhook de remboursement qui écrit refunded. Une réservation payée à l'arrivée est remboursée directement par l'hôte.
  • Annuler libère aussitôt les nuits, et prévient chaque admin qui peut voir les réservations.

Qui peut faire quoi

PermissionAutorise
bookings.viewLire les réservations, et être prévenu des paiements, des demandes de paiement à l'arrivée et des annulations
bookings.editConfirm, Check in, Complete et Cancel, et la note interne
settings.view, settings.editVoir et modifier l'onglet Paiements : le paiement à l'arrivée et la politique d'annulation

Les deux rôles du seed détiennent bookings.view et bookings.edit ; seul le Super Admin détient les permissions des paramètres.

Les routes derrière tout cela

GET /api/payments/methods répond { methods: [{ method, hosted }], allowPayOnArrival, simulated }. POST /api/bookings est public et répond avec la référence de la réservation, son access_token privé, son statut et son statut de paiement, le total, et une redirect_url vers la page du processeur pour un moyen hébergé ; un moyen que la liste ne contient pas répond 422 avec payment_method_unavailable. Les routes propres au voyageur acceptent ce jeton, ou l'e-mail utilisé pour la réservation : GET /api/bookings/:reference, POST /api/bookings/:reference/settle (la capture de la page de retour), /cancel et /review. Le tableau de bord lit et fait avancer les réservations avec GET et PATCH /api/bookings/manage/:reference, ce dernier avec { "action": "confirm" }, check_in, complete ou cancel, et admin_notes.

Comment les passerelles de paiement s'articulent

Inclus avec votre achat. Connectez-vous pour le lire, ou ouvrez-le dans votre téléchargement.

L'interface de passerelle, comment un moyen trouve son processeur, et comment ajouter le vôtre.

Bloqué sur une étape ?

Trouvez une solution avant de tout recommencer.

Dépannage

Préférences des Cookies

Nous utilisons des cookies pour améliorer votre expérience de navigation, analyser le trafic du site et personnaliser le contenu. En cliquant sur "Accepter Tout", vous consentez à notre utilisation des cookies pour l'analyse et la publicité personnalisée.