Payment
Integrate Stripe or Creem payments in LaunchSaaS. Handle one-time purchases, subscriptions, webhooks, and customer billing with a unified API.
Payment
LaunchSaaS supports multiple payment providers with a unified, extensible architecture. You can easily switch between providers, add custom implementations, or disable payment entirely.
Supported Providers
- Stripe - Industry-standard payment processor
- Creem - Alternative payment provider
- Custom - Extend with your own payment provider
Architecture Overview
The payment system consists of:
- Order - Represents a confirmed monetary transaction (paid/irreversible)
- Entitlement - Represents user access to a product
- Payment Hooks - Extensible hooks for post-payment actions
- Provider Factory - Manages payment provider instances
Configuration
Enable Payment Provider
Configure your payment provider in src/configuration/features.ts:
export const features: Features = {
payment: {
provider: "stripe", // "stripe" | "creem" | "disabled"
hooks: {
github: true, // Enable GitHub integration
email: true, // Enable payment completion emails
},
},
// ... other features
};Setup Stripe
1. Create Stripe Account
- Sign up at stripe.com
- Complete account verification (required for production)
- You can start development with test mode immediately
2. Get API Keys
- Go to Stripe Dashboard →
Developers→API keys - Copy your Secret key (starts with
sk_test_for test mode) - Add to your
.envfile:
STRIPE_SECRET_KEY="sk_test_..."Use test keys (sk_test_...) for development and live keys (sk_live_...)
for production.
3. Create Products and Prices
- Go to Stripe Dashboard →
Product Catalog - Click
Add product - Fill in product details:
- Name: e.g., "Lifetime Access"
- Description: Your product description
- Price: Set your price (one-time or recurring)
- Click "Save product"
- Copy the Price ID (starts with
price_)
4. Configure Products
Update the product configuration in src/configuration/product.ts:
const prod: ProviderProductConfiguration = {
stripe: {
onetime: [
{
id: "price_1SWtddRwnUQyjRPerb8ge9xD",
name: "Lifetime Access",
hooks: ["github-integration", "payment-completed-email"],
},
],
subscription: [
{
id: "price_1SOwEE2Kn68A5jDtD9vcpirC",
name: "Pro Monthly",
hooks: ["payment-completed-email"],
},
],
pricingPageProduct: {
type: "onetime",
id: "price_1SWtddRwnUQyjRPerb8ge9xD",
},
},
};5. Set Up Webhooks
Webhooks notify your application of payment events in real-time.
Development (Local Testing)
Use the Stripe CLI to forward webhooks to your local server:
- Install Stripe CLI:
# macOS
brew install stripe/stripe-cli/stripe
# Other platforms: https://stripe.com/docs/stripe-cli- Login to Stripe:
stripe login- Forward webhooks:
stripe listen --forward-to localhost:3000/api/payment/stripe/webhook- Copy the webhook secret (starts with
whsec_) and add to your.envfile:
STRIPE_WEBHOOK_SECRET="whsec_..."Keep the stripe listen command running while developing.
Production
- Go to Stripe Dashboard →
Developers→Webhooks - Click
Add endpoint - Set endpoint URL:
https://yourdomain.com/api/payment/stripe/webhook - Select events to listen to:
checkout.session.completedcustomer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deletedinvoice.payment_succeededinvoice.payment_failed
- Click
Add endpoint - Copy the Signing secret and add to your production environment
Testing Cards
For testing Stripe integration, use test credit cards:
| Card Number | Description |
|---|---|
4242 4242 4242 4242 | Successful payment |
4000 0000 0000 3220 | 3D Secure required |
4000 0000 0000 9995 | Insufficient funds |
Use any future expiration date and any 3-digit CVC.
Setup Creem
1. Create Creem Account
- Sign up at creem.io
- Complete account verification
- Create your products
2. Get API Keys
- Go to Creem Dashboard → Settings → API Keys
- Copy your API key and webhook secret
- Add to your
.envfile:
CREEM_API_KEY="your-api-key"
CREEM_WEBHOOK_SECRET="your-webhook-secret"3. Configure Products
Update the product configuration in src/configuration/product.ts:
const prod: ProviderProductConfiguration = {
creem: {
onetime: [
{
id: "prod_3h218lKmpAIM9xTv97Mdy7",
name: "Lifetime Access",
hooks: ["github-integration", "payment-completed-email"],
},
],
pricingPageProduct: {
type: "onetime",
id: "prod_3h218lKmpAIM9xTv97Mdy7",
},
},
};4. Set Up Webhooks
Configure webhook endpoint in Creem Dashboard:
- URL:
https://yourdomain.com/api/payment/creem/webhook - Events: All payment-related events
If you are setting up the environment, now you can go back to the Environment Setup guide and continue.
Payment Hooks
LaunchSaaS provides an extensible hook system for post-payment actions. Hooks are configured in src/configuration/features.ts.
Built-in Hooks
GitHub Integration
Automatically adds customers as GitHub collaborators after payment.
Enable in features.ts:
payment: {
hooks: {
github: true,
},
}Configure environment variables:
GITHUB_TOKEN="your-personal-access-token"
GITHUB_REPO="owner/repo"Generate a GitHub Personal Access Token with admin:org and repo scopes at GitHub Settings
Payment Completed Email
Sends confirmation emails after successful payments.
Enable in features.ts:
payment: {
hooks: {
email: true,
},
}Custom Hooks
Create custom payment hooks by implementing the PaymentHook interface in src/lib/payment/hooks/:
import { PaymentHook, AfterHookContext } from "@/lib/payment/hook";
export class CustomHook implements PaymentHook {
name = "custom-hook";
async onCheckoutComplete(context: AfterHookContext): Promise<void> {
// Your custom logic here
console.log(`Payment completed for product ${context.productId}`);
}
}Register your hook in src/lib/payment/hook-register.ts:
if (features.payment.hooks.custom) {
hooks.push(new CustomHook());
}Database Schema
Order Table
Represents confirmed monetary transactions:
- Created when payment is confirmed
- One-time products create an order upon checkout completion
- Subscription products create an order upon each successful payment
Entitlement Table
Represents user access to products:
- Granted/extended when order is paid
- One-time products create entitlement with status "active"
- Subscription products create entitlement with status "pending", becomes "active" after first payment
- Contains period information for subscriptions
Custom Payment Provider
To add a custom payment provider:
- Implement the
PaymentProviderinterface insrc/lib/payment/providers/ - Register in
src/lib/payment/factory.ts - Add to the
Featurestype insrc/schemas/site-configuration.ts
Example:
export class CustomProvider implements PaymentProvider {
readonly name = "custom";
async createCheckout(options: CheckoutOptions): Promise<CheckoutResult> {
// Implement checkout creation
}
async handleWebhook(request: Request): Promise<Response> {
// Implement webhook handling
}
// ... other required methods
}