How to design mixed payment methods with store credits
Scaling a convenient alternative to cash refunds sows the seeds for a multi-method payment system, and a sophisticated loyalty program
Most companies make a colossal mistake when they decide to accept alternative payment methods. They choose the wrong one to start with.
Once they accept credit cards, these companies’ founders look outside. They see PayPal, Apple Pay. They want to give their customers more options.
And that’s, to quote Bane from The Dark Knight Rises, fighting like a younger man. “Admirable, but mistaken”.
If you’ve never accepted payments beyond cards, there is a simple alternative payment method to try. One that’s completely under your control, but which will give you the opportunity to build the scaffolding that will make integrating with the PayPals and the ApplePays way easier.
It all starts with how you refund.
I’m Alvaro Duran, and this is The Payments Engineer Playbook. Go spend 5 minutes on Youtube and you’ll see tons of tutorials on how to pass software design interviews that use payment systems.
But there’s not much that teaches you how to build one for real users and real money.
The reason I know this is because I’ve built and maintained payment systems for almost ten years. I’ve been able to see all types of interesting conversations about what works and what doesn't behind closed doors.
And I thought, “you know what? It’s time we have these conversations in public”.
In The Payments Engineer Playbook, we investigate the technology that transfers money. All to help you become a smarter, more skillful and more successful payments engineer. And we do that by cutting off one sliver of it and extract tactics from it.
Today, we’re going to look closely at store credits, and how a protocol with bad reputation is a great fit for mixed payments.
But first, I want to address the elephant in the room: why even bother with credits?
Like I said, it’s all about how you refund. When customers return what they bought, companies often give them the amount paid, in cash.
This is completely fine. But it’s expensive, if they paid with card. For companies that sell products that are either low priced, or low margin, refunds often cost a significant percentage of the profit.
If you’re refunding a card payment, you will need a few sales to offset that cost. That puts an incredible amount of pressure on your company.
Most of the time, your only recourse is to be continually selling at discount on a non-refundable policy. That’s why it feels as if many fashion stores are always on “sale”.
From a business point of view, offering a refund is bad business.
But you’ve probably noticed that well known fashion stores don’t give cash refunds that easily. What they give you instead is a branded card, preloaded with the refund amount.
This is called store credits. Or, in payments lingo, a staged closed loop wallet.
Store credits are amazing for three reasons. First, they keep the money within the business.
Second, there’s the breakage, which is the industry term for funds unused by the customer. You get to keep the returned product, and some of the money that was used to pay for it. Although depending on where you’re doing business, the government might claim that money. Check this fact sheet by Consumer Reports if you want to learn more.
And third, store credits are an incentive for future purchases. Every company that implements store credits ends up realizing that the retention feature of store credits overshadows the savings from not having to give cash back.
That last point only can explain why you come back to Zara or H&M more often than to one of those struggling fashion stores that give cash refunds.
Store Credits is an Async Ledger
How should you go about implementing store credits?
I’ve been working with store credits intensely for the last couple of weeks, and the biggest surprise for me was realizing that store credits is an asynchronous payment method.
Which may be a bit surprising at first, but it makes total sense, because store credits are meant to be used in combination with another payment method.
Yes, you can make a payment exclusively with store credits. But in practice, that’s the exception, not the norm. In fact, your company benefits the most from store credits especially when they’re used to generate more revenue.
As a result, the best thing you can do from a software design perspective is to lean on mixed payments with store credits from the very beginning.
Not only is it inevitable, it’s also something that you might decide to implement in the future, and store credits are the simplest payment method with which to build mixed payments.
Store credits, therefore, must have a prepare stage, where the amount of store credits to be used is locked; and an approve stage, where the amount is removed from the account.
Notice that these are analogous to the authorize and capture stages of card payments. But I’d rather use terms that don’t overlap with other domains, because it muddles the conversation, and confuses the hell out of everybody.
In practice, this means that you need to keep track of credit transactions that could be in one of three states: pending, which are created during the prepare stage; posted, which result from the approve stage; and discarded, if you want to keep track of credit transactions that weren’t approved (you should!).
This smells like a ledger, and it is. I strongly recommend that you also keep track of the funds added into the users’ accounts from the business, and implement a complete ledger, rather than focusing on the users’ side only.
I didn’t track those funds once, and it was terrible.
How to mix card payments with store credits
Async store credits let you mix store credits with card payments, because multiple async methods can be combined using a Two-phase commit (2PC) protocol.
If you’ve never heard of 2PC, it’s a consensus protocol that coordinates the work around a launch status check. The coordinator polls every node for a go/no go decision, and commands every node to act only when all of them have replied with a go.
Now, I’m aware that 2PC has a bad reputation in the distributed systems community. Gregor Hohpe famously wrote that Starbucks doesn’t use it. And I didn’t mention that explicitly in my article on Sagas, but the Saga pattern is the direct result of the frustrations that arise from using 2PC at scale.
2PC has three main downsides:
O(n) time complexity: More nodes means more go/no go messages flying around.
Single point of failure: The protocol revolves around the coordinator. If it crashes, even when all nodes have replied with a go, the combined action won’t happen.
Reduced throughput: The combined result is dragged down by the slowest node.
These are very valid points. But consider this:
Payments that combine an increasing number of payment methods are increasingly less frequent. Card only is the most frequent option; mixed with credits, less so; and mixed with yet another one, very rare.
Payment systems should be resilient to crashes anyway. Even if the user is paying with a card alone, your payment system is still coordinating the payment.
Third party payment methods are by definition the slowest. Throughput isn’t effectively reduced by introducing store credits
In other words, the tradeoffs of 2PC have little effect when it’s used to mix payment methods. Despite its reputation, I believe payment systems should use 2PC to combine multiple payment methods.
How does 2PC work in mixed payments
You can combine two (or more) payment methods using a design that follows these steps:
The user’s store credits get prepared (locked, but not approved yet)
The payment by card gets authorized (not yet captured)
If the authorization succeeds, you can approve the use of the user’s store credits, so that they cannot be used in the future anymore. If not, the user’s store credits get unlocked and can be used in the future.
Finally, the payment by card gets captured.
Notice that step 2 can be as complex as needed. The strength of 2PC comes from not putting any constraints on how complex each individual node can be. In fact, step 2 can be a Saga in and of itself.
What store credits introduce is the ability to switch cash refunds for topping up the user’s store credit account.
What is the downside to store credits? Fraud. Lots of fraud, actually. The better the program, the more it attracts fraudsters, because store credits, unlike credit cards, have less controls built into them.
Their simplicity is at the same time virtue and sin.
Entrepreneurs who run gift card marketplaces either go out of business or become the payment industry’s most ruthlessly effective fraud busters.
— Patrick McKenzie, The Fraud Supply Chain
That said, one of the things that impacted me the most when doing research on store credits is this: they enable sophistication.
Well designed, store credits are the stepping stone for a more “industrialized” retention program. You may start with a humble ledger with your users’ accounts. But give it long enough, it can become a fully fledged loyalty program.
And, in time, it can become something similar to Target’s RedCard, responsible for more than 20% of the company’s revenue.
This is why the engineering of payments is so fascinating to me. There are millions of avenues to explore. But if you build the right thing, and see to it that it grows with the company, there’s a direct link between software and profit.
And that, to me, is what valuable software is all about.
This has been The Payments Engineer Playbook. I’ll see you next week.
PS: Do you have 2 minutes?
Years ago, when I became interested in finance for the first time, a newsletter like this didn’t exist. I sure wish it had. I had been a paying subscriber for Stratechery right after I read it for the first time. I read all of Michael Lewis’s books voraciously. Especially Flash Boys.
But none of that helped me build better money software. I learned a lot, yes. But I couldn’t apply any of it.
With The Payments Engineer Playbook, I set out to write what I needed back then. What would’ve made me a better payments engineer. What would’ve led me to avoid lots of costly mistakes along the way.
There are a few newsletters that many of us in the payments industry know about. But they are focused on one of two things: system design job interviews, and soft skills.
And look, I get it! These are probably the only topics that are broadly applicable for software engineers. System design interviews are mostly the same, regardless if you’re interviewing for one company or another, and soft skills are valuable everywhere.
But what’s going to put you ahead is doing your damned job right.
If you build software that moves money around, being a paid subscriber of The Playbook pays for itself.
You may know that this newsletter is going to become a paid publication in 2025. Before then, you can pledge a subscription for a lower price, because as soon as the year starts, the price will increase.
If you know somebody who can benefit from this newsletter, can I ask you to forward this email to them?
Even if they can’t afford it themselves, most companies have a training budget for their employees (ask your manager). These things move slowly though, so if you need approval from your company, better hurry up before the window closes.
And if someone you respect shared this article with you, do me a favor and subscribe. Every week I feel I’m getting better at this. That means that my best articles on how to build payment systems are probably yet to be written.
You can only find out if you subscribe to The Payments Engineer Playbook. I’ll see you around.
And a second question: let's say a store credits ledger is implemented as a separate sub-system, what challenges do you see in using eventual consistency in the purchase flow?
One approach might be logging a payment intent in the database and processing the transaction asynchronously. If something fails, appropriate rollbacks would be applied. Kind of like a Saga with orchestration, but without extra complexity: without changing the downstream services or building Saga middlewares.
Thanks for the interesting read, as always!
I'm curious why a payment system isn't designed to avoid the need for complex distributed transactions? Such an approach could enhance cohesion and maintainability. A ledger with store credits could be implemented in the same service, as payments and store credits are inherently linked and share similar architectural characteristics. By separating them into distinct entities, we might gain no real advantage. Am I missing something?