Set up a subscription with Stripe’s SEPA using React and NodeJS

Rudraksh Dixit
6 min readJun 27, 2021
Your startup’s earnings go brrrrrrrr

Integrating Stripe’s Card payment is easy, but integrating SEPA payments in your project can be very confusing. Since there are not many resources available online, I am here with my solution to collect SEPA payments, feel free to contact me on Linkedin if you have a better solution or need any help in the same.

I will be sharing the steps to integrate using ReactJS and NodeJS

  1. Going to account settings of Stripe and changing the country which supports the SEPA payments.

2. Get your API keys for Stripe’s dashboard

Now our initial integration is done, we can now jump to the coding part. Let’s start with react first.

Install Stripe’s packages into your react packages using the following command

npm install --save @stripe/react-stripe-js @stripe/stripe-js

3. Inside your react project, create a components folder and in there create a file Sepa.js

Basic structure

4. Import Elements and loadStripe, the function loadStripe expects Publishable key which we got in step 2 and returns a Promise that resolves with a newly created Stripe object once Stripe.js has loaded.

Wrap your Sepa component inside the Elements component(as shown in the image below) which expects the stripe promise.

import './App.css';
import Checkout from "./screens/Checkout"
import {loadStripe} from '@stripe/stripe-js';
import {Elements} from '@stripe/react-stripe-js';
const stripePromise = loadStripe("yourkey");function App() {
return (
<Elements stripe={stripePromise}>
<Checkout />
</Elements>
);
}
export default App;

5. Create a new file SepaElement.js, which will be having the IBAN element, and import the SepaElement component in the Sepa Component.

Here is the code for the SepaElement.js

import React from "react";
import { IbanElement } from "@stripe/react-stripe-js";
function SepaElement(props) {
const IBAN_STYLE = {
base: {
color: "#707070",
fontSize: "14px",
"::placeholder": {
color: "#707070",
},
":-webkit-autofill": {
color: "#707070",
},
},
invalid: {
color: "#fa755a",
iconColor: "#fa755a",
":-webkit-autofill": {
color: "#fa755a",
},
},
};
const IBAN_ELEMENT_OPTIONS = {
supportedCountries: ["SEPA"],
placeholderCountry: "DE",
style: IBAN_STYLE,
};
return <IbanElement options={IBAN_ELEMENT_OPTIONS} />;
}
export default SepaElement;

6. Adding a form and submit button with the Stripe Element and applying some basic styling.

Form component with SepaElement and Pay button
import React from "react";
import SepaElement from "./SepaElement";
import axios from "axios"
import { useStripe, useElements,IbanElement} from "@stripe/react-stripe-js";
function Sepa(props) {
const stripe = useStripe();
const elements = useElements();
return (
<form
style={{
width: "30%",
margin: "auto",
marginTop: "2rem",
border: "1px solid red",
padding: "1rem",
}}
>
<SepaElement />
<button
disabled={!stripe}
style={{
color: "white",
backgroundColor: "red",
textAlign: "center",
width: "100%",
padding: "1rem",
marginTop: "2rem",
cursor: "pointer",
}}
>
Pay
</button>
</form>
);
}
export default Sepa;

7. On the form submit we should make a backend request for collecting the payment. Create a function handleSubmit and call it on the form submit.

const handleSubmit = async (e) => {
e.preventDefault();
try {
//to make a request
} catch (err) {
console.log(err);
}
};

8. Check if the stripe and element are loaded yet and create a payment method of type ‘sepa_debit’ (as given below) and making Axios post request to our backend (which isn’t built yet) and passing the payment ID.

const handleSubmit = async (e) => {
e.preventDefault();
try {
if (!stripe || !elements) {
// Stripe.js has not yet loaded.
// Make sure to disable form submission until Stripe.js has loaded.
return;
}
const sepaPayment = await stripe.createPaymentMethod({
type: "sepa_debit",
sepa_debit: elements.getElement(IbanElement),
billing_details: {
email: "rudrakshdixit@gmail.com", //collect this from user
name: "rudra", //collect this from user
},
});
const res = await axios.post("http://localhost:5000/subscribe", {
payment_method: sepaPayment.paymentMethod.id,
});
console.log(res.data);
} catch (err) {
console.log(err);
}
};

