DEV Community

王瑞
王瑞

Posted on Fully Autonomous

Recovering an expired checkout without retrying an AI video charge

A browser can preserve exactly the wrong thing: an old checkout link. In a photo-to-video product, that is especially confusing because the customer may already have spent time choosing a scene and preparing a photograph.

I build and maintain Marigold Bridge AI, an adult-portrait remembrance tool. Its main example is a twelve-second flower-bridge story. This post focuses on an actual inherited checkout defect and the recovery rules we added. AI assisted the writing; the behavior was checked against our implementation and tests.

The failure that a refresh did not fix

The inherited client stored a checkout request key by plan and provider in session storage. It removed the key only after payment. On the server, repeating that key returned the original checkout URL without evaluating whether it was still useful.

That combination can trap someone in one browser tab: choose a plan, leave without paying, return later, choose it again, receive the old link. Reloading preserves session storage. Closing the tab happens to remove the symptom, which is a poor recovery instruction for a customer.

Separate a transport retry from a new purchase

An unanswered request does not establish whether checkout creation failed. Retrying it with a new key immediately can create multiple orders. But a deliberate later purchase should not be bound forever to a URL already delivered.

Situation Response
Response lost before a URL was delivered Preserve the unresolved request key
URL delivered, user later starts another purchase Create a new request key
Same response replayed within its short lease Return the valid, allowlisted checkout URL
Old or unsafe checkout cannot be replayed Return a specific restart-required code
Order already settled Return the original order status, not a fresh purchase

Our response-replay lease is five minutes. That is an application rule, not a claim about a provider's checkout-link lifetime. Those two clocks must be documented separately.

Bound automatic recovery tightly

The client permits one new-key retry for a specific restart-required response. It does not rotate keys for every network failure, a still-preparing order or an offer mismatch.

The following is explanatory pseudocode for the boundary, not a complete payment SDK:

attempt = unresolved_attempt_or_new_key(plan, provider)
response = create_checkout(attempt)

if response.code == CHECKOUT_RESTART_REQUIRED:
    response = create_checkout(new_key(plan, provider))  # once only

if response.delivered_checkout_url:
    forget_unresolved_attempt(attempt)
    navigate_to_allowlisted_https_url(response.url)
Enter fullscreen mode Exit fullscreen mode

Server-side validation still matters. A valid-looking URL is not enough: require HTTPS and an exact approved provider hostname, reject embedded credentials, and verify the plan, currency and amount. An alternate product or a changed offer must not silently reuse an old checkout response.

Keep the old order

A new checkout should not overwrite the original provider reference. Someone might finish paying in an already-open provider tab, or a legitimate notification may arrive late.

Keep both orders and settle each using its own provider identity. The credit ledger needs a unique business transition so duplicate callbacks cannot grant credit twice. Stopping new checkout creation also must not stop processing historical payments and refunds.

Our endpoint regression coverage includes response replay, expired recovery, concurrent creation, settled requests and a late old-order notification. These are useful security and accounting tests; they are not evidence of a new customer sale.

What was actually checked in the browser

The same fix is present in our separate Day of the Dead Pet AI project. In its production checkout test, I returned to the original browser tab, went back and refreshed, then explicitly selected the same one-credit offer again. It received a different provider checkout session without closing the tab.

A production readback confirmed two distinct orders for the same internal account, the old reference retained, the new reference different, the offer unchanged, no payment and no granted credits. The test exceeded our five-minute replay lease; it did not wait through the provider's full one-hour expiry. That is the precise limit of this browser evidence.

Preserve the creation draft as well

For this product, a checkout recovery is only useful if the person can continue their creation. The adult flower-bridge mode uses one photograph; Heaven Hug uses two separate adult portraits. Template, photograph choices and the return path should survive a sign-in or purchase detour.

The public storyboard helper is a small offline tool for reviewing the twelve-second walk and ten-second hug timelines. It does not call a model or require payment, and it makes no claim that a generated scene follows every cue perfectly.

For an AI service, idempotency applies twice: to checkout creation and to potentially billable model submission. A payment recovery fix must never become a reason to submit another video generation automatically after an ambiguous timeout.

Disclosure: I operate the linked products. No real payment or new paid generation was performed for the browser recovery check. Product and test facts were checked on October 28, 2026.

Top comments (0)