# Is the thank-you page proof of payment?

> No: anybody can open it, paid or not, and somebody who paid may never reach it. Confirm a booking only on the payment provider's signed message.

- Anybody can open the thank-you page, paid or not.
- Only the payment provider's signed message confirms a booking.
- The slot is held for 15 minutes while they pay, unless you change it.

## What the page after paying proves

When somebody has paid, the payment page sends them on to an address you gave
it: your thank-you page. Arriving there proves one thing, that a browser
opened that address. It goes wrong both ways round:

- **Somebody who did not pay can open it.** It is an ordinary address, and it
  can be typed, bookmarked, shared or guessed.
- **Somebody who paid may never reach it.** They close the tab, the phone loses
  its signal, the battery runs out. Stripe says the same of its own checkout: a
  customer is not guaranteed to visit that page.

Confirm on the page and you give away appointments to the first kind of
visitor, and lose bookings that were paid for to the second.

## What confirms a booking instead

The payment provider tells the server directly, with a signed message that
never passes through the customer's browser. In BackendFree that message is the
only thing that moves a booking from waiting for payment to confirmed. Then the
confirmation email goes out, and your own webhook endpoint hears
`booking.confirmed`.

The message arrives whether or not anybody comes back to the page, and the same
message arriving twice confirms nothing twice.

## What the thank-you page should do

Say what is true at that moment. Name the page with `{id}` when booking, as in
`https://salon.example/thanks?booking={id}`, and the booking's id is filled in.
With a publishable key, read the booking with that id and the manage token your
site kept when it booked, and show its status:

```ts title=thanks.ts
const booking = await bookings.booking(id, { token });

if (booking.status === 'confirmed') {
  // paid for and confirmed: show the time, on the business's clock
} else if (booking.status === 'pending_payment') {
  // not reported yet: say the payment is being confirmed, and look again shortly
}
```

The provider's message can arrive after the customer does, so a booking still
`pending_payment` on that page is not a failure. If the business confirms each
booking by hand, a paid booking reads `pending_confirmation` instead: paid, and
waiting for them.

## If they do not pay

The slot is held while the customer pays,
15 minutes unless the business
changes it, and then given back. Somebody who backed out of the
payment page or lost it can be offered the same payment again within that time,
without booking a second time.

If the money arrives after the hold ran out, the booking comes back when the
time is still free. If somebody else has taken it since, the booking is marked
as owing a refund, and the refund is the business's to make.

[Payments](/product/payments/) has the rest, and [How to take a
deposit](/guides/taking-a-deposit/) covers asking for part of the price.

## Questions people ask next

### Can the thank-you page check the payment itself?

**Only by asking the server.** Anybody can open a page in a browser, so what it shows has to come from your server or the API, never from the address it was opened at.

### What if they close the tab before coming back?

**The booking is still confirmed.** The payment provider's message reaches the server without the browser, and the confirmation email tells the customer.

### What should the page say while the payment is not reported yet?

**That it is being confirmed.** The provider's message can arrive after the customer does. Say the payment is being confirmed, read the booking again shortly, and let the email follow.

### What if the money arrives after the hold ran out?

**The booking comes back if the time is still free.** If somebody else has taken the time since, the booking is marked as owing a refund, and the refund is yours to make.

## Sources

- [Fulfill orders](https://docs.stripe.com/checkout/fulfillment), Stripe
