Skip to content
Create account
or
Sign in
The Stripe Docs logo
/
Ask AI
Create account
Sign in
Get started
Payments
Revenue
Platforms and marketplaces
Money management
Developer resources
Overview
About Stripe payments
Upgrade your integration
Payments analytics
Online payments
OverviewFind your use caseManaged Payments
Use Payment Links
Build a checkout page
Build an advanced integration
Build an in-app integration
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
    Crypto
    Bank debits
      ACH Direct Debit
      Bacs Direct Debit
        Accept a payment
        Import Bacs data to Stripe
        Save bank details
      Pre-authorized debit in Canada
      Australia BECS Direct Debit
      New Zealand BECS Direct Debit
      SEPA Direct Debit
    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 interfaces
Payment Links
Checkout
Web Elements
In-app Elements
Payment scenarios
Handle multiple currencies
Custom payment flows
Flexible acquiring
Orchestration
In-person payments
Terminal
Beyond payments
Incorporate your company
Crypto
Financial Connections
Climate
Understand fraud
Radar fraud protection
Manage disputes
Verify identities
HomePaymentsAdd payment methodsBank debitsBacs Direct Debit

Bacs Direct Debit payments

Accept Bacs Direct Debit payments from customers with a UK bank account.

Accepting Bacs Direct Debit payments on your website consists of creating an object to track a payment, collecting payment method information and mandate acknowledgement, submitting the payment to Stripe for processing, and verifying your customer’s bank account.

Stripe uses this payment object, the PaymentIntent, to track and handle all the states of the payment until the payment completes.

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 bank account for future payments, it must be attached to a Customer.

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 enables 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
:"

Collect payment method details

Note

The Bacs Direct Debit scheme rules require that your customer accept a mandate in order for Stripe to debit their account. The Payment Element collects this mandate when accepting the customer’s payment details, so you don’t need to take any action to comply with this requirement.

You’re ready to collect payment details on the client with the Payment Element. The Payment Element is a prebuilt UI component that simplifies collecting payment details for a variety of payment methods.

The Payment Element contains an iframe that securely sends payment information to Stripe over an HTTPS connection. Avoid placing the Payment Element within another iframe because some payment methods require redirecting to another page for payment confirmation.

The checkout page address must start with https:// rather than http:// for your integration to work. You can test your integration without using HTTPS, but remember to enable it when you’re ready to accept live payments.

Set up Stripe.js

The Payment Element is automatically available as a feature of Stripe.js. Include the Stripe.js script on your checkout 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.

checkout.html
<head> <title>Checkout</title> <script src="https://js.stripe.com/basil/stripe.js"></script> </head>

Create an instance of Stripe with the following JavaScript on your checkout page:

checkout.js
// Set your publishable key: remember to change this to your live publishable key in production // See your keys here: https://dashboard.stripe.com/apikeys const stripe = Stripe(
'pk_test_TYooMQauvdEDq54NiTphI7jx'
);

Add the Payment Element to your checkout page

The Payment Element needs a place on your checkout page. Create an empty DOM node (container) with a unique ID in your payment form:

checkout.html
<form id="payment-form"> <div id="payment-element"> <!-- Elements will create form elements here --> </div> <button id="submit">Submit</button> <div id="error-message"> <!-- Display error message to your customers here --> </div> </form>

After the form above loads, create an Elements instance with a mode, amount, and currency. These values determine which payment methods your customer sees. To provide a new payment method in your form, make sure you enable it in the Dashboard.

