iDEAL Payments with Payment Methods

    Use the Payment Intents and Payment Methods APIs to accept iDEAL payments, a common payment method in the Netherlands.

    Customers pay with iDEAL by redirecting away from your website, sending you payment, then returning to your website where you can immediately confirm whether the payment succeeded or failed. This means it is a push-based, single-use, and synchronous payment method.

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

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

    2 Collect payment method details using iDEAL Bank Element Client-side

    Setting up Stripe.js and Stripe Elements allows you to build a payment form and redirect the customer.

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

    Elements creates a UI component that is hosted by Stripe and placed on your payment form, rather than you creating it directly.

    <form id="payment-form">
      <div class="form-row">
        <label for="name">
          Name
        </label>
        <input name="name">
      </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="ideal-bank-element">
          iDEAL Bank
        </label>
        <div id="ideal-bank-element">
          <!-- A Stripe Element will be inserted here. -->
        </div>
      </div>
    
      <button>Submit Payment</button>
    
      <!-- Used to display form errors. -->
      <div id="error-message" role="alert"></div>
    </form>
    

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

    var options = {
      // Custom styling can be passed to options when creating an Element.
      style: {
        base: {
          // Add your base input styles here. For example:
          fontSize: '16px',
          color: '#32325d',
          padding: '10px 12px',
        },
      }
    }
    
    // Create an instance of the idealBank Element.
    var idealBank = elements.create('idealBank', options);
    
    // Add an instance of the idealBank Element into
    // the `ideal-bank-element` <div>.
    idealBank.mount('#ideal-bank-element');
    const options = {
      // Custom styling can be passed to options when creating an Element.
      style: {
        base: {
          // Add your base input styles here. For example:
          fontSize: '16px',
          color: '#32325d',
          padding: '10px 12px',
        },
      }
    }
    
    // Create an instance of the idealBank Element.
    const idealBank = elements.create('idealBank', options);
    
    // Add an instance of the idealBank Element into
    // the `ideal-bank-element` <div>.
    idealBank.mount('#ideal-bank-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.confirmIdealPayment to handle the redirect away from your page and to complete the payment. Add a return_url to this function to indicate where Stripe should redirect the user after they complete the payment on their bank’s website or mobile application.

    var form = document.getElementById('payment-form');
    
    form.addEventListener('submit', function(event) {
      event.preventDefault();
    
      // Redirects away from the client
      stripe.confirmIdealPayment(
        '{PAYMENT_INTENT_CLIENT_SECRET}',
        {
          payment_method: {
            ideal: idealBank,
          },
          return_url: 'http://<your website>/checkout/complete',
        }
      );
    });
    

    The return_url should correspond to a page on your website that provides the status of the payment, by verifying the status of the PaymentIntent when rendering the return page. When Stripe redirects the customer to the return_url, the following URL query parameters are provided to verify status. You may also append your own query parameters when providing the return_url. They will persist through the redirect process.

    Parameter Description
    payment_intent The unique identifier for the PaymentIntent.
    payment_intent_client_secret The client secret of the PaymentIntent object.

    A customer might close the browser after payment completes but before returning to the return_url. We recommend using a method such as webhooks to handle order fulfillment, instead of relying on your customer to return to the payment status page. When a customer completes payment, the PaymentIntent will transition to succeeded and emit the payment_intent.succeeded webhook event. If a customer does not pay, the PaymentIntent will emit the payment_intent.payment_failed webhook event and return to a status of requires_payment_method.

    You can find details about the bank account the customer used to complete the payment on the resulting Charge under the payment_method_details property.

    For example:

    "payment_method_details": {
      "ideal": {
        "bank": "ing",
        "bic": "INGBNL2A",
        "iban_last4": "****",
        "verified_name": "JENNY ROSEN"
      },
      "type": "ideal"
    }
    

    Optional Handle the iDEAL Bank Element

    You can update the configuration options (e.g. the style) of the idealBank Element by using .update(options).

    The iDEAL Bank Element outputs the customer’s selected bank as it changes. To perform additional logic with the bank value (e.g. requiring the field for form validation), you can listen to the change event:

    idealBank.on('change', function(event) {
      var bank = event.value;
      // Perform any additional logic here...
    });
    

    The change event contains other helpful parameters:

    Parameter Description
    elementType The name of the element. The default value is idealBank.
    empty If true, the value is empty.
    complete If true, the customer has selected the value. You can use this parameter to progressively disclose the rest of your form or to enable form submission.
    value The iDEAL bank that the customer selected from the Element. The iDEAL guide contains the complete list of banks.

    Optional Handle the iDEAL redirect manually

    We recommend relying on Stripe.js to handle iDEAL redirects and payments with confirmIdealPayment. However, you can also manually redirect your customers by:

    1. Providing the URL where your customers will be redirected after they complete their payment.
    curl https://api.stripe.com/v1/payment_intents/{PAYMENT_INTENT_ID}/confirm \
      -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
      -d return_url="http://<your website>/checkout/complete"
    
    1. Confirming the PaymentIntent has a status of requires_action. The type for the PaymentIntent’s next_action will be redirect_to_url.
    "next_action": {
      "type": "redirect_to_url",
      "redirect_to_url": {
        "url": "https://hooks.stripe.com/..."",
        "return_url": "http://<your website>/checkout/complete"
      }
    }
    
    1. Redirecting the customer to the address provided in the next_action property.
    var action = intent.next_action;
    if (action && action.type === 'redirect_to_url') {
      window.location = action.redirect_to_url.url;
    }
    

    When the customer finishes the payment process, they are sent to the return_url destination. The payment_intent and payment_intent_client_secret URL query parameters are included and you may pass through your own query parameters, as described above.

    Disputed payments

    iDEAL has a low risk of fraud or unrecognized payments because the customer must authenticate the payment with their bank. Therefore, there is no dispute process that can result in a chargeback and funds withdrawn from your Stripe account.

    Refunds

    iDEAL payments can be refunded up to 180 days after the original payment.

    Storing customer bank preferences

    You cannot reuse iDEAL PaymentMethods or save them to customers. You will need to create a new iDEAL PaymentMethod each time your customer selects this method of payment in your checkout, using the iDEAL Bank Element. To track your customer’s bank preference, we recommend storing bank values in your own database or using the metadata field on the Customer object.

    You can prefill the iDEAL Bank Element with the customer’s bank preference when creating the Element:

    var options = {
      // Include the bank name along with any custom styling.
      value: "rabobank",
      style: {
        base: {
          fontSize: '16px',
          color: '#32325d',
          padding: '10px 12px',
        },
      }
    }
    
    // Create an instance of the Element.
    var idealBank = elements.create('idealBank', options);
    
    // Mount the Element
    idealBank.mount('#ideal-bank-element');
    

    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