BunshipBunship
Integrations

Stripe Billing

Subscription billing with monthly/yearly prices, unique lookup keys, and webhook-driven credit sync.

Setup

1. Configure Stripe credentials

Configure secret key, webhook secret, and environment-specific callback endpoints.

2. Create products and prices (monthly/yearly)

Use one Stripe product per plan, and create two recurring prices under that product:

  • Monthly price: recurring.interval = month
  • Yearly price: recurring.interval = year

Use a globally unique lookup_key for each price.

PlanMonthly lookup keyYearly lookup key
Creatorcreator_monthlycreator_yearly
Propro_monthlypro_yearly
Scalescale_monthlyscale_yearly

For top-up credit packs (one-time prices), use:

  • credits_starter
  • credits_growth
  • credits_scale

All lookup keys in your Stripe account must be unique.

3. Configure yearly discount

Recommended: create a dedicated yearly price with discount already applied (for example monthly * 12 * 0.9).

Optional: use coupon/promotion code, but keep webhook and entitlement logic idempotent.

4. Map price references in env

This project supports both:

  • Direct price_id (price_xxx)
  • Lookup reference (lookup:creator_monthly or plain creator_monthly)

You can set price_id in env and override lookup fallback:

  • STRIPE_PRICE_SUB_CREATOR_MONTHLY
  • STRIPE_PRICE_SUB_CREATOR_YEARLY
  • STRIPE_PRICE_SUB_PRO_MONTHLY
  • STRIPE_PRICE_SUB_PRO_YEARLY
  • STRIPE_PRICE_SUB_SCALE_MONTHLY
  • STRIPE_PRICE_SUB_SCALE_YEARLY
  • STRIPE_PRICE_CREDITS_STARTER (compatible with STRIPE_PRICE_CREDITS_500)
  • STRIPE_PRICE_CREDITS_GROWTH (compatible with STRIPE_PRICE_CREDITS_1200)
  • STRIPE_PRICE_CREDITS_SCALE (compatible with STRIPE_PRICE_CREDITS_3000)

5. Verify webhook event handling

Validate checkout completion, subscription renewal, payment failure, and cancellation events.

6. Seed product/payment config

bun run seed:prod -- --env-file ../../apps/ship-api/.env.production

What Bunship Already Implements

  • Subscription checkout and one-time checkout
  • Customer portal session generation for self-service plan management
  • Webhook pipeline in apps/ship-api/src/services/webhook/stripe.ts
  • Idempotent credit refresh for renewals (invoice.paid / invoice.payment_succeeded)

Code Map

  • API routes: apps/ship-api/src/module/subscription.ts, apps/ship-api/src/module/orders.ts
  • Webhook endpoint: apps/ship-api/src/module/webhook/stripe.ts
  • Webhook business logic: apps/ship-api/src/services/webhook/stripe.ts
  • Product/price seed: packages/db/src/drizzle/seed/product.ts

Buyer Checklist

  1. Stripe products/prices in dashboard match your seed config.
  2. Webhook endpoint is reachable from Stripe in production.
  3. Failed payment, cancellation, and renewal flows are tested.
  4. Dashboard and admin pages show consistent order/subscription status.

Next Steps