Skip to main content

Overview

Stripe is a payment processing platform that allows you to accept payments online. With Superun’s Stripe integration, you can easily add payment functionality to your applications, including one-time payments, subscriptions, and marketplace features. Superun now lets you set up Stripe entirely through chat. Chat‑driven auto‑setup (recommended)
After you connect Superun Cloud (or Supabase) and save your Stripe Secret Key via Build tab → Service section, just describe what you need:
  • “Add three subscription tiers: Basic at 9/month,Proat9/month, Pro at 29/month, and Enterprise at $99/month”
  • “Create a one‑time checkout for my e‑book at $29”
  • “Set up a payment form for my product page”
Superun generates the checkout components, database tables, and payment logic—no manual coding or webhooks unless you ask for them.
  • For one‑off sales, be sure your cart or product page already works.
  • For subscriptions, confirm Superun Cloud (or Supabase) Auth is in place so Superun can link Stripe customers to each user’s id

Key takeaways

  • Use the chat‑driven flow for both subscriptions and one‑off payments.
  • Never paste your Stripe Secret Key in chat. Configure it via Build tab → Service section → StripeEnable.
  • Webhooks are opt‑in. Superun can handle payments without webhooks, but you can set them up for advanced use cases.
  • Debug in Browser Console → Network/Errors, Superun Cloud → Logs, and Stripe Dashboard → Logs.
  • Always test in Stripe Test Mode, then deploy.

What is Stripe

Stripe provides a comprehensive suite of payment APIs and tools:
  • Payment Processing: Accept credit cards, digital wallets, and local payment methods
  • Subscriptions: Recurring billing and subscription management
  • Marketplace: Multi-party payments and marketplace functionality
  • Connect: Platform payments for marketplaces and platforms
  • Billing: Invoicing and billing management
  • Tax: Automatic tax calculation and compliance

Key Benefits

  • Global Reach: Accept payments from customers worldwide
  • Multiple Payment Methods: Credit cards, digital wallets, bank transfers, and more
  • Developer-Friendly: Well-documented APIs and excellent developer experience
  • Compliance: PCI DSS compliant, handles sensitive payment data securely
  • Real-time: Instant payment processing and webhook notifications

Requirements

Before integrating Stripe, ensure the following prerequisites are met:
  • The project must be connected to Superun Cloud (or Supabase). Learn more about Superun Cloud or Supabase integration
  • A Stripe account with properly configured products (for subscriptions)
  • A working frontend:
    • For individual product sales, ensure a shopping cart and checkout page are functional.
    • For subscriptions, set up login functionalities and different pricing tiers.
Please note Stripe integration doesn’t work in preview. To test the integration, make sure to deploy your project. You should also make sure to be in test mode in Stripe when trying out the functionality. When testing payment, use test card number: 4242 4242 4242 4242, any 3 digits as CVC, and any future date.

Stripe payment setup (No‑code chat flow)

Superun now generates all Stripe logic for you. Once your Stripe Secret Key is configured via Build tab → Service section and your project is connected to Superun Cloud (or Supabase), simply tell Superun what you need in chat—no manual coding required.
1

Step 1: Prep your project

  • Superun Cloud (or Supabase) connected
  • Stripe Secret Key added via Build tab → Service section → StripeEnable
  • (Optional) Prices or product IDs handy from Stripe Dashboard
2

Step 2: Describe your payment needs in chat

Examples:
  • “Create a one-time checkout for my ‘Digital Course’ at $29”
  • “Set up an annual Premium plan for $99, tied to each user’s id”
  • “Add three subscription tiers: Basic at 9/month,Proat9/month, Pro at 29/month, and Enterprise at $99/month”
  • “Create a payment form for my product page”
3

Step 3: Review & apply

Superun auto‑scaffolds the payment components, database tables (if using Superun Cloud), and UI elements (all tied to the user’s id). Check the preview, then click Apply to deploy.
  • Subscriptions should always be linked to the authenticated user’s id in Superun Cloud (or Supabase) for secure, role‑based access.

Getting Started

1. Create a Stripe Account

  1. Go to stripe.com and sign up
  2. Complete the account setup process
  3. Verify your business information
  4. Activate your account (test mode is available immediately)

2. Get Your API Keys

In your Stripe dashboard:
  1. Go to Developers → API Keys
  2. Copy your Publishable Key (starts with pk_test_ or pk_live_)
  3. Copy your Secret Key (starts with sk_test_ or sk_live_)
  4. Keep your secret key secure and never expose it in client-side code
Important Security WarningNever paste your Secret Key directly in Superun chat. Treat it like the keys to your house—exposing it could allow unauthorized access to your Stripe account. Instead, store it securely using the Build tab → Service section → StripeEnable feature.

3. Configure Stripe in Superun

