paddle.engineering [Engineering]

Payment routing part #1: Unifying the payments lifecycle

How Paddle built a unified payment lifecycle to standardize integrations with multiple payment service providers, enabling intelligent routing and better acceptance rates.

This is part one of a two-part series on payment routing, where we explore how we built payment routing. Read part #2 here.

As a merchant of record, we use various payment providers to efficiently manage payments across different regions, ultimately driving better results for our users.

In this blog post, we’ll explore how we achieve this, the complexities of integrating with multiple payment service providers, and how we developed a unified payment lifecycle for our users.

How payments work in Paddle

Paddle offers multiple payment methods for customers at checkout. Behind the scenes, we integrate with several independent payment service providers (PSPs) to make this possible. What you might not know is that Paddle also holds several merchant accounts in different regions around the world where we accept payments.

A merchant account is a single bank account in Paddle’s name that is attached to global payment networks with the help of a PSP. The concept of opening merchant accounts to accept payments nearer to the end customer is called local acquiring.

Local acquiring brings some big benefits for users who process international transactions. It means that payments are often considered domestic, because both the acquiring bank and the issuing bank are within the same country or regulatory region. This results in better payment acceptance rates, as domestic transactions are more likely to be approved over international ones, plus lower fees from the payment networks.

In some cases, we have integrations with multiple PSPs in the same region. At first, this might seem redundant because we’re already achieving local acquiring with one PSP, but there are some key benefits:

  • Different providers offer different payment methods. This lets us enable more alternative payment methods for our users.
  • We can route to the best provider. We’ve found significant differences in acceptance rates between PSPs even in the same regions, which is most likely a result of providers using different acquiring banks.
  • Redundancy is crucial. If a PSP has a reliability issue, an outage, a regulatory issue, or even goes bankrupt, we have alternative providers to maintain consistent service to our users.

To get here, we needed to build a system that was capable of choosing which destination a payment should be processed on. A “destination” is a merchant account in a specific region using a specific PSP, and we call this process “routing”.

---
title: Why do we need to route payments?
---
graph TD
    subgraph PM ["Payment method"]
        A[Apple Pay]
        B[Card]
        C[PayPal]
    end

    A --> PR[Payment routing]
    B --> PR
    C --> PR

    subgraph SP ["Service provider"]
        PSP1[PSP A]
        PSP2[PSP B]
        PSP3[PSP C]
    end

    PR --> PSP1
    PR --> PSP2
    PR --> PSP3

    subgraph MA ["Merchant account"]
        MA1[💳 Account A]
        MA2[💳 Account B]
        MA3[💳 Account C]
    end

    PSP1 --> MA1
    PSP2 --> MA2
    PSP3 --> MA3

    classDef paymentMethod fill:#f9f9f9,stroke:#333,stroke-width:2px
    classDef routing fill:#ffab91,stroke:#ff5722,stroke-width:2px
    classDef psp fill:#bbdefb,stroke:#2196f3,stroke-width:2px
    classDef account fill:#f9f9f9,stroke:#333,stroke-width:2px
    classDef header fill:#333,color:#fff,stroke:#333,stroke-width:2px

    class A,B,C paymentMethod
    class PR routing
    class PSP1,PSP2,PSP3 psp
    class MA1,MA2,MA3 account

Routing is just half of the story. We also need to be able to:

  • Accurately measure performance for all payment methods across all PSPs in all regions to fully understand the impact of our payments strategy.
  • Quickly change our payments strategy over time to improve performance, without requiring engineering changes, and to run experiments to influence new strategies.
  • Add integrations to new destinations quickly and immediately measure performance accurately to maximize benefits.

To do this, we needed to standardize all of our integrations with payment service providers into one unified lifecycle.

Unifying the payment lifecycle

Paddle Checkout provides a choice of payment methods and each payment method might require different PSPs to support local acquiring.

Here’s an example of a simple hypothetical payment lifecycle. Paddle’s is a bit more complicated, but follows the same principles.

---
title: Payment lifecycle
---
graph TD
    A[Screening] --> B[Authentication]
    B --> C[Authorization]
    C --> D[Captured]
    D -.-> E[Refund]

    A --> F[High risk]
    A --> G[Expired or invalid card]
    B --> H[Auth failed]
    C --> I[Declined]
    C --> K[Failure]

    I --> J[Retry]
    K --> J[Retry]
    J -.-> A

    classDef success fill:#e8f5e8,stroke:#4caf50,stroke-width:2px
    classDef failure fill:#ffebee,stroke:#f44336,stroke-width:2px
    classDef process fill:#f9f9f9,stroke:#333,stroke-width:2px
    classDef optional fill:#fff3e0,stroke:#ff9800,stroke-width:1px,stroke-dasharray: 5 5

    class A,B,C process
    class D success
    class F,G,H,I,K failure
    class E optional
    class J process

This payment setup can get quite complicated on its own and becomes a huge challenge when developing a routing system on top of it all. What we need is a consistent data model and API contract for all of our payment methods and integrations.

This is important because:

  • We want to directly compare different payment integrations fairly against each other. It’s not useful to route payments to one destination over another if we’re not confident that they perform better.
  • We want to be able to add new payment methods, PSPs, and regional merchant accounts over time, and they should be able to take advantage of the existing routing, analytics, and retry features.
  • We want to provide consistent and meaningful experiences for all Paddle users when they interact with payment data in the dashboard, APIs, and reports. For example, when understanding payment decline reasons.

Developing this was an engineering challenge, but one that we considered truly worthwhile to unlock the value of local acquiring. We’ve done this work so our users don’t have to.

The first challenge to overcome is the technical complexity involved in standardization because every PSP integration is different. Some have SDKs, others don’t; some use XML, others use JSON; and they all have varying meanings attached to an HTTP status (or none at all!). Some necessitate a complex PCI-proxy setup to keep card data safe.

We found that the main ingredients required to unify these integrations are:

  • A suitable data model to implement the “lifecycle” of a payment as a state machine.
    This is used for both the transactional processing of payments, and also as the basis of an analytics model which Paddle can use to compare the performance of all potential integrations.
  • An API to move payments through this lifecycle.
    It needs to be simple enough for other Paddle systems to interact with, but capable of accommodating specific features that might vary depending on payment method or the nature of the payment. For example, card payments require a unique approach to fraud detection, and also necessitate 3D-Secure.
  • A way for each integration to describe the final outcome of a transaction in a shared language across all integrations.
    We call this “response mapping”. This lets us understand why a transaction ended up with that particular outcome. A very common example of this is being able to identify an “insufficient funds” decline, or being able to differentiate between payment declines and system failures that can occur downstream.

With a unified payment lifecycle, we’re able to standardize payments from different PSPs, measure performance, and build a rules engine that determines how each payment gets routed.

In the next blog post, we walk you through our rules engine, the two strategies we currently use, and outline some challenges and plans for payment routing at Paddle. Read it now.

// About the author
George Wilson profile photo

About George Wilson

George Wilson is Head of Engineering for the Payments Group at Paddle, leading teams that build, maintain and scale our payments stack.

[We're hiring]

Build the stack that simplifies their stack

Join us and help solve the biggest product and engineering challenges in fintech. Make a difference to thousands of SaaS, app, and AI companies on their journey to global growth.

Find your role