What we’ve learned from processing £100k+ of transactions every week

We process several hundred thousand pounds of transactions for our clients every week. During peak periods, we’ll process this volume in a single day alone, and in exceptional cases, within a few minutes. Taking money from customers may sound simple, but there are many different factors and facets that have to be considered when designing and building a payment system.

We’ve built payment systems that allow our clients to handle payments via Card, Direct Debit, Google Pay and Apple Pay by integrating with major payment providers such as Stripe, GoCardless, Braintree and PayPal.

In this post, our team share some of the lessons that they’ve learned from designing and implementing payment systems for handling traditional e-commerce all the way through to event sales and membership subscriptions.

Pick a Provider Carefully

Integrating with a payment provider is a non-trivial undertaking, and once implemented, the payment integration will become a critical part of the business and system. Therefore picking a provider that is commercially viable and is a good fit for current and future business requirements is vital.

A key commercial consideration will be the transaction fees that a provider wants to charge. A more traditional payment provider such as Global Pay or The Access Group may offer more favourable transaction fees when compared to a provider such as Stripe or Braintree, however, it is worth considering the total cost of ownership for a payment solution.

Whilst a provider may have lower transaction fees compared to a competitor, this could be quickly negated if the developer experience is poor.

A poor developer experience will require the technical team to do more work to support the payment provider, which could add days, weeks or even months to the build cost.

A poor developer experience could look as follows:

  • Rudimentary API documentation
  • Access to APIs but no pre-built SDKs
  • No value-add off the shelf functionality

On the other hand, a good developer experience could look as follows:

  • Comprehensive API documentation
  • Access to APIs with pre-built SDKs in the language(s) you require for your technology stack
  • Ability to leverage off-the-shelf functionality so that you’d developers don’t have to build as much functionality from scratch.

Off-the-shelf vs Bespoke

Design choices around the business requirements and user experience for your payment system will determine whether you can leverage off-the-shelf functionality from your payment provider (assuming this is an option) or if you have to build everything from scratch.

For example, Stripe provides the option of using hosted payment pages. With a hosted payment page, Stripe hosts the checkout part of the user experience. Provided the use case is correct, this can work great, because there is no need to build a checkout within your application – you can just hand off the user to Stripe without needing to build all of the checkout logic yourself.

Whether or not this approach will work for you will depend on your specific use case and circumstances.

If your circumstances won’t allow you to leverage a hosted payment page, you may still be able to benefit from pre-built building blocks. For example, Braintree provides Drop-in UI, and Stripe provides Stripe Elements. Both of these options will allow you to build a checkout experience that is tailored to your needs without having to build everything from scratch.

At the extreme end, you may require an entirely custom user experience and a set of business requirements that require you to go entirely bespoke with your payment process. This is entirely possible but will naturally require the most development effort when compared to the other options.

In summary:

  • Hosted or External Payment Pages
    Often requires the least development effort when compared to alternative options, however the functionality and user experience is usually limited to what the provider allows to be configured. 
  • Drop-in UI/Elements
    A payment provider may provide elements or components which can be used to build out the payment experience. This will often do a considerable amount of the heavy lifting for you. Whilst this often requires more development effort than Hosted/External payment pages, this usually provides the necessary level of flexibility to allow the user experience and business requirements to be satisfied. 
  • Entirely Bespoke
    This option almost always requires the most development effort to achieve. However, if you have particular business and UX requirements that aren’t satisfied by the alternatives, this option will allow you to build what you need for your business.

Whilst opting for an entirely bespoke implementation provides the luxury of allowing you to build whatever you want, however you want, it does come with a cost. Therefore any decision around the correct approach should only be taken after a careful cost-benefit analysis has been undertaken. And remember, everything that your developers have to built also has to be maintained in the future – so more bespoke options have greater maintenance costs.

For instance, if you have only a small number of requirements calling for an entirely bespoke solution, careful consideration should be given as to whether those requirements can be alternatively satisfied – or, if they’re even worth the effort at all.

Payment Method Choice

There are many different options when it comes to allowing customers to pay for goods and services. The most common of these are:

  • Debit/Credit Card
  • Direct Debit
  • BACS Transfer
  • Google Pay
  • Apple Pay

