Setting up Stripe for hosted billing
Reading time: 8 minutes. Hands-on time: ~30 minutes (most of it inside Stripe’s dashboard, not this codebase). What you’ll have at the end: a working hosted-mode billing flow — customers can pick a plan from
/pricing, complete checkout on Stripe, get a 14-day trial, and self-serve plan changes via the Stripe Customer Portal.
This tutorial only matters if you’re running the hosted mode of Scarif One. Self-host installs (Sovereignty Package customers) don’t pay subscriptions and don’t need any of this.
Prerequisites
- A Stripe account in live mode (Test mode works for staging — same flow, different keys).
- Your business verified with Stripe (UK-based businesses need to complete the Bank Account / KYC step before going live).
- Optional but recommended: Stripe Tax enabled if you sell to EU customers. Stripe handles VAT calculation automatically.
Step 1 — Create the products
In your Stripe Dashboard → Catalog → Products → Add product.
You’ll create four products total. Each has one or two prices attached.
Product 1: Scarif One — Solo
- Name: Scarif One — Solo
- Description: Replace your freelance copywriter. 100 ad gens / 50 emails / 4 trends per month. Single tenant.
- Image: optional — upload your logo if you want it on Checkout pages
Add two prices to this product:
- Price 1 (monthly): £29.00 GBP, recurring, billed monthly. Copy the resulting
price_…ID. - Price 2 (annual): £290.00 GBP, recurring, billed yearly. Copy the resulting
price_…ID.
Product 2: Scarif One — Pro
- Name: Scarif One — Pro
- Description: The full marketing engine. 500 ad gens / 250 emails / 20 trends + 3 team seats.
- Two prices: £99/mo and £990/year.
Product 3: Scarif One — Agency
- Name: Scarif One — Agency
- Description: Manage many brands as one. 2000 ad gens / 1000 emails / unlimited trends + 15 seats + multi-tenant switcher.
- Two prices: £249/mo and £2490/year.
Product 4: Scarif One — Sovereignty Package
- Name: Scarif One — Sovereignty Package
- Description: Run on your own hardware. £999 once. Same software as the hosted plan, deployed on yours.
- One price: £999.00 GBP, one-time (not recurring). Copy the
price_…ID.
Optional Product 5: Sovereignty Support add-on
- Name: Scarif One — Sovereignty Support
- Description: Priority email response, early access, 2 named tickets/month.
- One price: £199.00 GBP, recurring, billed yearly. Copy the
price_…ID.
Tip: name the prices something obvious like “Pro · Monthly”, “Pro · Annual” so you can tell them apart in the Stripe dashboard later. Use Stripe’s lookup keys (
pro_monthly,pro_annual, etc.) for an extra layer of safety.
Step 2 — Get your API keys
- Developers → API keys.
- Copy the Secret key (starts with
sk_live_…orsk_test_…). Set asSTRIPE_SECRET_KEYin.env.local. - The Publishable key is not required by Scarif One — we only do server-side checkout creation.
Step 3 — Configure the webhook
Webhooks let Stripe tell us when subscriptions change so we can keep tenant.profile.subscription in sync.
- Developers → Webhooks → Add endpoint.
- Endpoint URL:
https://scarifone.com/api/billing/webhook(replace with your domain). - Events to listen to — add exactly these five:
customer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deletedcheckout.session.completedinvoice.payment_failed
- Click Add endpoint.
- On the endpoint detail page, click Reveal under “Signing secret”. Copy the
whsec_…value. Set asSTRIPE_WEBHOOK_SECRETin.env.local.
Step 4 — Configure the Customer Portal
The portal handles plan changes, payment-method updates, invoice downloads, and cancellations. Customers reach it from /billing → Manage subscription.
- Settings → Customer Portal.
- Functionality — enable:
- Invoice history
- Update payment method
- Cancel subscription (cancellation takes effect at end of period)
- Switch plan — toggle on, and add all six of your subscription prices (Solo monthly+annual, Pro monthly+annual, Agency monthly+annual). This lets customers self-serve upgrades/downgrades.
- Branding — upload your logo + set your brand colour (
#a31b1bif you’re using TRI’s) so the portal feels cohesive with Scarif One. - Save.
Step 5 — Set environment variables
Drop these into your .env.local:
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
STRIPE_PRICE_SOLO_MONTHLY=price_...
STRIPE_PRICE_SOLO_ANNUAL=price_...
STRIPE_PRICE_PRO_MONTHLY=price_...
STRIPE_PRICE_PRO_ANNUAL=price_...
STRIPE_PRICE_AGENCY_MONTHLY=price_...
STRIPE_PRICE_AGENCY_ANNUAL=price_...
STRIPE_PRICE_SOVEREIGNTY=price_...
STRIPE_PRICE_SOVEREIGNTY_SUPPORT=price_...
# Optional
STRIPE_AUTOMATIC_TAX=true
Restart your dev server (or your prod container) so the new env vars are picked up.
Step 6 — Test the flow
Testing locally with Stripe CLI
# Install if you haven't: https://stripe.com/docs/stripe-cli
stripe login
# Forward webhooks to your local dev server
stripe listen --forward-to localhost:3000/api/billing/webhook
The CLI prints a webhook signing secret — use that as STRIPE_WEBHOOK_SECRET while developing locally.
Trial flow
- Open
localhost:3000/pricingin an incognito window. - Click Choose Pro. You land on
/signupwith the plan pre-selected. - Fill the signup form. Submit.
- You’re redirected to
{slug}.scarifone.com/billing/start?plan=pro&cadence=monthly&next=/setup. - That page server-side creates a Stripe Checkout Session and bounces you to Stripe.
- On Stripe Checkout, use a test card (e.g.
4242 4242 4242 4242with any future expiry and any CVC). - After payment, Stripe redirects to
/billing/successand the webhook updatestenant.profile.subscription. - Click Continue setup to finish onboarding.
Self-serve plan change
- Sign in to a tenant with a subscription.
- Open
/billing→ Manage subscription. - Stripe Customer Portal opens. Switch from Pro → Agency. Confirm.
- The webhook fires
customer.subscription.updated. Yoursubscription.priceIdupdates. The dashboard now shows Agency limits.
One-time Sovereignty purchase
- From
/sovereigntyor/pricing, click Buy + install — £999. - Same signup flow, but
cadence=onetimeis preserved. - Stripe Checkout opens in payment mode (not subscription). Card charged immediately for £999.
- Webhook fires
checkout.session.completed. We append the purchase totenant.profile.oneTimePurchases. - Manual step (Phase 49): Tom emails the customer their licence key + Docker install instructions. Phase 49 will automate this via Resend.
Step 7 — Going live
- Switch your
STRIPE_SECRET_KEYfromsk_test_…tosk_live_…. - Re-create the webhook in live mode (different signing secret) and update
STRIPE_WEBHOOK_SECRET. - Re-create products + prices in live mode (test-mode IDs don’t carry over). Update each
STRIPE_PRICE_*env var. - Verify in Stripe Settings → Bank account that your payouts are routed to the correct UK account.
- Open
scarifone.com/pricingin an incognito window and run through one real-money payment to verify (you can refund yourself afterward via the Stripe dashboard).
Common issues
“STRIPE_PRICE_PRO_MONTHLY not set”
The env var isn’t set or you forgot to restart the server. echo $STRIPE_PRICE_PRO_MONTHLY from your shell to verify.
Webhook returns 400 “Webhook verification failed”
The stripe-signature header doesn’t match — usually because:
- You’re using the test-mode webhook secret in production (or vice versa)
- Your reverse proxy is mangling the request body (set
body-parserto raw / use Next’s default) - The Stripe CLI is forwarding to the wrong URL — double-check the
--forward-toflag
Customer didn’t get charged but I see them in Stripe
Trial period is active — they won’t be charged for 14 days. Check subscription.status is trialing. The webhook updates this on transition to active.
Self-host install showing “Billing not enabled”
Correct — that’s by design. Self-host is a one-time purchase, no recurring billing. The /billing page shows a friendly explainer.
What this tutorial doesn’t cover (yet)
- VAT / Sales Tax automation — Stripe Tax handles this; flip
STRIPE_AUTOMATIC_TAX=trueonce you’ve enabled it in your Stripe dashboard. - Promo codes / discounts — already enabled (
allow_promotion_codes: truein checkout). Create codes in Stripe Dashboard → Coupons. - Refunds — handled in Stripe Dashboard, not Scarif One. We log incoming
invoice.payment_failedfor visibility. - Dunning — Stripe Smart Retries handle failed-payment retries automatically. Configure under Settings → Subscriptions and emails → Dunning.
Need help? Email <a href="mailto:hello@scarifone.com">hello@scarifone.com</a>.