Skip to content
Create account or Sign in
The Stripe Docs logo
/
Ask AI
Create accountSign in
Get started
Payments
Revenue
Platforms and marketplaces
Money management
Developer resources
APIs & SDKsHelp
OverviewAccept a paymentUpgrade your integration
Online payments
OverviewFind your use case
Use Payment Links
Use a pre-built checkout page
Build a custom integration with Elements
Build an in-app integration
Use Managed Payments
Recurring payments
In-person payments
Terminal
Payment Methods
Add payment methods
    Overview
    Payment method integration options
    Manage default payment methods in the Dashboard
    Payment method types
    Cards
    Pay with Stripe balance
    Stablecoin payments
    Bank debits
      ACH Direct Debit
      Bacs Direct Debit
      Pre-authorised debit in Canada
      Australia BECS Direct Debit
      New Zealand BECS Direct Debit
      SEPA Direct Debit
        Accept a payment
        Save bank details
    Bank redirects
    Bank transfers
    Credit transfers (Sources)
    Buy now, pay later
    Real-time payments
    Vouchers
    Wallets
    Enable local payment methods by country
    Custom payment methods
Manage payment methods
Faster checkout with Link
Payment operations
Analytics
Balances and settlement time
Compliance and security
Currencies
Declines
Disputes
Fraud prevention
Radar fraud protection
Payouts
ReceiptsRefunds and cancellations
Advanced integrations
Custom payment flows
Flexible acquiring
Off-Session Payments
Multiprocessor orchestration
Beyond payments
Incorporate your company
Crypto
Agentic commerce
Machine payments
Financial Connections
Climate
Verify identities
United States
English (United Kingdom)
HomePaymentsAdd payment methodsBank debitsSEPA Direct Debit

Accept a SEPA Direct Debit payment

Learn to accept SEPA Direct Debit payments.

Note

When processing SEPA Direct Debit payments using the Stripe Creditor ID, we recommend you use the pre-built checkout page to collect SEPA Direct Debit mandates.

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 or iDEAL.

Set up Stripe
Server-side

First, you need a Stripe account. Register now.

Use our official libraries for access to the Stripe API from your application:

Command Line
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
# Available as a gem sudo gem install stripe
Gemfile
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
# If you use bundler, you can add this line to your Gemfile gem 'stripe'

Create or retrieve a Customer
Server-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.

Command Line
cURL
Stripe CLI
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
curl -X POST https://api.stripe.com/v1/customers \ -u "
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:"

Create a PaymentIntent
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 doesn’t support other currencies). If you already have an integration using the Payment Intents API, add sepa_debit 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_session. SEPA Direct Debit only accepts an off_session value for this parameter.

Command Line
cURL
Stripe CLI
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
curl https://api.stripe.com/v1/payment_intents \ -u "
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:"
\ -d amount=1099 \ -d currency=eur \ -d setup_future_usage=off_session \ -d customer=
"{{CUSTOMER_ID}}"
\ -d "payment_method_types[]"=sepa_debit \ -d "metadata[integration_check]"=sepa_debit_accept_a_payment

Collect payment method details and mandate acknowledgment
Client-side

You’re ready to collect payment information on the client with Stripe Elements. Elements is a set of pre-built UI components for collecting payment details.

A Stripe Element contains an iframe that securely sends the payment information to Stripe over an HTTPS connection. The checkout page address must also start with https:// rather than http:// for your integration to work.

You can test your integration without using HTTPS. Enable it when you’re ready to accept live payments.

Set up Stripe Elements

Stripe Elements is automatically available as a feature of Stripe.js. Include the Stripe.js script on your payment page by adding it to the head of your HTML file. Always load Stripe.js directly from js.stripe.com to remain PCI compliant. Don’t include the script in a bundle or host a copy of it yourself.

submit_payment.html
<head> <title>Submit Payment</title> <script src="https://js.stripe.com/clover/stripe.js"></script> </head>

Create an instance of Elements with the following JavaScript on your payment page. Pass the mode, currency, and amount to enable the Payment Element to collect SEPA Direct Debit payment details:

