Skip to main content
Lavendly ships a one-shot setup script that creates every Stripe product, price, and webhook endpoint the API needs. Run it once per environment (sandbox + production) and the billing flow is live.

What it creates

Every price uses a stable lookup_key, so re-running the script never creates duplicates, it finds existing prices and skips them.

One-shot flow

1

Get a sandbox key

Stripe dashboard → test mode → API keys.Use the Secret key (starts with sk_test_…) or a Restricted key (rk_test_…) with these permissions enabled:
  • Products → Write
  • Prices → Write
  • Webhook endpoints → Write (only if you pass --webhook)
2

Drop it into .env.local

STRIPE_API_KEY=rk_test_… is also accepted if that’s the var name your tooling uses.
3

Dry run

Prints exactly what it would create. No API mutation.
4

Apply and write back the price IDs

Creates every product + price (idempotent via lookup_key), then appends or updates the STRIPE_PRICE_* block in .env.local.
5

Register the webhook (optional, recommended)

Creates the endpoint subscribed to:
  • checkout.session.completed
  • customer.subscription.deleted
  • customer.subscription.paused
  • invoice.payment_failed
The signing secret is printed on first creation, copy it into STRIPE_WEBHOOK_SECRET. On re-runs it’s stored in the dashboard (Webhooks → endpoint → Signing secret → click to reveal).
6

Restart the API to pick up the new env

7

Verify

Open the canvas, click any “Generate” CTA on a workflow that requires more credits than you have, and the inline buy-credits sheet should pop with three real Stripe Checkout tiles.

Going to production

The exact same script with a live key:
The --live flag is REQUIRED for live keys. Without it the script refuses to run, even in dry mode. There’s no auto-detection, you explicitly opt in.

Re-running safely

The script is idempotent. Re-running it:
  • Finds each existing product by name → reuses it
  • Finds each existing price by lookup_key → reuses it
  • Finds the existing webhook by URL → updates the subscribed events
If you want to change a price (say bumping Starter from 29to29 to 39), the script will not touch the existing price (Stripe prices are immutable once created). Instead:
  1. Archive the old price in the Stripe dashboard.
  2. Pick a new lookup_key (e.g. lavendly_starter_monthly_v2) in scripts/stripe-setup.mjs.
  3. Re-run with --apply.
  4. Update the corresponding STRIPE_PRICE_* env var.

Troubleshooting

Your key isn’t a Stripe secret/restricted key. Check the prefix, valid forms are sk_test_, sk_live_, rk_test_, rk_live_.
Restricted key with insufficient permissions. Edit the key in the Stripe dashboard and grant Write on Products + Prices (and Webhook endpoints if you use --webhook).
Pass --live explicitly. The script never assumes you want to touch your live account.