checkout.js
const options = { mode: 'payment', amount: 1099, currency: 'gbp', // Fully customizable with appearance API. appearance: {/*...*/}, }; // Set up Stripe.js and Elements to use in checkout form const elements = stripe.elements(options); // Create and mount the Payment Element const paymentElementOptions = { layout: 'accordion'}; const paymentElement = elements.create('payment', paymentElementOptions); paymentElement.mount('#payment-element');

You can customize the Payment Element to match the design of your site by passing the appearance object into options when creating the Elements provider.

Collect addresses

By default, the Payment Element only collects the necessary billing address details. To collect a customer’s full billing address (to calculate the tax for digital goods and services, for example) or shipping address, use the Address Element.

Create a PaymentIntent
Server-side

Run custom business logic immediately before payment confirmation

Navigate to step 5 in the finalize payments guide to run your custom business logic immediately before payment confirmation. Otherwise, follow the steps below for a simpler integration, which uses stripe.confirmPayment on the client to both confirm the payment and handle any next actions.

When the customer submits your payment form, use a PaymentIntent to facilitate the confirmation and payment process. Create a PaymentIntent on your server with an amount and currency. To prevent malicious customers from choosing their own prices, always decide how much to charge on the server-side (a trusted environment) and not the client.

Included on a PaymentIntent is a client secret. Return this value to your client for Stripe.js to use to securely complete the payment process.

main.rb
Ruby
Python
PHP
Node.js
Java
Go
.NET
No results
require 'stripe' Stripe.api_key =
'sk_test_BQokikJOvBiI2HlWgH4olfQ2'
post '/create-intent' do intent = Stripe::PaymentIntent.create({ # To allow saving and retrieving payment methods, provide the Customer ID. customer: customer.id, amount: 1099, currency: 'gbp', }) {client_secret: intent.client_secret}.to_json end

Submit the payment to Stripe
Client-side

Use stripe.confirmPayment to complete the payment using details from the Payment Element.

Provide a return_url to this function to indicate where Stripe redirects the user after they complete the payment. Your user might be initially redirected to an intermediate site, such as a bank authorization page, before being redirected to the return_url. Card payments immediately redirect to the return_url when a payment is successful.

If you don’t want to redirect for card payments after payment completion, you can set redirect to if_required. This only redirects customers that check out with redirect-based payment methods.

checkout.js
const form = document.getElementById('payment-form'); const submitBtn = document.getElementById('submit'); const handleError = (error) => { const messageContainer = document.querySelector('#error-message'); messageContainer.textContent = error.message; submitBtn.disabled = false; } form.addEventListener('submit', async (event) => { // We don't want to let default form submission happen here, // which would refresh the page. event.preventDefault(); // Prevent multiple form submissions if (submitBtn.disabled) { return; } // Disable form submission while loading submitBtn.disabled = true; // Trigger form validation and wallet collection const {error: submitError} = await elements.submit(); if (submitError) { handleError(submitError); return; } // Create the PaymentIntent and obtain clientSecret const res = await fetch("/create-intent", { method: "POST", }); const {client_secret: clientSecret} = await res.json(); // Confirm the PaymentIntent using the details collected by the Payment Element const {error} = await stripe.confirmPayment({ elements, clientSecret, confirmParams: { return_url: 'https://example.com/order/123/complete', }, }); if (error) { // This point is only reached if there's an immediate error when // confirming the payment. Show the error to your customer (for example, payment details incomplete) handleError(error); } else { // Your customer is redirected to your `return_url`. For some payment // methods like iDEAL, your customer is redirected to an intermediate // site first to authorize the payment, then redirected to the `return_url`. } });

Handle post-payment events

Bacs Direct Debit is a delayed notification payment method, so funds aren’t immediately available.

Timelines

With Bacs Direct Debit, it can take several business days for funds to become available in your Stripe balance. The number of business days it takes for funds to become available is called the settlement timing. Payments submitted after the daily cutoff are processed on the next business day.

It takes 4 business days to confirm the success or failure of a Bacs Direct Debit payment when a mandate is already in place and 7 business days when you must collect a new mandate.

In some cases, the bank might notify us of a payment failure after the payment has been marked as successful in your Stripe account. In this case the payment failure is identified as a dispute with the appropriate reason code.

The following table describes the settlement timings for Bacs Direct Debit payments that Stripe offers.

Settlement typePayment SuccessFunds AvailableCutoff time
Standard SettlementT+3 at 21:00 UTCT+4 at 00:00 UTC20:00 Europe/London

Set up webhooks

Stripe sends multiple events during the payment process and after the payment is complete. Use the Dashboard webhook tool or follow the webhook guide to receive these events and run actions, like sending an order confirmation email to your customer, logging the sale in a database, or starting a shipping workflow.

For Bacs Direct Debit you need to handle the payment_intent.succeeded event to confirm that the payment has succeeded. Stripe also recommends handling the payment_intent.processing, and payment_intent.payment_failed events.

To test webhooks locally, you can use Stripe CLI. After you have it installed, you can forward events to your server:

Command Line
stripe listen --forward-to localhost:4242/webhook Ready! Your webhook signing secret is '{{WEBHOOK_SIGNING_SECRET}}' (^C to quit)

Learn more about setting up webhooks.

Test the integration

There are several test bank account numbers you can use in a sandbox to make sure this integration is ready.

Sort code Account numberDescription
10880000012345The payment succeeds and the PaymentIntent transitions from processing to succeeded.
10880090012345The payment succeeds after three minutes and the PaymentIntent transitions from processing to succeeded.
10880033333335The payment is accepted but then immediately fails with a debit_not_authorized failure code and the PaymentIntent transitions from processing to requires_payment_method. The Mandate becomes inactive and the PaymentMethod can not be used again.
10880093333335The payment fails after three minutes with a debit_not_authorized failure code and the PaymentIntent transitions from processing to requires_payment_method. The Mandate becomes inactive and the PaymentMethod can not be used again.
10880022222227The payment fails with an insufficient_funds failure code and the PaymentIntent transitions from processing to requires_payment_method. The Mandate remains active and the PaymentMethod can be used again.
10880092222227The payment fails after three minutes with an insufficient_funds failure code and the PaymentIntent transitions from processing to requires_payment_method. The Mandate remains active and the PaymentMethod can be used again.
10880055555559The payment succeeds after three minutes and the PaymentIntent transitions from processing to succeeded, but a dispute is immediately created.
10880000033333Payment Method creation succeeds, but the Mandate is refused by the customer’s bank and immediately transitions to inactive.
10880000044444The request to set up Bacs Direct Debit fails immediately due to an invalid account number and the customer is prompted to update their information before submitting. Payment details are not collected.
10880034343434The payment fails with a charge_exceeds_source_limit failure code due to the payment amount causing the account to exceed its weekly payment volume limit.
10880012121212The payment fails with a charge_exceeds_weekly_limit failure code due to the payment amount exceeding the account’s transaction volume limit.

You can test using any of the account numbers provided above. However, because Bacs Direct Debit payments take several days to process, use the test account numbers that operate on a three-minute delay to better simulate the behavior of live payments.

Note

By default, Stripe automatically sends emails to the customer when payment details are initially collected and each time a debit will be made on their account. These notifications aren’t sent in sandboxes.

Payment failures

Payments can fail for a variety of reasons. The reason for a failure is available through charge.failure_code. Only payments with certain failure codes may be retried. If a payment can’t be retried, we recommend reaching out to the customer and asking them to pay again using a different bank account or a different payment method.

Below is a list of failure codes we currently send for Bacs Direct Debit. We may add more at any time, so in developing and maintaining your code, you should not assume that only these types exist.

Failure codeDescriptionRetryable
account_closedThe bank account has been closed.No
bank_ownership_changedThe account has been transferred to a new Payment Service Provider (PSP). Check if you have been notified of the new PSP’s details. If not, you must collect a new mandate from the customer.No
debit_not_authorizedThe customer has notified their bank that this payment was unauthorized or there is no mandate held by the paying bank.No
generic_could_not_processThis payment could not be processed.Yes
insufficient_fundsThe customer’s account has insufficient funds to cover this payment.Yes
invalid_account_numberThe account number is not valid. This could mean it is not for a GBP account or that the account can’t process Direct Debit payments.No

To retry a payment, confirm the PaymentIntent again using the same PaymentMethod.

To ensure success, we recommend reaching out to the payer before retrying a payment.

OptionalConfigure customer debit date

OptionalCustomize mandate references with a prefix

See also

  • PaymentIntent webhooks
  • Manage mandates
Was this page helpful?
YesNo
  • Need help? Contact Support.
  • Join our early access program.
  • Check out our changelog.
  • Questions? Contact Sales.
  • LLM? Read llms.txt.
  • Powered by Markdoc