Stripe go live workflow
Skill Pdbjork/hermosskills-site/skills/stripe-go-live-workflow
Hermesskills — a curated marketplace & repository of AI-agent skills. OpenClaw-compatible catalog at /catalog/v1/skills.json. 30% of commissions fund public-good AI.
npx -y skills add Pdbjork/hermosskills-site --skill stripe-go-live-workflowAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
3 things to look at
- 29 days oldThe repository was created 29 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Operational workflow for taking a working test-mode Stripe integration to live AND for verifying an already-live integration end-to-end. Covers the Dashboard walkthrough, the "never see the live key" safety rule, the test-mode dry run, the live deploy ritual, and the Express/Node verify-the-pipes ritual. Load when a user says "go live," "flip to live," "launch payments," "we're ready for real cards," "real money now," "production time," "I need money," "verify the live Stripe pipes," "smoke test the checkout," or "show me money," or has either a working test-mode Stripe integration that needs to ship OR an already-live Express/Worker integration that needs end-to-end verification. Default assumption when a user says "go live" is wrong: the integration may already be live from a previous session. Always audit state first. Skip for API design questions, key-management theory, or pure code-review tasks — those are covered by `stripe-best-practices`.
SKILL.md
37.0 KB, as published. Nobody here has run it
Stripe go-live workflow
A working test-mode Stripe integration is not a working live-mode Stripe integration. The API calls are the same; the operational sequence around them is different. This skill is the playbook for the second half.
For the API design half (Checkout Sessions vs PaymentIntents,
dynamic payment methods, RAK permissions, webhook signature
verification, deprecation migrations), load
stripe-best-practices. This skill assumes the integration is
already designed correctly and needs to ship.
The single safety rule
The agent must never see, paste, log, or store the live Stripe
key. The user types it directly into wrangler secret put (or
equivalent) from their own machine.
Concretely:
- The agent never accepts an
rk_live_…orsk_live_…value in chat, even if the user offers. - The agent's
.env, shell history, log output, and tool transcripts must not contain live keys. - If the user accidentally pastes one, the agent must (a) refuse to store it, (b) tell the user to roll the key immediately in the Stripe Dashboard, and (c) not echo the value back.
The Worker itself should have a runtime guard: refuse to start if
the key prefix does not match a configured live-mode flag
(Offline Helper's keyMatchesLiveFlag pattern is the model:
a live key with the flag off, or a test key with the flag on,
both refuse to start with a clear 412 error).
Sequenced workflow
Phase 0: The hidden blocker — assume nothing, audit first
The skill's default mental model is greenfield go-live: Worker not yet deployed, key not yet pushed, webhooks not yet wired. That is often wrong. A common case — and the one this skill must handle well — is the integration was set live in a prior session, the user has come back months later, and the catalog and Operator-agent data file may have drifted apart while the Worker kept running. The two failure modes:
- Worker is already live (
/api/healthreturnslive_approved: true), secrets are already pushed, the "go live" work was done before. In that case, the right action is audit + verify, not rebuild. - Worker is not yet live (
live_approved: falseor flag missing entirely), the Operator-agent data file has different liveprice_…IDs than the Worker'sCATALOGconstant, the user is in the wrong Stripe mode, or some mix. In that case the work below is the real Phase 0.
A pre-flight audit is fast and saves the entire conversation from going down the wrong path. The recipe lives in references/live-state-audit.md; the short form is:
# 1. What mode is the Worker actually in?
curl -s --max-time 5 https://<worker-url>/api/health
# or use the browser tool if curl hangs (see pitfall below).
# Look for: "live_approved": true | false
# 2. What does the Worker think the catalog is? (compare to Operator data file)
grep -E "price_" /path/to/worker/src/index.js # Worker's CATALOG
grep -E "price_" /path/to/data/products.json # Operator data file
# These MUST agree on the live price_… IDs. If they don't, you have catalog
# drift and the user has to decide which one is canonical before pushing.
# 3. Are the policy pages live on the domain? (real URLs, not example.com)
for p in /terms/ /privacy/ /refund-policy/; do
code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "https://${DOMAIN}${p}")
echo " https://${DOMAIN}${p} -> HTTP $code" # all three must return 200
done
If the audit shows the Worker is already live and the catalog is consistent, skip Phase 1–5 and go straight to Phase 6 (real-card test charge) and Phase 7 (verify the charge lands in Live mode in the Dashboard). The session-level rule: never re-litigate a deploy the user has already paid for; verify it.
Phase 0a: The hidden blocker — policy pages
Before the user can complete Stripe's Live-mode onboarding form, they need three real URLs on their own domain:
- Terms of Service
- Privacy Policy
- Refund Policy
The Stripe form defaults these to https://example.com/....
Saving those placeholders is technically allowed but creates real
legal exposure: every Checkout receipt and confirmation email
will link to a generic Stripe docs page, and there will be no
real privacy policy at all. Multiple US states (CA, VA, CO, CT,
UT, …) require a real, accessible privacy policy before a
business can collect payment data.
Do this before the user starts the Dashboard walkthrough.
Hand them three freshly-shipped URLs on their domain and have
them paste those into the Stripe form. See
ai-visibility-for-small-sites/references/policy-page-templates.md
for the templates and the ~90 minute build.
Verify on the live site before the user pastes into Stripe:
for p in /terms/ /privacy/ /refund-policy/; do
code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 \
"https://example.com${p}")
echo " https://example.com${p} -> HTTP $code"
done
# all three must return 200
Phase 0.5: Pricing-table alternative to a custom Worker
Stripe has a no-code stripe-pricing-table component
(<stripe-pricing-table pricing-table-id="prctbl_…" publishable-key="pk_…">) that lets the user list their three
products on a static page with a Stripe-hosted checkout, with
zero backend code. If the user pastes one of these snippets into
chat, they have already built the storefront in the Dashboard.
Three options. Always ask which they want before continuing:
| Option | Worker role | Trade-off |
|---|---|---|
| (a) Pricing table only, kill the Worker | None | Simplest. Loses fit-check metadata, Telegram-bot routing, KV fulfillment queue. |
| (b) Pricing table for marketing, Worker for confirmed-fit buyers | Captures fit_check_id + setup_window metadata, routes through to fulfillment queue | Preserves the funnel you designed. Slightly more code to maintain. |
| (c) Pricing table for v1, retire the Worker, re-introduce custom checkout later | None for now | Cheapest v1. Fastest to learn from real data. |
Option (b) is the right answer for most solo-founder service businesses — pricing tables for cold traffic, custom checkout for buyers the founder has already qualified.
If the user goes with (a) or (c), the Worker code can be archived, not deleted — leave a one-line note in the repo README explaining when to revive it.
Phase 1: Confirm test mode is genuinely clean
Run a 4242 4242 4242 4242 test card through the full path. Verify every step before flipping to live:
- Checkout Session creation returns a
url. - Browser redirect (303) lands on Stripe's hosted Checkout.
- Webhook endpoint receives
checkout.session.completedand HMAC signature verification passes. - Fulfillment record is written to the Worker datastore (KV, D1, Postgres, etc.).
- Success URL renders the right page on the user's domain.
- Cancel URL renders the right page on the user's domain.
-
/api/healthreturns the expected catalog andlive_approved: false.
If any step is broken in test, do not flip live. Fix the test path first. The live path will have the same bugs plus a real bank and a real customer.
Phase 2: User-only steps in Stripe Dashboard
Five things only the human operator can do. Be explicit about the division of labor:
| Step | Who | Notes |
|---|---|---|
| Switch toggle to Live mode | Human | Agent cannot do this. |
| Complete Branding + connect bank/payouts | Human | Required for live settlement. Bank verification is usually 1–2 business days. |
| Replicate products + prices in Live | Human | Prices have separate IDs in test vs live. The user copies the new price_… IDs and pastes them back to the agent. |
| Create Restricted API Key (Live) | Human | Name it after the integration (e.g. offline-helper-payments-live). Resources: minimum needed — usually Checkout Sessions: write + read and Webhooks: read. Copy the rk_live_… value into the user's password manager. Never paste it in chat. |
| Create webhook endpoint in Live | Human | Use the new Worker URL (or existing one if not renamed). Events: checkout.session.completed, checkout.session.async_payment_succeeded. Copy the new whsec_… signing secret. Same secret-isolation rule. |
Phase 3: Agent's "bump on go-live" audit
While the user is in the Dashboard, audit the Worker for go-live correctness:
- Stripe API version. Update
Stripe-Versionheader to the current latest. Older versions may not support current payment method types, fraud signals, or Checkout features. - No
payment_method_typesin any API call. Walk every Checkout Session / PaymentIntent / SetupIntent / Subscription creation site. Omit the parameter entirely; let Stripe pick dynamically. Only exception: Terminal (payment_method_types: ['card_present']). - No
automatic_payment_methodson Checkout Sessions. Stripe returns400 parameter_unknownfor it. Dynamic payment methods are the default for Checkout and require no parameter.automatic_payment_methods: { enabled: true }is only valid onPaymentIntents.create/SetupIntents.createon API version 2023-08-16+. If you copy-pasted a PaymentIntent snippet into your Checkout flow, the same call will 400 in production. The fix is to delete the line; do not "set it to null" or "set it to false" — Stripe still rejects unknown keys. Seereferences/headless-cloudflare-deploy.mdfor the Stripe request-log URL pattern that surfaces the exact failing parameter. - No deprecated
ChargesorSourcesAPI calls. Migrate to Checkout Sessions / PaymentIntents / Setup Intents. - Webhook signature verification present and correct. HMAC with the raw request body, constant-time compare. Never trust the event payload without verifying.
- All secrets in platform secret store, not in source code.
wrangler secret putfor Cloudflare. Env vars set in the platform dashboard for Vercel / Netlify / Heroku. Never in.envcommitted to the repo, never hardcoded. - Catalog
price_…IDs updated to live values. Do not assume the test IDs will work in live (they will not). User pastes the live IDs; agent edits the Worker'sCATALOG.
Phase 4: User pushes the secrets
From the user's own machine (not the agent's VPS), the user types:
# 1. Push the live RAK. User pastes rk_live_… directly.
read -rs RAK_LIVE
echo "$RAK_LIVE" | npx wrangler secret put STRIPE_SECRET_KEY
unset RAK_LIVE
# 2. Push the webhook signing secret.
read -rs WH_SECRET
echo "$WH_SECRET" | npx wrangler secret put STRIPE_WEBHOOK_SECRET
unset WH_SECRET
read -rs reads without echo; the variable is unset immediately
after, so it does not linger in shell history or environment.
Wrangler writes the value directly to Cloudflare's encrypted
secret store. The agent never sees the value.
Phase 5: Provision resources + deploy
From the Worker directory (on the user's machine, with their
authenticated wrangler session, or via the agent's
CLOUDFLARE_API_TOKEN pattern if running on a headless VPS):
# 1. Provision the KV namespace if not already done.
npx wrangler kv namespace create OFFLINE_HELPER_QUEUE
# Paste the returned id into wrangler.toml [[kv_namespaces]] block.
# 2. Flip the live flag in wrangler.toml.
sed -i 's/STRIPE_LIVE_APPROVED = "0"/STRIPE_LIVE_APPROVED = "1"/' wrangler.toml
# 3. Deploy.
npx wrangler deploy
Phase 6: Verify the live Worker is actually live
This is the gate. Local validation, screenshots, and "I ran
wrangler deploy" are not the same as "it's live."
-
curl -I https://<worker-url>/api/healthreturns 200. -
/api/healthJSON contains"live_approved": true. - Run one real-card test charge at the smallest available amount. This proves end-to-end: key works, bank accepts, webhook fires, KV record writes, success page renders.
- Refund the test charge immediately if it was a non-real product.
- Confirm the charge appears in Stripe Dashboard → Live mode → Payments. (Not Test mode — a common mix-up.)
- Fast check for which mode a Checkout Session opened
in: the URL's
cs_live_…prefix (vscs_test_…) and the browser tab title (set to the business name from Dashboard Branding on a live session, with no "Test mode" banner). This is faster than asking the user to re-check the Dashboard toggle.
Phase 7: Then and only then, report "live."
Same discipline as ai-visibility-for-small-sites: "built and
ready to ship" is not the same as "live." The user will check.
Pitfalls specific to go-live
-
Same Worker code, but different price IDs. Test and live prices have separate
price_…IDs. Updating CATALOG is mandatory. -
The
<stripe-pricing-table>prctbl_…ID is not aprice_…ID. The pricing-table ID is a container that groups multiple products; it works in the embedded<stripe-pricing-table>element on a static page but is rejected by the Worker'sline_items[].pricefield. The Worker (and any custom Checkout integration) needs each product's individualprice_…ID, not the container. If the user pastes aprctbl_…ID and the Worker is wired to it, every checkout returns 404 from Stripe. Same shape applies to CSV product imports, which return av2.commerce.product_catalog_importobject withstatus: "awaiting_upload"— useful internally to Stripe, not an artifact the integration consumes. Always ask for the individualprice_…IDs when you need them, and verify theprice_…IDs the integration uses by re-fetching the deployed bundle (GET /accounts/<id>/workers/scripts/<name>from the Cloudflare API returns the raw source) before declaring the catalog wired. -
Webhook endpoint URL changes when the Worker redeploys. If the Worker is renamed, moved, or its
account_idchanges, update the webhook endpoint URL in Dashboard or events will silently 404. -
Old test webhook still firing. Either delete the test webhook in Dashboard after the test dry run, or accept that you'll see duplicate test events during the transition.
-
Bank account not yet verified. Stripe lets you create charges before bank verification, but payouts are held (usually 1–2 business days for micro-deposits). Warn the user.
-
Tax settings. If the user is selling in multiple states or countries, Stripe Tax + Registrations API is mandatory. For a US-only small service business, the default is usually fine, but flag it.
-
Statement descriptor. Set in Branding settings. Appears on the customer's card statement. Default is the business name, shortened to 22 chars. Tell the user about it; do not silently leave the default.
-
Mixing test and live modes. Mode toggle is in the top-left of Dashboard. Easy to miss. Always confirm "this is Live mode" before creating the RAK or webhook.
-
Policy pages still at
https://example.com/.... If the user has been sitting on the Dashboard form for more than a day, re-check that they have not saved the example.com placeholders. Pasting realhttps://offlinehelpers.com/...URLs into the form requires the pages to be live on the user's domain first. See Phase 0. -
Catalog drift between Operator data file and Worker CATALOG. The operator-agent pattern stores the live catalog in a JSON data file (e.g.
data/offline-helper-products.json) and the Worker stores the same catalog as a JSconst CATALOG = { … }insrc/index.js. The two must agree on the liveprice_…IDs at all times. A common failure mode: a prior session updated the data file (after recreating a live price in the Dashboard) but the Worker was not redeployed, or vice versa. Symptom:--checkand--planprint one set of price IDs,curl /api/healthand the live Checkout Session use a different set. The two must reconcile before any live test charge. Run the static comparison (Phase 0 above) and ask the user which one is canonical. The fix is mechanical: edit the stale side to match, then redeploy. Do not let the discrepancy ride into a real-card test or the audit trail will not match what the customer was charged. -
Confusing "ready to ship" with "live." The same deployment-discipline failure as
ai-visibility-for-small-sites: you update the Worker'sCATALOG, commit locally, and tell the user "Worker updated." They ask "is it deployed and live?" and you realize nothing has been pushed, the Worker is not running the new code, and the live-mode test charge will fail. The fix is mechanical: after every Worker edit during a go-live flow, run the full ship sequence —git add,git commit,git push, thennpx wrangler deploy(or confirm the user runs it on their machine) — before reporting progress. Local file edits and a cleangit statusare not the same as "the Worker is running this code in production." The "committed and live?" question from the user is a cue to verify, not to re-claim progress. Re-curl the live Worker URL, re-check the deployedcatagainst the local source, re-confirm the catalog price IDs are the live ones, then answer. -
Stale
account_idinwrangler.toml. If the config was copied from a different Cloudflare account, or the account was re-created,wrangler whoamisucceeds (uses the token's default account) butwrangler deployerrors withaccount_id … does not match any of your authenticated accountsand a 10000 auth code. Fix: runnpx wrangler whoami, paste the Account ID intowrangler.toml'saccount_id = "…"line, or remove the line entirely. Verify withwrangler deploy --dry-runbefore any--livepush. Seereferences/headless-cloudflare-deploy.mdfor the full headless-VPS pattern (~/.cloudflare_token,deploy.sh,set-secrets.sh). -
CLOUDFLARE_API_TOKEN does not persist across shells. Setting
export CLOUDFLARE_API_TOKEN=…in one shell, then runningwranglerfrom a different shell (e.g., a fresh terminal, a backgrounded process, a cron-style command), silently loses the variable. Either run all wrangler commands from the same shell, or stash the token in~/.cloudflare_token(chmod 600) and load it via a one-lineexportat the top of every deploy script. The template scripts intemplates/deploy.shandtemplates/set-secrets.shalready do this. -
Strict
LIVE_APPROVEDgate blocks the test dry run. A Worker that hard-rejects (HTTP 412) when the Stripe key prefix mismatches theLIVE_APPROVEDflag is safer in theory but makes the test-mode dry run impossible: you cannot load a liverk_live_…key with the flag off to test the live catalog, and you cannot load a test key with the flag on to test the production path. The two-step dry run (test-key-then-swap) is the textbook answer but doubles the key-swap dance. The pragmatic middle ground: relax the gate to aconsole.warnfor thelive_approved=0 + live keycombination (still production-safe because the flag still controls real charges), and keep the hard reject for the impossiblelive_approved=1 + test keycombination. Document the relaxation in the code so a future maintainer does not reintroduce the strict gate and re-block testing. -
Browser automation cannot reliably fill the Stripe Payment Element form during the dry run. The form is React-controlled with hidden iframes for the card field.
browser_type+browser_clickof "Pay with card" works for card number / expiry / CVC, but JS-injected values for ZIP and phone number get cleared on the blur event the browser tools emit, leaving the form in the "incomplete" state. Spend at most 5 minutes on automation before handing the Checkout URL to the human user to complete in their own browser, or fall back to a real $0.50 charge with refund. Seereferences/stripe-checkout-automation.mdfor the full failure modes. -
Cloudflare's
workers.devsubdomain doubles up if the script name is the only Worker in the account. Whenwrangler deployis the first deploy in an account, the account-levelworkers.devsubdomain gets auto-set to the script name. The published URL is thenhttps://<script-name>.<script-name>.workers.dev(e.g.offline-helper-payments.offline-helper-payments.workers.dev). Three ways to handle it: accept the doubled URL as-is (it works, just long), set a shorter account subdomain via the API (PUT /accounts/<id>/workers/subdomainwith{"subdomain": "pdbjork"}), or route a custom domain instead. Verify the chosen URL responds 200 from a browser, not justcurl— some VPS curl builds fail TLS handshakes to doubled-prefix hostnames even when the browser gets through cleanly, which is a local cert / SNI issue, not a real outage. **Right reflex whencurl https://<doubled>.workers.dev/api/healthhangs from a VPS: open the URL in the browser tool (browser_navigatebrowser_snapshot) and read the JSON body from the accessibility tree. A 30-second hang in curl is not a Worker problem; it is the doubled-prefix SNI issue and the Worker is almost certainly fine.**
-
wrangler 4.99(and later) prompts to install Cloudflare skills for detected AI agents. The first time a user runsnpx wrangler deployon a new machine, wrangler scans forgemini-cli,antigravity,hermes-agentand offers to install Cloudflare'scloudflare/workersskill pack. This is interactive — a non-TTY context (backgrounded process,nohup, cron) will block. Either pre-install the skills vianpx skills add cloudflare/skills, or run wrangler from a real TTY once to dismiss the prompt before any non-interactive deploys. -
read -rsreturns empty and you write a 1-byte token file. If the paste toread -rs CLOUDFLARE_API_TOKENcaptures only a trailing newline (common in some terminal emulators), the subsequentecho > ~/.cloudflare_tokenwrites a single newline,wc -cprints1, andwranglerfails with a confusing auth error later. Always verifywc -c ~/.cloudflare_tokenshows 40+ (Cloudflare tokens are 40 chars) immediately after theread -rsblock, before anywranglercommand. -
The agent's tool chain can rewrite
$(cat …)in shell scripts. If the script you intend to write contains a command-substitution token, the file on disk may end up with the$()stripped and a stray)left over, producing a bash syntax error. Symptom:bash -nthe script →syntax error near unexpected token ')'on the line that looks correct in the source. The fix is mechanical: use bash input redirection instead of command substitution (read -r VAR < fileplus a separateexport VAR), which has no$()to filter. This is the right default for any token-loading helper script that may be authored or re-saved through an agent tool chain. -
Workers that depend on a paid LLM will 500 the day the account runs out of quota. A 429
insufficient_quotafrom OpenAI / Anthropic is not a key-push problem — it is a billing problem on the LLM account. Common with brand-new accounts whose free credits expired, or accounts with no payment method on file. The Stripe payment path is independent of the LLM billing path, so the rest of the live integration (Checkout Session creation, webhook → KV, fulfillment) can be fully live while the chat funnel is dead. Build the form-fallback before the chat. A 5-field static form that POSTs to the samecompleteendpoint preserves thefit_check_idround-trip and the Stripe metadata chain with no LLM call. Seereferences/ai-fit-check-chat.mdfor the full pattern and the "form is load-bearing, chat is polish" framing. -
The "two-machine problem" — assuming the user means the wrong shell. When the project lives on both the user's laptop and the agent's VPS (or two agents, or a CI runner and a dev box), and the user says "you do it" or "push the key" or "deploy it," the agent has to pick a machine. Wrong default: assume the user's laptop. Right default: assume the machine the agent has been working on, which is usually the VPS, and state the machine out loud and confirm before running. The cost of getting this wrong is a secret bound to the wrong Worker, a 500 the user can't diagnose, and 10 minutes of "I pushed it but it's not working" debugging. The reflex is the same as the "committed and live?" pitfall: verify, don't assume.
-
"I need money" / "verify the live Stripe pipes" is NOT a go-live request. When the user says that, the default action is not to rebuild or flip modes — it's to prove the existing live plumbing works end-to-end. This is the Express-served verify-the- pipes ritual (or Phase 6 + Phase 7 of this skill for Workers): start the existing server, hit
/api/health, fire realcs_live_…checkout sessions, cross-verify each with Stripe REST (livemode=True), expire any orphan sessions left by prior runs, kill the servers. Six steps, ~3 minutes. Seereferences/express-live-smoke-test.mdfor the full ritual andscripts/live-smoke-test.shfor the one-shot executable. The Worker equivalent iswrangler tail+ a real-card charge. Always run the orphan-cleanup loop at the end. Smoke sessions accumulate in the Stripe Dashboard's open-sessions view across runs that never cleaned up; a single unrun cleanup over months can produce 10+ orphan sessions that look like abandoned carts and skew the "recent activity" view. Treating the smoke test as just "fire some sessions" without the cleanup is the same shape of failure as treating "go live" as just "flip the toggle." -
The "live" may already be live — audit before you build. When the user says "ship Offline Helper payments live" or "Phase 1: Stripe live," the default assumption is "build it from test mode to live mode." That is the wrong default. The previous session (or a prior workflow) may have already pushed the live key, set
STRIPE_LIVE_APPROVED = "1", and deployed. The very first thing the agent should do is verify the current state before any "go live" planning:curl -sS https://<worker-url>/api/healthfrom a browser (VPS curl often fails TLS on doubledworkers.devsubdomains) and read thelive_approvedfield. If it'strue, the Worker is already in live mode.- Read the Worker's
wrangler.tomlto confirmSTRIPE_LIVE_APPROVEDand the[[kv_namespaces]]binding. - Read the Worker's
CATALOGand the operator agent'sdata/*.jsonand reconcile price IDs. A divergence between the two is the canonical "deployed but stale" tell. The Worker is what buyers see; the data file is what the operator script will reach for if you run--apply. They must match. - Confirm policy pages are 200 on the user's
domain (
/terms/,/privacy/,/refund-policy/). - Confirm the live webhook endpoint is wired in the Dashboard (ask the user — this is user-only).
Only then should you and the user talk about what's actually left: a real-card end-to-end test, a refund, the catalog reconciliation, or — if everything checks out — "Phase 1 is done, you are live, here is your $0.50 refund receipt." The build-from-scratch plan is the contingency, not the default. Defaulting to it is the same "committed and live?" reflex in reverse: you assume work that doesn't need doing and create work for the user that may not be necessary.
-
"The doc says X" is not "the live site does X." Generalize the audit reflex beyond deploy state. The previous pitfall covers Worker/server deploy state. The closer pattern that bites even when the integration is greenfield: a brief, design doc, yesterday's YOLO summary, or a prior session's hand-off states a fact about the product surface (not the deploy state), and the agent treats that fact as ground truth. Examples observed in 2026-07-05 Offline Helper work:
- "The landing page has no payments" — true on the intent layer, false on the deploy layer: the Worker with full Stripe Catalog existed in the repo but had never been deployed; the confirmed-fit-payment page referenced a doubled-subdomain Worker URL that would 404 even after deploy. The doc was describing the intent, not the deployed reality.
- A new navigation link on
index.htmlto a page that exists locally but isn't on origin's main yet → 404 on the live site. Local repo state ≠ GitHub Pages state. - "The Capture endpoint returns 500 with body X" stated in a brief → the live endpoint returns 200 with body Y because a different upstream worker has been swapped in. Briefs are snapshots of intent, not live state.
Right reflex before designing against any doc premise about product behavior: for each stated fact, run a 30-second live probe and cite the response in your plan. The minimum probe set for "Stripe on landing" / "checkout on marketing page" requests is:
- Worker URL or server port reachable?
curl -s --max-time 5 <url>/api/healthfrom the VPS, orbrowser_navigate+browser_snapshotto read JSON. Read bothlive_approvedand the catalog id list. - Hardcoded Stripe URLs in the live HTML
actually point to a deployed Worker?
curl -s https://<domain>/<page>.html | grep -Eo 'https?://[^\"'"'"' ]*' | grep -i 'stripe\|workers.dev'. (A doubled-subdomain URL is a deploy signal even if curl returns 200; the URL is the wrong URL.) - Pages referenced by nav actually 200?
for p in /nav-page-a /nav-page-b; do curl -s -o /dev/null -w "%{http_code} $p\n" https://<domain>$p; done. - Endpoints cited in the brief —
/api/stats,/api/interest, etc. — match the endpoints the live page actually calls?grep -Eo 'api/[a-z_-]+' index.htmland compare.
The docs describe what should be true; the live site describes what is. When they disagree, the work is to converge them — not to assume the doc is right. "I shipped the deploy the brief described" against a doc that didn't match live state creates a parallel checkout path next to the existing-but-broken one. Probing first costs 30–120 seconds; rebuilding on a wrong premise costs an entire session.
Signals that should trigger this skill
- Greenfield go-live: "Go live," "launch payments," "flip to live," "we're ready for real cards," "real money now," "production time," or similar.
- Already-live verification: "I need money," "verify the live
Stripe pipes," "smoke test the checkout," "show me money," or
any request to prove an existing Express/Worker Stripe
integration is healthy end-to-end. Use the Express ritual in
references/express-live-smoke-test.md(or the Worker Phase 6- Phase 7 path) for this branch.
- A working test-mode Stripe integration that needs to ship.
- Questions about RAKs, restricted API keys,
rk_live_, the difference between test and live prices, or webhook signature verification in production.
Signals that should NOT trigger this skill
- "How do I use Checkout vs PaymentIntents?" →
stripe-best-practices - "Is my Worker code PCI-compliant?" →
stripe-best-practices - "Should I use Subscriptions or one-time charges?" →
stripe-best-practices - Pure code review with no production-deploy intent.
Related skills
stripe-best-practices— API design, RAK permissions, dynamic payment methods, webhook signature verification, deprecation migrations. Load first for any design question; this skill assumes the design is correct.stripe-live-rollouthas been consolidated into this skill. Its unique material — the AI fit-check chat pattern and thecs_live_…browser-title trick — now lives inreferences/ai-fit-check-chat.mdand the "Live-mode verification" section below, respectively.ai-visibility-for-small-sites— closing the "AI says nothing about you" gap. Companion workstream that often ships alongside go-live: the JSON-LD on the live site should reflect the live-mode Stripe catalog, not the test-mode one.wranglerandworkers-best-practices— for the Cloudflare Worker deploy mechanics.github-pages-product-landing— for the static-site side of the integration (success/cancel pages, FAQ, schema.org).
Support files
templates/deploy.sh—wrangler deploywrapper that readsCLOUDFLARE_API_TOKENfrom~/.cloudflare_tokenand defaults to dry-run (use--liveto actually push).templates/set-secrets.sh—wrangler secret putwrapper forSTRIPE_SECRET_KEY+STRIPE_WEBHOOK_SECRETwith hidden prompts. No values written to disk.references/headless-cloudflare-deploy.md— full headless-VPS pattern, theaccount_idmismatch pitfall, the token-persistence pitfall, and the empty-read -rs/ 1-byte token file gotcha.references/live-state-audit.md— the 60-second pre-flight audit: Worker mode (live vs test), catalog drift between Operator data file and Worker CATALOG, policy pages, Stripe-mode sanity, and what the audit does not cover (webhook URL, bank verification, statement descriptor). Read this before the "go live" request to route greenfield-vs-already-live correctly.references/page-state-probe.md— the probe playbook for verifying any design-doc premise about the product surface (live HTML, hardcoded URLs, nav links, endpoint citations) before designing against it. Companion tolive-state-audit.md; together they cover deploy-state and page-state. Read before any "Stripe on landing" / "checkout on marketing page" request where a brief, design doc, or yesterday's YOLO summary has stated a fact about user-visible behavior.references/stripe-checkout-automation.md— what works and what doesn't when the agent usesbrowser_*tools to fill the Stripe Payment Element during the test dry run. Read this before spending time on browser-form automation.references/ai-fit-check-chat.md— the AI fit-check chat pattern (gpt-4o-mini →[READY_TO_SCORE]token → scoring function →fit_check_idround-trip into Stripe Checkout metadata), the per-serviceset-openai-key.shsibling pattern, the$(cat ...)tool-filter pitfall, the 429-insufficient-quota failure mode with the static-form fallback, the "which machine am I on?" reflex for two-machine sessions, and the "Failed to fetch" CORS + opaque-redirect trap on the buyer's checkout click (theResponse.redirect()gotcha- the
fetch(..., { redirect: 'manual' })gotcha, with the native-form-submit fix).
- the
references/user-communication-cadence.md— the one-word-prompt-during-known-flow handling, the hybrid-storefront (pricing table + Worker) framing, the "placeholder values are a STOP signal" rule, and thecs_live_…browser-title live-mode verification trick. Consolidated from the archivedstripe-live-rolloutskill.references/express-live-smoke-test.md— the Express/Node verify-the-pipes ritual for when the integration is already live (env file at/etc/<product>.env, Expressserver.mjs) and the user says "show me money" or "verify the live Stripe pipes" rather than "go live." Six steps: find env + port, background-start server withset -a; . /etc/...env; set +a, hit/api/health, fire live-mode checkout sessions via curl, cross-verify each with Stripe REST (livemode=True), expire every orphan session on the account, kill the servers. Includes the test-key- masquerading-as-live-key pitfall, the localhost-only binding convention on this VPS, and the "always expire orphans — they accumulate" housekeeping rule. The Cloudflare Worker equivalent is Phase 6 + Phase 7 of the main SKILL.md.scripts/live-smoke-test.sh— one-shot executable that runs the six-step ritual for a list of products in one invocation. Read each/etc/<product>.env, start each server on its port, fire one session per price tier, cross-verify, expire orphans across all touched accounts, kill all servers, print a green/red summary. Usage:live-smoke-test.sh chromebloom 3017 cart seed-red-anthurium-planter hermosskills 3019 plan sponsor hermosskills 3019 plan commission.