You can enable Stripe integration in two ways:
  1. In your Superun project, go to the Build tab
  2. Scroll to the Service section
  3. Find Stripe and click Enable
  4. Enter your Publishable Key and Secret Key when prompted
  5. Choose your environment (Test or Live)
Superun will automatically configure your project to use Stripe.

Option 2: Enable via Chat

You can also enable Stripe by asking Superun in the chat:
Enable Stripe payment processing for my project
or
Add Stripe integration with test keys
Superun will guide you through the setup process and automatically configure the integration. When prompted, use the Build tab → Service section to securely add your API keys.

Manual Payment Setup (Advanced)

Recommended: Use the chat-driven flow described above for the easiest setup. The following sections are for advanced users who want to implement payments manually or customize the generated code.

Install Stripe SDK

Superun automatically includes the Stripe SDK when you enable Stripe integration, but you can also install it manually:
npm install @stripe/stripe-js

Initialize Stripe

import { loadStripe } from '@stripe/stripe-js';

// Initialize Stripe
const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY);

One-Time Payments

Creating a Payment Intent

// Server-side: Create payment intent
const createPaymentIntent = async (amount, currency = 'usd') => {
  const response = await fetch('/api/create-payment-intent', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      amount: amount * 100, // Amount in cents
      currency,
    }),
  });

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

Processing Payment

import { Elements, CardElement, useStripe, useElements } from '@stripe/react-stripe-js';

const CheckoutForm = () => {
  const stripe = useStripe();
  const elements = useElements();
  const [loading, setLoading] = useState(false);

  const handleSubmit = async (event) => {
    event.preventDefault();

    if (!stripe || !elements) {
      return;
    }

    setLoading(true);

    // Create payment intent
    const clientSecret = await createPaymentIntent(50); // $50.00

    // Confirm payment
    const { error, paymentIntent } = await stripe.confirmCardPayment(clientSecret, {
      payment_method: {
        card: elements.getElement(CardElement),
      },
    });

    if (error) {
      console.error('Payment failed:', error);
    } else if (paymentIntent.status === 'succeeded') {
      console.log('Payment succeeded:', paymentIntent);
      // Handle successful payment
    }

    setLoading(false);
  };

  return (
    <form onSubmit={handleSubmit}>
      <CardElement
        options={{
          style: {
            base: {
              fontSize: '16px',
              color: '#424770',
              '::placeholder': {
                color: '#aab7c4',
              },
            },
          },
        }}
      />
      <button disabled={!stripe || loading}>
        {loading ? 'Processing...' : 'Pay $50.00'}
      </button>
    </form>
  );
};

// Wrap your app with Elements
const App = () => {
  return (
    <Elements stripe={stripePromise}>
      <CheckoutForm />
    </Elements>
  );
};

Subscriptions

Creating a Subscription

// Create a subscription
const createSubscription = async (priceId, customerId) => {
  const response = await fetch('/api/create-subscription', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      priceId,
      customerId,
    }),
  });

  const { subscription } = await response.json();
  return subscription;
};

Subscription Management

// Cancel a subscription
const cancelSubscription = async (subscriptionId) => {
  const response = await fetch('/api/cancel-subscription', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      subscriptionId,
    }),
  });

  const { subscription } = await response.json();
  return subscription;
};

// Update subscription
const updateSubscription = async (subscriptionId, newPriceId) => {
  const response = await fetch('/api/update-subscription', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      subscriptionId,
      newPriceId,
    }),
  });

  const { subscription } = await response.json();
  return subscription;
};

Customer Management

Creating Customers

// Create a customer
const createCustomer = async (email, name) => {
  const response = await fetch('/api/create-customer', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      email,
      name,
    }),
  });

  const { customer } = await response.json();
  return customer;
};

Customer Portal

// Create customer portal session
const createPortalSession = async (customerId) => {
  const response = await fetch('/api/create-portal-session', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      customerId,
    }),
  });

  const { url } = await response.json();
  return url;
};

// Redirect to customer portal
const handleManageSubscription = async () => {
  const url = await createPortalSession(customerId);
  window.location.href = url;
};

Advanced integration: Webhooks & Superun Cloud

For complex payment structures such as subscriptions and role-based access, Superun recommends using Superun Cloud (or Supabase) to securely handle Stripe integration. This allows for proper webhook handling, subscription management, and role-based access control based on payment tiers.
Webhooks are optional for basic payment flows. Superun can handle payments without webhooks, but setting them up enables real-time updates and better subscription management.

Setting Up Webhooks

1

Step 1: Connect Superun Cloud

Getting started is simple. Superun makes connecting Superun Cloud effortless:
  1. Go to Build tab → Service section
  2. Find Superun Cloud and click Enable
  3. Follow the instructions to set up your cloud project
  4. Once connected, Superun Cloud enables secure payment processing, subscription management, webhook handling, customer data storage, and error handling.