If we want to put the customer first, it could be argued that we should support every method of payment possible! Whilst in theory this sounds great, in practice it may not be appropriate for every use case.

Whilst it probably goes without saying that the demographic of your target market will be an influencing factor on which payment methods should be supported, the nature of what you are selling is also important.

For example, let’s imagine that you’re selling an online subscription service where you provide immediate access to digital content. The subscription is £5/month with a minimum term of 3 months.

In this situation, card payments would be a great way to collect payment from a customer. Payments are instant, and you can support subscriptions with card payments. However, the business may push for Direct Debits to be supported. Typically Direct Debit transaction fees are usually a tenth of the cost of card payments – so it is understandable why supporting Direct Debit may be desirable.

Here are a few facts to consider for Direct Debits:

  • A Direct Debit payment often takes 3 days to clear for an established mandate
  • A new Direct Debit takes 3 days for the mandate to be established and a further 3 days for the first payment to process. This means that a payment for a new Direct Debit typically takes 6 days
  • The customer can cancel a Direct Debit via their bank at any point
  • Direct Debits are protected by the Direct Debit Guarantee

Therefore, in our example situation, these facts should prompt the following discussions:

  1. If we support Direct Debits and provide the customer access straight away, we’ll have to wait 6 days to receive the payment, and the payment could fail if the customer has insufficient funds. Do we really want to allow this? Or should we wait for the payment to fail, which could cause a bad user experience?
  2. If the customer cancels their Direct Debit via their bank account within the first three months how will we ensure the first three months is paid for as we will not be able to use the cancelled Direct Debit to capture the funds?
  3. How will the Direct Debit Guarantee impact our ability to handle any payment disputes?

The specific answers to these questions will depend on individual circumstances. As you can see, supporting a given payment method may prompt more challenges or problems than others.

In contrast, if we consider card payments for our scenario:

  1. Card payments either succeed synchronously or fail – therefore, there is no issue of a delay and subsequent payment failure.
  2. A subscription card payment cannot be cancelled from the bank in the same way as a Direct Debit can be. Whilst we will need to deal with edge cases such as card expiry that would prevent fund collection, the cancellation process can be orchestrated to ensure any owed money is collected first.
  3. Card payments do have certain consumer protections which will need to be considered

In short, supporting different payment methods may impact the complexity of your system, associated build costs and/or supporting business processes.

Failures and Edge Cases

Every business collects money from customers, so taking payments online should be straightforward?
In theory, yes. In practice, there are a lot of failure and edge cases that need to be dealt with and tested.

Let’s look at the different scenarios that exist for successful and unsuccessful payment capture.


  1. The customer provides the correct payment details and has sufficient funds


  1. The payment cannot be processed because the customer does not have sufficient funds in their account to cover the payment amount
  2. The customer has attempted to pay with a card that has been reported as lost
  3. The customer has attempted to pay with a card that has been reported as stolen
  4. The customer attempted to pay with a card that had expired
  5. The customer has provided an incorrect CVV
  6. The customer has provided an incorrect card or account number
  7. The customer has exceeded their “velocity limit” – e.g. the payment is being prevented because this will take them over a spending limit
  8. The customer fails the 3D Secure customer verification process

Whilst there is one happy path for successfully taking money off of a customer, there are many failure cases for why a payment may not succeed, which need to be handled. We have listed the eight most common above. Some of these only apply to specific payment methods, and its possible your provide may have more edge cases.

In any payment system, dealing with failure cases is just as important as dealing with a successful payment. Whilst some of the failures may feel similar, payment provides often differentiate the specific cause for a payment failure – and as a result, all of these scenarios need to be handled and tested.

Another consideration with payment failures is whether the customer is present or not.

Consider a subscription where a customer pays by card. The customer will be present on the checkout screen to provide their card details for the first payment. Therefore if there is a problem, the customer is informed synchronously and can then decide how to deal with this (e.g. correct the details, use an alternative card, etc…)

However, when the subscription renews next month, this will be done automatically by the system without the customer being present… what happens if the customer’s card has expired or has insufficient funds?

  1. Should the customer be notified by email of a payment failure?
  2. Should there be a process to flag the customer to the sales team within the business?
  3. Should the customer’s subscription and access be suspended until payment is taken?
  4. Should the system pre-emptively warn a customer if their card is due to expire?

