Stripe powers our payment system, offering robust processing, subscription management, and global support.

Stripe Setup

  1. Create a Stripe account or sign in.
  2. Configure your account and add products or subscription plans.
  1. Navigate to Product Catalogue in the Stripe Dashboard.
  2. Click “Create product” and input details. For our credit system, we’ll use one-off payments.
  3. On the product page, create price variations (e.g., credits-small for 50 credits, credits-large for 100 credits).
  4. Select “Create payment link” and configure settings.
  5. Add custom metadata in the payment link settings:
    • Click “Add metadata”
    • Set a key (e.g., “type”) and value (e.g., “credits-large”)

This metadata is crucial for determining the purchase type in your webhook handler.

Webhook Configuration

Stripe Webhook Secret

  1. Go to Developers -> Webhooks in the Stripe Dashboard.
  2. Click “Add endpoint”.
  3. Set the Endpoint URL to https://yourwebsite.com/api/payments/stripe.
  4. Select events to listen for (at minimum, choose “checkout.session.completed”).
  5. Copy the Signing secret and add it to your .env file as STRIPE_WEBHOOK_SECRET.

Also add your Stripe secret key to .env as STRIPE_SECRET_KEY. Find this under Developers -> API Keys.

Webhook Handling

The API route at app/api/payments/stripe/route.ts manages Stripe payments and subscriptions:

  1. Verifies request legitimacy using STRIPE_WEBHOOK_SECRET.
  2. Processes the “checkout.session.completed” event.
  3. Retrieves product information and determines purchase type from metadata.
  4. Matches user email with the profiles table:
    • For matching users, updates the purchase column in profiles.
    • For non-matching users, records the purchase in purchases.
    • Performs specific actions based on metadata (e.g., adding user credits).

Storing webhook data

We’ll store all webhook data coming from LemonSqueezy in our own database as well.

Copy-paste the following your Supabase SQL editor:

create table
  public.purchases (
    id bigint generated by default as identity,
    user_email text null,
    type text null,
    created_at timestamp with time zone null default now(),
    purchase_id text null,
    payload jsonb null,
    constraint purchases_pkey primary key (id)
  ) tablespace pg_default;

Then, turn on RLS. We don’t need to add any rules as we’ll be using the service key for to interact with this table.

Purchase Type Determination

The webhook handler identifies the purchase type in this order:

  1. Checks session.metadata.type (set in payment link).
  2. If not found, checks product.metadata.type.
  3. If still not found, infers from the product name (premium, core, or enterprise).

This prioritization allows precise control over purchase types via payment link metadata.

User Profile Updates

After a successful purchase, the webhook handler:

  1. Records the purchase in the purchases table.
  2. Updates the user’s profile in the profiles table with the new purchase type.

Customize the updateUserProfile function in @/lib/hooks/userData to handle various purchase or subscription types based on metadata.

Paywall Implementation

Demo apps include a credit-based paywall. Modify app/api/payments/stripe/route.ts to add credits after successful purchases.

Adjust the code to manage access based on specific purchase column values for handling lifetime access or subscriptions.

Paywall Logic Flow

  1. Check if the demo app is paywalled (defined in toolConfig.ts).
  2. Verify user credit balance:
    • If sufficient, grant access.
    • If insufficient, display the PaymentModal.
app/(apps)/audio/page.tsx
let credits;
if (toolConfig.paywall) {
  const { data: profile } = await supabase
    .from("profiles")
    .select("*")
    .eq("id", user.id)
    .single();

  credits = profile.credits;

  if (credits < toolConfig.credits) {
    return <PaymentModal />;
  }
}

Payment Flow Implementation

  1. Create a UI element linking to your Stripe payment URL.
  2. Stripe sends a webhook to your endpoint upon purchase completion.
  3. Your webhook handler processes the payment, using metadata to determine the purchase type.
  4. Update the user’s profile in your database with purchase information.
  5. Grant access to premium features based on the updated profile.

This flow, combined with payment link metadata, enables easy management of product tiers and database updates for purchases.