DocsSetting up Stripe for hosted billing
▸ Tutorial 14

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

  1. A Stripe account in live mode (Test mode works for staging — same flow, different keys).
  2. Your business verified with Stripe (UK-based businesses need to complete the Bank Account / KYC step before going live).
  3. 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 → CatalogProductsAdd 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

  1. DevelopersAPI keys.
  2. Copy the Secret key (starts with sk_live_… or sk_test_…). Set as STRIPE_SECRET_KEY in .env.local.
  3. 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.

  1. DevelopersWebhooksAdd endpoint.
  2. Endpoint URL: https://scarifone.com/api/billing/webhook (replace with your domain).
  3. Events to listen to — add exactly these five:
    • customer.subscription.created
    • customer.subscription.updated
    • customer.subscription.deleted
    • checkout.session.completed
    • invoice.payment_failed
  4. Click Add endpoint.
  5. On the endpoint detail page, click Reveal under “Signing secret”. Copy the whsec_… value. Set as STRIPE_WEBHOOK_SECRET in .env.local.

Step 4 — Configure the Customer Portal

The portal handles plan changes, payment-method updates, invoice downloads, and cancellations. Customers reach it from /billingManage subscription.

  1. SettingsCustomer Portal.
  2. 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.
  3. Branding — upload your logo + set your brand colour (#a31b1b if you’re using TRI’s) so the portal feels cohesive with Scarif One.
  4. 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

  1. Open localhost:3000/pricing in an incognito window.
  2. Click Choose Pro. You land on /signup with the plan pre-selected.
  3. Fill the signup form. Submit.
  4. You’re redirected to {slug}.scarifone.com/billing/start?plan=pro&cadence=monthly&next=/setup.
  5. That page server-side creates a Stripe Checkout Session and bounces you to Stripe.
  6. On Stripe Checkout, use a test card (e.g. 4242 4242 4242 4242 with any future expiry and any CVC).
  7. After payment, Stripe redirects to /billing/success and the webhook updates tenant.profile.subscription.
  8. Click Continue setup to finish onboarding.

Self-serve plan change

  1. Sign in to a tenant with a subscription.
  2. Open /billingManage subscription.
  3. Stripe Customer Portal opens. Switch from Pro → Agency. Confirm.
  4. The webhook fires customer.subscription.updated. Your subscription.priceId updates. The dashboard now shows Agency limits.

One-time Sovereignty purchase

  1. From /sovereignty or /pricing, click Buy + install — £999.
  2. Same signup flow, but cadence=onetime is preserved.
  3. Stripe Checkout opens in payment mode (not subscription). Card charged immediately for £999.
  4. Webhook fires checkout.session.completed. We append the purchase to tenant.profile.oneTimePurchases.
  5. 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

  1. Switch your STRIPE_SECRET_KEY from sk_test_… to sk_live_….
  2. Re-create the webhook in live mode (different signing secret) and update STRIPE_WEBHOOK_SECRET.
  3. Re-create products + prices in live mode (test-mode IDs don’t carry over). Update each STRIPE_PRICE_* env var.
  4. Verify in Stripe SettingsBank account that your payouts are routed to the correct UK account.
  5. Open scarifone.com/pricing in 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:

  1. You’re using the test-mode webhook secret in production (or vice versa)
  2. Your reverse proxy is mangling the request body (set body-parser to raw / use Next’s default)
  3. The Stripe CLI is forwarding to the wrong URL — double-check the --forward-to flag

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=true once you’ve enabled it in your Stripe dashboard.
  • Promo codes / discounts — already enabled (allow_promotion_codes: true in checkout). Create codes in Stripe Dashboard → Coupons.
  • Refunds — handled in Stripe Dashboard, not Scarif One. We log incoming invoice.payment_failed for visibility.
  • Dunning — Stripe Smart Retries handle failed-payment retries automatically. Configure under SettingsSubscriptions and emailsDunning.

Need help? Email <a href="mailto:hello@scarifone.com">hello@scarifone.com</a>.