Stripe Integration
Connect your Stripe account to enable payment processing, subscription management, and automatic customer synchronization with Tether.
Prerequisites
- A Stripe account (create one at stripe.com)
- Access to your Stripe Dashboard
- Basic understanding of webhooks
Step 1: Get Your API Keys
Navigate to the API Keys section in your Stripe Dashboard to get your keys.
⚠️ Important: Start with test mode keys to safely test your integration before going live.
You'll need two keys:
- Publishable Key (pk_test_...): Used in your frontend code
- Secret Key (sk_test_...): Used in your backend code
Step 2: Configure Environment Variables
Add your Stripe keys to your environment configuration:
1# Stripe API Keys
2NEXT_PUBLIC_STRIPE_TETHER_PUBLISHABLE_KEY=pk_test_your_publishable_key
3STRIPE_TETHER_SECRET_KEY=sk_test_your_secret_key
4
5# Stripe Webhook Secret (we'll get this in Step 4)
6STRIPE_TETHER_WEBHOOK_SECRET=whsec_your_webhook_secretStep 3: Install Stripe SDK
The Stripe SDK is already included in Tether, but if you need to verify:
1npm install stripe @stripe/stripe-jsStep 4: Set Up Webhooks
Webhooks allow Stripe to notify Tether when events occur (like a successful payment or new customer).
Create a Webhook Endpoint
Go to the Webhooks section in your Stripe Dashboard and click "Add endpoint".
Enter your webhook URL:
1https://your-domain.com/api/webhooks/stripeSelect Events to Listen To
Important: Subscribe to exactly these 6 events. Tether only handles these; other events are ignored.
checkout.session.completed- When checkout completes (syncs subscription to products)customer.subscription.updated- Subscription changes (plan, status, trial)customer.subscription.deleted- Subscription cancelledinvoice.payment_succeeded- When invoice is paid (sets active, trial conversion)invoice.payment_failed- Payment failed (sets past_due)customer.subscription.trial_will_end- Trial ending soon
Note: Use invoice.payment_succeeded (not invoice.paid). Products must have stripe_customer_id set for invoice events to update correctly.
Get Your Webhook Secret
After creating the webhook, copy the "Signing secret" (starts with whsec_) and add it to your environment variables.
Step 5: Test the Integration
Test your Stripe connection with a simple API call:
1import Stripe from 'stripe';
2
3const stripe = new Stripe(process.env.STRIPE_TETHER_SECRET_KEY!, {
4 apiVersion: '2024-11-20.acacia',
5});
6
7// Test the connection
8async function testStripeConnection() {
9 try {
10 const customers = await stripe.customers.list({ limit: 1 });
11 console.log('✓ Stripe connection successful');
12 return true;
13 } catch (error) {
14 console.error('✗ Stripe connection failed:', error);
15 return false;
16 }
17}Step 6: Create Your First Customer
Create a test customer to verify everything works:
1import { stripe } from '@/lib/stripe';
2
3async function createCustomer(email: string, name: string) {
4 const customer = await stripe.customers.create({
5 email,
6 name,
7 metadata: {
8 source: 'tether_platform',
9 },
10 });
11
12 return customer;
13}
14
15// Usage
16const customer = await createCustomer(
17 'test@example.com',
18 'Test Customer'
19);
20
21console.log('Customer ID:', customer.id);Step 7: Process a Test Payment
Use Stripe's test card numbers to process a test payment:
1import { stripe } from '@/lib/stripe';
2
3async function createPaymentIntent(amount: number, currency: string = 'usd') {
4 const paymentIntent = await stripe.paymentIntents.create({
5 amount, // Amount in cents
6 currency,
7 automatic_payment_methods: {
8 enabled: true,
9 },
10 });
11
12 return paymentIntent;
13}
14
15// Create a $10 payment intent
16const paymentIntent = await createPaymentIntent(1000);Test card numbers provided by Stripe:
| Card Number | Description |
|---|---|
| 4242 4242 4242 4242 | Successful payment |
| 4000 0000 0000 0002 | Card declined |
| 4000 0000 0000 9995 | Insufficient funds |
Step 8: Monitor Webhooks
Use the Stripe Dashboard to monitor webhook deliveries and debug any issues.
💡 Development Tip
Use the Stripe CLI to test webhooks locally during development:
stripe listen --forward-to localhost:3000/api/webhooks/stripe
Going Live
When you're ready to go live:
- Complete your Stripe account activation
- Replace test API keys with live keys
- Create a new webhook endpoint for production
- Update your environment variables
- Test with real cards (small amounts)
- Monitor the first few transactions closely
Troubleshooting
Webhook Signature Verification Failed
Make sure your STRIPE_TETHER_WEBHOOK_SECRET matches the signing secret from your Stripe webhook endpoint.
API Key Invalid
Verify you're using the correct keys for your environment (test vs live). Test keys start with pk_test_ or sk_test_.
Payment Intent Creation Failed
Check that the amount is in the smallest currency unit (cents for USD). For example, $10 = 1000 cents.
Subscription / Product Not Updating When Payment Succeeds
If the products table (subscription_status, trial_ends_at) isn't updating when customers pay:
- Webhook endpoint configured? In Stripe Dashboard → Webhooks, ensure you have an endpoint for
https://your-domain.com/api/webhooks/stripewith the 6 events listed above. - Webhook secret set?
STRIPE_TETHER_WEBHOOK_SECRETmust be set in your deployment environment. Without it, the route returns 500. - Test vs live mode? The webhook secret is different for test and live mode. Use the secret from the endpoint that matches your Stripe API keys.
- Product has stripe_customer_id? Invoice events (payment_succeeded, payment_failed) look up the product by
stripe_customer_id. If the product was created before Stripe setup or the link failed, it may be missing. Use Admin → Products → connect Stripe, or callPOST /api/admin/products/connect-stripewith the product ID.
Check Stripe Dashboard → Webhooks → your endpoint → Recent deliveries to see if events are being sent and whether they succeed or fail.