# Stripe Integration Testing Guide ## Table of Contents 1. [Prerequisites](#prerequisites) 2. [Environment Setup](#environment-setup) 3. [Stripe Dashboard Configuration](#stripe-dashboard-configuration) 4. [Test Card Numbers](#test-card-numbers) 5. [Testing Scenarios](#testing-scenarios) 6. [Webhook Testing](#webhook-testing) 7. [Common Issues & Solutions](#common-issues--solutions) 8. [Production Checklist](#production-checklist) --- ## Prerequisites Before you begin testing, ensure you have: - ✅ Stripe account created (sign up at [stripe.com](https://stripe.com)) - ✅ Node.js and Python environments set up - ✅ Frontend application running (React + Vite) - ✅ Backend API running (FastAPI) - ✅ Database configured and accessible - ✅ Redis instance running (for caching) --- ## Environment Setup ### Step 1: Access Stripe Test Mode 1. Log in to your Stripe Dashboard: [https://dashboard.stripe.com](https://dashboard.stripe.com) 2. Click on your profile icon in the top right corner 3. Ensure **Test Mode** is enabled (you'll see "TEST DATA" banner at the top) 4. If not enabled, toggle to "Switch to test data" ### Step 2: Retrieve API Keys 1. Navigate to **Developers** → **API keys** 2. You'll see two types of keys: - **Publishable key** (starts with `pk_test_...`) - Used in frontend - **Secret key** (starts with `sk_test_...`) - Used in backend 3. Click "Reveal test key" for the Secret key and copy both keys ### Step 3: Configure Environment Variables #### Frontend `.env` file: ```bash # Create or update: /frontend/.env VITE_STRIPE_PUBLISHABLE_KEY=pk_test_your_publishable_key_here ``` #### Backend `.env` file: ```bash # Create or update: /services/tenant/.env STRIPE_SECRET_KEY=sk_test_your_secret_key_here STRIPE_WEBHOOK_SECRET=whsec_your_webhook_secret_here ``` **Note:** The webhook secret will be obtained in Step 4 when setting up webhooks. ### Step 4: Install/Update Dependencies #### Backend: ```bash cd services/tenant pip install -r requirements.txt # This will install stripe==14.1.0 ``` #### Frontend: ```bash cd frontend npm install # Verifies @stripe/react-stripe-js and @stripe/stripe-js are installed ``` --- ## Stripe Dashboard Configuration ### Step 1: Create Products and Prices 1. In Stripe Dashboard (Test Mode), go to **Products** → **Add product** 2. **Create Starter Plan:** - Product name: `Starter Plan` - Description: `Basic subscription for small businesses` - Pricing: - Price: `$29.00` - Billing period: `Monthly` - Currency: `USD` (or your preferred currency) - Click **Save product** - Copy the **Price ID** (starts with `price_...`) - you'll need this 3. **Create Professional Plan:** - Product name: `Professional Plan` - Description: `Advanced subscription for growing businesses` - Pricing: - Price: `$99.00` - Billing period: `Monthly` - Currency: `USD` - Click **Save product** - Copy the **Price ID** 4. **Update your application configuration:** - Store these Price IDs in your application settings - You'll use these when creating subscriptions ### Step 2: Configure Webhooks 1. Navigate to **Developers** → **Webhooks** 2. Click **+ Add endpoint** 3. **For Local Development:** - Endpoint URL: `https://your-ngrok-url.ngrok.io/webhooks/stripe` - (We'll set up ngrok later for local testing) 4. **Select events to listen to:** - `checkout.session.completed` - `customer.subscription.created` - `customer.subscription.updated` - `customer.subscription.deleted` - `invoice.payment_succeeded` - `invoice.payment_failed` - `customer.subscription.trial_will_end` 5. Click **Add endpoint** 6. **Copy the Webhook Signing Secret:** - Click on the newly created endpoint - Click **Reveal** next to "Signing secret" - Copy the secret (starts with `whsec_...`) - Add it to your backend `.env` file as `STRIPE_WEBHOOK_SECRET` --- ## Test Card Numbers Stripe provides test card numbers to simulate different scenarios. **Never use real card details in test mode.** ### Basic Test Cards | Scenario | Card Number | CVC | Expiry Date | |----------|-------------|-----|-------------| | **Successful payment** | `4242 4242 4242 4242` | Any 3 digits | Any future date | | **Visa (debit)** | `4000 0566 5566 5556` | Any 3 digits | Any future date | | **Mastercard** | `5555 5555 5555 4444` | Any 3 digits | Any future date | | **American Express** | `3782 822463 10005` | Any 4 digits | Any future date | ### Authentication & Security | Scenario | Card Number | Notes | |----------|-------------|-------| | **3D Secure authentication required** | `4000 0025 0000 3155` | Triggers authentication modal | | **3D Secure 2 authentication** | `4000 0027 6000 3184` | Requires SCA authentication | ### Declined Cards | Scenario | Card Number | Error Message | |----------|-------------|---------------| | **Generic decline** | `4000 0000 0000 0002` | Card declined | | **Insufficient funds** | `4000 0000 0000 9995` | Insufficient funds | | **Lost card** | `4000 0000 0000 9987` | Lost card | | **Stolen card** | `4000 0000 0000 9979` | Stolen card | | **Expired card** | `4000 0000 0000 0069` | Expired card | | **Incorrect CVC** | `4000 0000 0000 0127` | Incorrect CVC | | **Processing error** | `4000 0000 0000 0119` | Processing error | | **Card declined (rate limit)** | `4000 0000 0000 9954` | Exceeds velocity limit | ### Additional Scenarios | Scenario | Card Number | Notes | |----------|-------------|-------| | **Charge succeeds, then fails** | `4000 0000 0000 0341` | Attaches successfully but charge fails | | **Dispute (fraudulent)** | `4000 0000 0000 0259` | Creates a fraudulent dispute | | **Dispute (warning)** | `4000 0000 0000 2685` | Creates early fraud warning | **Important Notes:** - For **expiry date**: Use any future date (e.g., 12/30) - For **CVC**: Use any 3-digit number (e.g., 123) or 4-digit for Amex (e.g., 1234) - For **postal code**: Use any valid format (e.g., 12345) --- ## Testing Scenarios ### Scenario 1: Successful Registration with Payment **Objective:** Test the complete registration flow with valid payment method. **Steps:** 1. **Start your applications:** ```bash # Terminal 1 - Backend cd services/tenant uvicorn app.main:app --reload --port 8000 # Terminal 2 - Frontend cd frontend npm run dev ``` 2. **Navigate to registration page:** - Open browser: `http://localhost:5173/register` (or your frontend URL) 3. **Fill in user details:** - Full Name: `John Doe` - Email: `john.doe+test@example.com` - Company: `Test Company` - Password: Create a test password 4. **Fill in payment details:** - Card Number: `4242 4242 4242 4242` - Expiry: `12/30` - CVC: `123` - Cardholder Name: `John Doe` - Email: `john.doe+test@example.com` - Address: `123 Test Street` - City: `Test City` - State: `CA` - Postal Code: `12345` - Country: `US` 5. **Select a plan:** - Choose `Starter Plan` or `Professional Plan` 6. **Submit the form** **Expected Results:** - ✅ Payment method created successfully - ✅ User account created - ✅ Subscription created in Stripe - ✅ Database records created - ✅ User redirected to dashboard - ✅ No console errors **Verification:** 1. **In Stripe Dashboard:** - Go to **Customers** → Find "John Doe" - Go to **Subscriptions** → See active subscription - Status should be `active` 2. **In your database:** ```sql SELECT * FROM subscriptions WHERE tenant_id = 'your-tenant-id'; ``` - Verify subscription record exists - Status should be `active` - Check `stripe_customer_id` is populated 3. **Check application logs:** - Look for successful subscription creation messages - Verify no error logs --- ### Scenario 2: Payment with 3D Secure Authentication **Objective:** Test Strong Customer Authentication (SCA) flow. **Steps:** 1. Follow steps 1-3 from Scenario 1 2. **Fill in payment details with 3DS card:** - Card Number: `4000 0025 0000 3155` - Expiry: `12/30` - CVC: `123` - Fill remaining details as before 3. **Submit the form** 4. **Complete authentication:** - Stripe will display an authentication modal - Click **"Complete"** (in test mode, no real auth needed) **Expected Results:** - ✅ Authentication modal appears - ✅ After clicking "Complete", payment succeeds - ✅ Subscription created successfully - ✅ User redirected to dashboard **Note:** This simulates European and other markets requiring SCA. --- ### Scenario 3: Declined Payment **Objective:** Test error handling for declined cards. **Steps:** 1. Follow steps 1-3 from Scenario 1 2. **Use a declined test card:** - Card Number: `4000 0000 0000 0002` - Fill remaining details as before 3. **Submit the form** **Expected Results:** - ❌ Payment fails with error message - ✅ Error displayed to user: "Your card was declined" - ✅ No customer created in Stripe - ✅ No subscription created - ✅ No database records created - ✅ User remains on payment form - ✅ Can retry with different card **Verification:** - Check Stripe Dashboard → Customers (should not see new customer) - Check application logs for error handling - Verify user-friendly error message displayed --- ### Scenario 4: Insufficient Funds **Objective:** Test specific decline reason handling. **Steps:** 1. Use card number: `4000 0000 0000 9995` 2. Follow same process as Scenario 3 **Expected Results:** - ❌ Payment fails - ✅ Error message: "Your card has insufficient funds" - ✅ Proper error handling and logging --- ### Scenario 5: Subscription Cancellation **Objective:** Test subscription cancellation flow. **Steps:** 1. **Create an active subscription** (use Scenario 1) 2. **Cancel the subscription:** - Method 1: Through your application UI (if implemented) - Method 2: API call: ```bash curl -X POST http://localhost:8000/api/v1/subscriptions/cancel \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_AUTH_TOKEN" \ -d '{ "tenant_id": "your-tenant-id", "reason": "Testing cancellation" }' ``` **Expected Results:** - ✅ Subscription status changes to `pending_cancellation` - ✅ `cancellation_effective_date` is set - ✅ User retains access until end of billing period - ✅ Response includes days remaining - ✅ Subscription cache invalidated **Verification:** 1. Check database: ```sql SELECT status, cancellation_effective_date, cancelled_at FROM subscriptions WHERE tenant_id = 'your-tenant-id'; ``` 2. Verify API response: ```json { "success": true, "message": "Subscription cancelled successfully...", "status": "pending_cancellation", "cancellation_effective_date": "2026-02-10T...", "days_remaining": 30 } ``` --- ### Scenario 6: Subscription Reactivation **Objective:** Test reactivating a cancelled subscription. **Steps:** 1. **Cancel a subscription** (use Scenario 5) 2. **Reactivate the subscription:** ```bash curl -X POST http://localhost:8000/api/v1/subscriptions/reactivate \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_AUTH_TOKEN" \ -d '{ "tenant_id": "your-tenant-id", "plan": "starter" }' ``` **Expected Results:** - ✅ Subscription status changes back to `active` - ✅ `cancelled_at` and `cancellation_effective_date` cleared - ✅ Next billing date set - ✅ Subscription cache invalidated --- ### Scenario 7: Retrieve Invoices **Objective:** Test invoice retrieval from Stripe. **Steps:** 1. **Create subscription with successful payment** (Scenario 1) 2. **Retrieve invoices:** ```bash curl -X GET http://localhost:8000/api/v1/subscriptions/{tenant_id}/invoices \ -H "Authorization: Bearer YOUR_AUTH_TOKEN" ``` **Expected Results:** - ✅ List of invoices returned - ✅ Each invoice contains: - `id` - `date` - `amount` - `currency` - `status` - `invoice_pdf` URL - `hosted_invoice_url` URL **Verification:** - Click on `hosted_invoice_url` to view invoice in browser - Download PDF from `invoice_pdf` URL --- ## Webhook Testing Webhooks are critical for handling asynchronous events from Stripe. Test them thoroughly. ### Option 1: Using Stripe CLI (Recommended for Local Development) #### Step 1: Install Stripe CLI **macOS:** ```bash brew install stripe/stripe-cli/stripe ``` **Windows:** Download from: https://github.com/stripe/stripe-cli/releases **Linux:** ```bash wget https://github.com/stripe/stripe-cli/releases/latest/download/stripe_linux_x86_64.tar.gz tar -xvf stripe_linux_x86_64.tar.gz sudo mv stripe /usr/local/bin/ ``` #### Step 2: Login to Stripe ```bash stripe login ``` This opens a browser to authorize the CLI. #### Step 3: Forward Webhooks to Local Server ```bash stripe listen --forward-to localhost:8000/webhooks/stripe ``` **Expected Output:** ``` > Ready! Your webhook signing secret is whsec_abc123... (^C to quit) ``` **Important:** Copy this webhook signing secret and add it to your backend `.env`: ```bash STRIPE_WEBHOOK_SECRET=whsec_abc123... ``` #### Step 4: Trigger Test Events Open a new terminal and run: ```bash # Test subscription created stripe trigger customer.subscription.created # Test payment succeeded stripe trigger invoice.payment_succeeded # Test payment failed stripe trigger invoice.payment_failed # Test subscription updated stripe trigger customer.subscription.updated # Test subscription deleted stripe trigger customer.subscription.deleted # Test trial ending stripe trigger customer.subscription.trial_will_end ``` #### Step 5: Verify Webhook Processing **Check your application logs for:** - ✅ "Processing Stripe webhook event" - ✅ Event type logged - ✅ Database updates (check subscription status) - ✅ No signature verification errors **Example log output:** ``` INFO Processing Stripe webhook event event_type=customer.subscription.updated INFO Subscription updated in database subscription_id=sub_123 tenant_id=tenant-id ``` ### Option 2: Using ngrok (For Public URL Testing) #### Step 1: Install ngrok Download from: https://ngrok.com/download #### Step 2: Start ngrok ```bash ngrok http 8000 ``` **Output:** ``` Forwarding https://abc123.ngrok.io -> http://localhost:8000 ``` #### Step 3: Update Stripe Webhook Endpoint 1. Go to Stripe Dashboard → Developers → Webhooks 2. Click on your endpoint 3. Update URL to: `https://abc123.ngrok.io/webhooks/stripe` 4. Save changes #### Step 4: Test by Creating Real Events Create a test subscription through your app, and webhooks will be sent to your ngrok URL. ### Option 3: Testing Webhook Handlers Directly You can also test webhook handlers by sending test payloads: ```bash curl -X POST http://localhost:8000/webhooks/stripe \ -H "Content-Type: application/json" \ -H "stripe-signature: test-signature" \ -d @webhook-test-payload.json ``` **Note:** This will fail signature verification unless you disable it temporarily for testing. --- ## Common Issues & Solutions ### Issue 1: "Stripe.js has not loaded correctly" **Symptoms:** - Error when submitting payment form - Console error about Stripe not being loaded **Solutions:** 1. Check internet connection (Stripe.js loads from CDN) 2. Verify `VITE_STRIPE_PUBLISHABLE_KEY` is set correctly 3. Check browser console for loading errors 4. Ensure no ad blockers blocking Stripe.js ### Issue 2: "Invalid signature" on Webhook **Symptoms:** - Webhook endpoint returns 400 error - Log shows "Invalid webhook signature" **Solutions:** 1. Verify `STRIPE_WEBHOOK_SECRET` matches Stripe Dashboard 2. For Stripe CLI, use the secret from `stripe listen` output 3. Ensure you're using the test mode secret, not live mode 4. Check that you're not modifying the request body before verification ### Issue 3: Payment Method Not Attaching **Symptoms:** - PaymentMethod created but subscription fails - Error about payment method not found **Solutions:** 1. Verify you're passing `paymentMethod.id` to backend 2. Check that payment method is being attached to customer 3. Ensure customer_id exists before creating subscription 4. Review backend logs for detailed error messages ### Issue 4: Test Mode vs Live Mode Confusion **Symptoms:** - Keys not working - Data not appearing in dashboard **Solutions:** 1. **Always check the mode indicator** in Stripe Dashboard 2. Test keys start with `pk_test_` and `sk_test_` 3. Live keys start with `pk_live_` and `sk_live_` 4. Never mix test and live keys 5. Use separate databases for test and live environments ### Issue 5: CORS Errors **Symptoms:** - Browser console shows CORS errors - Requests to backend failing **Solutions:** 1. Ensure FastAPI CORS middleware is configured: ```python from fastapi.middleware.cors import CORSMiddleware app.add_middleware( CORSMiddleware, allow_origins=["http://localhost:5173"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) ``` ### Issue 6: Webhook Events Not Processing **Symptoms:** - Webhooks received but database not updating - Events logged but handlers not executing **Solutions:** 1. Check event type matches handler (case-sensitive) 2. Verify database session is committed 3. Check for exceptions in handler functions 4. Review logs for specific error messages 5. Ensure subscription exists in database before update ### Issue 7: Card Element vs Payment Element Confusion **Symptoms:** - TypeError when calling `stripe.createPaymentMethod()` - Elements not rendering correctly **Solutions:** - Use `PaymentElement` (modern, recommended) - Call `elements.submit()` before creating payment method - Pass `elements` object to `createPaymentMethod({ elements })` - **Our implementation now uses the correct PaymentElement API** --- ## Production Checklist Before going live with Stripe payments: ### Security - [ ] All API keys stored in environment variables (never in code) - [ ] Webhook signature verification enabled and working - [ ] HTTPS enabled on all endpoints - [ ] Rate limiting implemented on payment endpoints - [ ] Input validation on all payment-related forms - [ ] SQL injection prevention (using parameterized queries) - [ ] XSS protection enabled - [ ] CSRF tokens implemented where needed ### Stripe Configuration - [ ] Live mode API keys obtained from Stripe Dashboard - [ ] Live mode webhook endpoints configured - [ ] Webhook signing secret updated for live mode - [ ] Products and prices created in live mode - [ ] Business information completed in Stripe Dashboard - [ ] Bank account added for payouts - [ ] Tax settings configured (if applicable) - [ ] Stripe account activated and verified ### Application Configuration - [ ] Environment variables updated for production - [ ] Database migrations run on production database - [ ] Redis cache configured and accessible - [ ] Error monitoring/logging configured (e.g., Sentry) - [ ] Payment failure notifications set up - [ ] Trial ending notifications configured - [ ] Invoice email delivery tested ### Testing - [ ] All test scenarios passed (see above) - [ ] Webhook handling verified for all event types - [ ] 3D Secure authentication tested - [ ] Subscription lifecycle tested (create, update, cancel, reactivate) - [ ] Error handling tested for all failure scenarios - [ ] Invoice retrieval tested - [ ] Load testing completed - [ ] Security audit performed ### Monitoring - [ ] Stripe Dashboard monitoring set up - [ ] Application logs reviewed regularly - [ ] Webhook delivery monitoring configured - [ ] Payment success/failure metrics tracked - [ ] Alert thresholds configured - [ ] Failed payment retry logic implemented ### Compliance - [ ] Terms of Service updated to mention subscriptions - [ ] Privacy Policy updated for payment data handling - [ ] GDPR compliance verified (if applicable) - [ ] PCI compliance requirements reviewed - [ ] Customer data retention policy defined - [ ] Refund policy documented ### Documentation - [ ] API documentation updated - [ ] Internal team trained on Stripe integration - [ ] Customer support documentation created - [ ] Troubleshooting guide prepared - [ ] Subscription management procedures documented --- ## Quick Reference Commands ### Stripe CLI Commands ```bash # Login to Stripe stripe login # Listen for webhooks (local development) stripe listen --forward-to localhost:8000/webhooks/stripe # Trigger test events stripe trigger customer.subscription.created stripe trigger invoice.payment_succeeded stripe trigger invoice.payment_failed # View recent events stripe events list # Get specific event stripe events retrieve evt_abc123 # Test webhook endpoint stripe webhooks test --endpoint-secret whsec_abc123 ``` ### Testing Shortcuts ```bash # Start backend (from project root) cd services/tenant && uvicorn app.main:app --reload --port 8000 # Start frontend (from project root) cd frontend && npm run dev # Update backend dependencies cd services/tenant && pip install -r requirements.txt # Run database migrations (if using Alembic) cd services/tenant && alembic upgrade head ``` --- ## Additional Resources - **Stripe Documentation:** https://stripe.com/docs - **Stripe API Reference:** https://stripe.com/docs/api - **Stripe Testing Guide:** https://stripe.com/docs/testing - **Stripe Webhooks Guide:** https://stripe.com/docs/webhooks - **Stripe CLI Documentation:** https://stripe.com/docs/stripe-cli - **React Stripe.js Docs:** https://stripe.com/docs/stripe-js/react - **Stripe Support:** https://support.stripe.com --- ## Support If you encounter issues not covered in this guide: 1. **Check Stripe Dashboard Logs:** - Developers → Logs - View detailed request/response information 2. **Review Application Logs:** - Check backend logs for detailed error messages - Look for structured log output from `structlog` 3. **Test in Isolation:** - Test frontend separately - Test backend API with cURL - Verify webhook handling with Stripe CLI 4. **Contact Stripe Support:** - Live chat available in Stripe Dashboard - Email support: support@stripe.com - Community forum: https://stripe.com/community --- **Last Updated:** January 2026 **Stripe Library Versions:** - Frontend: `@stripe/stripe-js@4.0.0`, `@stripe/react-stripe-js@3.0.0` - Backend: `stripe@14.1.0`