Automatic payment confirmation

Updated on 2026-04-26

Automatic payment confirmation

As soon as a guest pays their deposit or full amount via Stripe or Bancontact, the entire flow is kicked off automatically. You can see everything coming in in real-time on the Payments page.

Payments overview with outstanding, paid and processed transactions

What happens when a payment comes in?

  1. A webhook (from Stripe or Bancontact) arrives at /webhooks/stripe-payment or /webhooks/bancontact
  2. BedFlow updates the invoice:
    • financial.paid += amount
    • financial.balance = total - paid
    • financial_state becomes 'partial' (deposit) or 'paid' (in full)
    • An individual payment record is added to payments[]
  3. The booking moves from pending to confirmed + deposit_paid = true
  4. An email is sent to the guest — which email depends on the situation:
    • First payment (deposit or full in one go) → "Payment received" (template booking-confirmed)
    • Remainder after an earlier deposit → "Fully paid" (template booking-fully-paid)
  5. A Telegram notification is sent to your phone:
    • 💳 "Payment received" (on deposit) or ✅ "Fully paid"
    • With guest name, amount, remaining balance, arrival date, reference
  6. WhatsApp to the guest (only on the first payment — for the final payment the email is enough)
  7. The guest portal URL is generated and stored on the booking — the guest can open their portal from the email

Example flow: Jan Jansen books 3 nights

| Moment | What Jan sees | What you see | |---|---|---| | Books via widget | "Thanks — check your inbox for the payment link" | Telegram 🎫 "New booking" | | Opens email, clicks Stripe | Stripe checkout, pays €96 deposit | — | | Stripe webhook | "Payment received — €231 remaining on arrival" | Telegram 💳 "€96 received from Jan" | | 2 days later pays the rest | "Fully paid! See you soon." | Telegram ✅ "Fully paid by Jan" |

Where is this built?

  • app/Http/Controllers/PaymentController.php::handleBookingPaymentConfirmed() is the heart
  • app/Services/EmailAutomationService::processEvent() picks the right template
  • app/Services/TelegramNotificationService::info('payment_received', ...) sends the admin push