Public Payment Pages
Some of the most important people in your billing flow never sign in to anything: your customers' accounts-payable clerks, procurement officers, and sole proprietors paying an invoice from their phone. Floatless gives them hosted public pages — branded, no-login, token-protected — for the two jobs that matter: paying an invoice and updating a saved card.
When should I read this?
- You want customers to pay from the invoice itself, without a portal account.
- A customer's card expired and they will not read card numbers over the phone.
- You are auditing where card data can (and cannot) touch.
Use cases
| Scenario | What you do |
|---|---|
| Invoice goes out by email | The email carries a pay link; the clerk pays by card in two minutes. |
| Customer's saved card declines in dunning | The warning email carries a payment-update link (24h validity); the customer fixes it themselves. |
| A prospect accepted a quote | They land on the same public invoice surface — one continuous, login-free flow. |
Pay an invoice (hosted payment page)
The public pay page lives at /pay/{invoice_id} and is normally reached from the invoice email link or the invoice's share link. The invoice ID alone exposes no money movement — charging a saved card requires a signed payment token from the invoice email (pt parameter).
Steps
Open the pay link
The page shows the invoice number, customer, amount due, and currency — everything needed to recognize what is being paid.
Pay with the saved card (if present)
If the customer has a card on file, it appears as Use Saved Card with brand, last four digits, and expiry. This path requires the email link's signed token — an extra check that someone forwarding the invoice URL around cannot charge a card.
Or pay with a different card
Choose Use a different card instead. Floatless creates a Stripe PaymentIntent and renders Stripe's card element — card data goes directly from the browser to Stripe, never to Floatless. Strong-customer-authentication (3-D Secure) challenges appear right in the flow when the bank requires them.
Confirmation
After a successful payment the page shows the amount paid, the invoice summary, and a note that a confirmation email was sent.
Already-paid invoices show a friendly "fully paid" state instead of payment controls — nobody can double-charge an invoice by sharing its link.

Update a payment method
The payment-update page lives at /public/update-payment and is reached from a single-use link token sent by email (dunning warnings and the portal both hand these out):
- The token is valid for 24 hours and is stripped from the URL as soon as the page loads, so it does not leak through browser history or referrers.
- The page greets the customer by name and organization, then collects the new card through Stripe's card element.
- On save, the card becomes the customer's default payment method — future retries and auto-pay pick it up automatically.
Expired or used tokens get a clear "link expired" state with instructions to request a new one. There is no grace period and no page state that survives without a valid token.
What this means for compliance
- Card data never touches Floatless. Both pages use Stripe's hosted elements; Floatless stores only the Stripe customer and payment-method references.
- Tokens are narrow. Each link does exactly one job (pay this invoice / update this customer's card), for one customer, for a limited time.
- Audit trail stays complete. Payments made through public pages create the same payment records and webhooks as console-initiated ones — your reconciliation does not change.
Common issues
- "Paying with a saved card requires the email link." That is the token check working. Forward the original invoice email, or pay with a new card instead.
- Customer says the update link is dead. It expired (24 hours). Trigger a new one from the portal or dunning flow.
- 3-D Secure loop. The customer's bank requires authentication in a popup; ask them to allow popups or try a different card.