Skip to main content
Back to Elite Events

Elite Events Documentation

Technical documentation, guides, and API references for the Elite Events platform.

Security & Integrations/Stripe Integration

Stripe Payment Integration Guide

Overview

This guide explains how to integrate Stripe payment processing into the Elite Events application. The integration uses Stripe's Payment Intent API for secure payment handling.

Prerequisites

  1. A Stripe account (sign up at https://stripe.com)
  2. Stripe API keys (Secret and Publishable keys)
  3. Node.js and npm installed
  4. The application running locally or on a server

Setup Instructions

1. Get Your Stripe Keys

  1. Go to https://dashboard.stripe.com/apikeys
  2. Find your Publishable key (starts with pk_)
  3. Find your Secret key (starts with sk_)
  4. Use test keys initially (they have _test_ in them)

2. Configure Environment Variables

Add your Stripe keys to .env:

STRIPE_SECRET_KEY="sk_test_YOUR_KEY_HERE"
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY="pk_test_YOUR_KEY_HERE"

Important:

  • Keep STRIPE_SECRET_KEY private (server-side only)
  • NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY is safe to expose (used in browser)
  • Never commit .env file to version control

3. Install Dependencies

The required packages are already installed:

  • stripe: Stripe server SDK
  • @stripe/react-stripe-js: React library for Stripe
  • @stripe/stripe-js: Stripe.js library for payment handling

Architecture

Components

  1. StripeProvider (src/components/providers/StripeProvider.tsx)

    • Wraps payment components with Stripe Elements context
    • Initializes Stripe.js with publishable key
  2. StripePaymentForm (src/components/features/checkout/StripePaymentForm.tsx)

    • Client component for collecting payment details
    • Uses CardElement for secure card input
    • Validates and confirms payment with Stripe
  3. PaymentForm (src/components/features/checkout/PaymentForm.tsx)

    • Legacy payment form with local validation
    • Supports multiple payment methods
    • Can be used as fallback or alternative

API Routes

  1. POST /api/payments/create-intent

    • Creates a Stripe PaymentIntent
    • Returns clientSecret for payment confirmation
    • Required: orderId, amount
    • Authenticated: Yes (requires user session)
    • Rate limited: 20 requests per minute per IP
  2. POST /api/payments

    • Processes payment confirmation
    • Updates order status to "SHIPPED"
    • Validates payment intent from Stripe
    • Authenticated: Yes (requires user session)
    • Rate limited: 10 requests per minute per IP

Implementation Guide

Using Stripe in Checkout

// 1. Wrap checkout with StripeProvider in parent layout
import { StripeProvider } from "@/components/providers/StripeProvider";

<StripeProvider>
  <Checkout />
</StripeProvider>

// 2. In checkout component, create payment intent
const response = await fetch("/api/payments/create-intent", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    orderId: order.id,
    amount: order.total,
  }),
});

const { clientSecret } = await response.json();

// 3. Use StripePaymentForm to collect and process payment
<StripePaymentForm
  orderId={order.id}
  amount={order.total}
  clientSecret={clientSecret}
  onSuccess={() => router.push(`/order-confirmation/${order.id}`)}
  onError={(error) => toast.error(error)}
/>

Testing

Test Card Numbers

Stripe provides test card numbers for different scenarios:

Successful Payment:

  • Number: 4242 4242 4242 4242
  • Expiry: Any future date (e.g., 12/25)
  • CVC: Any 3 digits (e.g., 123)

Insufficient Funds:

  • Number: 4000 0000 0000 0002
  • Expiry: Any future date
  • CVC: Any 3 digits

Declined Card:

  • Number: 4000 0000 0000 0069
  • Expiry: Any future date
  • CVC: Any 3 digits

3D Secure Required:

  • Number: 4000 0025 0000 3155
  • Expiry: Any future date
  • CVC: Any 3 digits
  • Then follow the 3DS authentication flow

Testing the Flow

  1. Create a test order in the checkout
  2. On the payment form, use a test card number above
  3. Click "Pay" to process payment
  4. Check Stripe dashboard for payment intent
  5. Verify order status updates to "SHIPPED"

Security Considerations

Best Practices

  1. Never transmit card data to your server

    • Stripe.js handles card tokenization
    • Your server only receives payment intents/tokens
  2. Use HTTPS in production

    • Stripe requires secure connections
    • Never use Stripe in development over HTTP
  3. Validate on both client and server

    • Client-side: Better UX, catches obvious errors
    • Server-side: Essential for security
  4. Store PaymentIntent IDs

    • Save paymentIntentId in your database
    • Use for reconciliation and support
  5. Implement webhooks (optional but recommended)

    • Listen for payment_intent.succeeded events
    • Handle asynchronous payment confirmations
    • Update order status reliably

PCI Compliance

The integration is PCI Level 1 compliant because:

  • Card data never touches your server
  • Stripe handles tokenization securely
  • You never process raw card data

Environment Variables Reference

# Stripe API Keys (from https://dashboard.stripe.com/apikeys)
STRIPE_SECRET_KEY=sk_test_...       # Server-side only
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...  # Browser-safe

Troubleshooting

Common Issues

"Stripe not loaded"

  • Ensure NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY is set
  • Check browser console for loading errors
  • Verify StripeProvider wraps payment components

"Invalid API Key"

  • Check key format (starts with sk_ or pk_)
  • Ensure no extra spaces in .env
  • Restart development server after env changes

"Payment intent creation failed"

  • Verify user is authenticated
  • Check order exists and belongs to user
  • Review rate limiting (20 req/min)
  • Check API logs for details

"CardElement not working"

  • Ensure component wrapped with <Elements>
  • Check Stripe.js loaded successfully
  • Verify card element has proper CSS styling

Debug Mode

Enable Stripe debug logging:

// In StripePaymentForm.tsx
const handleSubmit = async (e) => {
  console.log("Starting payment...");
  console.log("Stripe loaded:", !!stripe);
  console.log("Elements ready:", !!elements);
  // ... rest of code
};

Check Stripe dashboard:

  1. Go to https://dashboard.stripe.com/test/logs
  2. Look for payment intent creation errors
  3. Review API request/response details

Migration from Mock Payments

If you were using mock payments before:

  1. Remove mock payment handler

    • Delete simulatePayment function if using old implementation
  2. Update checkout flow

    • Call /api/payments/create-intent first
    • Get clientSecret before showing payment form
    • Show StripePaymentForm with client secret
  3. Update order status

    • No longer update status manually
    • Stripe confirmation triggers /api/payments
    • Server updates status automatically

Next Steps

Optional Enhancements

  1. Webhook Integration

    • Set up Stripe webhooks for async confirmations
    • Handle payment_intent.succeeded events
  2. Save Payment Methods

    • Allow customers to save cards
    • Use setup_intent for future payments
  3. Subscription Billing

    • Create recurring charges
    • Manage subscription plans
  4. Apple Pay / Google Pay

    • Add mobile payment support
    • Use PaymentRequestButton element
  5. Refund Management

    • Process refunds through Stripe dashboard
    • Or implement refund API endpoint

Resources

Support

For issues or questions:

  1. Check Stripe Dashboard logs
  2. Review browser console for errors
  3. Contact Stripe Support: https://support.stripe.com
  4. Check application logs for API errors
Documentation | Elite Events | Philip Rehberger