6 Comments
User's avatar
⭠ Return to thread
Alvaro Duran's avatar

Thanks again for your question Olek, I hope these articles are helping you as much as they're helping me writing them. Let me try to address both questions.

The reason you need distributed transactions in payment systems is that most of the time you're not approved for handling the payment yourself. Card payments, in particular, are a very regulated environment. Even digital wallets are subject to somewhat strict regulation when it comes to whether you're allowed to keep the breakage.

That's why there are companies called PayFacs, which provide the APIs to connect to card payments and all that.

What these PayFacs tend to do is imply that you shouldn't be doing payments at all, and that you should handle all payment concerns to them. They might suggest that the less you have in your systems that is payments related, the better. That's how I'm reading your second question: can we just not do this.

I believe that's not a good idea. Payments, your customers' money, that's important data for your business. It is indeed simpler to just do as little as possible and let the PayFac handle that for you. But, and this is a crucial BUT, there are fees involved in this, a power play of sorts. Giving this data to them is giving up on an important negotiation lever, because the more the PayFac does for you, the less able you are to switch providers.

So your suggestion has technical sense. You can do what you're suggesting— it's doable from a technical standpoint, and it's easier. But if I remove my tech hat and put my business hat on, I would recommend against it.

Expand full comment
Olek Gornostal's avatar

Thanks for the answer!

I realize now that my previous question wasn't clear. Of course, you won't get away from the distributed nature of transactions and you would want to do them via PayFacs. I only wanted to challenge the distributed solution for the store credits :)

I have in mind solution like this.

```

try {

db.transaction.begin()

stripe.paymentIntents.create(...)

debitStoreCredits(userId, amount) // store credits are stored in a DB

db.transaction.commit()

} catch(e) {

db.transaction.rollback()

}

```

Then if a card transaction on the Stripe side is declined, credit the same amount back to the user's Store Credit account.

Even if Store Credits are managed by a remote server, you could still have a solution simple enough. Using outbox pattern, for example.

Do you see any problem with it?

Thanks!

Expand full comment
Alvaro Duran's avatar

Yes, there's an issue with this specific approach, and that's that payments via Stripe can finalize asynchronously (the status may go to "pending"). That's why the 2 phased commit pattern is inevitable here: you can only confirm the credits once the payment is authorized, and not a moment earlier.

Otherwise you have to engage in compensating entries in the credit ledger, which is unnecessary in my opinion.

Expand full comment
Olek Gornostal's avatar

Right. The compensating entries may be required in my approach.

Expand full comment