💳 Prompt Pack · Day 4 · S3 · Payments

Eight prompts. First dollar.

Fri 10 Jul · Stripe + Supabase edge functions + webhook loop. Copy · paste · your app takes a real (test) payment by 5 PM.

💡 How this pack works. Every prompt below is designed to run inside your Cowork Project (the one that already knows your MVP, PRD, and what's been built on Day 4 S1 + S2). Prompts reference your Project-Plan.md · your Supabase MCP · your Stripe MCP · and Lovable. P00 is your context filler · run it first if your Project doesn't already have Stripe context. Then work through P01–P08 in order.
🎯 Your S3 loop: Setup (P01–P02) → Feature Builder Loop with 5 gated stages (P03) → Debug (P04) → Test (P05) → Polish + Go-Live (P06–P07) → Plan (P08). P03 is the core. If you only run one prompt today · run that one.
📚 Contents · 9 prompts total
P00 · Context Loader
SetupStripe MCP
Payments context loader
Run this once at the top of your S3 chat. Loads your MVP context · reads your Project-Plan.md · queries Stripe MCP + Supabase MCP for current state · reports what's ready and what's missing. The rest of the pack assumes this ran.
ROLE
You are a senior payments engineer working inside my Cowork Project. You have full context on my MVP (from Foundation Doc, PRD, and Day 4 S1 build).

GOAL
Prime this chat with everything needed to add Stripe payments today. Do NOT write code yet · just report state.

CONTEXT · READ THESE
1. Foundation Doc + PRD in this Project's Knowledge
2. Project-Plan.md (features shipped so far)
3. Supabase MCP → list_tables · report which tables exist (esp. `subscriptions` if any)
4. Stripe MCP → get_stripe_account_info · fetch_stripe_resources (products, prices)
5. Existing edge functions → mcp list_edge_functions

OUTPUT · 6 sections
1. What I'm selling (product name · one-time or subscription · price · currency) — derived from PRD
2. Stripe state (account exists yes/no · test mode active · products in test mode)
3. Supabase state (subscriptions table yes/no · RLS enabled)
4. Edge fn state (create-checkout-session · stripe-webhook · deployed yes/no)
5. Frontend state (Pricing page exists in Lovable · Success page · Cancel page)
6. Gaps to close today · ranked · with recommended next prompt (P01–P08)

SELF-CHECK
- Did I actually query the MCPs (Supabase + Stripe) or just guess? If guess → re-do with MCP.
- Did I read Project-Plan.md? If not → read it.
- Did I recommend the RIGHT next prompt? (If Stripe account doesn't exist → P01. If it exists but no products → P02. If both exist → P03.)
Pro tip: If Cowork can't reach Stripe MCP · connect it first: Settings → Connectors → Stripe → Add. Uses your test-mode API key. Takes 30 seconds.
P01 · Setup
Setup
Stripe setup coach
Walks you through Stripe account creation with the exact minimum info needed for test mode. No fluff. No "we need your EIN" panic. Just: sign up · enable 2FA · confirm test mode · bookmark 3 pages. 5 minutes.
ROLE
You are my Stripe onboarding coach. Talk me through account creation like I'm building an MVP · not a public company.

GOAL
Get me to a state where I have (a) a Stripe account (b) 2FA enabled (c) test mode confirmed active (d) API keys copied and stored safely.

OUTPUT · a numbered 8-step walkthrough
For each step: exact URL to visit · what to click · what to type · what I should see next.

Steps to cover:
1. Sign up at stripe.com · what info to give (real vs "figure out later")
2. Business type · pick "Individual/Sole Prop" if unsure
3. Country + currency — stress that CANNOT be changed later
4. Enable 2FA · Settings → Team + Security (required for live mode later)
5. Confirm Test Mode toggle in top-right is ON
6. Developers → API keys · reveal + copy `pk_test_…` and `sk_test_…`
7. Where to store secret key safely (Supabase Edge Function env · never Lovable public var)
8. Bookmark 3 pages: Products · Webhooks · API keys

SELF-CHECK
- Did I tell them WHERE to put `sk_test_` (Supabase secrets · not Lovable)?
- Did I flag the "country can't be changed" gotcha?
- Did I skip anything they don't need for TEST mode? (Bank account · tax ID · full business address — all optional for test.)
Pro tip: Stripe will nag you to "activate live" · ignore it. Test mode is enough for the entire cohort. Flip to live only when you're ready to charge real money (Sellathlon Day 8 or launch).
P02 · Products
BuildStripe MCP
Products + Prices generator
Uses Stripe MCP to create your Product + Price(s) programmatically · returns the price_ids you'll paste into P03. Handles one-time · monthly · yearly · trial · in one shot.
ROLE
You are a Stripe API operator. Use the Stripe MCP to create products + prices for my MVP.

CONTEXT
- My MVP: {{from Project-Plan.md · e.g. "AI journal app"}}
- Pricing model I want: {{one-time / monthly sub / yearly sub / freemium}}
- Price: {{$X}} in {{USD}}
- If subscription: trial days? {{0 or 7 or 14}}

GOAL
Create in test mode via Stripe MCP:
1. One Product with name + description
2. All required Prices (monthly · yearly · one-time · whatever I picked)
3. Return the `price_id`s in a copy-able table

STEPS
1. Confirm my pricing model by echoing it back
2. Call Stripe MCP `stripe_api_write` → create Product
3. Call Stripe MCP `stripe_api_write` → create each Price (with `recurring` param if sub)
4. If trial: include `trial_period_days` on the price
5. Return a Markdown table with: Price name · Amount · Interval · price_id
6. Update Project-Plan.md → Features → "Stripe products created" ✓

SELF-CHECK
- Am I in test mode? (price_id should start with `price_1…test…` context)
- Did I use the correct currency? (matches account default)
- If sub → is `recurring.interval` set to "month" or "year"?
- Did I return the price_ids in a copy-able format?
Pro tip: Create both monthly and yearly · even if you'll only show monthly first. Yearly is the upsell lever on Day 8 Sellathlon. Set yearly = 10× monthly (2 months free) unless you know better.
P03 · CORE ⭐
CoreBuildTest
Payments Feature Builder Loop
The one prompt to run today. Mirrors S1's 5-stage gated loop but for payments. Stage 1 = HTML mockup preview in chat (Pricing + Success + Cancel pages) · Stage 2 = Supabase subscriptions migration + BOTH edge functions + webhook signing secret walkthrough · Stage 3A = Lovable QA review · Stage 3B = 3 test cards + human review · Stage 4 = iterate · Plan update. Every stage gates on your approval.
ROLE
You are my senior payments engineer + designer. I want to ship Stripe Checkout end-to-end today. You will run a 5-stage gated loop and STOP at each gate until I approve.

CONTEXT
- Product: {{name}} · Price IDs from P02: {{price_monthly}} · {{price_yearly}}
- Mode: subscription (or one-time · adjust accordingly)
- Design tokens: light theme · indigo/violet gradient · Outfit + Instrument Serif + JetBrains Mono (or my brand tokens from Foundation Doc)
- App stack: Lovable frontend · Supabase auth + DB + edge functions
- Trial: {{0 or 7 or 14 days}}

GOAL
Ship: Pricing page → Checkout Session → Stripe → Success page → Webhook writes to `subscriptions` table → user has "active" status.

═══ STAGE 1 · HTML MOCKUP PREVIEW · IN CHAT · NOT LOVABLE ═══
Generate ONE self-contained .html file rendered inline in this chat with:
- Pricing page (monthly · yearly toggle · CTA button)
- Success page (with confetti or celebratory glass card)
- Cancel page (empathetic · "no worries · try again")
- Inline <style> using my design tokens
- Hardcoded mock user + mock plan
- All 3 pages as toggleable sections at top

GATE 1: STOP. Ask: "Approve the mockup or want changes? Which page needs work?"

═══ STAGE 2 · SUPABASE + EDGE FUNCTIONS ═══

2A · Supabase schema (via Supabase MCP `apply_migration`):
- Create `subscriptions` table with columns: id · user_id · stripe_customer_id · stripe_subscription_id · stripe_price_id · status (trialing/active/past_due/cancelled) · current_period_end · cancel_at_period_end · created_at · updated_at
- Enable RLS · policy: user reads own only · service role writes
- Indexes on user_id + stripe_subscription_id

2B · Edge functions · TWO of them
Ask me: "Ready to create both edge functions? (create-checkout-session + stripe-webhook)"
If yes → walk me STEP-BY-STEP with EXACT:
  - File paths: `supabase/functions/create-checkout-session/index.ts` and `stripe-webhook/index.ts`
  - Full Deno TypeScript code for BOTH (CORS · auth check on Session · signature verify on webhook)
  - Exact URL to get webhook signing secret: https://dashboard.stripe.com/test/webhooks
  - Exact Supabase Dashboard path for secrets: Project → Edge Functions → Secrets
  - Secret names: STRIPE_SECRET_KEY · STRIPE_WEBHOOK_SECRET · SUPABASE_SERVICE_ROLE_KEY · SITE_URL
  - Deploy commands: `supabase functions deploy create-checkout-session` and `supabase functions deploy stripe-webhook --no-verify-jwt` (webhook MUST be no-verify-jwt)
  - Local test with Stripe CLI: `stripe listen --forward-to [url]` + `stripe trigger checkout.session.completed`
  - Common failure: "signature failed" → cause = req.json() instead of req.text() → fix

2C · Wire mockup to Lovable
Full Lovable prompt with approved mockup HTML pasted at top · wires "Buy" button to invoke create-checkout-session · redirects to session.url · Success + Cancel pages read session_id from URL.

GATE 2: STOP. Ask: "Migration applied? Both fns deployed? Signing secret added? Lovable wired?"

═══ STAGE 3A · LOVABLE QA REVIEW ═══
Give me a paste-ready Lovable prompt: "Review the Pricing / Success / Cancel pages for 10-star UX. Check: loading states on buy button · error voice if session fails · a11y (contrast, keyboard, screen reader) · mobile layout · empty state · first-10-seconds friction. Suggest 3 concrete improvements."
GATE 3A: STOP. Ask: "What did Lovable suggest?"

═══ STAGE 3B · 3 PATHS TEST + HUMAN REVIEW ═══
Test scripts (already anticipated in 2B build · now execute):
- HAPPY · card 4242 4242 4242 4242 · any future date · any CVC · confirm subscriptions row appears with status=active
- EDGE · card 4000 0025 0000 3155 (3D Secure) · confirm 3DS challenge shows · confirm still lands correctly
- BROKEN · card 4000 0000 0000 9995 (insufficient funds) · confirm error message is human · confirm no partial row

Then HUMAN review checklist:
- Does the flow FEEL like MY product · not Stripe's default?
- Would I be embarrassed to show this to a stranger right now?
- If my 60-year-old parent tried to buy · would they succeed?
- Does the error copy sound like my brand voice · not "Error 500"?
- Does the success page make me smile?

GATE 3B: STOP. Ask: "3 paths result? Human concerns?"

═══ STAGE 4 · ITERATE ═══
Based on 3A + 3B feedback · give me ONE polish per page (Pricing · Success · Cancel · Error toast).
Lovable prompts to implement each.
GATE 4: STOP. Ask: "Ship or another iteration?"

═══ PLAN UPDATE ═══
Update Project-Plan.md:
- Payments status: Mocked → Wired → Tested → SHIPPED
- Note trial length · price IDs used · edge function names
- Next: P05 (extensive test cards) OR P06 (customer portal) OR P07 (go-live check)

NON-NEGOTIABLE
- Stage 1 is ALWAYS HTML preview in chat first · NEVER Lovable first
- Stage 2B ALWAYS gets my "yes" before writing edge fn code
- Signing secret walkthrough ALWAYS includes exact URL + secret name
- Stage 3B ALWAYS includes human-review (not just Lovable auto-review)
- Every stage gates on my approval before proceeding
Pro tip: If Cowork tries to skip Stage 1 (mockup) and jump straight to Lovable · reply: "no · render as HTML in chat first · I want to see it before you touch Lovable." The gates only work if you enforce them.
P04 · Debug
Debug
Webhook debugger
When your webhook fires but Supabase doesn't update — or worse, signature verification fails. Runs a 6-step diagnostic covering the 90% of causes. Uses Supabase logs + Stripe Dashboard events + Stripe CLI to triangulate.
ROLE
You are a payments debugger. Something's off between Stripe → my edge function → Supabase. Diagnose systematically.

SYMPTOM
{{describe: e.g. "payment succeeded in Stripe but no row in subscriptions table" · or "webhook returns 400" · or "signature failed"}}

GOAL
Find root cause · confirm fix · verify with a test event.

DIAGNOSTIC · 6 checks
1. Stripe Dashboard → Developers → Events · did the event fire? What's the response code from my endpoint?
2. Supabase MCP get_logs for edge fn `stripe-webhook` last 20 min · what's the error?
3. Signature check: is the code using `req.text()` (correct) or `req.json()` (breaks signature)?
4. Env var check: STRIPE_WEBHOOK_SECRET matches the Stripe endpoint's signing secret? (These differ between endpoints — even test vs live · and between prod endpoint vs `stripe listen` local)
5. RLS check: is the fn using `SUPABASE_SERVICE_ROLE_KEY` (bypasses RLS · required) not `SUPABASE_ANON_KEY`?
6. Idempotency check: are you upserting on stripe_subscription_id · or blindly inserting (dupes)?

OUTPUT
- Root cause · 1 sentence
- Exact code fix (diff format)
- Test command: `stripe trigger checkout.session.completed` · then check subscriptions table appears

SELF-CHECK
- Did I actually query Stripe events + Supabase logs · or guess?
- Did I confirm the fix WORKS (not just "should work")?
Pro tip: 8 out of 10 webhook bugs = wrong signing secret. If you tested locally with stripe listen · that CLI generated a DIFFERENT secret. Use the dashboard endpoint's secret for deployed code · CLI's secret for local dev.
P05 · Test
Test
Test cards runner
Systematic 6-scenario test matrix using Stripe's test cards. Covers happy path · 3D Secure · decline · dispute · trial end. Confirms your DB reflects reality for each. This is the "did I actually build it right" prompt.
ROLE
You are my QA lead for payments. Walk me through 6 test scenarios · check DB state after each · flag any gap.

CONTEXT
- My Pricing page URL: {{url}}
- Subscriptions table in Supabase (via MCP)
- Stripe test mode active

TEST MATRIX · 6 scenarios
For each: give me the card · what should happen · what DB state to check via Supabase MCP query.

1. HAPPY (subscription) · 4242 4242 4242 4242
   → subscriptions row · status=active · stripe_subscription_id set
2. 3D SECURE · 4000 0025 0000 3155
   → user sees 3DS challenge · after auth · row appears · status=active
3. 3DS AUTH FAILS · 4000 0000 0000 3220
   → error page · no row in DB · no ghost customer in Stripe
4. DECLINE · 4000 0000 0000 9995 (insufficient funds)
   → error toast with human copy · no row · Cancel page or retry
5. DISPUTE · 4000 0084 0000 1629
   → charge succeeds initially · Stripe fires `charge.dispute.created` webhook later
   → verify: does my webhook handler catch this? (Bonus if yes · optional if no)
6. SUB CANCEL · use Stripe Dashboard → Customers → cancel a subscription
   → verify subscriptions row status flips to "cancelled"

OUTPUT · results table
| # | Scenario | Card | UI result | DB result | Pass/Fail |

SELF-CHECK
- Did I query Supabase MCP after each test · not just trust the UI?
- Any scenario where UI + DB disagreed? (That's the interesting bug.)
- Did I test on mobile too · not just desktop?
Pro tip: Run these tests in incognito windows · signed in as different test users. This catches auth bugs where "logged-in Alice pays and Bob gets the subscription."
P06 · Polish
Build
Customer Portal + cancellation
Wires up Stripe Customer Portal so users self-serve their subscription (update card · cancel · view invoices) · which cuts your support load ~80%. Includes cancellation-flow polish (retention prompt · pause option · win-back copy) · which pays for itself the first time it saves a $19 sub.
ROLE
You are a churn-reduction engineer. Wire up Stripe Customer Portal + a polished cancellation flow.

GOAL
User can:
1. Click "Manage subscription" in-app → hit Stripe-hosted Customer Portal
2. Update payment method · view invoices · cancel · pause · switch plan
3. See a branded "we'd miss you" retention screen BEFORE the cancel button (Stripe supports this)
4. My webhook picks up any change and mirrors it in `subscriptions` table

STEPS
1. Enable Customer Portal · Stripe Dashboard → Settings → Billing → Customer Portal · configure branding · enable "pause subscription" · enable "cancellation reasons"
2. Add a 3rd edge function: `create-portal-session` · takes stripe_customer_id · returns portal URL
3. Frontend: "Manage subscription" button in Settings · calls the edge fn · redirects to portal URL
4. Return URL: back to `/settings?portal=return` · show toast "changes saved · syncing…"
5. Webhook events to handle:
   - `customer.subscription.updated` (plan change · pause)
   - `customer.subscription.deleted` (canceled)
   - `invoice.paid` (extend period)
   - `invoice.payment_failed` (flag past_due · trigger email)
6. Retention polish: cancellation reason capture · offer 20% off next cycle · pause 1-3 months option
7. Update Project-Plan.md · Payments milestone → "Portal live"

SELF-CHECK
- Portal branding matches app (logo · colors · font · not raw Stripe)?
- Cancellation reasons are captured in Stripe metadata (I can review later)?
- Retention offer is TASTEFUL · not desperate?
Pro tip: The "pause subscription" option in Portal is underrated. Users who'd cancel outright often pause 1–3 months and come back. Retention math: pause = 60% keep · cancel = 15% keep.
P07 · Ship
ShipWhen ready to charge real money
Go-live readiness audit
Run right before flipping to live keys (usually Day 8 Sellathlon or launch). Audits 12 things: business info · bank account · tax setup · webhook live endpoint · email receipts · dispute strategy · refund policy · terms + privacy · currency · currency · currency (always the gotcha). Only runs green when you're actually ready.
ROLE
You are my go-live checkpoint. I'm about to flip from test mode to live mode. Audit 12 things · block me if I'm not ready.

CHECKLIST · 12 items
1. Stripe account fully activated (Settings → Account status)
2. Business info complete (address · tax ID if applicable)
3. Bank account added and verified (for payouts)
4. 2FA on Stripe login
5. Live webhook endpoint added in Dashboard → Webhooks · live signing secret in Supabase
6. Frontend env var swap: pk_test_ → pk_live_
7. Edge fn env swap: STRIPE_SECRET_KEY test → live · STRIPE_WEBHOOK_SECRET updated
8. Stripe Tax enabled (or explicit decision to skip)
9. Email receipts enabled in Settings → Emails
10. Refund policy page linked from Pricing + Success page
11. Terms of Service + Privacy Policy pages exist
12. Dispute response strategy · who checks Stripe every 3 days?

OUTPUT
- Traffic light per item: 🟢 ready · 🟡 warning · 🔴 blocker
- Blocker count · if > 0 · list exact fixes
- If all green · give me the go-live playbook: 5 steps to flip · what to test first · what to watch for in first 24h

SELF-CHECK
- Did I query Stripe MCP for account status · not guess?
- Did I confirm the LIVE webhook secret is different from test?
- Did I flag the currency-can't-change gotcha (again)?
Pro tip: The first live payment is a moment. Charge yourself $1 as the first live customer. Screenshot it. Post it in the pod thread. That first-dollar photo is peak founder energy.
P08 · Sync
Ship
Plan updater
Syncs your Project-Plan.md after payments is shipped so subsequent prompts (Day 5 polish · Day 6 deploy · Sellathlon) have accurate context. Run this at end of session.
ROLE
You are my product delivery lead. Update Project-Plan.md with everything shipped in S3.

GOAL
Reflect payments state accurately so Day 5–10 prompts don't re-ask questions or re-build features.

UPDATE · these sections
1. Features Shipped · add:
   - Stripe products created (list price_ids)
   - subscriptions table + RLS
   - create-checkout-session edge fn
   - stripe-webhook edge fn
   - Pricing page · Success page · Cancel page (Lovable)
   - Customer Portal (if P06 shipped)
2. Status · Payments milestone: Mocked → Wired → Tested → SHIPPED (test mode)
3. Known gaps · anything from P05 that failed · anything deferred to Week 2
4. Next unlocks ·
   - Day 5 can now polish real payment flow
   - Day 6 can deploy with confidence payments works
   - Day 8 Sellathlon can flip to live keys (run P07 first)
5. Metrics to track · first test payment timestamp · first live payment (target: Day 8)

OUTPUT
Show me the diff of Project-Plan.md before writing. Confirm with me before applying.

SELF-CHECK
- Did I actually read the current Project-Plan.md first?
- Did I not overwrite non-payments sections?
- Am I honest about what's SHIPPED vs what's DEFERRED?
Pro tip: The Project-Plan.md is your compounding asset · every session that updates it makes every future session cheaper (fewer re-asks · fewer duplicated builds). Skip this at your peril.
✓ Copied · paste into Cowork