# Review an AI-built Stripe Checkout before taking payments

> A founder's test-mode review of Checkout, signed webhooks, delayed payments, duplicate events, and fulfillment before launch.

Canonical HTML: https://canopyide.dev/guides/review-ai-built-stripe-checkout-before-launch
Article date: 2026-09-28

A successful redirect from Stripe Checkout proves that the browser reached a page. It does not prove your app granted the right account access, handled a delayed payment, or avoided granting access twice. For a one-time purchase, trace a test Checkout Session from the button through Stripe's event delivery to the final entitlement or order record. Keep all trials in Stripe's testing environment with test keys and test payment methods.

## Name the purchase and the final result

Pick one concrete product, such as a paid report. Write down the expected price and product, which signed-in customer owns the purchase, what the customer receives, and what the app should show for success, failure, or a still-pending payment. Ask the implementing agent to identify the Checkout Session creation route, return page, webhook endpoint, fulfillment function, and database record. These are separate steps. Stripe's Checkout fulfillment guide says a landing page alone is unreliable because a customer may pay and never reach it. The server needs a webhook-driven path to complete fulfillment.

*A test record for one-time Checkout; adapt it to your own product and payment methods.*

| Case | Expected Stripe state | Expected app result |
| --- | --- | --- |
| Successful test card | Payment succeeds | One order or entitlement for the intended customer |
| Declined test card | Payment does not succeed | No paid access; clear recovery path |
| Delayed payment method | Payment remains pending, then succeeds or fails | No early fulfillment; update after final event |
| Return page never opens | Payment may still succeed | Webhook completes fulfillment |
| Same event is delivered again | Duplicate delivery | No duplicate fulfillment |

## Run the real local chain in a sandbox

Use the project's actual test configuration and Stripe's sandbox or test mode. Start the app and its backend in the correct checkout. Stripe documents using its CLI listener to forward events to a local webhook endpoint; confirm the listener's printed signing secret is wired to the local handler and kept out of commits and screenshots. Complete one Checkout with Stripe's documented test payment method, then inspect the Stripe test event, listener output, server log, and your app's order or entitlement record. Repeat with a declined method and, if your enabled payment methods allow it, a delayed-success flow. Do not use real card details in a live account as a test.

- Write down the checkout branch, local URL, Stripe environment, event ID, and app record ID; redact sensitive values.
- Use test fixtures for customers and products so a successful trial is easy to compare with a failed one.
- Confirm the app's visible state agrees with the server record, not only with the return-page message.

## Read the webhook and fulfillment code

The webhook should verify Stripe's signature with the raw request body before acting on the event. Review the event types the app accepts, the Checkout Session it retrieves, the payment state it checks, and how it maps that session to the intended customer and product. Stripe's fulfillment guide requires a function that is safe to call more than once, including concurrently, for one Checkout Session. Its webhook guide says duplicate deliveries occur and event order is not guaranteed. A database uniqueness rule or equivalent atomic guard around the fulfillment key is stronger evidence than an in-memory flag. If the landing page also calls fulfillment for speed, both paths must share the same safe function.

- Try a request with an invalid signature and confirm no order or entitlement is created.
- Replay the same test event and verify exactly one final result.
- Check a delayed event cannot grant access while the Checkout Session is still unpaid.

## Review the failure and deployment boundary

Inspect what happens when the app's database write fails after a verified event: is the failure visible, retryable, and protected from duplicate fulfillment? Check Stripe Workbench event deliveries for delivered, pending, or failed attempts and compare them with application logs. Before launch, verify that the production endpoint is a reachable HTTPS URL, subscribed to the needed events, and using its own live signing secret and API keys in the approved secret store. The local CLI listener and sandbox keys do not configure production for you. For subscriptions, recurring invoices and entitlement changes add more states; use Stripe's subscription guidance and get a review tailored to that flow rather than extending this one-time checklist by assumption.

- Record who can reconcile a paid Stripe Session with a missing app entitlement.
- Check live configuration names and destinations without publishing secret values.
- Have an experienced reviewer inspect changes that can grant paid access or move money before launch.

## Close the PR with evidence from the latest commit

Ask a second agent for read-only findings tied to the changed files and the test matrix, then reproduce important claims yourself. A green build, a pretty success page, and an agent's assurance are each incomplete evidence. Review the exact head commit after any fix, run the affected sandbox cases again, and record the Stripe event, app record, test result, and open risk. The general PR guide covers comment and CI workflow; the access-control guide covers who may see the purchased content after fulfillment. Only approve when someone owns the remaining operational and product decisions.

## Copyable resources

### Checkout review handoff

Use test mode only and redact account identifiers and secret values before sharing.

````text
One-time product and expected price: [ ]
PR head commit / branch / local URL: [ ]
Stripe sandbox or test environment: [ ]
Checkout creation route / return page / webhook endpoint: [ ]
Customer-to-Session mapping and fulfillment key: [ ]
Successful test: event [ ], app record [ ], access [ ]
Decline: event/result [ ], app access remains blocked [ ]
Delayed payment: pending [ ], final success/failure [ ]
No return page: webhook still fulfills [ ]
Invalid signature: rejected without fulfillment [ ]
Repeated event: one final fulfillment [ ]
Database failure: recovery owner and retry path [ ]
Latest diff and checks reviewed by: [ ]
Production HTTPS endpoint and live secrets verified by: [ ]
````

## Frequently asked questions

### The success page loaded. Is the payment integration finished?

No. Confirm the paid Stripe Session, verified webhook, and one correct app order or entitlement. A customer may never reach the return page.

### Why test the same webhook twice?

Stripe can deliver duplicate events, and Checkout fulfillment may be called by both a webhook and return page. The same purchase must not produce duplicate fulfillment.

### Can I use my own card for a small live test?

Use Stripe's sandbox or test mode and its documented test payment methods. Keep test keys and events separate from live configuration.

### Does this cover subscriptions?

It covers a one-time Checkout flow. Subscriptions add renewal, failed invoice, cancellation, and entitlement-state decisions that need their own product rules and tests.

## Sources and further reading

- [Stripe Checkout fulfillment and test listener](https://docs.stripe.com/checkout/fulfillment?payment-ui=stripe-hosted)
- [Stripe webhook signatures, retries, duplicates, and event ordering](https://docs.stripe.com/webhooks)
- [Stripe testing and test payment methods](https://docs.stripe.com/testing)
- [Canopy current-main README and release caveat](https://github.com/FluidWorksApp/canopy-ide/blob/main/README.md)

## Related Canopy pages

- [How to review an AI-generated access-control PR](https://canopyide.dev/guides/review-ai-generated-access-control-pr.md)
- [How to review an AI-generated pull request](https://canopyide.dev/guides/review-ai-generated-pull-requests.md)
- [How do I start my website, API, and worker with one click?](https://canopyide.dev/use-cases/one-click-local-dev-stack.md)
- [How to hand an AI-built app to a developer for review](https://canopyide.dev/guides/handoff-ai-built-app-to-developer.md)
- [Can I launch my AI-built app? A founder's decision sheet](https://canopyide.dev/guides/ai-built-app-launch-checklist-for-founders.md)

Canopy runs installed coding CLIs; CLI accounts, model selection, and provider billing remain separate. Check the installed release before relying on version-specific behavior.
