iDEAL is a popular single use payment method in the Netherlands where customers are required to authenticate their payment. Customers pay with iDEAL by redirecting to a webview, authorizing the payment, then returning to your app where you get immediate notification on whether the payment succeeded or failed.
You can also use iDEAL to save your customer’s IBAN bank details into a SEPA Direct DebitPaymentMethod. You can then use the SEPA Direct Debit PaymentMethod to accept payments or set up a subscription. This reduces friction for your customer as they don’t have to enter their IBAN again. You also receive their verified name and validated IBAN.
Accepting iDEAL payments consists of creating a PaymentIntent object to track a payment, collecting payment method details and mandate acknowledgement, and submitting the payment to Stripe for processing. Stripe uses the PaymentIntent to track and handle all the states of the payment until the payment completes. Use the ID of the SEPA Direct Debit PaymentMethod collected from your initial iDEAL PaymentIntent to create future payments.
Create a Customer when they create an account with your business and associate it with your internal representation of their account. This enables you to retrieve and use their saved payment method details later.
Create a PaymentIntent on your server and specify the amount to collect, the eur currency, the customer ID, and off_session as an argument for setup future usage. There is no minimum charge amount and iDEAL doesn’t support other currencies. If you have an existing Payment Intents API integration, add ideal to the list of payment method types.
The PaymentIntent includes a client secret that the client side uses to securely complete the payment process. You can use different approaches to pass the client secret to the client side.
Retrieve the client secret from an endpoint on your server, using the browser’s fetch function. This approach is best if your client side is a single-page application, particularly one built with a modern frontend framework like React. Create the server endpoint that serves the client secret:
get '/secret'do
intent =# ... Create or retrieve the PaymentIntent{client_secret: intent.client_secret}.to_json
end
And then fetch the client secret with JavaScript on the client side:
(async()=>{const response =awaitfetch('/secret');const{client_secret: clientSecret}=await response.json();// Render the form using the clientSecret})();
Collect payment information on the client with Stripe Elements. Elements is a set of prebuilt 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. Do not include the script in a bundle or host a copy of it yourself.
Create an instance of Elements with the following JavaScript on your checkout page:
const stripe =Stripe(
'pk_test_TYooMQauvdEDq54NiTphI7jx'
);const elements = stripe.elements();
Add and configure an idealBank Element
Elements needs a place to live in your payment form. Create empty DOM nodes (containers) with unique IDs in your payment form and then pass those IDs to Elements.
To process SEPA Direct Debit payments, you must collect a mandate agreement from your customer. Display the following standard authorization text for your customer to implicitly sign the mandate.
Replace Rocket Rides with your company name.
Authorization text template
By providing your payment information and confirming this payment, you authorise (A)
Replace this with your company name
and Stripe, our payment service provider, to send instructions to your bank to debit your account and (B) your bank to debit your account in accordance with those instructions. As part of your rights, 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. Your rights are explained in a statement that you can obtain from your bank. You agree to receive notifications for future debits up to 2 days before they occur.
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.
<formid="payment-form"><divclass="form-row"><labelfor="accountholder-name">
Name
</label><inputid="accountholder-name"name="accountholder-name"></div><divclass="form-row"><labelfor="accountholder-email">
Email
</label><inputid="accountholder-email"name="accountholder-email"></div><divclass="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.
--><labelfor="ideal-bank-element">
iDEAL Bank
</label><divid="ideal-bank-element"><!-- A Stripe Element will be inserted here. --></div></div><buttonid="submit-button"data-secret="{CLIENT_SECRET}">Submit</button><!-- Display mandate acceptance text. --><divid="mandate-acceptance">
By providing your payment information and confirming this payment, you
authorise (A) Rocket Rides and Stripe, our payment service provider, to
send instructions to your bank to debit your account and (B) your bank to
debit your account in accordance with those instructions. As part of your
rights, 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.
Your rights are explained in a statement that you can obtain from your
bank. You agree to receive notifications for future debits up to 2 days
before they occur.
</div><!-- Used to display form errors. --><divid="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:
const options ={// Custom styling can be passed to options when creating an Element
style:{
base:{
padding:'10px 12px',
color:'#32325d',
fontSize:'16px','::placeholder':{
color:'#aab7c4'},},},};// Create an instance of the idealBank Elementconst idealBank = elements.create('idealBank', options);// Add an instance of the idealBank Element into// the `ideal-bank-element` <div>
idealBank.mount('#ideal-bank-element');
Elements are completely customizable. You can style Elements to match the look and feel of your site, providing seamless checkout for your customers. It’s also possible to style various input states, for example when the Element has focus.
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. Do not log it, embed it in URLs, or expose it to anyone but the customer.
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.
Include your customer’s name and email address in payment_method[billing_details]. They will be used when generating the SEPA Direct Debit PaymentMethod.
Caution
In order to pass the setup_future_usage parameter as shown below, you must modify the API version you passed when creating your instance of Elements. Review the instructions for setting up Stripe Elements from above if you are unable to pass setup_future_usage at this step.
client.js
const form = document.getElementById('payment-form');const accountholderName = document.getElementById('accountholder-name');
form.addEventListener('submit',(event)=>{
event.preventDefault();// Redirects away from the clientconst{error}=await stripe.confirmIdealPayment('{{PAYMENT_INTENT_CLIENT_SECRET}}',{
payment_method:{
ideal: idealBank,
billing_details:{
name: accountholderName.value,},},
return_url:'https://example.com/checkout/complete',});});
When your customer submits a payment, Stripe redirects them to the return_url and includes the following URL query parameters. The return page can use them to get the status of the PaymentIntent so it can display the payment status to the customer.
When you specify the return_url, you can also append your own query parameters for use on the return page.
When the customer is redirected back to your site, you can use the payment_intent_client_secret to query for the PaymentIntent and display the transaction status to your customer.
When you need to charge your customer again, create a new PaymentIntent. Find the ID of the SEPA Direct Debit payment method by retrieving the previous PaymentIntent and expanding the latest_charge field where you will find the generated_sepa_debit ID inside of payment_method_details.
Using your test API keys, select any bank from the list. After confirming the PaymentIntent, you’re redirected to a test page with options to authorize or fail the payment.
Click Authorize test payment to test the case when the payment is successful. The PaymentIntent transitions from requires_action to succeeded.
Click Fail test payment to test the case when the customer fails to authenticate. The PaymentIntent transitions from requires_action to requires_payment_method.
Test your SEPA Direct Debit integration
Set payment_method.billing_details.email to one of the following values to test the PaymentIntent status transitions. You can include your own custom text at the beginning of the email address followed by an underscore. For example, test_1_generatedSepaDebitIntentsFail@example.com results in a SEPA Direct Debit PaymentMethod that always fails when used with a PaymentIntent.
Email Address
Description
generatedSepaDebitIntentsSucceed@example.com
The PaymentIntent status transitions from processing to succeeded.