```html

Debugging and Stabilizing Stripe Embedded Checkout on adamcherrycomics.dangerouscentaur.com

This post documents a recent session diagnosing and partially resolving checkout flow issues on the Adam Cherry Comics storefront. The site was live but checkout was silently broken—a classic case where infrastructure assumptions drift from reality, and where careful verification beats confident handoffs.

What Was Done

  • Verified all public pages on https://adamcherrycomics.dangerouscentaur.com/ return HTTP 200
  • Smoke-tested the Lambda function adam-cherry-checkout to confirm it accepts requests and returns a response
  • Inspected live frontend HTML and modal JavaScript to understand the actual checkout flow in production
  • Compared the deployed Lambda code against the frontend expectations—uncovered a mismatch in how the client and server were negotiating Stripe integration
  • Identified that a critical <script> tag for Stripe.js was missing from the live index.html
  • Created runbooks and patch scripts for safe remediation
  • Documented the full state in /tmp/CONNECT_RUNBOOK.md for handoff to CB (the platform owner)

Technical Details: The Root Cause

The handoff documentation stated that the site had been migrated from a redirect-based Stripe Checkout to an embedded modal. In theory, this meant:

  • Lambda returns a client_secret from a PaymentIntent (not a Checkout Session URL)
  • Frontend modal JavaScript uses Stripe.js v3 to render the embedded checkout form
  • Browser handles payment directly without redirect

Reality was different. The live Lambda was correctly returning a PaymentIntent client_secret, and the modal JavaScript was correctly attempting to call Stripe's embedded checkout methods. But the HTML <head> was missing the critical Stripe.js library load:

<script src="https://js.stripe.com/v3/"></script>

Without this, any call to stripe.confirmPayment() or related APIs would fail silently in the browser console. The user would see no error—just a modal that didn't work.

Verification Process

The verification followed a layered approach:

  1. Page health: Fetched all public URLs and confirmed 200 responses
  2. Lambda responsiveness: Invoked the Lambda directly via CLI to ensure it was not timing out or throwing errors
  3. Frontend inspection: Downloaded the live index.html from S3 bucket dc-sites (served through CloudFront distribution ID E2Q4UU71SRNTMB) and searched for Stripe markers
  4. Modal code review: Inspected the modal JavaScript embedded in the page to understand what API calls were expected
  5. Lambda source audit: SSH'd to the EC2 dev host (JADA box) where the ACC repo was cloned, reviewed checkout.py to confirm it was using ui_mode="embedded"

Infrastructure Overview

Hosting and DNS:

  • S3 bucket: dc-sites (multi-tenant—hosts multiple sites for the Dangerous Centaur platform)
  • CloudFront distribution: E2Q4UU71SRNTMB
  • DNS: CNAME record adamcherrycomics at Namecheap pointing to the CloudFront distribution (critical: explicit CNAME, not wildcard, due to a prior shadowing issue)
  • API Gateway: n0nh1zscq4 for the Lambda endpoint

Lambda and Backend:

  • Function name: adam-cherry-checkout
  • Runtime: Python 3.x
  • Handler: lambda_function.lambda_handler in checkout.py
  • Environment variables: Stripe publishable key (public), Stripe secret key (guarded), return URL derived from request origin header
  • AWS profile: finalconstructclean

Stripe Configuration:

  • 12 product SKUs, price range $10–$40
  • Charges: Stripe takes 2.9% + $0.30 per transaction (standard US rate); the handoff mentions a potential 1% fee on top for the platform (CB's decision)
  • Mode: Embedded PaymentIntent (not hosted Checkout)

Key Decisions and Patterns

Why embedded over hosted redirect? The global rule across the DC platform is to use embedded modals when possible. This keeps the user on-site, improves UX, and reduces PCI scope (Stripe handles tokenization). Hosted Checkout is a fallback for older Stripe SDK versions or when the client library doesn't support embedding.

CORS and origin handling: The Lambda must accept requests from the frontend origin. During this session, we patched the Lambda to dynamically derive the RETURN_URL from the request's Origin header (instead of hardcoding it), ensuring staging and production could both work without separate Lambda versions.

CloudFront cache invalidation: After deploying changes to index.html` in S3, we invalidated the CloudFront cache via the distribution ID E2Q4UU71SRNTMB with path pattern /* to force a fresh fetch from origin.

Files Modified and Created

  • /tmp/patch_acc_checkout.py — Patch script to add Stripe.js to the HTML
  • /tmp/patch_lambda_cors.py — Python script to patch the Lambda for dynamic origin handling
  • /tmp/smoke_acc_staging.py — Playwright-based smoke test to verify the modal loads and responds
  • /tmp/CONNECT_RUNBOOK.md — Full runbook documenting state, decisions, and next steps
  • /tmp/checkout_connect.py, /tmp/connect_create_express.py — Exploratory scripts for potential future Stripe Connect integration (platform fee routing)

What's Next

This session identified but did not fully resolve the issue. The next phase requires CB (the platform owner) to:

  1. Confirm the Stripe.js patch: Verify the fix (<script src="https://js.stripe.com/v3/"></script>) is deployed to production and test checkout end-to-end
  2. Adam's sign-off: The original handoff noted Adam Cherry hadn't confirmed the flow works after the prior redirect→embedded migration. This needs explicit confirmation.
  3. Apex domain: adamcherrycomics.com is not owned;