2

Step 2: Retrieve the Webhook Endpoint URL

After Superun generates the webhook handler, retrieve the endpoint URL from:
  • Superun CloudFunctions → Your webhook function
  • Or ask Superun in chat: “What’s my Stripe webhook endpoint URL?”
3

Step 3: Configure Webhook in Stripe Dashboard

  1. Go to Stripe DashboardDevelopersWebhooksAdd endpoint
  2. Enter your webhook URL from Step 2
  3. Select the events you want to listen for:
  • payment_intent.succeeded
  • payment_intent.payment_failed
  • customer.subscription.created
  • customer.subscription.updated
  • customer.subscription.deleted
  1. Copy the Webhook Signing Secret (starts with whsec_)
4

Step 4: Store Webhook Secret Securely

Store the webhook signing secret in your Superun Cloud environment variables or ask Superun in chat to help you configure it securely.
If unsure about naming the secret, ask Superun in chat mode for guidance.

Processing Webhooks

// webhook handler
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);

export default async function handler(req, res) {
  if (req.method !== 'POST') {
    return res.status(405).end();
  }

  const sig = req.headers['stripe-signature'];
  const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;

  let event;

  try {
    event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
  } catch (err) {
    console.error('Webhook signature verification failed:', err.message);
    return res.status(400).send(`Webhook Error: ${err.message}`);
  }

  // Handle the event
  switch (event.type) {
    case 'payment_intent.succeeded':
      const paymentIntent = event.data.object;
      console.log('Payment succeeded:', paymentIntent.id);
      // Update your database, send confirmation email, etc.
      break;

    case 'customer.subscription.created':
      const subscription = event.data.object;
      console.log('Subscription created:', subscription.id);
      // Activate user's premium features
      break;

    case 'customer.subscription.updated':
      const updatedSubscription = event.data.object;
      console.log('Subscription updated:', updatedSubscription.id);
      // Update subscription status
      break;

    case 'customer.subscription.deleted':
      const deletedSubscription = event.data.object;
      console.log('Subscription cancelled:', deletedSubscription.id);
      // Deactivate user's premium features
      break;

    default:
      console.log(`Unhandled event type ${event.type}`);
  }

  res.json({ received: true });
}

Advanced Features

Payment Methods

// Save payment method for future use
const savePaymentMethod = async (customerId, paymentMethodId) => {
  const response = await fetch('/api/save-payment-method', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      customerId,
      paymentMethodId,
    }),
  });

  const { paymentMethod } = await response.json();
  return paymentMethod;
};

// List customer's payment methods
const getPaymentMethods = async (customerId) => {
  const response = await fetch(`/api/payment-methods/${customerId}`);
  const { paymentMethods } = await response.json();
  return paymentMethods;
};

Invoicing

// Create an invoice
const createInvoice = async (customerId, items) => {
  const response = await fetch('/api/create-invoice', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      customerId,
      items,
    }),
  });

  const { invoice } = await response.json();
  return invoice;
};

// Send invoice to customer
const sendInvoice = async (invoiceId) => {
  const response = await fetch('/api/send-invoice', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      invoiceId,
    }),
  });

  const { invoice } = await response.json();
  return invoice;
};

Marketplace Payments

// Create a connected account
const createConnectedAccount = async (email, country) => {
  const response = await fetch('/api/create-connected-account', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      email,
      country,
    }),
  });

  const { account } = await response.json();
  return account;
};

// Create account link for onboarding
const createAccountLink = async (accountId) => {
  const response = await fetch('/api/create-account-link', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      accountId,
    }),
  });

  const { url } = await response.json();
  return url;
};

Testing Your Integration

Test Mode Setup

  • Use Stripe’s Test Mode to safely test payments before going live
  • Switch to Test Mode in Stripe Dashboard (toggle in the top right)
  • Use test API keys (starts with pk_test_ and sk_test_)

Test Cards

Use these test card numbers for testing:
  • Successful payment: 4242 4242 4242 4242
    • Any future expiration date (e.g., 12/25)
    • Any 3-digit CVC (e.g., 123)
  • Declined payment: 4000 0000 0000 0002
  • Requires authentication: 4000 0025 0000 3155
  • Insufficient funds: 4000 0000 0000 9995
Important: Stripe integration does not work in preview mode. Make sure to deploy your app to test the integration.

Test Scenarios

// Test different payment scenarios
const testCards = {
  success: '4242424242424242',
  declined: '4000000000000002',
  requiresAuth: '4000002500003155',
  insufficientFunds: '4000000000009995',
};

