Hosted manage payments
Send customers to a hosted page where they sign in with a one-time code and manage their saved cards and default card, and receive webhooks for the changes they make.
Hosted manage payments
Every client has a hosted manage payments page. Send a customer to it and they can sign in with a one-time code sent to their email, see the cards they have saved with you, add or replace a card, remove a card, and choose their default card. You build nothing: there is no session to create, no component to render, and no setting to turn on.
Who this is for
This guide is for developers who want to give customers a self-service way to update the card they pay with, for example from an account page, a receipt email, or a failed-payment email. If you want to build the payment-methods page into your own product instead, see Save and manage payment methods.
Send customers to the page
The page lives at one address per environment. Replace {clientId} with your client UUID, the same value you use as the Basic authentication username:
| Environment | Link |
|---|---|
| Production | https://checkout.flopay.com/manage/{clientId} |
| Stage | https://checkout.stage.flopay.com/manage/{clientId} |
You can add the customer's email address as the optional email query parameter, so the customer does not have to type it:
https://checkout.flopay.com/manage/{clientId}?email=customer%40example.comURL-encode the address. The page reads it, pre-fills the sign-in form, and removes it from the address bar once the page has loaded.
The client UUID and email are the only inputs. The page is always on for every client, and the link does not expire. Anyone who opens it still has to sign in, so you can put it in emails and on public pages.
How customers sign in
- The customer enters their email address, or confirms the one the link pre-filled, and chooses Send code.
- An invisible bot check runs in the browser. No code is sent until it passes.
- If, and only if, the address belongs to one of your customers, the page emails a 6-digit one-time code to it.
- The customer enters the code and is signed in.
The page shows the same "Enter your code" screen whether or not the address matched one of your customers. That way the page never reveals who your customers are. An address that is not one of your customers never receives a code, and the page never creates a customer.
The code follows these rules:
| Rule | Limit |
|---|---|
| How long a code is valid | 10 minutes. |
| Wrong attempts | The code stops working after 5 wrong attempts. |
| Resending | The customer can ask for a new code 60 seconds after the last one. |
| Codes per hour | At most 5 codes per email address per hour. |
| Older codes | Sending a new code cancels the previous one. |
| Reloading the page | Within 60 seconds of sending, a reload shows the code screen again without sending another code. |
Limits per network also apply. A customer who reaches a limit sees how long to wait before trying again.
The code email
The code email carries your brand: your logo and colors, with your name as the sender name. It is sent from a fixed address with no reply-to address, so a customer's reply does not reach you.
If you have not saved a brand, the email is neutral: it is sent as "Flopay" and does not name your business.
The customer's session
A signed-in session ends at whichever of these comes first:
- The customer closes the browser.
- 15 minutes pass without activity.
- 1 hour passes after sign-in.
- The customer chooses Sign out, which ends it immediately.
Nothing is remembered between visits: the customer signs in again each time. A session only ever reaches that customer's own data with you, and never another customer's or another client's.
What customers can do
Once signed in, the customer sees their saved cards with you, with their default card marked Default. Each card shows what it pays for: the plan and its next renewal date.
| Action | What happens |
|---|---|
| Add a card | The customer enters the card in a secure card form, including 3D Secure where the card needs it. The new card becomes their default card. |
| Replace a card | The customer adds a new card in place of an existing one. The new card becomes their default card and the page removes the old one. If the old card cannot be removed, the page says why and keeps it. |
| Remove a card | The card is removed, unless it cannot be. The page explains why a removal was refused, for example when the card still pays for an active subscription that has no other card to move to, or a payment with the card is still being processed. |
| Make default | The chosen card becomes the customer's default card. |
What happens to subscriptions
Choosing a default card, or adding a card on the page (which makes it the default automatically), moves the customer's active subscriptions with you onto that card wherever the card can pay for them. Future renewals use the default card first.
Some subscriptions stay on their current payment method, and the page tells the customer so:
- A subscription paid with PayPal.
- A subscription billed through a payment provider the card is not saved with.
PayPal
A saved PayPal account is shown read-only. The customer cannot remove it, replace it, or make it their default from the page.
When adding and replacing cards is available
Adding and replacing a card saves a card without a purchase, which needs card setup on your payment provider. If your account cannot take card setup without a purchase, the page hides Add a card and Replace. Customers can still see their cards, remove a card, and choose their default card.
Branding and the back button
The page uses your saved brand from the moment it first appears: your logo, colors, and name. Your brand is the hosted checkout theme you save with PUT /v1/branding (see Create or replace branding for its fields). If you have not saved a brand, the page has a neutral look, with no logo and no name.
A Back button appears when your brand's logo has a link (hostedCheckoutTheme.logo.href). It takes the customer to that link, and only an https link is used. With no brand, or a brand whose logo has no link, there is no back button.
Webhooks
The page sends three client webhook events for the changes customers make on it. Subscribe to them like any other event: add them to the events array of an endpoint with POST /v1/webhooks or PATCH /v1/webhooks/{id}. See Configuration. Existing endpoints are not subscribed automatically.
| Event type | Sent when |
|---|---|
payment_method.added | The customer added a card, including the new card of a replace. |
payment_method.removed | The customer removed a card, including the old card of a replace. |
payment_method.default_changed | A card became the customer's default card, including a card added on the page that became the default automatically. |
These events are sent only for changes a customer makes on the hosted page. Changes made through your own integration, such as the payment methods and setup session endpoints, send none of them.
More detail on when each event is sent:
- A card added on the page that becomes the default sends
payment_method.addedand thenpayment_method.default_changed. A card that could not become the default sends onlypayment_method.added. - Choosing the card that is already the default sends nothing. A default change that fails changes nothing and sends nothing.
- A removal that is refused, or a removal of a card that was already removed, sends nothing.
- A card change has no product, so an endpoint with a product filter never receives these events. Subscribe to them on an endpoint without a filter.
Payload
Every event has eventVersion: "v1", objectType: "payment_method", its own eventId, the user that holds the card, and a paymentMethod object. payment_method.added and payment_method.removed share this shape:
{
"eventVersion": "v1",
"eventId": "6f1c1b8e-6f43-4f53-9e57-2d7b3c1f0a11",
"eventType": "payment_method.added",
"objectType": "payment_method",
"user": {
"id": "8af796dd-b8f3-4ac8-a5d1-c85fbb8d5168",
"clientUserId": "customer_123",
"email": "customer@example.com"
},
"paymentMethod": {
"id": "4e676a49-976c-4f37-8e15-2b7a64f72891",
"clientId": "0c2f8a3e-1d0b-4f39-8f0e-5a3c9b1d7e21",
"type": "card",
"occurredAt": "2026-10-18T10:00:00.000Z"
}
}payment_method.default_changed adds the previous default and what the change did to the customer's subscriptions with you:
{
"eventVersion": "v1",
"eventId": "0d5a3f62-2c4e-4b8e-9b1f-7a6c2e9d4b30",
"eventType": "payment_method.default_changed",
"objectType": "payment_method",
"user": {
"id": "8af796dd-b8f3-4ac8-a5d1-c85fbb8d5168",
"clientUserId": "customer_123",
"email": "customer@example.com"
},
"paymentMethod": {
"id": "4e676a49-976c-4f37-8e15-2b7a64f72891",
"clientId": "0c2f8a3e-1d0b-4f39-8f0e-5a3c9b1d7e21",
"type": "card",
"occurredAt": "2026-10-18T10:00:00.000Z",
"previousDefaultId": "9b2e4c71-58d3-4a6f-a1e0-3c7d8f2b6e54",
"movedSubscriptionIds": ["2b8d6f1a-7c3e-4e59-b0a4-6d1f9c8e2a73"],
"subscriptionsNotMoved": [
{ "subscriptionId": "5e9a1c3d-4b7f-4d28-8e6a-0f2c7b9d1e46", "reason": "paypal_funded" }
]
}
}| Field | Type | Meaning |
|---|---|---|
user.id | string | The customer's UUID. |
user.clientUserId | string, nullable | Your own customer id, if you stored one. |
user.email | string | The customer's email address. |
paymentMethod.id | string | The payment method id, the same id the payment methods endpoints return. |
paymentMethod.clientId | string | Your client UUID. |
paymentMethod.type | card | Always card. |
paymentMethod.occurredAt | string | When the customer made the change, in ISO 8601. |
paymentMethod.previousDefaultId | string, nullable | payment_method.default_changed only. The card that was the default before, or null when there was none. For a card saved with more than one payment provider, it is one of that card's payment method ids. |
paymentMethod.movedSubscriptionIds | string array | payment_method.default_changed only. The subscriptions that moved onto the new default card. |
paymentMethod.subscriptionsNotMoved | object array | payment_method.default_changed only. The subscriptions that stayed on their payment method, each with subscriptionId and reason. |
reason is paypal_funded when the subscription is paid with PayPal, or gateway_not_available when it is billed through a payment provider the card cannot be charged on.
The payload carries ids and the change only. It never includes a card number, expiry date, brand, last four digits, or any other card detail. To show card details, list the customer's payment methods from your server with the payment methods endpoints, and treat that list as the source of truth.
For delivery, signing, and retries, see Delivery. For the other event types, see Events.
What is not supported
These are not available on the hosted manage payments page today.
- Languages other than English.
- Adding or removing PayPal or wallets, such as Apple Pay and Google Pay.
- Embedding the page in an iframe.
- A return URL in the link. The only way back is the Back button from your brand's logo link.
- Signed links, or identifying a customer by your own customer id. Customers always sign in with their email address.
- Invoices and plan changes.
Save and manage payment methods
Let customers add, list, replace, and remove saved cards, wallets, PayPal, and bank methods without a purchase, from trusted server and browser boundaries.
Subscriptions and recurring
Model products and prices, configure recurring rebills and trials, and recover failed Flo-managed rebills.