Save bank details during a Bancontact payment
Learn how to save your customer's IBAN bank details from a Bancontact payment.
Caution
We recommend that you follow the Save payment details during payment guide. If you’ve already integrated with Elements, see the Payment Element migration guide.
Bancontact is a popular single use payment method in Belgium where customers are required to authenticate their payment. Customers pay with Bancontact by redirecting from your website, authorizing the payment, then returning to your website where you get immediate notification on whether the payment succeeded or failed.
You can use Bancontact to save your customer’s IBAN bank details into a SEPA Direct Debit PaymentMethod. 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.
Caution
To use Bancontact to set up SEPA Direct Debit payments, you must activate SEPA Direct Debit in the Dashboard. You must also comply with the Bancontact Terms of Service and SEPA Direct Debit Terms of Service.
Accepting Bancontact 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 Bancontact PaymentIntent to create future payments.
Set up StripeServer-side
First, you need a Stripe account. Register now.
Use our official libraries for access to the Stripe API from your application:
Create a CustomerServer-side
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 PaymentIntentServer-side
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. If you have an existing Payment Intents integration, add bancontact to the list of payment method types.
curl https://api.stripe.com/v1/payment_intents \ -u ":" \ -d amount=1099 \ -d currency=eur \ -d "payment_method_types[]=bancontact" \ -d customer={{CUSTOMER_ID}} \ -d setup_future_usage=off_sessionsk_test_BQokikJOvBiI2HlWgH4olfQ2
Retrieve the client secret
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:
And then fetch the client secret with JavaScript on the client side:
(async () => { const response = await fetch('/secret'); const {client_secret: clientSecret} = await response.json(); // Render the form using the clientSecret })();
Collect payment method details and mandate acknowledgementClient-side
Create a payment form on your client to collect the required billing details from the customer.
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.
By providing your payment information and confirming this payment, you authorise (A) 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’re 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.
| Field | Value |
|---|---|
name |
The full name (first and last) of the customer. |
email |
The customer’s email. |
<form id="payment-form"> <div class="form-row"> <label for="name"> Name </label> <input id="name" name="name" required> </div> <div class="form-row"> <label for="email"> Email </label> <input id="email" name="email" required> </div> <button id="submit-button">Pay with Bancontact</button> <!-- Display mandate acceptance text. --> <div id="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. --> <div id="error-message" role="alert"></div> </form>
Submit the payment to StripeClient-side
Create a payment on the client side with the client secret of the PaymentIntent. The client secret is different from your API keys that authenticate Stripe API requests. It 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.
Call stripe.confirmBancontactPayment to redirect your customer to Bancontact’s website or app to complete the payment. Include a return_url to redirect your customer after they complete the payment. You must also provide the customer’s full name and email in billing_.
var stripe = Stripe(); var accountholderName = document.getElementById('name'); var accountholderEmail = document.getElementById('email'); // Redirects away from the client const {error} = await stripe.confirmBancontactPayment( '{{PAYMENT_INTENT_CLIENT_SECRET}}', { payment_method: { billing_details: { name: accountholderName.value, email: accountholderEmail.value, }, }, return_url: 'https://example.com/checkout/complete', } ); if (error) { // Inform the customer that there was an error. }'pk_test_TYooMQauvdEDq54NiTphI7jx'
When your customer submits a payment, Stripe redirects them to the return_ 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_, you can also append your own query parameters for use on the return page.
| Parameter | Description |
|---|---|
payment_ |
The unique identifier for the PaymentIntent. |
payment_ |
The client secret of the PaymentIntent object. For subscription integrations, this client_secret is also exposed on the Invoice object through confirmation_
|
When the customer is redirected back to your site, you can use the payment_ to query for the PaymentIntent and display the transaction status to your customer.
Charge the SEPA Direct Debit PaymentMethod later
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_ field where you’ll find the generated_ ID inside of payment_.
The SEPA Direct Debit payment method ID is the generated_ ID under payment_method_details in the response.
{ "latest_charge": { "payment_method_details": { "bancontact": { "bank_code": "VAPE", "bank_name": "VAN DE PUT & CO", "bics": "VAPEBE22", "iban_last4": "7061", "generated_sepa_debit": "pm_1GrddXGf98efjktuBIi3ag7aJQ", "preferred_language": "en", "verified_name": "Jenny Rosen" }, "type": "bancontact" }, }, "payment_method_options": { "bancontact": {}
Create a PaymentIntent with the SEPA Direct Debit ID and the customer’s ID.
curl https://api.stripe.com/v1/payment_intents \ -u ":" \ -d "payment_method_types[]=sepa_debit" \ -d amount=1099 \ -d currency=eur \ -d "customer_account=sk_test_BQokikJOvBiI2HlWgH4olfQ2" \ -d payment_method={{SEPA_DEBIT_PAYMENT_METHOD_ID}} \ -d confirm=true{{CUSTOMER_ACCOUNT_ID}}
Test your integration
Set payment_ 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_ results in a SEPA Direct Debit PaymentMethod that always fails when used with a PaymentIntent.
| Email Address | Description |
|---|---|
generatedSepaDebitIntentsSucceed@example. |
The PaymentIntent status transitions from processing to succeeded. |
generatedSepaDebitIntentsSucceedDelayed@example. |
The PaymentIntent status transitions from processing to succeeded after at least three minutes. |
generatedSepaDebitIntentsFail@example. |
The PaymentIntent status transitions from processing to requires_. |
generatedSepaDebitIntentsFailDelayed@example. |
The PaymentIntent status transitions from processing to requires_ after at least three minutes. |
generatedSepaDebitIntentsSucceedDisputed@example. |
The PaymentIntent status transitions from processing to succeeded, but a dispute is created immediately. |
generatedSepaDebitIntentsFailsDueToInsufficientFunds@example. |
The PaymentIntent status transitions from processing to requires_ with the insufficient_ failure code. |