Skip to content

Stripe Integration

Stripe powers all monetary transactions in Honeycomb. The integration spans three areas: platform subscriptions (users paying Mindhyv), Stripe Connect (creators receiving payouts), and webhook processing (keeping the database in sync with Stripe events).

The Stripe client is initialised as a lazy singleton in src/lib/server/stripe.ts:

import Stripe from "stripe";
import { STRIPE_SECRET_KEY } from "$env/static/private";
export const stripe = new Stripe(STRIPE_SECRET_KEY);

The same module exports the platform fee constant and plan definitions:

export const PLATFORM_FEE_PERCENT = 5;
export const PLANS = {
starter: {
name: "Starter",
priceMonthly: 9,
features: ["Business profile", "1 extension", "Basic analytics", "Standard support"],
},
pro: {
name: "Pro",
priceMonthly: 29,
features: [
"Business profile", "Unlimited extensions", "Advanced analytics",
"Priority support", "Custom domain", "API access",
],
},
} as const;

All Stripe operations go through a single POST endpoint at src/routes/(app)/api/stripe/+server.ts. The action field in the request body determines the operation.

Creates a Stripe Express connected account for the user (if one does not exist) and returns an Account Links onboarding URL.

Flow:

  1. Check business_accounts for an existing stripe_account_id.
  2. If missing, call stripe.accounts.create({ type: "express" }).
  3. Upsert the business_accounts row and set the profile type to "business".
  4. Generate an onboarding link via stripe.accountLinks.create().
  5. Return { url } to the client, which redirects the user.

The webhook endpoint lives at src/routes/api/stripe/webhook/+server.ts (note: outside the (app) group so no auth middleware runs).

const event = stripe.webhooks.constructEvent(body, signature, STRIPE_WEBHOOK_SECRET);
EventAction
customer.subscription.createdUpdate profile subscription_status, subscription_plan, subscription_expires_at
customer.subscription.updatedSame as above
customer.subscription.deletedSet status to "canceled", clear plan
account.updatedSync stripe_onboarding_complete, charges_enabled, payouts_enabled on business_accounts
checkout.session.completedRoute to app-specific handlers based on metadata.app_slug

When a checkout.session.completed event arrives with metadata.seller_id, the handler:

  1. Records a wallet_transactions entry for the seller.
  2. Reads metadata.app_slug to dynamically import the correct service handler.

Supported app slugs: courses, live-sessions, events, products, bundles, subscriptions, honeycomb-membership, honeycomb-tip.

FilePurpose
src/lib/server/stripe.tsSDK singleton, plans, fee constant
src/routes/(app)/api/stripe/+server.tsClient-facing Stripe API route
src/routes/api/stripe/webhook/+server.tsWebhook receiver
src/routes/(app)/business/upgrade/+page.server.tsLoads subscription and Connect status for the upgrade page
User clicks "Upgrade to Business"
-> POST /api/stripe { action: "connectOnboard" }
-> Server creates Express account + onboarding link
-> User completes Stripe onboarding
-> Redirect back to /business/upgrade?success=true
-> POST /api/stripe { action: "connectStatus" }
-> Server syncs onboarding flags to DB