SEPA Direct Debit Payments with Payment Intents and Payment Methods

    Use the Payment Intents and Payment Methods APIs to accept SEPA Direct Debit payments.

    Stripe users in Europe and the United States can accept SEPA Direct Debit payments from customers in countries within the Single Euro Payments Area by using the Payment Intents and Payment Methods APIs.

    SEPA Direct Debit is a pull-based, reusable, and asynchronous payment method. This means that it can take up to 14 business days to confirm the success or failure of a payment after you initiate a debit from the customer’s account, though the average is five business days.

    Prerequisite Collect mandate acceptance

    Before a PaymentIntent can be confirmed, your customer must read and accept the SEPA Direct Debit mandate.

    Display the following standard authorization text on the payment confirmation page. Replace Rocketship Inc with your company name.

    The details of the accepted mandate are generated when setting up a PaymentMethod or confirming a PaymentIntent. Because the customer has implicitly signed the mandate when accepting the terms suggested above, you must communicate the terms on the payment confirmation page or in an email.

    1 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 does not support other currencies). If you already have a PaymentIntents configuration, include sepa_debit in the list of payment method types for your PaymentIntent.

    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.

    curl https://api.stripe.com/v1/payment_intents \
      -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
      -d "payment_method_types[]"=sepa_debit \
      -d amount=1099 \
      -d setup_future_usage=off_session \
      -d currency=eur
    

    2 Collect payment method details using IBAN Element

    Setting up Stripe.js and Stripe Elements allows you to build a payment form and securely collect payment information.

    var stripe = Stripe('pk_test_TYooMQauvdEDq54NiTphI7jx');
    var elements = stripe.elements();
    

    Bank account information is sensitive by nature. Using Stripe.js and the IBAN Element prevents IBAN details from touching your server and reduces the amount of sensitive data that you need to handle securely. Elements creates a UI component that is hosted by Stripe and placed on your payment form, rather than you creating it directly.

    You can determine where to insert the component by creating an empty DOM element (container) with a unique ID on your payment form.

    <form action="/charge" method="post" id="payment-form">
      <div class="form-row inline">
        <div class="col">
          <label for="accountholder-name">
            Name
          </label>
          <input id="accountholder-name" name="accountholder-name" placeholder="Jenny Rosen" required>
        </div>
    
        <div class="col">
          <label for="email">
            Email Address
          </label>
          <input id="email" name="email" type="email" placeholder="jenny.rosen@example.com" required>
        </div>
      </div>
    
      <div class="form-row">
        <!--
          Using a label with a for attribute that matches the ID of the
          Element container enables the Element to automatically gain focus
          when the customer clicks on the label.
        -->
        <label for="iban-element">
          IBAN
        </label>
        <div id="iban-element">
          <!-- A Stripe Element will be inserted here. -->
        </div>
      </div>
    
      <button id="submit-button">Submit Payment</button>
    
      <!-- Used to display form errors. -->
      <div id="error-message" role="alert"></div>
    
      <!-- Display mandate acceptance text. -->
      <div id="mandate-acceptance">
        By providing your IBAN and confirming this payment, you are authorizing
        Rocketship Inc. and Stripe, our payment service provider, to send
        instructions to your bank to debit your account in accordance with those
        instructions. You are entitled to a refund from your bank under the terms
        and conditions of your agreement with your bank. A refund must be claimed
        within 8 weeks starting from the date on which your account was debited.
      </div>
    </form>
    

    When the form above has loaded, create an instance of an iban Element and mount it to the Element container created above:

    // Custom styling can be passed to options when creating an Element.
    var style = {
      base: {
        // Add your base input styles here. For example:
        fontSize: '16px',
        color: "#32325d",
      }
    };
    
    var options = {
      style: style,
      supportedCountries: ['SEPA'],
      // If you know the country of the customer, you can optionally pass it to
      // the Element as placeholderCountry. The example IBAN that is being used
      // as placeholder reflects the IBAN format of that country.
      placeholderCountry: 'DE',
    }
    
    // Create an instance of the iban Element.
    var iban = elements.create('iban', options);
    
    // Add an instance of the iban Element into the `iban-element` <div>.
    iban.mount('#iban-element');
    // Custom styling can be passed to options when creating an Element.
    const style = {
      base: {
        // Add your base input styles here. For example:
        fontSize: '16px',
        color: "#32325d",
      },
    };
    
    const options = {
      style,
      supportedCountries: ['SEPA'],
      // If you know the country of the customer, you can optionally pass it to
      // the Element as placeholderCountry. The example IBAN that is being used
      // as placeholer will reflect the IBAN format of that country.
      placeholderCountry: 'DE',
    }
    
    // Create an instance of the iban Element.
    const iban = elements.create('iban', options);
    
    // Add an instance of the iban Element into the `iban-element` <div>.
    iban.mount('#iban-element');

    3 Submit the payment to Stripe Client-side

    To create a payment on the client side, pass the client secret of the PaymentIntent object that you created in Step 1.

    Use stripe.confirmSepaDebitPayment to complete the payment. Including the customer’s name and email address in the billing_details property of the payment_method_data parameter is required to create a SEPA Direct Debit PaymentMethod.

    var form = document.getElementById('payment-form');
    var accountholderName = document.getElementById('accountholder-name');
    var email = document.getElementById('email');
    var submitButton = document.getElementById('submit-button');
    var clientSecret = submitButton.dataset.secret;
    
    form.addEventListener('submit', function(event) {
      event.preventDefault();
      stripe.confirmSepaDebitPayment(
        '{PAYMENT_INTENT_CLIENT_SECRET}',
        {
          payment_method: {
            sepa_debit: iban,
            billing_details: {
              name: accountholderName.value,
              email: email.value
            }
          }
        }
      );
    });
    

    4 Attach the PaymentMethod to a Customer for later use

    When you create a new Customer, pass the PaymentMethod ID to immediately add a PaymentMethod.

    curl https://api.stripe.com/v1/customers \
      -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
      -d payment_method="{PAYMENT_METHOD_ID}"
    

    If you have an existing Customer, you can do either of the following:

    • Attach the PaymentMethod to the existing Customer object as a separate request
    • Attach the PaymentIntent to the existing Customer object while making the payment

    To attach the PaymentMethod to the existing Customer object as a separate request:

    curl https://api.stripe.com/v1/payment_methods/{PAYMENT_METHOD_ID}/attach \
      -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
      -d customer="{CUSTOMER_ID}"
    

    To attach the PaymentIntent to the existing Customer object at the same time as making the payment:

    stripe.confirmSepaDebitPayment(
      '{PAYMENT_INTENT_CLIENT_SECRET}',
      {
        payment_method: {
          sepa_debit: iban,
          billing_details: {
            name: accountholderName.value,
            email: email.value
          }
        },
        customer: '{CUSTOMER_ID}',
        // Specify `save_payment_method` to save the PaymentMethod
        // as part of making a payment
        save_payment_method: true
      }
    );
    

    Note that the save_payment_method parameter attaches the PaymentMethod to the Customer regardless of whether the payment succeeds or fails.

    After you attach the PaymentMethod or PaymentIntent to the existing Customer object, you can associate the ID of the Customer object with your internal representation of a customer. This allows you to use the stored PaymentMethod to collect future payments without prompting for your customer’s bank account details.

    5 Confirm the PaymentIntent succeeded

    When you create a new Customer, pass the PaymentMethod ID to immediately add a PaymentMethod.

    SEPA Direct Debit payments are asynchronous, so funds are not immediately available. Once the Charge has succeeded, the PaymentIntent status is updated from processing to succeeded.

    The following events are sent when the PaymentIntent status is updated:

    Event Description Expected Integration
    succeeded The customer’s payment succeeded. Fulfill the goods or services that the customer purchased.
    payment_failed The customer’s payment was declined. Contact the customer via 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.

    6 Test the integration

    You can create a test PaymentIntent that either succeeds or fails by doing the following:

    1. Create a test PaymentMethod with a test IBAN account number.
    2. Use the resulting PaymentMethod in a confirmSepaDebitPayment request to create the test charge.
    Test IBAN account numbers
    Account Number Description
    AT611904300234573201 The PaymentIntent status transitions from processing to succeeded.
    AT861904300235473202 The PaymentIntent status transitions from processing to requires_payment_method due to payment failure.
    AT591904300235473203 The PaymentIntent status transitions from processing to succeeded, but a dispute is immediately created.
    Account Number Description
    BE62510007547061 The PaymentIntent status transitions from processing to succeeded.
    BE68539007547034 The PaymentIntent status transitions from processing to requires_payment_method due to payment failure.
    BE08510007547063 The PaymentIntent status transitions from processing to succeeded, but a dispute is immediately created.
    Account Number Description
    DK5000400440116243 The PaymentIntent status transitions from processing to succeeded.
    DK8003450003179681 The PaymentIntent status transitions from processing to requires_payment_method due to payment failure.
    DK9300400440116245 The PaymentIntent status transitions from processing to succeeded, but a dispute is immediately created.
    Account Number Description
    FR1420041010050500013M02606 The PaymentIntent status transitions from processing to succeeded.
    FR8420041010050500013M02607 The PaymentIntent status transitions from processing to requires_payment_method due to payment failure.
    FR5720041010050500013M02608 The PaymentIntent status transitions from processing to succeeded, but a dispute is immediately created.
    Account Number Description
    DE89370400440532013000 The PaymentIntent status transitions from processing to succeeded.
    DE62370400440532013001 The PaymentIntent status transitions from processing to requires_payment_method due to payment failure.
    DE35370400440532013002 The PaymentIntent status transitions from processing to succeeded, but a dispute is immediately created.
    Account Number Description
    IE29AIBK93115212345678 The PaymentIntent status transitions from processing to succeeded.
    IE02AIBK93115212345679 The PaymentIntent status transitions from processing to requires_payment_method due to payment failure.
    IE51AIBK93115212345670 The PaymentIntent status transitions from processing to succeeded, but a dispute is immediately created.
    Account Number Description
    IT40S0542811101000000123456 The PaymentIntent status transitions from processing to succeeded.
    IT60X0542811101000000123456 The PaymentIntent status transitions from processing to requires_payment_method due to payment failure.
    IT83S0542811101000000123458 The PaymentIntent status transitions from processing to succeeded, but a dispute is immediately created.
    Account Number Description
    LU280019400644750000 The PaymentIntent status transitions from processing to succeeded.
    LU980019400644750001 The PaymentIntent status transitions from processing to requires_payment_method due to payment failure.
    LU710019400644750002 The PaymentIntent status transitions from processing to succeeded, but a dispute is immediately created.
    Account Number Description
    NL39RABO0300065264 The PaymentIntent status transitions from processing to succeeded.
    NL91ABNA0417164300 The PaymentIntent status transitions from processing to requires_payment_method due to payment failure.
    NL82RABO0300065266 The PaymentIntent status transitions from processing to succeeded, but a dispute is immediately created.
    Account Number Description
    PT50000201231234567890154 The PaymentIntent status transitions from processing to succeeded.
    PT23000201231234567890155 The PaymentIntent status transitions from processing to requires_payment_method due to payment failure.
    PT93000201231234567890156 The PaymentIntent status transitions from processing to succeeded, but a dispute is immediately created.
    Account Number Description
    ES0700120345030000067890 The PaymentIntent status transitions from processing to succeeded.
    ES9121000418450200051332 The PaymentIntent status transitions from processing to requires_payment_method due to payment failure.
    ES5000120345030000067892 The PaymentIntent status transitions from processing to succeeded, but a dispute is immediately created.

    Optional Handle the IBAN Element

    You can update the configuration options (e.g. the style or the placeholderCountry) of the IBAN Element by using element.update(options).

    Elements validates user input as it is typed. To help your customers catch mistakes, you should listen to change events on the IBAN Element and display any errors:

    iban.on('change', function(event) {
      var displayError = document.getElementById('error-message');
      if (event.error) {
        displayError.textContent = event.error.message;
      } else {
        displayError.textContent = '';
      }
    });
    

    The change event contains other helpful parameters:

    Parameter Description
    elementType The name of the element. The default value is iban.
    empty If true, the value is empty.
    complete If true, the Element contains a potentially complete, well-formed value. You can use this parameter to progressively disclose the rest of your form or to enable form submission.
    complete does not indicate that a customer has finished their input. In many cases the customer may still add input.
    Do not use complete to perform an action, such as advancing the cursor to a subsequent field or performing a confirmSepaDebitPayment call.
    country The country of the specified IBAN.
    bankName The financial institution that services the IBAN account specified for the Element.
    error The validation error that’s comprised of a message, code, and type (set to validation_error).

    Debit notification emails

    The SEPA Direct Debit rulebook requires that you notify your customer each time you debit their account.

    By default, Stripe will automatically send the customer a standard email notifying them that you have initiated a debit. If you would like to send custom notification emails, you can turn off Stripe emails in the Stripe Dashboard email settings by turning off the Direct debits button.

    If you decide to send send your customers a custom notification, it must include:

    • The last 4 digits of the debtor’s bank account
    • The mandate reference (sepa_debit[reference] on the Mandate)
    • The amount to be debited
    • Your SEPA creditor identifier
    • Your contact information

    While these notifications should be sent at least 14 calendar days before you create a payment, SEPA rules allow to send notifications closer to the payment date if your mandate makes it clear when your customer can expect to receive them. The mandate provided by Stripe specifies this can happen up to two calendar days in advance of future payments, allowing you to send notifications at payment creation. For recurring payments of the same amount (e.g., a subscription of a fixed amount), you may indicate multiple upcoming debits with corresponding dates in a single notice.

    Disputed payments

    SEPA Direct Debit provides a dispute process for customers to dispute payments.

    Customers can dispute a payment through their bank on a “no questions asked” basis up to eight weeks after their account is debited. Any disputes within this period are automatically honored.

    After eight weeks and up to 13 months, a customer can only dispute a payment with their bank if the debit is considered unauthorized. If this occurs, we automatically provide the bank with the mandate that the customer approved. This does not guarantee cancellation of the dispute; the bank can still decide that the debit was unauthorized and the customer is entitled to a refund.

    A dispute can also occur if the bank is unable to debit the customer’s account because of an issue (e.g. the account is frozen or has unsufficient funds), but has already provided the funds to make the charge successful. If this occurs, the bank reclaims the funds in the form of a dispute.

    When a dispute is created, a dispute.created webhook event is sent and Stripe deducts the dispute amount and dispute fee from your Stripe balance. The dispute fee varies based on your account’s default settlement currency:

    Settlement Currency Dispute Fee
    CHF 10.00 Fr
    DKK 75.00-kr.
    EUR €7.50
    GBP £7.00
    NOK 75.00-kr.
    SEK 75.00-kr.
    USD $10.00

    Unlike credit card disputes, SEPA Direct Debit disputes are final and there is no appeals process. If a customer successfully disputes a payment, you must contact them if you want to resolve the situation. If you’re able to come to an arrangement and your customer is willing to return the funds to you, they must make a new payment.

    In general, each dispute includes the reason for its creation, though this can vary from country to country. For example, disputed payments in Germany do not provide additional information for privacy reasons.

    Refunds

    Refunds for payments made with SEPA Direct Debit must be submitted within 180 days from the date of the original payment. Refunds require additional time to process (typically 3 to 4 business days). If you accidentally debit your customer, please contact them immediately to avoid a payment dispute.

    Refunds are processed only after the payment process is complete. If you create a full or partial refund on a payment that has not yet completed, the refund is actioned when the Charge object’s status transitions to succeeded. If the Charge object’s status transitions to failed, the full or partial refund is marked as cancelled because the money was never debited from the customer’s bank account.

    SEPA does not explicitly label refunds when the funds are deposited back to a customer’s bank account. Instead, refunds are processed as a credit and include a visible reference to the original payment’s statement descriptor.

    Due to longer settlement time periods and how banks process SEPA Direct Debit transactions, there is potential for confusion between you, your customer, your customer’s bank, and Stripe. For example, your customer may contact both you and their bank to dispute a payment. If you proactively issue your customer a refund while the customer’s bank also initiates the dispute process, your customer may receive two credits for the same transaction.

    When issuing a refund, you should inform your customer immediately that the refund can take up to five business days to arrive in their bank account.

    See also

    Congrats, you are done with your integration! You can learn about saving bank account details without a payment and integrating with Connect.

    Was this page helpful?

    Thank you for helping improve Stripe's documentation. If you need help or have any questions, please consider contacting support.

    On this page