Stripe & Convex Payment Subscriber Payment Integration - acdc-digital/soloist_pro GitHub Wiki

Payment Integration - Soloist Pro

This document outlines the payment integration system for Soloist Pro, which combines Next.js, Convex, and Stripe to provide a robust and flexible payment solution.

Architecture Overview

The payment system consists of three main components:

  1. Frontend UI (Next.js) - Handles user interaction, payment form rendering, and checkout flow
  2. API Layer (Next.js/Convex) - Provides secure endpoints for payment processing
  3. Backend (Convex) - Manages data storage, payment record creation, and business logic

Payment Flows

The system supports two primary payment flows:

1. Modal Checkout (Stripe Elements)

This flow keeps the user on your site and processes the payment in a modal dialog.

User → Pricing Page → Modal Checkout → Payment Success/Failure → Account Updated
  • Uses Stripe Elements for UI components
  • Creates a Payment Intent on the server
  • Processes payment directly on the site
  • Provides real-time feedback

2. Redirect Checkout (Stripe Checkout)

This flow redirects the user to Stripe's hosted checkout page.

User → Pricing Page → Redirect to Stripe → Payment Processing → Return to Site → Account Updated
  • Uses Stripe's hosted checkout page
  • Creates a Checkout Session on the server
  • Handles payment on Stripe's servers
  • Returns user to the site after completion

Key Components

Frontend Components

  • StripeCheckout.tsx - Core component with support for both modal and redirect checkout
  • PaymentButton.tsx - Reusable button component that triggers payment flows

API Routes

  • /api/stripe/create-payment-intent - Creates a Stripe Payment Intent for modal checkout
  • /api/stripe/create-checkout-session - Creates a Stripe Checkout Session for redirect checkout
  • /api/stripe/verify-payment - Verifies payment status after completion
  • /api/webhooks/stripe - Webhook endpoint for processing Stripe events

Convex Backend

  • payments.ts - Data models and mutations for payment records
  • stripe.ts - Server-side Stripe integration
  • http.ts - HTTP action handlers for webhooks

Data Model

The payment system uses the following data model in Convex:

payments: defineTable({
  userId: v.optional(v.string()),
  amount: v.number(),
  currency: v.string(),
  status: v.string(), // "pending", "completed", "failed"
  stripeId: v.optional(v.string()),
  stripeSessionId: v.optional(v.string()),
  metadata: v.optional(v.object({
    planType: v.optional(v.string()),
    duration: v.optional(v.string()),
    features: v.optional(v.array(v.string())),
    date: v.optional(v.string()),
    plan: v.optional(v.string()),
    priceId: v.optional(v.string()),
    user_interface: v.optional(v.string())
  })),
  createdAt: v.number(),
  updatedAt: v.optional(v.number()),
})

Payment Processing Workflow

  1. Payment Initiation:

    • User selects a pricing plan
    • Frontend creates a payment request with plan details
  2. Payment Intent/Session Creation:

    • Server creates a Stripe Payment Intent or Checkout Session
    • Convex creates a payment record with "pending" status
    • Client receives session details or client secret
  3. Payment Processing:

    • User completes payment form (modal) or is redirected to Stripe
    • Stripe processes the payment transaction
    • Result is sent back to the application
  4. Payment Fulfillment:

    • Stripe sends webhook events on payment status changes
    • Webhook handler processes events and updates payment records
    • For successful payments, user account is updated with purchased features
  5. User Notification:

    • User is shown success/failure message
    • User is redirected to appropriate page based on outcome

Error Handling

The system implements comprehensive error handling:

  • Invalid payment details are caught and displayed to the user
  • Network errors trigger appropriate UI feedback
  • Server-side errors are logged and gracefully communicated
  • Email validation issues are handled appropriately

Stripe Integration

Required Configuration

Set the following environment variables in Convex:

STRIPE_KEY - Your Stripe Secret Key
STRIPE_WEBHOOKS_SECRET - Your Stripe Webhook Signing Secret
HOSTING_URL - The URL of your application (e.g., https://your-app.com)

In your Next.js application:

NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY - Your Stripe Publishable Key
NEXT_PUBLIC_CONVEX_URL - Your Convex deployment URL

Webhook Setup

  1. Create a webhook endpoint in the Stripe Dashboard
  2. Point it to: https://YOUR_CONVEX_DEPLOYMENT.convex.site/api/webhooks/stripe
  3. Subscribe to the following events:
    • checkout.session.completed
    • payment_intent.succeeded

Usage Examples

Modal Checkout

import StripeCheckout from '@/components/StripeCheckout';

// Inside your component
const handlePayment = async () => {
  try {
    await StripeCheckout.openModalCheckout({
      priceId: 'price_xxxxx',  // Your Stripe Price ID
      email: user?.email,
      customerData: {
        userId: user?.id,
        planType: 'pro',
        date: new Date().toISOString(),
      },
      onSuccess: (paymentId) => {
        // Handle successful payment
      },
      onCancel: () => {
        // Handle cancellation
      }
    });
  } catch (error) {
    console.error('Payment failed:', error);
  }
};

Redirect Checkout

import StripeCheckout from '@/components/StripeCheckout';

// Inside your component
const handlePayment = async () => {
  try {
    await StripeCheckout.redirectToCheckout({
      priceId: 'price_xxxxx',  // Your Stripe Price ID
      email: user?.email,
      customerData: {
        userId: user?.id,
        planType: 'pro',
        date: new Date().toISOString(),
      },
      successUrl: '/thank-you',
      cancelUrl: '/pricing'
    });
  } catch (error) {
    console.error('Payment failed:', error);
  }
};

Security Considerations

  • Stripe webhooks are validated using the webhook secret
  • Payment data is never stored or logged in plain text
  • API routes validate requests to prevent unauthorized access
  • Email validation prevents errors with empty or invalid emails
  • Convex provides secure data storage and access control

Testing

To test the payment flow:

  1. Use Stripe test mode and test API keys
  2. Use Stripe's test card numbers (e.g., 4242 4242 4242 4242)
  3. Monitor webhook events in the Stripe Dashboard
  4. Check payment records in the Convex database

Troubleshooting

Common issues and solutions:

  • Webhook failures: Check webhook secret and endpoint URL
  • Payment intent creation fails: Verify Stripe API keys
  • Invalid email errors: Ensure email validation is working properly
  • Session URL not returned: Check Stripe error response for details
  • Metadata validation errors: Ensure schema includes all expected fields

This payment integration provides a flexible, secure, and user-friendly payment experience while maintaining robust error handling and data integrity.