3) Env vars (server)

Add to your server’s environment:

STRIPE_SECRET_KEY=sk_test_********************************
STRIPE_WEBHOOK_SECRET=whsec_********************************
APP_BASE_URL=https://your-domain.tld
COVER_TEMPLATE_PRICE_CENTS=1499
COVER_TEMPLATE_CURRENCY=usd
# optional if you want a Pro coupon later:
# STRIPE_COUPON_PRO_20=coupon_********************************


In local dev, set APP_BASE_URL=http://localhost:3000 (or your client URL).

4) Local testing with Stripe CLI (webhook forwarding)

Install Stripe CLI (if not already).

In a terminal:

stripe listen --events checkout.session.completed --forward-to http://localhost:YOUR_API_PORT/api/stripe/webhook


It prints a Signing secret (starting with whsec_...). Use this value for STRIPE_WEBHOOK_SECRET in your local env.

Keep this terminal running while testing.

5) Test the full flow (end to end)

Start your API and web app in test mode.

In your gallery, click a template → Buy As-Is (or Buy with My Image).

You’ll be redirected to Stripe Checkout (test).

Use test card 4242 4242 4242 4242 with any future date, any CVC, any ZIP.

Complete payment → Stripe redirects to your success URL.

Webhook fires (checkout.session.completed) → our server marks the purchase paid and sets download_url.

Verify DB row in cover_purchases: status=paid, download_url populated.

Try the download link (PPTX / Keynote / Google Slides / ZIP).

6) Stripe dashboard steps (if you still want to see items created)

If you choose Option A (auto-create):

As soon as you run a checkout once, go to Products: you’ll see:

Product: Cover + Divider Template (Editable)

Price: $14.99 with lookup_key = ibrandbiz_cover_divider_price_v1

You can change the product description safely in Dashboard (doesn’t break code).

To change the price later, create a new Price and update the code’s lookup_key (e.g., ibrandbiz_cover_divider_price_v2) and env cents.

If you insist on manual product/price and want to avoid the API-created product:

Create a Product in Dashboard (“Cover + Divider Template (Editable)”).

Create a Price for $14.99 USD.

I’ll adjust the code to find price by product name/metadata instead of fixed IDs. (Say the word and I’ll paste that variant.)

7) Troubleshooting

Webhook error 400: Ensure the endpoint handling uses express.raw() before express.json(). In our wiring, /api/stripe/webhook is mounted raw, then we call app.use(express.json()) for others. Keep that order.

No download URL after payment: Confirm the webhook secret matches your environment and that your webhook route is reachable (Stripe CLI forwarding OK).

Price mismatch: If you changed COVER_TEMPLATE_PRICE_CENTS, bump the price lookup key in code from ..._price_v1 → ..._price_v2 to force a new Price creation.

8) What you’ll see in Stripe

Payments: every one-off purchase recorded.

Customers: created for each buyer (via Checkout).

Products/Prices: one product, one active price at $14.99 (test mode).
Later, you can add a live key and repeat in Live mode.