Your Checkout Doesn’t Need to Know Who Took the Money

Hard-wire one payment provider and you’ve quietly welded your whole app to it. VBWD hides every processor behind one adapter, so swapping Stripe for a regional rail is a plugin, not a rewrite.

Rewritten for redrobot.

Here is a small test. Open your checkout code and count how many times the word “Stripe” appears. If the answer is more than zero, your checkout knows something it has no business knowing — and that knowledge is exactly what will cost you when the next market shows up with a processor Stripe has never heard of.

Payments feel like a solved problem right up until you cross a border. A card flow that clears cleanly in Frankfurt hits a wall in Moscow, where the local rail is YooKassa, not a Western card network. A wallet redirect that customers expect in Jakarta looks alien to a buyer in Lisbon. The uncomfortable truth is that “accepting payment” is not one capability. It is a different capability in every region, wearing the same label. Any platform that treats it as singular is quietly making a bet that its users will only ever sell in one country.

The partner who inherits your assumptions

The people who feel this first are OEM partners — the ones who take a platform, brand it, and stand it up for their own customers in their own markets. An OEM does not get to negotiate away geography. One deployment lands in the EU, another in Russia, a third across several Latin American markets, and each arrives with its own rails, its own compliance regime, and its own idea of what a normal payment looks like.

So the interesting question is never “which payment processor should we build against?” It is “how do we let every deployment choose its own processor without any of us maintaining a separate fork?” Answer that badly and every new market becomes a code change in the most dangerous file you own: the one that moves money.

How a hard-wired processor rots a codebase

Follow the easy path and watch where it leads. You wire a processor’s SDK straight into checkout. You parse its webhook JSON straight into your billing logic. It ships in a week and it works — for market one.

Market two brings a processor with a different capture model, different webhook field names, a different signing scheme, and a refund endpoint that wants a different identifier. Every spot that touched the first processor’s shape now needs a branch. Checkout grows an if. Billing grows an if. Invoice reconciliation grows one too. Market three doubles the branches again. What started as a payment integration has become a lattice of processor-specific special cases woven through your core business logic, and nobody can change one without fearing the others.

The defect underneath all of it is a dependency aimed the wrong way. When checkout depends on a concrete processor’s API, checkout cannot be understood without that processor in the room. That single fact is why the second market costs as much as the first, and the third costs more than both.

Four verbs, and nothing else

The fix is to make checkout depend on a promise instead of a product. In VBWD’s architecture, every payment provider is a plugin that sits behind one common adapter port, and both the checkout flow and the billing engine depend on that port — never on a named processor. The contract every provider plugin must satisfy is deliberately tiny:

  • authorize — reserve funds or open a payment intent
  • capture — settle an authorized payment
  • handle-webhook — receive the provider’s asynchronous callback and translate it
  • refund — reverse a capture, whole or partial

Stripe, PayPal, and YooKassa ship as plugins against that contract today. The number is not the point. The point is that the core genuinely cannot tell them apart. Checkout calls authorize and capture and never learns whether a card network, a redirect wallet, or a regional bank rail answered. When a new processor is needed, it arrives as one more provider plugin implementing the same four verbs — a bounded, self-contained unit of work rather than a change that ripples outward. That is what “provider-agnostic” earns you in practice: a new processor touches exactly one plugin directory, and the core stays ignorant of every processor’s quirks.

The webhook is where trust is won or lost

Of the four verbs, handle-webhook is the one that punishes carelessness. It is also where naive integrations leak processor detail back into the core and, worse, get security wrong.

A processor does not announce success in your vocabulary. It announces it in its own — its event names, its JSON, its signature. The adapter’s job is to translate that into domain-neutral events the platform actually speaks: payment captured, payment failed. Everything downstream — billing, invoice reconciliation, entitlement grants — subscribes to those neutral events and never touches a raw provider payload. That translation boundary is precisely what stops a new processor from becoming a new conditional in your billing code.

Two rules inside that method are not optional. First, verify the signature before you trust a single field. A webhook endpoint is a public URL, and anything on the internet can POST to it; the signature check is the only thing separating a genuine settlement notice from a forgery, and it must run before the payload influences any state. Second, a plugin that writes to the database inside an event callback must commit its own session — the dispatch path will not manage that transaction for you, and a plugin that assumes otherwise will silently drop the write it thought it had saved.

Paying money out deserves the same discipline

Taking money in is only half the flow. Marketplaces and multi-vendor OEM deployments also pay money out — to sellers, to referral partners, to sub-accounts — and payouts vary by region just as intake does. So they get the same shape: a provider-agnostic IConnectProvider port. The core’s payout logic depends on that port, not on any single provider’s marketplace product. One deployment can settle through one connect provider; another can use a local rail implemented against the same interface. The billing engine orchestrates the movement of funds while the plugin knows how a specific network actually moves them. Keeping intake and payout symmetric means an operator reasons about both the same way instead of learning two unrelated models.

Which rails are live is a setting, not a commit

Because providers are plugins and the core depends only on ports, the set of active rails is a per-deployment decision rather than a code decision. VBWD is self-hosted and source-available — Flask and Postgres on the backend, Vue 3 on the frontend, Docker for delivery — so every OEM runs its own instance and enables the plugins that fit its market. The EU deployment enables its card and wallet rails; the Russia deployment enables YooKassa; a partner spanning several regions runs several deployments, each with its own enabled providers, all sharing one core and one checkout. Nobody edits billing to change which processor is live. The deployment docs describe how that enable state is persisted and mounted so every part of a running instance agrees on which rails are on.

The licensing posture suits this cleanly. VBWD ships under BSL 1.1: free for commercial use while annual VBWD-attributable sales stay below the value of 6.7 BTC, with a commercial license required above that. It is source-available — open to read, run, and modify under those terms — which is exactly what an OEM needs when it has to audit and trust the payment stack it is deploying.

What the port will not do for you

An adapter bounds the integration work. It does not erase a processor’s inherent complexity, and pretending it does would be dishonest. Some processors demand multi-step confirmation — 3-D Secure challenges, redirect-and-return dances, off-session retries. Some settle asynchronously, so “captured” lands minutes or hours after the buyer believes they paid, which makes correct webhook handling your only real source of truth. Regional compliance adds weight the payment API never sees: local tax reporting, data-residency rules, know-your-customer obligations.

Two operator duties follow. Test every provider plugin against that provider’s own sandbox before real money flows — the contract guarantees the interface, not that you configured credentials, webhook secrets, and confirmation flow correctly for your account. And PCI scope and broader compliance stay with the operator; self-hosting means you own the deployment and the regulatory posture that comes with it. VBWD hands you a clean integration seam. It does not sign your compliance paperwork.

Which brings the small test at the top full circle. When checkout knows nothing about who took the money, a new market’s processor is one plugin against four known verbs — scoped, sandbox-testable, enabled per deployment. When checkout knows too much, that same market is a rewrite threaded through the code you least want to touch. The gap between those two futures is the whole reason the port exists.

Learn more about VBWD

VBWD is a self-hosted, source-available platform for building subscription products, marketplaces, and AI-powered apps. Explore it further:

VBWD is source-available — get the SDK on GitHub.

Happy
Happy
0%
Sad
Sad
0%
Excited
Excited
0%
Angry
Angry
0%
Surprise
Surprise
0%
Sleepy
Sleepy
0%

Which Way Does the Money Flow? A Hub That Refuses to Choose

The 2am Cancellation Problem: How GHRM Sells and Un-Sells a Private Repo Without You

Leave a Reply

Your email address will not be published. Required fields are marked *

eleven − 8 =