22 KiB
Stripe Integration Testing Guide
Table of Contents
- Prerequisites
- Environment Setup
- Stripe Dashboard Configuration
- Test Card Numbers
- Testing Scenarios
- Webhook Testing
- Common Issues & Solutions
- Production Checklist
Prerequisites
Before you begin testing, ensure you have:
- ✅ Stripe account created (sign up at 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
- Log in to your Stripe Dashboard: https://dashboard.stripe.com
- Click on your profile icon in the top right corner
- Ensure Test Mode is enabled (you'll see "TEST DATA" banner at the top)
- If not enabled, toggle to "Switch to test data"
Step 2: Retrieve API Keys
-
Navigate to Developers → API keys
-
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
- Publishable key (starts with
-
Click "Reveal test key" for the Secret key and copy both keys
Step 3: Configure Environment Variables
Frontend .env file:
# Create or update: /frontend/.env
VITE_STRIPE_PUBLISHABLE_KEY=pk_test_your_publishable_key_here
Backend .env file:
# 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:
cd services/tenant
pip install -r requirements.txt
# This will install stripe==14.1.0
Frontend:
cd frontend
npm install
# Verifies @stripe/react-stripe-js and @stripe/stripe-js are installed
Stripe Dashboard Configuration
Step 1: Create Products and Prices
-
In Stripe Dashboard (Test Mode), go to Products → Add product
-
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)
- Price:
- Click Save product
- Copy the Price ID (starts with
price_...) - you'll need this
- Product name:
-
Create Professional Plan:
- Product name:
Professional Plan - Description:
Advanced subscription for growing businesses - Pricing:
- Price:
$99.00 - Billing period:
Monthly - Currency:
USD
- Price:
- Click Save product
- Copy the Price ID
- Product name:
-
Update your application configuration:
- Store these Price IDs in your application settings
- You'll use these when creating subscriptions
Step 2: Configure Webhooks
-
Navigate to Developers → Webhooks
-
Click + Add endpoint
-
For Local Development:
- Endpoint URL:
https://your-ngrok-url.ngrok.io/webhooks/stripe - (We'll set up ngrok later for local testing)
- Endpoint URL:
-
Select events to listen to:
checkout.session.completedcustomer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deletedinvoice.payment_succeededinvoice.payment_failedcustomer.subscription.trial_will_end
-
Click Add endpoint
-
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
.envfile asSTRIPE_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:
-
Start your applications:
# Terminal 1 - Backend cd services/tenant uvicorn app.main:app --reload --port 8000 # Terminal 2 - Frontend cd frontend npm run dev -
Navigate to registration page:
- Open browser:
http://localhost:5173/register(or your frontend URL)
- Open browser:
-
Fill in user details:
- Full Name:
John Doe - Email:
john.doe+test@example.com - Company:
Test Company - Password: Create a test password
- Full Name:
-
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
- Card Number:
-
Select a plan:
- Choose
Starter PlanorProfessional Plan
- Choose
-
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:
-
In Stripe Dashboard:
- Go to Customers → Find "John Doe"
- Go to Subscriptions → See active subscription
- Status should be
active
-
In your database:
SELECT * FROM subscriptions WHERE tenant_id = 'your-tenant-id';- Verify subscription record exists
- Status should be
active - Check
stripe_customer_idis populated
-
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:
-
Follow steps 1-3 from Scenario 1
-
Fill in payment details with 3DS card:
- Card Number:
4000 0025 0000 3155 - Expiry:
12/30 - CVC:
123 - Fill remaining details as before
- Card Number:
-
Submit the form
-
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:
-
Follow steps 1-3 from Scenario 1
-
Use a declined test card:
- Card Number:
4000 0000 0000 0002 - Fill remaining details as before
- Card Number:
-
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:
- Use card number:
4000 0000 0000 9995 - 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:
-
Create an active subscription (use Scenario 1)
-
Cancel the subscription:
- Method 1: Through your application UI (if implemented)
- Method 2: API call:
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_dateis set - ✅ User retains access until end of billing period
- ✅ Response includes days remaining
- ✅ Subscription cache invalidated
Verification:
-
Check database:
SELECT status, cancellation_effective_date, cancelled_at FROM subscriptions WHERE tenant_id = 'your-tenant-id'; -
Verify API response:
{ "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:
-
Cancel a subscription (use Scenario 5)
-
Reactivate the subscription:
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_atandcancellation_effective_datecleared - ✅ Next billing date set
- ✅ Subscription cache invalidated
Scenario 7: Retrieve Invoices
Objective: Test invoice retrieval from Stripe.
Steps:
-
Create subscription with successful payment (Scenario 1)
-
Retrieve invoices:
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:
iddateamountcurrencystatusinvoice_pdfURLhosted_invoice_urlURL
Verification:
- Click on
hosted_invoice_urlto view invoice in browser - Download PDF from
invoice_pdfURL
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:
brew install stripe/stripe-cli/stripe
Windows: Download from: https://github.com/stripe/stripe-cli/releases
Linux:
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
stripe login
This opens a browser to authorize the CLI.
Step 3: Forward Webhooks to Local Server
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:
STRIPE_WEBHOOK_SECRET=whsec_abc123...
Step 4: Trigger Test Events
Open a new terminal and run:
# 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
ngrok http 8000
Output:
Forwarding https://abc123.ngrok.io -> http://localhost:8000
Step 3: Update Stripe Webhook Endpoint
- Go to Stripe Dashboard → Developers → Webhooks
- Click on your endpoint
- Update URL to:
https://abc123.ngrok.io/webhooks/stripe - 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:
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:
- Check internet connection (Stripe.js loads from CDN)
- Verify
VITE_STRIPE_PUBLISHABLE_KEYis set correctly - Check browser console for loading errors
- 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:
- Verify
STRIPE_WEBHOOK_SECRETmatches Stripe Dashboard - For Stripe CLI, use the secret from
stripe listenoutput - Ensure you're using the test mode secret, not live mode
- 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:
- Verify you're passing
paymentMethod.idto backend - Check that payment method is being attached to customer
- Ensure customer_id exists before creating subscription
- 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:
- Always check the mode indicator in Stripe Dashboard
- Test keys start with
pk_test_andsk_test_ - Live keys start with
pk_live_andsk_live_ - Never mix test and live keys
- Use separate databases for test and live environments
Issue 5: CORS Errors
Symptoms:
- Browser console shows CORS errors
- Requests to backend failing
Solutions:
- Ensure FastAPI CORS middleware is configured:
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:
- Check event type matches handler (case-sensitive)
- Verify database session is committed
- Check for exceptions in handler functions
- Review logs for specific error messages
- 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
elementsobject tocreatePaymentMethod({ 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
# 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
# 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:
-
Check Stripe Dashboard Logs:
- Developers → Logs
- View detailed request/response information
-
Review Application Logs:
- Check backend logs for detailed error messages
- Look for structured log output from
structlog
-
Test in Isolation:
- Test frontend separately
- Test backend API with cURL
- Verify webhook handling with Stripe CLI
-
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