Skip to main content

createCheckoutSession

Creates a Stripe Checkout session for a team to subscribe to a pricing plan. This function automatically handles user authentication, redirects unauthenticated users to sign-up, and creates a subscription checkout session with a 14-day trial period.

Function Signature

async function createCheckoutSession({
  team,
  priceId
}: {
  team: Team | null;
  priceId: string;
}): Promise<never>

Parameters

team
Team | null
required
The team object for which to create the checkout session. If null, the user will be redirected to sign-up.The Team type includes:
  • id: number
  • name: string
  • stripeCustomerId: string | null
  • stripeSubscriptionId: string | null
  • stripeProductId: string | null
  • planName: string | null
  • subscriptionStatus: string | null
priceId
string
required
The Stripe Price ID to subscribe to. This should be a valid Stripe price identifier (e.g., price_1234567890).

Return Value

This function never returns normally as it always calls redirect(). It either:
  • Redirects unauthenticated users to /sign-up?redirect=checkout&priceId={priceId}
  • Redirects authenticated users to the Stripe Checkout session URL

Behavior

  1. Authentication Check: Retrieves the current user using getUser()
  2. Validation: If no team or user exists, redirects to sign-up with return parameters
  3. Session Creation: Creates a Stripe Checkout session with:
    • Payment method: Card only
    • Mode: Subscription
    • Trial period: 14 days
    • Promotion codes: Enabled
    • Success URL: /api/stripe/checkout?session_id={CHECKOUT_SESSION_ID}
    • Cancel URL: /pricing
  4. Customer Association: Links to existing Stripe customer if team.stripeCustomerId exists
  5. Redirect: Sends user to Stripe Checkout

Usage Example

import { createCheckoutSession } from '@/lib/payments/stripe';
import { getTeamForUser } from '@/lib/db/queries';

export async function subscribeAction(formData: FormData) {
  'use server';
  
  const priceId = formData.get('priceId') as string;
  const team = await getTeamForUser();
  
  await createCheckoutSession({
    team,
    priceId
  });
}

Server Action Example

// app/pricing/page.tsx
import { createCheckoutSession } from '@/lib/payments/stripe';
import { getTeamForUser } from '@/lib/db/queries';

export default function PricingPage() {
  async function handleCheckout(priceId: string) {
    'use server';
    const team = await getTeamForUser();
    await createCheckoutSession({ team, priceId });
  }
  
  return (
    <form action={() => handleCheckout('price_1234567890')}>
      <button type="submit">Subscribe</button>
    </form>
  );
}

Checkout Session Configuration

The function creates a Stripe Checkout session with the following configuration:
payment_method_types
string[]
Set to ['card'] - only card payments are accepted
mode
string
Set to 'subscription' for recurring billing
subscription_data.trial_period_days
number
Set to 14 - provides a 14-day free trial for all subscriptions
allow_promotion_codes
boolean
Set to true - allows customers to enter discount codes at checkout
client_reference_id
string
Set to the user’s ID for tracking the subscription origin

Environment Variables Required

  • STRIPE_SECRET_KEY: Your Stripe secret API key
  • BASE_URL: Your application’s base URL for success/cancel redirects

Error Handling

This function handles errors through redirects:
  • Missing team or user: Redirects to sign-up page
  • Stripe API errors: Will throw and should be caught by error boundaries

checkoutAction

A pre-built server action that wraps createCheckoutSession() with team middleware protection. This is the recommended way to use checkout in forms.

Function Signature

export const checkoutAction: (formData: FormData) => Promise<never>
Located in /lib/payments/actions.ts:7-10

Parameters

formData
FormData
required
Form data containing the priceId field

Usage Example

// app/pricing/page.tsx
import { checkoutAction } from '@/lib/payments/actions';

export default function PricingPage() {
  return (
    <form action={checkoutAction}>
      <input type="hidden" name="priceId" value="price_1234567890" />
      <button type="submit">Subscribe Now</button>
    </form>
  );
}

How It Works

The checkoutAction uses the withTeam middleware wrapper, which:
  1. Automatically retrieves the current user’s team
  2. Validates team membership
  3. Passes the team to createCheckoutSession()
  4. Handles errors if user is not authenticated or not part of a team
This action is protected by the withTeam middleware, ensuring only authenticated users with team membership can initiate checkout.
  • createCustomerPortalSession() - Manage existing subscriptions
  • handleSubscriptionChange() - Process webhook events
  • getStripePrices() - Fetch available pricing plans
  • customerPortalAction() - Server action for customer portal access

Build docs developers (and LLMs) love