The short answer
When a customer clicks Pay by credit card, the system creates a Stripe Checkout session and redirects them to Stripe. The invoice stays unpaid. The server confirms payment only after Stripe reports the checkout was completed for the correct invoice and amount. This protects the business record from browser errors, closed tabs or changed amounts.
What this article covers
The safe rule: the customer click starts payment, the server confirms payment
Adding a Stripe payment button to an invoice page looks simple on the customer side. They see a button, click it, enter card details and return to the invoice. But the website must be careful about when it marks the invoice as paid.
The safest rule is simple: the customer click starts payment, but the server confirms payment. A website should never mark an invoice paid just because a customer pressed a button, loaded a return page, or returned from Stripe. It should wait until Stripe confirms the checkout was completed and the payment was successful.
This matters because customer-side pages are not reliable enough to trust for financial records. A customer can close the browser after payment. A network connection can drop. A return page can be refreshed. A URL parameter can be changed. Payment records need to come from trusted server-side checks, not from whatever the browser says happened.
This is the same principle used in secure quote workflows. Just as a quote page should not be trusted to create official records on its own, an invoice page should not be trusted to confirm its own payment.
How a Stripe invoice workflow runs — step by step
Step 1: The customer opens the invoice page and clicks Pay by card. The website creates a Stripe Checkout session for the specific invoice and amount, then redirects the customer to Stripe.
Step 2: The customer enters their card details on the Stripe-hosted checkout page. Stripe handles all card data. The business website never sees the card number.
Step 3: After payment, the customer is redirected back to the invoice page. But the website does not trust this redirect alone. It verifies the result independently.
Step 4: The server checks the Stripe session to confirm payment status, amount and currency. If everything matches the approved invoice, the invoice is updated to paid and a receipt email is sent automatically.
Step 5: A webhook also notifies the website when Stripe confirms the payment. This is the backup confirmation path — it works even if the customer closes their browser before returning.
Want a practical invoice and payment workflow for your business?
Your IT & Tech Mates builds practical AI and automation systems for small businesses — including invoice payment workflows, receipt emails, payment tracking and admin dashboards. Use Quick Help to describe your current process and we will tell you what is realistic.
Why webhooks matter — and what they do
A webhook is a way for Stripe to tell the website that something happened — such as a checkout being completed — without the customer having to do anything. Stripe sends the event directly to a URL on the website server.
Webhooks are useful because they do not depend on the customer returning to the invoice page. A customer might pay successfully and then close the browser before the redirect completes. Without a webhook, the website might not know the payment succeeded.
A good webhook setup also needs duplicate protection. Stripe may send the same event more than once. The server should record processed event IDs and ignore duplicates. The invoice should only be marked paid once, with a clear payment reference and timestamp stored in the invoice payment log.
If a card payment fails, the webhook can notify the server of that too. The invoice stays unpaid. Admin can see the failed attempt in the payment log and follow up with the customer helpfully.
What the server should check before marking an invoice paid
Before updating an invoice to paid, the server should verify:
- Does the invoice token or invoice ID match the Stripe session?
- Has the Stripe payment status been confirmed as complete?
- Does the paid amount exactly match the invoice total?
- Does the currency match?
- Has this Stripe event already been processed?
If any check fails, the invoice should not be updated automatically. The system should log the mismatch and flag it for admin review rather than silently creating an incorrect record.
This level of verification is especially important when the business has a mix of fixed-price invoices and invoices with optional extras. See how fixed quotes and dynamic quotes handle amounts differently — the same care applies when those amounts become invoices.
Questions about this topic
Why not mark the invoice paid when the customer clicks Pay?
Because clicking Pay only starts the checkout. The invoice should stay unpaid until Stripe confirms the payment was successful for the correct amount.
Why use webhooks for payment confirmation?
Webhooks help the website receive confirmation even if the customer closes their browser before returning to the invoice page. A return page alone is not reliable enough.
What should the server check before marking an invoice paid?
It should check the invoice ID or token, the Stripe session, the payment status, the amount paid, the currency and whether the same event has already been processed.
What happens if a webhook is received twice?
The system should record processed event IDs and ignore duplicate events. This prevents the same payment from creating duplicate invoice updates.
Does this make the checkout harder for customers?
No. The customer still sees a professional invoice and a trusted Stripe checkout. The server-side checks happen invisibly behind the scenes.
Ready to build a cleaner invoice and payment workflow?
Use Quick Help to describe your current invoice and payment process. We will give you a clear picture of what a connected, automated system would look like — including how payments, receipts, logs and dashboards can all work together.