Accept a SEPA Direct Debit payment
Learn to accept SEPA Direct Debit payments.
Caution
We recommend that you follow the Accept a payment guide unless you need to use manual server-side confirmation, or your integration requires presenting payment methods separately. If you’ve already integrated with Elements, see the Payment Element migration guide.
Accepting SEPA Direct Debit payments on your website consists of creating an object to track a payment, collecting payment method information and mandate acknowledgement, and submitting the payment to Stripe for processing. Stripe uses this payment object, the PaymentIntent, to track and handle all the states of the payment until the payment completes.
You can also set up a SEPA Direct Debit PaymentMethod by having your customer authenticate their bank details with Bancontact, iDEAL, or Sofort.
Set up StripeServer-sideClient-side
Server-side 
This integration requires endpoints on your server that talk to the Stripe API. Use our official libraries for access to the Stripe API from your server:
Client-side 
The React Native SDK is open source and fully documented. Internally, it uses the native iOS and Android SDKs. To install Stripe’s React Native SDK, run one of the following commands in your project’s directory (depending on which package manager you use):
Next, install some other necessary dependencies:
- For iOS, navigate to the ios directory and run
pod install
to ensure that you also install the required native dependencies. - For Android, there are no more dependencies to install.
Stripe initialization
To initialize Stripe in your React Native app, either wrap your payment screen with the StripeProvider
component, or use the initStripe
initialization method. Only the API publishable key in publishableKey
is required. The following example shows how to initialize Stripe using the StripeProvider
component.
import React, { useState, useEffect } from 'react'; import { StripeProvider } from '@stripe/stripe-react-native'; function App() { const [publishableKey, setPublishableKey] = useState(''); const fetchPublishableKey = async () => { const key = await fetchKey(); // fetch key from your server here setPublishableKey(key); }; useEffect(() => { fetchPublishableKey(); }, []); return ( <StripeProvider publishableKey={publishableKey} merchantIdentifier="merchant.identifier" // required for Apple Pay urlScheme="your-url-scheme" // required for 3D Secure and bank redirects > // Your app code here </StripeProvider> ); }
Create or retrieve a CustomerServer-side
To reuse a SEPA Direct Debit account for future payments, it must be attached to a Customer.
You should create a Customer object when your customer creates an account with your business. Associating the ID of the Customer object with your own internal representation of a customer will enable you to retrieve and use the stored payment method details later.
Create a new Customer or retrieve an existing Customer to associate with this payment. Include the following code on your server to create a new Customer.
Create a PaymentIntentServer-sideClient-side
Server-side
A PaymentIntent is an object that represents your intent to collect payment from a customer and tracks the lifecycle of the payment process through each stage. First, create a PaymentIntent on your server and specify the amount to collect and the eur
currency (SEPA Direct Debit does not support other currencies). If you already have an integration using the Payment Intents API, add sepa_
to the list of payment method types for your PaymentIntent. Specify the id of the Customer.
To save the SEPA Direct Debit account for reuse, set the setup_future_usage parameter to off_
. SEPA Direct Debit only accepts an off_
value for this parameter.
Client-side 
On the client, request a PaymentIntent from your server and store its client secret.
const fetchPaymentIntentClientSecret = async () => { const response = await fetch(`${API_URL}/create-payment-intent`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ email, currency: 'eur', payment_method_types: ['sepa_debit'], }), }); const {clientSecret, error} = await response.json(); return {clientSecret, error}; };
Collect payment method details and mandate acknowledgmentClient-side
Collect the customer’s IBAN in your payment form and display the following standard authorization text for your customer to implicitly sign the mandate.
Display the following standard authorization text for your customer to implicitly sign the mandate.
Replace Rocket Rides with your company name.
Setting up a payment method or confirming a PaymentIntent creates the accepted mandate. As the customer has implicitly signed the mandate, you must communicate these terms in your form or through email.
export default function SepaPaymentScreen() { const [email, setEmail] = useState(''); const [iban, setIban] = useState(''); return ( <Screen> <TextInput placeholder="E-mail" keyboardType="email-address" onChange={(value) => setEmail(value.nativeEvent.text)} style={styles.input} /> <TextInput placeholder="Iban" onChange={(value) => setIban(value.nativeEvent.text.toLowerCase())} style={styles.input} /> <Button variant="primary" onPress={handlePayPress} title="Save IBAN" loading={loading} /> </Screen> ); }
Submit the payment to StripeClient-side
Retrieve the client secret from the PaymentIntent you created and call confirmPayment
.
The client secret should be handled carefully because it can complete the charge. Don’t log it, embed it in URLs, or expose it to anyone but the customer.
Note
addressCountry
and addressLine1
must be provided in the billingDetails
for IBANs with the following country codes: AD, PF, TF, GI, GB, GG, VA, IM, JE, MC, NC, BL, PM, SM, CH, WF. See the React Native SDK reference for a complete list of address fields.
export default function SepaPaymentScreen() { const [iban, setIban] = useState(''); const {confirmPayment, loading} = useConfirmPayment(); const handlePayPress = async () => { const { clientSecret, error: clientSecretError, } = await fetchPaymentIntentClientSecret(); if (clientSecretError) { Alert.alert(`Error`, clientSecretError); return; } const billingDetails: PaymentMethodCreateParams.BillingDetails = { name: 'Jenny Rosen', email: 'jenny.rosen@example.com', }; const {error, paymentIntent} = await confirmPayment(clientSecret, { paymentMethodType: 'SepaDebit', paymentMethodData: { billingDetails, iban, }, }); if (error) { Alert.alert(`Error code: ${error.code}`, error.message); } else if (paymentIntent) { if (paymentIntent.status === PaymentIntents.Status.Processing) { Alert.alert( 'Processing', `The debit has been successfully submitted and is now processing.`, ); } else if (paymentIntent.status === PaymentIntents.Status.Succeeded) { Alert.alert( 'Success', `The payment was confirmed successfully! currency: ${paymentIntent.currency}`, ); } else { Alert.alert('Payment status:', paymentIntent.status); } } }; return <Screen>{/* ... */}</Screen>; }
Confirm the PaymentIntent succeeded
SEPA Direct Debit is a delayed notification payment method, so funds are not immediately available. When the payment has been submitted successfully, the PaymentIntent status is updated from requires_
to processing
. After the payment has succeeded, the PaymentIntent status is updated from processing
to succeeded
.
The following events are sent when the PaymentIntent status is updated:
Event | Description | Next steps |
---|---|---|
payment_ | The customer’s payment was submitted to Stripe successfully. | Wait for the initiated payment to succeed or fail. |
payment_ | The customer’s payment succeeded. | Fulfill the goods or services that the customer purchased. |
payment_ | The customer’s payment was declined. | Contact the customer through email or push notification and request another payment method. |
We recommend using webhooks to confirm the charge has succeeded and to notify the customer that the payment is complete.
Note that because setup_future_usage and customer were set, the PaymentMethod will be attached to the Customer object once the payment enters the processing
state. This attachment happens regardless of whether payment eventually succeeds or fails.
Test the integration
You can test your form using the SEPA Debit Direct test account numbers with your confirmSepaDebitPayment request.