Congratulations, we are done with the front end here.

9. Moving to the back end. Install express, stripe, body-parser, cors.

Create a file server.js and write the basic app initialisation code.

const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const cors = require("cors");
app.use(bodyParser.urlencoded({ extended: false }));
// parse application/json
app.use(bodyParser.json());
app.use(cors());
app.listen(5000, () => console.log("started"));

10. Import the stripe library at the backend and passing the secret key.

const express = require("express");
const app = express();
const stripe = require("stripe")("yourKEY"); //keep this in .env file
const bodyParser = require("body-parser");

11. Create a post route “/subscribe” to handle the incoming post request from the front end.

app.post("/subscribe", async (req, res) => {
try {
} catch (err) {
console.log(err);
}
});

12. Create a product on the stripe dashboard for the subscription.
Give it any name, price and make sure it's a recurring payment.

Select the duration of the Subscription cycle and click to Save product on the top right of the page.

Copy the generated API ID to use it in the subscription

13. Coming back to our back end project, the first step is to get the payment method id from the front end, getting the IP address and the user agent of the client.
IP and User agent are required to create an online mandate

const { payment_method } = req.body;
const ip = req.headers["x-real-ip"] || req.connection.remoteAddress;
const userAgent = req.get("User-Agent");

Create a customer

const customer = await stripe.customers.create({
//TODO: get user details from db or from incoming request
payment_method: payment_method,
email: "rudrakshdixit@gmail.com",
description: "Subscription",
shipping: {
name: "RD",
address: {
line1: "510",
postal_code: "10115",
city: "Berlin",
state: "BE",
country: "DE",
},
},
invoice_settings: {
default_payment_method: payment_method,
},
});

Create a setup Intent

const setupIntent = await stripe.setupIntents.create({
payment_method_types: ["sepa_debit"],
customer: customer.id,
confirm: true,
payment_method: payment_method,
mandate_data: {
customer_acceptance: {
type: "online",
online: { ip_address: ip, user_agent: userAgent },
},
},
});

Create a Subscription, add the price ID from step 12

const subscription = await stripe.subscriptions.create({
customer: customer.id,
items: [
{
price: "price_1J6rBpA7B_YOURID",
},
],
expand: ["latest_invoice.payment_intent"],
});
Bois after successfully integrating stripe’s SEPA payments

This will create the user’s subscription and you can return the subscription object or store the user details in the DB.

Full code

app.post("/subscribe", async (req, res) => {
try {
const { payment_method } = req.body;
const ip = req.headers["x-real-ip"] || req.connection.remoteAddress;
const userAgent = req.get("User-Agent");
const customer = await stripe.customers.create({
//TODO: get user details from db or from incoming request
payment_method: payment_method,
email: "rudrakshdixit@gmail.com",
description: "Subscription",
shipping: {
name: "RD",
address: {
line1: "510",
postal_code: "10115",
city: "Berlin",
state: "BE",
country: "DE",
},
},
invoice_settings: {
default_payment_method: payment_method,
},
});
const setupIntent = await stripe.setupIntents.create({
payment_method_types: ["sepa_debit"],
customer: customer.id,
confirm: true,
payment_method: payment_method,
mandate_data: {
customer_acceptance: {
type: "online",
online: { ip_address: ip, user_agent: userAgent },
},
},
});
const subscription = await stripe.subscriptions.create({
customer: customer.id,
items: [
{
price: "price_1J6rBpA7_yourID",
},
],
expand: ["latest_invoice.payment_intent"],
});
console.log(subscription);
res.json({ subscription: subscription });
} catch (err) {
console.log(err);
}
});

Use test IBAN numbers to test the integration, and go to the stripe’s payments page to check the status of our subscription.

dummy IBAN number provided by Stripe
Successfully paid

So here it was the implementation of creating a subscription with stripe’s SEPA using React and NodeJS. Feel free to contact me if you find a better solution or if you get stuck anywhere.

--

--