Integrations
Stripe Bacs Direct Debit: pending states, failures and reconciliation
A Bacs Direct Debit is a request that gets answered days later, and sometimes changes its answer after that. Billing systems built around card payments get this wrong, so model the waiting as a state of its own.
By itmarkerz Technologies. Updated 30 October 2026.
Where this comes from
We build the collection side of a UK telecom billing platform, including Stripe card and Direct Debit payments, part payments, one charge covering several invoices, Bacs pending states and automatic reconciliation of payouts, refunds and disputes. The facts below come from Stripe’s Bacs documentation, read on 30 October 2026. Check it again when you build, since details change.
The timeline
| Stage | Existing mandate | New mandate |
|---|---|---|
| Submitted to Bacs | T+0 (cut-off 20:00 London time) | T+0, with the mandate |
| Mandate active | Already active | T+3 |
| Money leaves the customer’s bank | Typically T+2 | T+5 |
| Payment reported successful | T+3 at 21:00 UTC | Within 7 business days |
| Funds available in Stripe | T+4 at 00:00 UTC | T+7 |
Submissions on a non-business day, or after the cut-off, move to the next business day. Stripe also exposes an estimated expected_debit_date on the charge, which is useful for customer-facing text as long as you describe it as an estimate. Notice the gap: the customer’s money may have left before your system knows the payment worked. If they tell you they’ve paid, they may be right.
Your invoice needs a state for “waiting”
A card payment goes from unpaid to paid in one request. Bacs doesn’t. Add a pending state to your receipt, and decide what it means for everything else. That is usually the bigger piece of work.
| Stripe event (PaymentIntents) | With Checkout | What your system does |
|---|---|---|
payment_intent.processing | checkout.session.completed | Mark the receipt pending. Don’t mark invoices paid, or send a receipt |
payment_intent.succeeded | checkout.session.async_payment_succeeded | Allocate to invoices, post to the ledger, send confirmation |
payment_intent.payment_failed | checkout.session.async_payment_failed | Reopen invoices, record the reason, start your follow-up |
charge.dispute.created | Same | Reverse the receipt, reopen the invoice, flag the account |
mandate.updated | Same | Check the mandate status; stop debits if it isn’t active |
payment_method.automatically_updated | Same | Bank details changed; keep the mandate in use |
refund.updated | Same | Check the status. There’s no refund.succeeded event |
checkout.session.completed catches people out. It means the customer submitted the form, not that any money arrived. And while a payment is pending, make sure your dunning, your credit control and your “pay now” link all know about it. Otherwise you will chase a customer who has already paid, or take the money twice.
What each failure means
Stripe’s test accounts show the behaviour of the main failure codes. The platform we built for a UK client turns them into plain-language reasons for staff and customers, because “debit_not_authorized” means nothing to a credit controller.
| Code | Mandate afterwards | Plain-language meaning | Next step |
|---|---|---|---|
insufficient_funds | Stays active | Not enough money in the account | Retry, or use Stripe’s retries |
debit_not_authorized | Inactive; payment method unusable | The customer’s bank says this debit wasn’t authorised | Contact the customer; a new mandate is needed |
charge_exceeds_source_limit | Not stated in the test table | You have hit your account’s weekly volume limit | Talk to Stripe; this isn’t the customer’s fault |
charge_exceeds_transaction_limit | Not stated in the test table | This payment exceeds your per-payment limit | Split by agreement, or ask Stripe to raise it |
The last two matter for planning. Stripe’s default limit is £10,000 per Bacs transaction. New users also have a weekly limit of £10,000, which rises as they process more. A B2B biller moving existing customers onto Direct Debit can hit this on its first run, so talk to Stripe well before then.
For retries, Stripe’s Direct Debit retries cover insufficient-funds failures, up to 2 times within 30 days of the original attempt, for Billing invoices. If you run your own invoicing and collection, you have to build the equivalent. A customer on a payment arrangement may need a hold; the platform we built for a UK client supports payment holds so that nothing goes out while one is in place.
Success isn’t always final
Stripe warns that a bank may report failure after a payment was marked successful, in which case it appears as a dispute. Bacs disputes differ from card disputes in ways that affect your design:
- There is no set time limit for the customer to file, so a ledger entry from long ago can be reversed.
- You can’t submit evidence or appeal. The bank’s decision stands.
- Stripe deducts the amount and a fee from your balance when it creates the dispute.
- Disputes are for the full amount only. There are no partial disputes.
Refunds carry a trap. They are sent separately from the Bacs scheme, as a credit, within 180 days of the payment. Because a customer can still dispute afterwards, you could lose both the refund and the disputed amount. Stripe advises telling the customer you are refunding, so that they don’t also go to their bank, and refunding only once the payment has settled.
Collecting the mandate
Use Checkout unless you have a strong reason not to. It collects bank details and the mandate, and Stripe handles the required notifications by default. Note that the Payment Element can’t create a Bacs SetupIntent, so saving details for later needs Checkout in setup mode. A custom mandate form needs Stripe’s approval, and must meet the collection requirements, including exact checkbox wording.
Customers see Stripe’s name on their bank statement by default, unless you enable Custom Branding, which Stripe lists at £50 per active month and which typically takes 10 working days to activate. Bacs also doesn’t support per-transaction statement descriptors, so customers won’t see your invoice number on their statement. Put the debit date and amount in your own communications, because that’s how people will recognise it.
Matching payouts
On automatic payouts, wait for payout.reconciliation_completed, then list what the payout contains:
curl -G https://api.stripe.com/v1/balance_transactions \
-u "<<YOUR_SECRET_KEY>>:" \
-d payout=po_xxx \
-d "expand[]=data.source"Each balance transaction has a type, such as charge, refund or stripe_fee, and a source that you can match back to your receipt. The finance integration map shows how the result fits a clearing account.
Test the slow paths
Stripe’s test bank details use sort code 108800, with account numbers for each outcome. Use the versions with a three-minute delay, such as 90012345 for success and 92222227 for insufficient funds, since these behave most like a real debit. Then test what happens when a customer pays by card while a debit is pending, and when a dispute arrives for an invoice from a closed period. Those two cases find more bugs than the happy path.
Where we have built this
UK telecom billing and revenue-assurance platform for resellers and MSPs: CDR rating, locked bill runs, Stripe card and Direct Debit collection, full receivables and ledger, Xero/QuickBooks/Sage sync, supplier-invoice reconciliation. Laravel + Next.js, two and a half years and ongoing.
- Sector
- Telecom & IT services
- Region
- UK
- Stack
- Laravel, Next.js
- Engagement
- Long-term engineering partner, 2.5 years and ongoing
Questions
How long does a Stripe Bacs payment take?
Stripe says it takes 4 business days to confirm success or failure with an existing mandate, and up to 7 when collecting a new one. Funds typically leave the customer's account at T+2 on an existing mandate, before Stripe reports success at T+3.
Can we challenge a Bacs Direct Debit dispute?
No. Stripe's documentation says you can't submit evidence or counter one, the bank's decision is final, and there is no set time limit for customers to file. If you agree otherwise with the customer, they make a new payment, and the dispute fee isn't refunded.
Can a customer pay part of an invoice by Direct Debit?
Stripe debits whatever amount you request, so part payment and allocation are for your billing system to manage. The platform we built for a UK client records which invoices each charge paid. Bacs itself has no idea what an invoice is.
Is this page legal or Bacs scheme advice?
No. It is a developer's summary of Stripe's documentation as of 30 October 2026. Check the current documentation, and Stripe's mandate requirements if you build a custom form.
More on integrations
- Stripe Direct Debit, Xero, QuickBooks and Sage: a UK finance integration mapEach system by method, sync direction, limits and how it fails.
- Connecting to Sage 50: why we ship a daily journal fileWhen a file beats a live connection, and how to make it safe to import.
- Xero integration: what to sync and what to leaveCurrent API limits, a sync table, and the failures to design for.
- Three ad APIs, one modelAdapters for Facebook, Instagram and Google without merging what doesn't match.
- A bot on the same API as your websiteWhy a Telegram bot shouldn't have its own business logic.
Adding Direct Debit to your billing?
Tell us how you invoice and what you use for accounting. We will tell you what needs to change in your system before the first debit goes out.
We reply within one business day (IST).