Stripe | Financial Infrastructure to Grow Your Revenue

Stripe | Financial Infrastructure to Grow Your Revenue

4466 articles

Bacs Direct Debit payments


Bacs Direct Debit payments

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

Checkout

Elements

Stripe users in supported business locations can use Checkout in payment mode to accept Bacs Direct Debit payments from customers with a UK bank account.

A Checkout Session represents the details of your customer’s intent to purchase. You create a Checkout Session when your customer wants to pay for something. After redirecting your customer to a Checkout Session, Stripe presents a payment form where your customer can complete their purchase. When your customer has completed a purchase, they’re redirected back to your site.

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

Select a language

Ruby

Python

PHP

Java

Node.js

Go

.NET

No results

# Available as a gem
sudo gem install stripe

Gemfile

Select a language

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 products and prices

To use Checkout, you first need to create a Product and a Price. Different physical goods or levels of service should be represented by products. Each product’s pricing is represented by one or more prices.

For example, you can create a T-shirt product that has two prices for different currencies, 20 GBP and 25 EUR. This allows you to change and add prices without needing to change the details of your underlying products. You can either create a product and price through the API or in the Dashboard.

If you determine your price at checkout (for example, the customer sets a donation amount) or you prefer not to create prices upfront, you can also create ad-hoc prices at Checkout Session creation using an existing product.

Caution

If you have an existing Checkout integration that doesn’t use Prices, the Checkout API has changed since we introduced Prices. You can use this migration guide to upgrade, or keep your existing integration.

Note

Products created in a sandbox can be copied to live mode so that you don’t need to re-create them. In the Product detail view in the Dashboard, click Copy to live mode in the upper right corner. You can copy the same sandbox product to live mode more than once. Each copy creates a separate live product, and subsequent updates to the sandbox product aren’t reflected in existing live copies.

Make sure you’re in a sandbox, and define the items you want to sell. To create a new product and price:

  • Go to the Products section in the Dashboard
  • Click Add product
  • Select One time when setting the price

The product name, description, and image that you supply are displayed to customers in Checkout.

Create a Checkout Session Client-side Server-side

Add a checkout button to your website that calls a server-side endpoint to create a Checkout Session.

index.html

<html>
 <head>
 <title>Checkout</title>
 </head>
 <body>
 <form action="/create-checkout-session" method="POST">
 <button type="submit">Checkout</button>
 </form>
 </body>
</html>

Create a Checkout Session with line_items. Line items represent a list of items the customer is purchasing.

When your customer successfully completes their payment, they’re redirected to the success_url, a page on your website that informs the customer that their payment details have been successfully collected and their payment is being processed.

When your customer clicks on your logo in a Checkout Session without completing a payment, Checkout redirects them back to your website that the customer viewed prior to redirecting to Checkout.

Checkout can accept a payment and save the payment method for future use. Payment methods saved this way can be used for future payments using a PaymentIntent. After creating the Checkout Session, redirect your customer to the URL returned in the response.

Command Line

Select a language

curl

Ruby

Python

PHP

Java

Node.js

Go

.NET

No results

Note

The Bacs Direct Debit rules require that customers receive debit notification emails when payment details are initially collected and when their account is debitted. Stripe sends these emails for you by default.

Creating a Checkout Session returns a Session ID. Make the Session ID available on your success page by including the {the related setting} template variable in the success_url as in the above example.

Caution

Don’t rely on the redirect to the success_url alone for detecting payment initiation, because:

  • Malicious users could directly access the success _ url without paying and gain access to your goods or services.
  • After a successful payment, customers might close their browser tab before they’re redirected to the success _ url .

Handle post-payment events Server-side

When your customer completes a payment, Stripe redirects them to the URL that you specified in the success_url parameter. Typically, this is a page on your website that informs your customer that their payment was successful.

However, Bacs Direct Debit is a delayed notification payment method, which means that funds aren’t immediately available. A Bacs Direct Debit payment typically takes 3 business days to make the funds available. Because of this, you’ll want to delay order fulfillment until the funds are available. Once the payment succeeds, the underlying PaymentIntent status changes from processing to succeeded.

The following Checkout events are sent when the payment status changes:

Event NameDescriptionNext steps
checkout.session.completedThe customer has successfully authorized the debit payment by submitting the Checkout form.Wait for the payment to succeed or fail.
checkout.session.async_payment_succeededThe customer’s payment succeeded.Fulfill the goods or services that the customer purchased.
checkout.session.async_payment_failedThe customer’s payment was declined, or failed for some other reason.Contact the customer through email and request that they place a new order.

Your webhook code will need to handle all 3 of these Checkout events.

Each Checkout webhook payload includes the Checkout Session object, which contains information about the Customer and PaymentIntent.

The checkout.session.completed webhook is sent to your server before your customer is redirected. Your webhook acknowledgement (any 2xx status code) triggers the customer’s redirect to the success_url. If Stripe doesn’t receive successful acknowledgement within 10 seconds of a successful payment, your customer is automatically redirected to the success_url page.

On your success_url page, show a success message to your customer, and let them know that fulfillment of the order takes a few days as the Bacs Direct Debit payment method isn’t instant.

When accepting instant payments (such as credit cards) in addition to delayed notification payments, update your webhook endpoint to handle both kinds of payments when receiving a checkout.session.completed event.

Select a language

Ruby

Python

PHP

Java

Node.js

Go

.NET

No results

You can get information about the customer and payment by retrieving the Customer or PaymentIntent objects referenced by the customer, payment_intent properties in the webhook payload.

Testing webhooks locally

To test webhooks locally, you can use the Stripe CLI. After you install it, 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

By this point you should have a basic Bacs Direct Debit integration that collects bank account details and accepts a payment.

There are several test bank account numbers you can use in a sandbox to make sure this integration is ready. You can also use the corresponding token to skip manually entering bank account details.

Sort codeAccount numberTokenDescription
10880000012345pm_bacsDebit_successThe payment succeeds and the PaymentIntent transitions from processing to succeeded.
10880090012345pm_bacsDebit_successDelayedThe payment succeeds after three minutes and the PaymentIntent transitions from processing to succeeded.
10880033333335pm_bacsDebit_debitNotAuthorizedThe 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’t be used again.
10880093333335pm_bacsDebit_debitNotAuthorizedDelayedThe 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’t be used again.
10880022222227pm_bacsDebit_insufficientFundsThe 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.
10880092222227pm_bacsDebit_insufficientFundsDelayedThe 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.
10880055555559pm_bacsDebit_disputeThe payment succeeds after three minutes and the PaymentIntent transitions from processing to succeeded, but a dispute is immediately created.
10880000033333pm_bacsDebit_mandateRefusedPaymentMethod creation succeeds, but the mandate is refused by the customer’s bank and immediately transitions to inactive.
10880000044444—The 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 aren’t collected, so no synthetic token corresponds to this scenario.
10880034343434pm_bacsDebit_exceedsWeeklyLimitThe 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.
10880012121212pm_bacsDebit_exceedsTransactionLimitThe payment fails with a charge_exceeds_transaction_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. You can only retry payments with certain failure codes. If you can’t retry a payment, 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 might add more at any time, so in developing and maintaining your code, don’t 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’ve 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 couldn’t be processed.Yes
insufficient_fundsThe customer’s account has insufficient funds to cover this payment.Yes
invalid_account_numberThe account number isn’t valid. This could mean it isn’t 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.

Optional Configure customer debit date

See also

Last verified 2026-09-24

Is this helpful?