// Test webhook events
const testWebhook = async () => {
  const response = await fetch('/api/test-webhook', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      eventType: 'payment_intent.succeeded',
      data: { /* test data */ },
    }),
  });

  const result = await response.json();
  return result;
};

Security Best Practices

Environment Variables

# .env.local
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...

Server-Side Validation

// Always validate on the server
const validatePayment = async (paymentIntentId) => {
  const paymentIntent = await stripe.paymentIntents.retrieve(paymentIntentId);
  
  if (paymentIntent.status !== 'succeeded') {
    throw new Error('Payment not completed');
  }
  
  return paymentIntent;
};

Webhook Security

// Verify webhook signatures
const verifyWebhook = (payload, signature, secret) => {
  try {
    const event = stripe.webhooks.constructEvent(payload, signature, secret);
    return event;
  } catch (err) {
    throw new Error('Invalid webhook signature');
  }
};

Common Patterns

Payment Form Component

const PaymentForm = ({ amount, onSuccess, onError }) => {
  const stripe = useStripe();
  const elements = useElements();
  const [loading, setLoading] = useState(false);

  const handleSubmit = async (event) => {
    event.preventDefault();

    if (!stripe || !elements) {
      return;
    }

    setLoading(true);

    try {
      const { error, paymentIntent } = await stripe.confirmCardPayment(
        clientSecret,
        {
          payment_method: {
            card: elements.getElement(CardElement),
          },
        }
      );

      if (error) {
        onError(error);
      } else if (paymentIntent.status === 'succeeded') {
        onSuccess(paymentIntent);
      }
    } catch (err) {
      onError(err);
    } finally {
      setLoading(false);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <CardElement />
      <button disabled={!stripe || loading}>
        {loading ? 'Processing...' : `Pay $${amount}`}
      </button>
    </form>
  );
};

Subscription Status Component

const SubscriptionStatus = ({ customerId }) => {
  const [subscription, setSubscription] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchSubscription = async () => {
      try {
        const response = await fetch(`/api/subscription/${customerId}`);
        const data = await response.json();
        setSubscription(data.subscription);
      } catch (error) {
        console.error('Error fetching subscription:', error);
      } finally {
        setLoading(false);
      }
    };

    fetchSubscription();
  }, [customerId]);

  if (loading) return <div>Loading...</div>;

  if (!subscription) return <div>No active subscription</div>;

  return (
    <div>
      <h3>Subscription Status: {subscription.status}</h3>
      <p>Current Period: {subscription.current_period_start} - {subscription.current_period_end}</p>
      <p>Amount: ${subscription.items.data[0].price.unit_amount / 100}</p>
    </div>
  );
};

Debugging & Troubleshooting

1

Step 1

Open Developer Tools (Right-click → Inspect → Console in Chrome).
2

Step 2

Look for errors and review payment event logs.
3

Step 3

Copy error messages and ask Superun in chat for debugging assistance.
1

Step 1

Go to Build tab → Service section → Superun Cloud
2

Step 2

Navigate to Logs or FunctionsLogs
3

Step 3

Check for webhook errors and payment processing issues.
1

Step 1

Navigate to Stripe DashboardDevelopersWebhooks
2

Step 2

Click on your webhook endpoint
3

Step 3

Review the Events tab to confirm that Stripe is sending data correctly.
1

Step 1

Switch to chat mode and ask Superun follow-up questions.
2

Step 2

Describe your issue step by step:
  • “My payment form isn’t showing up”
  • “The subscription isn’t being created”
  • “Webhooks aren’t working”
3

Step 3

Use the Rubber Duck Method & explain your issue step by step to clarify the problem.

Common Issues

Q: Payment is failing with “Your card was declined” A: This could be due to:
  • Using a test card in live mode (or vice versa)
  • Insufficient funds (for test cards, use 4242 4242 4242 4242)
  • Card not supported for online payments
  • Incorrect card details
  • Bank blocking the transaction
Q: Webhooks are not being received A: Check:
  • Webhook URL is accessible from the internet
  • Webhook endpoint is returning 200 status
  • Webhook signing secret is correct
  • Events are properly selected in Stripe dashboard
  • You’re testing in deployed mode (not preview)
Q: Test payments are not working A: Ensure:
  • You’re using test API keys (pk_test_ and sk_test_)
  • Test card numbers are correct (4242 4242 4242 4242)
  • Amount is in cents (e.g., $10.00 = 1000 cents)
  • Your app is deployed (Stripe doesn’t work in preview mode)
  • You’re in Test Mode in Stripe Dashboard
Q: Subscription webhooks are not firing A: Verify:
  • Subscription is created successfully
  • Webhook events are selected for subscription events
  • Webhook endpoint is handling the events properly
  • Webhook secret is correctly stored in Superun Cloud

Need Help?

Check our FAQ for common Stripe integration questions and troubleshooting tips.