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:
- Frontend UI (Next.js) - Handles user interaction, payment form rendering, and checkout flow
- API Layer (Next.js/Convex) - Provides secure endpoints for payment processing
- 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 checkoutPaymentButton.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 recordsstripe.ts
- Server-side Stripe integrationhttp.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
-
Payment Initiation:
- User selects a pricing plan
- Frontend creates a payment request with plan details
-
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
-
Payment Processing:
- User completes payment form (modal) or is redirected to Stripe
- Stripe processes the payment transaction
- Result is sent back to the application
-
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
-
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
- Create a webhook endpoint in the Stripe Dashboard
- Point it to:
https://YOUR_CONVEX_DEPLOYMENT.convex.site/api/webhooks/stripe
- 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:
- Use Stripe test mode and test API keys
- Use Stripe's test card numbers (e.g., 4242 4242 4242 4242)
- Monitor webhook events in the Stripe Dashboard
- 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.