Integrating Banks, Merchants and Services into a Single Platform

Most companies do not plan their integration architecture. It grows by accident. The first version of a product needs to accept card payments, so a team wires in one bank's payment gateway. Later a second acquirer is added because it has better rates for a certain card type. Then a fiscalization service, an SMS provider, a credit-scoring API, a government registry. Each connection is built when it is needed, by whoever is available, in whatever style fits that week's deadline.
At a small scale this is fine. With one bank and a couple of services, the cost of inconsistency is invisible. The problem appears later — when a second bank arrives, when several merchants run on the same backend, when reconciliation has to match thousands of transactions a day across providers that each describe the same event differently. At that point the pile of point-to-point connections stops being a convenience and becomes the main source of incidents. This article is about how to design the integration layer so that adding the tenth provider is as routine as adding the second.
Why point-to-point integrations stop scaling
The trouble with separate connections is not any single one of them. It is the combinatorics. When every service talks directly to every other service, the number of links grows roughly as the square of the number of participants. Five systems can be wired together with a few connectors; fifteen systems produce a web that no one person fully understands. Knowledge fragments across teams, and the only complete map of "what calls what" lives in people's heads.
Each ad-hoc integration also tends to leak provider-specific assumptions into the business logic. One bank returns amounts in tiyin, another in soʻm. One uses a numeric status code, another a string. One confirms a payment synchronously in the HTTP response, another only via an asynchronous callback minutes later. When these differences are handled inline, scattered across controllers and background jobs, the business code becomes a museum of special cases. Replacing or adding a provider then means touching dozens of files, and every change risks a regression somewhere unrelated.
Common mistake: treating the first integration as a template. Teams copy the working bank connector for the second bank, then patch the differences in place. Within a year there are five near-identical-but-subtly-different connectors, no shared contract, and no one willing to refactor because every one of them is in production and handling money.
The single-platform approach: an integration layer with adapters
The alternative is to stop thinking about "integrations" and start thinking about a platform: one internal layer that the rest of your system talks to, behind which individual providers are interchangeable. The core idea is an abstraction with adapters. Your business logic speaks one canonical language — "charge this amount to this customer", "register this fiscal receipt", "send this notification" — and a per-provider adapter translates that canonical request into the specific dialect of a bank, merchant, or service, and translates the response back.
This is the well-known ports-and-adapters (hexagonal) pattern applied to external partners. The benefits are concrete. Adding a new bank means writing one adapter against a known interface, not editing the order service. Routing logic — "send corporate cards to bank A, consumer cards to bank B, fall back to C if A is down" — lives in one place and can be changed without redeploying every consumer. And testing becomes possible, because you can run the entire business flow against a mock adapter without touching a real bank's sandbox.
A practical integration layer usually has a few distinct responsibilities, and it helps to keep them separated:
- Canonical model: internal representations of payment, refund, receipt, customer, account, that do not mention any specific provider.
- Adapters: one per external system, responsible only for translation and transport. No business decisions here.
- Routing and orchestration: which provider handles a given request, in what order, with what fallback, and how multi-step flows (authorize then capture, pay then fiscalize) are sequenced.
- State and ledger: the authoritative record of every transaction's lifecycle, independent of any provider's own view.
- Observability: structured logs, correlation IDs, and metrics that let you answer "what happened to this payment" across all providers in one query.
Designing for the realities of money and integrations
An integration platform that moves money has to be built around failure, not around the happy path. The single most important design decision is idempotency. Networks time out, callbacks arrive twice, users double-click. Every operation that changes state must carry a unique key so that retrying it produces the same result instead of a second charge. This belongs in the integration layer, not in each adapter, so that the guarantee is uniform across every provider.
Asynchrony is the second reality. Many bank and merchant operations complete out-of-band: you initiate a payment, the user is redirected, and the final status arrives later via a webhook — or never arrives, and you must poll. A robust platform treats the callback and the poll as two paths to the same truth, reconciling both against its own ledger. The ledger, not the provider's last message, is the source of truth.
Key choice — synchronous facade vs. event-driven core. Expose a simple synchronous API to your product teams ("create payment, get a status") for developer ergonomics, but run the internals as an event-driven state machine. This gives callers a clean contract while letting the platform handle retries, delayed callbacks, and partial failures internally. Forcing the whole system to be synchronous end-to-end is the most common cause of stuck transactions.
Reconciliation deserves to be a first-class feature, designed in from the start rather than bolted on when finance complains. Every provider eventually disagrees with your records — a payment they consider settled that you marked failed, or vice versa. A daily automated reconciliation that pulls each provider's report, matches it against your ledger by stable identifiers, and flags discrepancies is what keeps a multi-bank platform trustworthy. Without it, errors accumulate silently until an audit forces a painful manual investigation.
Security, compliance and the Uzbekistan context
Consolidating integrations also consolidates risk, which is mostly a good thing: secrets, certificates, and credentials live in one managed place instead of being copied into every service. Use a secrets manager, rotate keys, and never embed credentials in code or configuration committed to a repository. For card data, minimize what you store — ideally let the bank or a PCI-DSS-compliant gateway hold the sensitive data and keep only tokens on your side.
For businesses operating in Uzbekistan there are local realities that shape the platform. Integration with national systems — fiscalization through the tax authority, instant-payment rails, and identity or registry services — often involves IP whitelisting, mutual TLS, and providers that are sensitive to where requests originate. Local acquirers such as the major card systems each have their own protocol quirks. An adapter-based design absorbs these differences cleanly: the whitelisting, certificate handling, and protocol specifics stay inside one adapter, and the rest of the platform never has to know.
Point-to-point vs. unified platform. With point-to-point, onboarding a new bank is a multi-week project that touches business logic, and routing changes require coordinated redeploys. With a unified platform, a new bank is a self-contained adapter delivered against a stable contract, routing is configuration, and reconciliation and monitoring come for free because they were built once at the layer, not per provider.
How to migrate without a big-bang rewrite
Few organizations can stop everything and rebuild their integrations at once, nor should they. The realistic path is incremental. Start by defining the canonical model and the adapter interface for one capability — usually payments, since it hurts the most. Wrap your existing, working bank connection in an adapter that conforms to the new interface, changing nothing about its behavior. Route new traffic through the platform while the old code stays as a safety net. Once one provider runs cleanly behind the abstraction, the second adapter is cheap, and the value of the design becomes obvious to everyone involved.
Resist two temptations during migration. Do not try to make the canonical model perfect before shipping anything — it will evolve as the second and third providers reveal what you missed. And do not let provider-specific concepts leak back into the core "just this once"; every exception you allow erodes the abstraction that justified the whole effort.
Conclusion
A collection of separate integrations is a perfectly reasonable way to start and a dangerous way to scale. The moment a second bank, multiple merchants, or non-trivial reconciliation enters the picture, the cost of inconsistency, duplicated logic, and invisible failures grows faster than the business. A unified integration platform — canonical model, interchangeable adapters, centralized routing, an authoritative ledger, and built-in reconciliation and observability — turns each new provider from a project into a routine task, and turns money-handling from a source of incidents into something you can trust and audit. If your team is feeling the pain of the second or third integration, that is exactly the right time to design the layer properly rather than after the tenth. The OneDev team has built and operated this kind of platform against local banks, merchants, and government services in Uzbekistan, and we are happy to review your current architecture and map a low-risk path forward — reach out to discuss your project with us.
When is it too early to build a unified integration platform?
How long does it take to add a new bank to an adapter-based platform?
What is the single most important technical detail to get right?
Do we have to migrate all integrations at once?
How does this approach handle local Uzbekistan requirements like fiscalization and IP whitelisting?
Where should reconciliation and monitoring live?
Need a similar system or want to discuss your project?
Describe the task — we will propose architecture, technical approach and a work plan. A short call is usually enough to get started.
Discuss project