Integrations
Stripe Direct Debit, Xero, QuickBooks and Sage: a UK finance integration map
These systems are usually documented one at a time, yet finance teams live with them together. This map shows each one by connection method, sync direction, limits and failure modes, followed by the rules that keep the books agreeing.
By itmarkerz Technologies. Updated 30 October 2026.
Where this comes from
For two and a half years we have been building a UK telecom billing and revenue-assurance platform that collects by card and Direct Debit through Stripe, syncs to Xero, QuickBooks Online and Sage Accounting, and produces a daily journal file for Sage 50 and 200. Most of our work is delivered under NDA, so many projects cannot be named. So the client stays unnamed, and the vendor facts below come from public documentation you can check.
The map
| System | How you connect | Usual direction | Limits to plan for | How it tends to fail |
|---|---|---|---|---|
| Stripe: Bacs Direct Debit | REST API and webhooks; mandate through Checkout, or a custom form with Stripe’s approval | You request the debit; Stripe reports the outcome later | £10,000 default per payment; a weekly limit for new users; 4 business days to confirm, 7 with a new mandate | Late failures, disputes with no appeal, mandates cancelled at the bank |
| Stripe: cards | REST API and webhooks | You charge; Stripe reports payouts, refunds and disputes | Stripe’s API limits; payouts group many transactions | Assuming a payout equals one payment, missed or repeated webhooks |
| Xero | OAuth 2.0 REST API, one connection per organisation | Usually your app to Xero; payment status may come back | 5 concurrent, 60 a minute, and 1,000 or 5,000 a day per organisation by tier | Lock dates, unmapped account or tax codes, duplicate contacts, HTTP 429 |
| QuickBooks Online | OAuth 2.0 REST API, one connection per company (realm) | Usually your app to QuickBooks | 500 requests a minute per realm, 10 a second; batches recommended up to 30 items, 40 batches a minute | HTTP 429 (Intuit says wait 60 seconds), mapping errors, closed books |
| Sage Accounting | OAuth 2.0 REST API for Sage’s cloud product | Usually your app to Sage | Check Sage’s documentation; we couldn’t confirm current figures at source | HTTP 429, mapping errors, expired connections |
| Sage 50 and 200 | A journal file imported by finance staff, or a connector on their own network | One way, from your app into Sage | A person has to run it, and to tell you it ran | Skipped days, imported twice, a nominal code missing from that installation |
Note that “Sage” covers different products. Sage Accounting is a cloud service with a REST API. Sage 50 and 200 are products usually found on a local or hosted server, and they are integrated differently. Confirm the exact product and edition with the customer’s finance team before you estimate anything.
Decide who owns what
Most finance integration problems start here: two systems both think they own a record. Write this table for your project and get finance to sign it before anyone writes code.
| Data | Typical master | Sent to | Rule to agree |
|---|---|---|---|
| Customers | Your application or CRM | Accounting | Which fields can accountants edit, if any? |
| Invoices | Your billing system | Accounting | Once issued, never edit: correct with a credit note |
| Credit notes | Your billing system | Accounting | Who may issue one, and against what? |
| Payments received | Stripe or bank | Your system, then accounting | When does a pending Bacs payment count? |
| Stripe fees | Stripe | Accounting | Which ledger code, at what level of detail? |
| Chart of accounts | Accounting | Your mapping table | Who updates the mapping when a code changes? |
| Tax codes | Accounting | Your mapping table | Your accountant decides treatment; don’t infer it |
| Period locks | Accounting | Your sync reads the error | What happens to entries dated in a closed period? |
A payout isn’t a payment
The most common reconciliation mistake is treating money arriving in the bank as a single customer payment. Stripe automatic payouts bundle many transactions, net of refunds, fees and disputes. Here is a made-up example, for the arithmetic only:
| Balance transaction | Amount (£) | Goes to |
|---|---|---|
| Card charge, invoice A | 500.00 | Clear invoice A |
| Bacs charge, invoices B and C | 1,200.00 | Allocate across invoices B and C |
| Refund, invoice D | −100.00 | Match to its credit note |
| Stripe fees | −30.00 | Fees ledger code |
| Payout to bank | 1,570.00 | Must match the bank line |
The usual pattern is a clearing account for Stripe in your books. Payments and fees post to it, the payout moves the balance to the bank, and that account should return to zero, apart from timing. Stripe’s payout reconciliation guide gives the mechanism for automatic payouts: listen for payout.reconciliation_completed, then list balance transactions filtered by that payout. Stripe can’t do this for manual payouts, so stick with automatic ones if you can.
Your own system also has to record what Stripe can’t know: which invoices a single charge paid. The platform we built for a UK client handles part payments and one charge covering several invoices. That needs an allocation table of its own, with the rule for what gets paid first agreed with finance. See the Stripe Bacs guide for how pending states and failures fit in.
Seven rules that keep the numbers agreeing
- Every sync must be safe to repeat. Store the other system’s ID against each of your records, and check before creating. Timeouts happen after the other side has acted, so a blind retry creates a duplicate invoice.
- Use a queue, one connection at a time. Xero allows 5 concurrent calls and 60 a minute per organisation. Throttle per connection, not globally, so one large customer doesn’t use up everyone’s time. Read the response headers instead of guessing.
- Failures go to a person who can act. “Tax code missing for product X” should reach finance in plain language, with a retry button. A log file that only developers read means finance finds out at month end.
- Mapping is data, not code. Ledger and tax codes differ per customer and change over time, so keep them in a table that finance can see, with a safe default of stopping when a code is unmapped.
- Post once, then correct. Don’t edit what has been posted. Send a credit note or a reversal, and the trail remains clear.
- Check balances every night. The platform we built for a UK client runs nightly balance checks and has a month-end checklist. A difference found the next morning is one day’s entries to search. A difference found in the year-end audit is much harder.
- Plan for lost connections. Accounting connections expire or get revoked when someone leaves the company. Detect it, stop posting, keep the queue, and ask a named person to reconnect.
Where Direct Debit makes accounting harder
Cards tell you the result straight away, but Bacs doesn’t. Stripe takes 4 business days to confirm a payment on an existing mandate, and 7 with a new one. So a receipt can spend a week in a pending state, and that state has to be represented somewhere finance can see. Don’t post it as received too early, or your customer balances will be overstated, and your credit controller will stop chasing someone whose payment later fails.
The harder case comes later. A bank can reverse a Bacs payment as a dispute, with no time limit for the customer to file and no appeal for you. That reversal may land in a period you have already closed, so decide in advance how it posts: usually dated today and clearly linked to the original invoice, which goes back to unpaid. Have your accountant agree this before go-live, since it will happen on a day when nobody remembers the design.
Multi-customer platforms have extra work
If you sell software to many businesses, each connects their own Stripe, Xero or QuickBooks account. That adds four jobs. Tokens must be encrypted and stored per customer. Limits count per connection, so one customer’s bulk import must not delay another’s. Xero also limits connections by your app’s tier, with Starter capped at 5 and Core at 50, so check the current tier table and its fees before you set your prices. Finally, customers arrive with history, so migrating opening balances needs its own tool and sign-off.
How to test before real money moves
- Stripe: a sandbox with test bank accounts for success, insufficient funds, cancelled mandates and disputes. Use the three-minute delayed ones, which behave more like real life.
- QuickBooks: Intuit provides a sandbox company, with the same throttling figures as production.
- Xero: a demo company, so you can post freely without touching real books.
- Sage 50: a test company or a backup, and your accountant’s eye on the import result before it goes near live data.
- Your own suite: keep sample API responses, including failures, so the rules above run on every change. The automated suite on the platform we built for a UK client runs on every change, for this reason.
Then have finance reconcile one complete test month by hand. If it won’t reconcile on paper, it won’t reconcile in production.
Questions to answer before anyone estimates
A finance integration quote is only as good as the answers behind it. Get these from the people who run the numbers, not just from whoever manages the software. If you are briefing a supplier, send them this list with your answers filled in.
| Question | Why it changes the work |
|---|---|
| Exactly which product and edition do you run? | Sage 50 and Sage Accounting are different integrations, and “QuickBooks” may be Desktop or Online |
| How many invoices, payments and customers a month, at peak? | Volumes decide whether rate limits matter, and whether you post documents or summaries |
| Do you post each document or a daily summary? | This sets the API calls you need and what finance can see in the ledger |
| Which currencies do you invoice in? | Exchange gains and losses need a rule, and your accountant should decide it |
| How are Stripe fees and refunds treated today? | Gross or net posting changes every journal you send |
| Do you close periods, and when? | Late entries need somewhere to go once a period is locked |
| Who approves changes to ledger and tax codes? | That person needs a screen, and needs to hear when a mapping breaks |
| Does any money arrive outside Stripe? | Bank transfers need allocating too, and they may not pass through your system |
| What opening balances must come across? | Migration needs its own tool, reconciliation and sign-off |
| Who looks at sync failures every day? | Without a named owner, errors wait until month end |
The most valuable answer is often the last one. A sync with a named owner and a short daily list of exceptions stays healthy. One where failures go to a shared inbox gets switched off a year later, when people stop trusting it.
Next steps
Our integration service covers these and other business systems. Detailed notes: what to sync with Xero and the Sage 50 journal file.
The platform behind this map
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
Should we post every invoice to the accounting system, or a daily summary?
Ask your accountant, because it depends on how they work. Invoice-level posting lets people look up a customer's document in the accounting system and uses more API calls. Daily summaries are smaller and easier to check, with the detail kept in your billing system. Either way, decide before building, because changing it later alters what finance sees.
Which system should be the master for customers?
Usually whichever system creates them, which is often your own application or CRM. The accounting package receives them and stores your ID. If accountants also edit contacts there, agree which fields are theirs, or your next sync will overwrite their work.
How current are the limits on this page?
We checked each one at the vendor's documentation on 30 October 2026, and we link to it. Vendors change these, and Xero's depend on your app's tier, so check again when you scope. We have left out figures we couldn't confirm at a primary source, including for Sage Accounting.
Do we need an accountant involved in the build?
Yes, at least for the mapping and for sign-off on test postings. Developers can move data reliably, but which ledger code a Stripe fee goes to is a finance decision. This page is technical guidance and not accounting or tax advice.
More on integrations
- Stripe Bacs Direct Debit: pending states, failures and reconciliationThe timeline, the events, what each failure means and how to match payouts.
- 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.
Scoping a finance integration?
Tell us which systems you run and where the numbers disagree today. We will tell you what we would connect first and what we would leave alone.
We reply within one business day (IST).