Stripe in Ensemble: Subscription Management Made Easy
With Ensemble, weβve made subscription management simple by providing native Stripe integration. Developers can initialize Stripe, present the Payment Sheet, and handle results directly in their apps β without writing custom client logic.
π Read the full Stripe docs here
π¨ Explore the KitchenSink example

π‘ Why Subscriptions Are Hard
Unlike one-time payments, subscriptions require a recurring billing flow:
- Initializing and authenticating the customer.
- Collecting payment details securely.
- Managing trials, upgrades, and downgrades.
- Handling payment failures and renewals.
Stripe provides powerful APIs for all of this, but integrating them into a mobile app can quickly get overwhelming.
π― How Ensemble Helps
Ensemble removes the complexity of frontend integration:
- Stripe initialization is handled with a simple action.
- Payment Sheet presentation works out of the box.
- Success and error handling can be wired directly into your appβs flow.
This lets you focus on your backend subscription logic (creating customers, generating Payment Intent client secrets, managing webhooks) while Ensemble takes care of the client experience.

βοΈ How It Works
- Your backend creates a Payment Intent in Stripe and returns the
clientSecret
. - Your Ensemble app initializes Stripe with your publishable key.
- Payment Sheet opens β the user enters their details.
- Result is handled in-app: success, failure, or cancellation.
π Example: Stripe in Ensemble
Initialize Stripe with your publishable key:
Button:
label: Initialize Stripe
onTap:
initializeStripe:
publishableKey: "pk_test_your_publishable_key_here"
merchantIdentifier: "merchant.com.yourapp"
onSuccess:
showToast:
message: "Stripe initialized successfully"
onError:
showToast:
message: "Failed to initialize Stripe"
Once initialized, show the Payment Sheet:
initializeStripe:
publishableKey: "pk_test_your_publishable_key_here"
merchantIdentifier: "merchant.com.yourapp"
onSuccess:
showPaymentSheet:
clientSecret: ${paymentIntentClientSecret}
configuration:
merchantDisplayName: "My Store"
style: "system"
primaryButtonLabel: "Pay $29.99"
onSuccess:
showToast:
message: "Payment successful!"
onError:
showToast:
message: "Payment failed"
onError:
showToast:
message: "Failed to initialize payment system"
π₯ Backend Example (Node.js/Express)
Ensemble handles the frontend, but youβll still need a backend to create a Payment Intent and return the clientSecret
. Hereβs a minimal Node.js example using Express and the official Stripe SDK:
// server.js
import express from "express";
import Stripe from "stripe";
const app = express();
const stripe = new Stripe("sk_test_your_secret_key_here");
app.post("/create-payment-intent", async (req, res) => {
try {
const paymentIntent = await stripe.paymentIntents.create({
amount: 2999, // amount in cents ($29.99)
currency: "usd",
automatic_payment_methods: { enabled: true },
});
res.json({ clientSecret: paymentIntent.client_secret });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.listen(4242, () => console.log("Server running on port 4242"));
π In your Ensemble app, call this endpoint to fetch the clientSecret
before showing the Payment Sheet.
π Things to Keep in Mind
- You need a backend to create the Payment Intent and return the
clientSecret
. Ensemble does not handle server-side billing logic. - Webhooks are essential to keep your backend in sync with Stripe subscription events (trial started, payment failed, subscription canceled, etc.).
- Test with Stripe CLI before going live to ensure your subscription lifecycle works end-to-end.

Stripe subscriptions are powerful but can be overwhelming to implement. Ensemble makes the frontend integration effortless: initialize Stripe, present the Payment Sheet, and handle results β all in just a few lines of config.
Your backend provides the Payment Intent client secret; Ensemble handles the rest.
With this, adding subscriptions to your app is no longer a chore β itβs just another Ensemble action.
π Check out the Stripe docs
π¨ See it in action in the KitchenSink