const stripe = Stripe(
'pk_test_TYooMQauvdEDq54NiTphI7jx'
); const options = { mode: 'payment', currency: 'eur', amount: 1099, // Automatically save the payment method for future payments setup_future_usage: 'off_session', }; const elements = stripe.elements(options);

Add the Payment Element

The Payment Element needs a place to live in your payment form. Create an empty DOM node (container) with a unique ID in your payment form. The Payment Element automatically displays the SEPA Direct Debit form and mandate acceptance text when SEPA Debit is enabled

submit_payment.html
<form action="/charge" method="post" id="payment-form"> <div id="payment-element"> <!-- The Payment Element will be inserted here. --> </div> <!-- Add the client_secret from the PaymentIntent as a data attribute --> <button id="submit-button" data-secret="{{CLIENT_SECRET}}">Submit Payment</button> <!-- Used to display form errors. --> <div id="error-message" role="alert"></div> </form>

When the form loads, create an instance of the Payment Element and mount it to the Element container. The Payment Element automatically collects the customer’s name, email, IBAN, and displays the mandate acceptance text:

// Create and mount the Payment Element const paymentElement = elements.create('payment'); paymentElement.mount('#payment-element');

Submit the payment to Stripe
Client-side

Rather than sending the entire PaymentIntent object to the client, use its client secret from step 3. This is different from your API keys that authenticate Stripe API requests.

The client secret should still 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.

Use stripe.confirmPayment to complete the payment when the user submits the form. The Payment Element automatically collects the customer’s name, email, IBAN, and handles mandate acceptance:

const form = document.getElementById('payment-form'); const submitButton = document.getElementById('submit-button'); const clientSecret = submitButton.dataset.secret; form.addEventListener('submit', async (event) => { event.preventDefault(); const {error} = await stripe.confirmPayment({ elements, clientSecret, confirmParams: { return_url: 'https://example.com/order/complete', }, }); if (error) { // Show error to your customer (for example, payment details incomplete) const errorMessage = document.getElementById('error-message'); errorMessage.textContent = error.message; } else { // Your customer will be redirected to your `return_url`. } });

Confirm the PaymentIntent succeeded

SEPA Direct Debit is a delayed notification payment method, so funds aren’t immediately available. When the payment has been submitted successfully, the PaymentIntent status is updated from requires_confirmation 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:

EventDescriptionNext steps
payment_intent.processingThe customer’s payment was submitted to Stripe successfully.Wait for the initiated payment to succeed or fail.
payment_intent.succeededThe customer’s payment succeeded.Fulfill the goods or services that the customer purchased.
payment_intent.payment_failedThe 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

Stripe provides several test numbers you can use to make sure your integration is ready for production. Use the SEPA Direct Debit test numbers when testing your Checkout integration with SEPA Direct Debit.

Test IBANs

Use these test IBANs with the Payment Element to test your SEPA Direct Debit integration. The Payment Element automatically validates the IBAN and displays the mandate when you enter one of these test values.

Account NumberTokenDescription
AT611904300234573201pm_success_atThe PaymentIntent status transitions from processing to succeeded.
AT321904300235473204pm_successDelayed_atThe PaymentIntent status transitions from processing to succeeded after at least three minutes.
AT861904300235473202pm_failed_atThe PaymentIntent status transitions from processing to requires_payment_method.
AT051904300235473205pm_failedDelayed_atThe PaymentIntent status transitions from processing to requires_payment_method after at least three minutes.
AT591904300235473203pm_disputed_atThe PaymentIntent status transitions from processing to succeeded, but a dispute is immediately created.
AT981904300000343434pm_exceedsWeeklyVolumeLimit_atThe payment fails with a charge_exceeds_source_limit failure code due to payment amount causing account to exceed its weekly payment volume limit.
AT601904300000121212pm_exceedsWeeklyTransactionLimit_atThe payment fails with a charge_exceeds_weekly_limit failure code due to payment amount exceeding account's transaction volume limit.
AT981904300002222227pm_insufficientFunds_atThe payment fails with an insufficient_funds failure code.

Note

The Payment Element automatically validates the IBAN and other payment details as the customer types. Error messages are displayed inline within the Payment Element, so you don’t need to handle validation manually.

OptionalConfigure customer debit date

You can control the date that Stripe debits a customer’s bank account using the target date. The target date must be at least three days in the future and no more than 15 days from the current date.

The target date schedules money to leave the customer’s account on the target date. You can cancel a PaymentIntent created with a target date up to three business days before the configured date.

Target dates that meet one of the following criteria delay the debit until next available business day:

  • Target date falls on a weekend, a bank holiday, or other non-business day.
  • Target date is fewer than three business days in the future.

This parameter operates on a best-effort basis. Each customer’s bank might process debits on different dates, depending on local bank holidays or other reasons.

OptionalCustomise mandate references with a prefix

You can customise SEPA Direct Debit mandate references to simplify mandate identification. To do this, provide the optional payment_method_options.sepa_debit.mandate_options.reference_prefix value. We add the reference_prefix to the beginning of a unique sequence to ensure the entire reference remains unique.

The reference_prefix must meet these requirements:

  • Maximum length: 12 characters
  • Must begin with a number or an uppercase letter
  • Allowed characters:
    • Uppercase letters
    • Numbers
    • Spaces
    • Special characters: ., /, &, -, _
  • Can’t begin with STRIPE

Include any desired delimiter in the prefix, as we don’t add one by default. We trim trailing spaces to a maximum of one space. With a valid prefix, the resulting reference is always 24 characters long.

Command Line
cURL
Stripe CLI
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
curl https://api.stripe.com/v1/payment_intents \ -u "
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:"
\ -d currency=eur \ -d amount=100 \ -d "payment_method_types[]"=sepa_debit \ -d "payment_method_options[sepa_debit][mandate_options][reference_prefix]"=EX4MPL3-

The generated reference looks like EX4MPL3-19CNCI920C2M02O3.

Error CodeMessage
invalid_sepa_mandate_reference_prefix_formatThe reference_prefix must be at most 12 characters long and can only contain uppercase letters, numbers, spaces, or the special characters /, _, -, &, and .. It can’t begin with STRIPE.

See also

  • Save SEPA Direct Debit details for future payments
  • Connect payments
Was this page helpful?
YesNo
  • Need help? Contact Support.
  • Chat with Stripe developers on Discord.
  • Check out our changelog.
  • Questions? Contact Sales.
  • LLM? Read llms.txt.
  • Powered by Markdoc