These are all considerations that need to go into the design of any payment system.

Refunds and Disputes

Refunds and disputes are another area where complications can arise.

Whilst refunds are fairly common, there are a few considerations that should not be overlooked:

  • Not all payments clear immediately
  • Not all payments will clear successfully
  • The timing of a refund may impact downstream business processes

For example, Direct Debit payments are not instant. Therefore if a customer asks for a refund for a purchase made via a Direct Debit, you may not have the funds from this transaction to refund.

This presents a number of choices and options:

  1. Only allow refunds of direct debits once the funds have cleared.
  2. Allow refunds of direct debits immediately, but queue up the refund to be processed if and when the original payment clears
  3. Assume the payment will be successful and refund the money without reversing the original transaction.

As with any aspect of designing a system, complications present choices, and not all choices are good choices.

Only allowing a refund to be requested and issued for a cleared payment is, by far, the simplest solution but doesn’t result in the best user experience.

Allowing refunds for pending payments to be “queued up” is more work to implement but results in a far better experience.

The final option in almost all cases is entirely undesirable, as this presents more challenges if the original payment does not succeed.

In addition to refunds, payments may be disputed – even if the payment is legitimate.  We have known clients to have to have payments disputed because the customer didn’t recognise how the charge appeared on their bank statement, or they simplify “forgot” what they purchased.

Payment systems need to support dealing with disputes. Just like a refund or a payment failure, a dispute will have ramifications for the business. Therefore the system needs to understand if a dispute has been lodged and what the business rules are for this.

A dispute can be registered with a payment provider at any time for a payment that has succeeded. If the dispute is upheld, the payment provider will reverse the payment, which means we will likely need to stop an order being dispatched or suspend access to a service.

Being aware of when a dispute is raised is important, because most payment providers will side with the customer if you do not provide a counter-argument and/or supporting evidence within a given timeframe.

Disputes can often prompt the following design questions:

  1. Who should be informed when a dispute is raised?
  2. Should we prevent certain actions when a dispute is raised? E.g. fulfilment of and order or access to a service
  3. Do we need to do anything when a dispute is lost? E.g. cancel order/subscription
  4. Do we need to do anything when a dispute is won? E.g. continue with order dispatch/subscription access

Operating at Scale

All systems have peaks and troughs of activity. Payment systems can sometimes have extreme peaks of activity.

Ensuring that a payment system can deal with extreme peaks of activity can be business-critical – especially for entirely online/digital businesses.

Certain types of sales – such as selling concert and event tickets – can cause intense peaks of activity for short time periods.

A well-implemented payment system needs to be designed with isolation to minimise intense peaks of activity from overwhelming or crashing the system.

In a basic payment system, you could arrive at an architecture as shown below:

This diagram shows a monolithic system which is responsible for handling all activity, including payments.

There are a number of drawbacks to an approach like this, however, we are going to focus on one key limitation with this approach which is critical for payment processing.

In certain cases, payment processes will need to inform your system of changes to payments and other such activities. This is usually achieved by the payment provider communicating with your system. 

With a monolithic architecture, a traffic spike could overwhelm the system making your system unresponsive or slow to updated from the payment provider. Whilst more payment providers will re-attempt any failure communication, your system will fall out of sync with the payment provider, which could cause further complications.

One way to mitigate this, is to have a more refined architecture which protects the integration between your system and the payment provider which will significantly reduce the likelihood of a traffic spike interrupting your ability to handle an process payments:

Launch Simple, and Iterate

Building a well-implemented payment system is complicated. With any system, decisions and complications often end up layering and compounding – the number of test cases and considerations can easily grow rapidly as more and more functionality has been added.

Aiming for a comprehensive, feature-rich solution from day 1 will warrant a commensurable build effort and timescales – and will likely be based on assumptions with little or limited validation.

Whereas arriving at a minimal system that contains just the right amount of functionality to start taking payments will be live and capturing payments much faster, and will unlock the goldmine of evaluating decisions based on real customer feedback. Minimal systems, by their very nature, minimise the pitfall of building functionality that’s great in theory, but underutilised or incorrect in reality.

Need help with a payment system?

Get in touch!