Checkout

Create Stripe checkout sessions to collect payment and start subscriptions.

How Checkout Works

StackBE uses Stripe Checkout for secure, PCI-compliant payment collection:

  1. Your app creates a checkout session via StackBE API
  2. Redirect the customer to the Stripe-hosted checkout page
  3. Customer enters payment details on Stripe's secure page
  4. On success, Stripe redirects to your success URL
  5. StackBE receives the webhook and creates the subscription

Important: Always create checkout sessions through StackBE, not directly with Stripe. This ensures subscriptions are properly tracked with the right metadata.

Create Checkout Session

Create a checkout session and redirect the customer to complete payment.

Using the SDK

typescript
import { StackBE } from '@stackbe/sdk';

const stackbe = new StackBE({
  apiKey: process.env.STACKBE_API_KEY!,
  appId: process.env.STACKBE_APP_ID!,
});

// Create checkout session
const { url } = await stackbe.checkout.createSession({
  // Customer identification (one of these required)
  customerId: 'cust_abc123',    // Existing customer ID
  // OR
  email: 'user@example.com',    // Email for new customers

  // Plan to subscribe to
  planId: 'plan_pro',

  // Redirect URLs
  successUrl: 'https://yourapp.com/success?session_id={CHECKOUT_SESSION_ID}',
  cancelUrl: 'https://yourapp.com/pricing',
});

// Redirect to Stripe Checkout
redirect(url);

Via API

bash
curl -X POST "https://api.stackbe.io/v1/checkout/session" \
  -H "Authorization: Bearer sk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "customerId": "cust_abc123",
    "planId": "plan_pro",
    "successUrl": "https://yourapp.com/success",
    "cancelUrl": "https://yourapp.com/pricing"
  }'

# Response:
# { "url": "https://checkout.stripe.com/c/pay/cs_xxx..." }

Apply Coupon Code

Apply a promo code to give customers a discount.

typescript
// With coupon code
const { url } = await stackbe.checkout.createSession({
  customerId: 'cust_abc123',
  planId: 'plan_pro',
  couponCode: 'SAVE20',  // 20% off coupon
  successUrl: 'https://yourapp.com/success',
  cancelUrl: 'https://yourapp.com/pricing',
});

// Validate coupon before checkout (optional)
const coupon = await stackbe.coupons.validate('SAVE20', {
  planId: 'plan_pro',
});

if (!coupon.valid) {
  return { error: coupon.reason };  // "Coupon expired" or "Not valid for this plan"
}

Trial Periods

Trials are configured on your plans in the StackBE dashboard. When a plan has a trial period, checkout automatically applies it.

typescript
// Checkout automatically uses the plan's trial period
const { url } = await stackbe.checkout.createSession({
  email: 'new@example.com',
  planId: 'plan_pro',  // Has 14-day trial configured
  successUrl: 'https://yourapp.com/welcome',
  cancelUrl: 'https://yourapp.com/pricing',
});

// Customer gets 14-day trial, then billing starts

Trial behavior: Configure whether payment method is required during trial in your app settings. Options are require_payment_method or no_payment_method.

Organization Checkout (B2B)

Create a checkout for an organization instead of an individual customer.

typescript
// Checkout for an organization
const { url } = await stackbe.checkout.createSession({
  organizationId: 'org_xyz789',  // Organization ID
  planId: 'plan_enterprise',
  successUrl: 'https://yourapp.com/org/settings?upgraded=true',
  cancelUrl: 'https://yourapp.com/org/settings',
});

// All org members share this subscription

Handling Success

After successful payment, Stripe redirects to your success URL. You can include the session ID to verify the purchase.

typescript
// Success page: app/success/page.tsx
export default async function SuccessPage({ searchParams }) {
  const sessionId = searchParams.session_id;

  // Option 1: Just show success message (subscription created via webhook)
  return (
    <div>
      <h1>Welcome to Pro!</h1>
      <p>Your subscription is now active.</p>
      <a href="/dashboard">Go to Dashboard</a>
    </div>
  );

  // Option 2: Fetch subscription details to show specifics
  // (The subscription is created by webhook, which is near-instant)
  const subscription = await stackbe.subscriptions.get(customerId, {
    expand: ['plan'],
  });

  return (
    <div>
      <h1>Welcome to {subscription.plan.name}!</h1>
      <p>Your subscription is active until {subscription.currentPeriodEnd}</p>
    </div>
  );
}

Checkout Options

typescript
const { url } = await stackbe.checkout.createSession({
  // Required
  planId: 'plan_pro',
  successUrl: 'https://yourapp.com/success',
  cancelUrl: 'https://yourapp.com/pricing',

  // Customer (one required)
  customerId: 'cust_abc123',    // Existing customer
  email: 'user@example.com',    // New customer (will be created)
  organizationId: 'org_xyz789', // For B2B checkout

  // Optional
  couponCode: 'SAVE20',         // Apply promo code
  collectBillingAddress: true,  // Require billing address
  metadata: {                   // Custom metadata (stored on subscription)
    referral: 'partner_abc',
    campaign: 'summer_2025',
  },
});

Best Practices

  • Always use StackBE for checkout — Don't create Stripe checkout sessions directly. StackBE adds required metadata for tracking.
  • Handle webhooks — The subscription is created via webhook. Set up webhook handling before going live.
  • Use absolute URLs — Success and cancel URLs must be absolute (include https://).
  • Don't block on session verification — The success page should work without fetching data. Webhook processing might take a second.

Next Steps