Abstract
Point-of-Sale (POS) Software-as-a-Service (SaaS) platforms increasingly integrate with multiple payment processors to meet regional coverage, redundancy, cost optimization, and merchant-specific routing requirements. In practice, such integrations often evolve into fragmented, processor-coupled code paths that duplicate logic, diverge in semantics, and leak processor-specific idiosyncrasies into application code. Existing commercial orchestration products address a subset of this problem but either operate as external black-box services or restrict architectural control in ways that limit deep integration with POS-specific concerns such as offline capability, per-merchant configurability, and tenant-scoped reconciliation.
This paper presents a unified payment orchestration architecture designed for POS SaaS vendors that wish to retain architectural ownership over processor fragmentation, routing, offline semantics, and reconciliation. This work contributes a practical, implementation-oriented architecture that bridges the gap between theoretical payment abstraction models and production-grade POS system requirements. The architecture consists of a layered design separating (i) a stable adapter interface over processor-specific protocols, (ii) a policy-driven routing and failover engine, (iii) an explicit transaction lifecycle state machine, and (iv) a normalized reconciliation pipeline. We articulate the design decisions that determine correctness under failure — idempotency modeling, state persistence locality, failure semantics, and adapter contract strictness — and we compare the architecture with commercial orchestration offerings. We conclude with a discussion of limitations, including adapter-construction cost, tenant-scale reconciliation complexity, and open problems in cross-processor identity. The proposed architecture improves system consistency, reduces processor-specific coupling, and enables scalable multi-processor integration in production POS environments.
1. Introduction
Payment processing in modern POS platforms is rarely serviced by a single processor. Merchant portfolios span regions, card brands, and risk profiles that individual processors cannot cover uniformly; contractual obligations to existing banking relationships force multi-processor integrations; and the operational reality of processor outages makes redundancy a correctness requirement rather than a nice-to-have.
The default engineering response to this situation is an incremental one. A POS platform integrates with one processor, then a second, then a third — accumulating per-processor code paths at each step. Over time, this yields a system whose processor-specific complexity is diffused throughout the application layer, where it becomes impossible to reason about routing, retry, failover, or reconciliation as coherent architectural concerns.
The canonical remediation is a payment orchestration layer: an architectural abstraction that mediates between application-layer intent and processor-layer protocol. Orchestration as a commercial product category exists (see Section 3), but off-the-shelf orchestration services impose constraints that POS SaaS vendors frequently cannot accept: opacity over failure semantics, insufficient offline support, coarse per-merchant policy expression, and data-residency limitations.
This paper describes an in-house orchestration architecture intended for POS SaaS vendors, with particular attention to the design decisions that govern correctness when the happy path breaks down. Our contribution is not the identification of orchestration as a useful pattern — that is well-established — but a structured exposition of the architectural contracts, state semantics, and design trade-offs required to build one that is safe under realistic failure conditions. Rather, we formalize a production-oriented architecture that captures the constraints, failure semantics, and operational requirements unique to POS payment systems.
2. Contributions
The contributions of this paper are as follows:
-
A layered decomposition of orchestration responsibilities into four components with explicit boundaries: adapters, routing policy, transaction state machine, and reconciliation pipeline — along with the rationale for what each component must and must not own.
-
A processor adapter contract that captures the minimum expressive surface required to mediate between heterogeneous processors without loss of diagnostically relevant information, including a two-level decline-reason taxonomy that preserves processor-specific codes while exposing a normalized category for business logic.
-
An explicit transaction lifecycle state machine modeling the full payment lifecycle including offline-queued states and error-ambiguity states, with transition persistence semantics that remain correct under network partitioning and processor-side state uncertainty.
-
A reconciliation architecture that normalizes heterogeneous processor settlement formats, matches against the orchestration layer's authoritative transaction records, and classifies discrepancies into categories with distinct resolution paths.
-
A comparison with existing commercial orchestration offerings (Stripe Terminal, Adyen, Spreedly, Primer, Gr4vy, Basis Theory) along the dimensions relevant to POS SaaS vendors, identifying where in-house orchestration is justified.
-
A taxonomy of the consequential design decisions — idempotency model, state persistence locality, failure semantics, adapter contract strictness — that determine system correctness under adverse conditions.
-
A discussion of limitations and open problems, including the cost curve of adapter construction, the complexity of cross-processor identity, and the unresolved tension between routing policy expressiveness and operational auditability.
-
A characterization of the practical impact of the architecture in production POS environments: improved system consistency through authoritative local state, reduced processor-specific coupling through a strict adapter contract, lower operational cost of adding new processors, and scalable multi-processor integration that preserves per-merchant policy expressiveness and tenant-scoped reconciliation semantics.
3. Background and Related Work
3.1 The Processor Fragmentation Problem
Payment processor APIs diverge in semantics, not merely in protocol. Operations that appear superficially equivalent — void, capture, refund — exhibit different preconditions, timing constraints, failure modes, and side effects across processors. A void operation against Processor A may succeed prior to batch close, while the same operation against Processor B is subject to a fixed two-hour window, and against Processor C may silently convert to a refund based on settlement-preview state that has no analog elsewhere. This is not an API compatibility problem — APIs can be adapted through conventional adapter patterns — but a semantic compatibility problem that naive abstractions fail to resolve.
3.2 Commercial Orchestration Offerings
Several commercial payment orchestration products exist:
| Product | Primary Mode | POS Focus | Offline Capability | Open Architectural Control |
|---|---|---|---|---|
| Stripe Terminal | Processor-native | Strong | Limited | Low |
| Adyen | Processor-native | Moderate | Via SDK | Low |
| Spreedly | Independent orchestration | Low | None | Moderate |
| Primer | Independent orchestration | Low | None | Moderate |
| Gr4vy | Independent orchestration | Low | Limited | Moderate |
| Basis Theory | Tokenization / vault-centric | Low | None | High (vault layer) |
These products collectively address portions of the orchestration problem but exhibit one or more of the following limitations from a POS SaaS perspective:
- Black-box failure semantics. The precise retry, failover, and idempotency behavior is not fully specified or auditable, which is problematic when the POS vendor is legally the merchant-of-record or otherwise liable for transaction outcomes.
- Limited offline support. Offline-first POS requirements — deferred authorization, optimistic issuance of local receipts, resynchronization under adversarial ordering — are poorly supported by orchestration layers designed around always-online e-commerce.
- Coarse per-merchant policy. Merchant-specific routing, fee structures, and compliance postures are often constrained to predefined configuration slots rather than arbitrary policy expressions.
- Data-residency and scope externalization. Using an external orchestrator can transfer or complicate PCI scope and data-residency obligations in ways that are unacceptable for certain merchant segments.
3.3 Architectural Antecedents
The orchestration architecture presented here draws on several well-established distributed-systems patterns: the adapter pattern for protocol mediation; the saga pattern for multi-step transaction coordination; event sourcing for auditable state transitions; and the transactional outbox pattern for reliable event publication across heterogeneous systems. Our contribution is the composition of these patterns in the specific service of payment orchestration, with attention to the failure semantics that distinguish financial systems from typical distributed applications.
4. System Design
4.1 Architectural Overview
The orchestration layer sits between the application layer (which owns business logic and transaction intent) and the processor adapters (which own protocol-specific integration). It is responsible for routing decisions, retry and failover, offline queuing, response normalization, and the state management required for reconciliation. It is explicitly not responsible for processor-specific protocol implementation, validation of business-level transaction semantics, or merchant configuration — these responsibilities reside elsewhere in the system.
Boundary integrity is the single most important architectural property. If application code obtains processor-specific data from the adapter layer, the abstraction erodes and the orchestration layer becomes a thin pass-through. If the orchestration layer embeds business-level validation logic, it becomes coupled to the domain and cannot be independently evolved.
4.2 The Adapter Contract
Each processor integration is realized as an adapter conforming to a common interface. The interface must be expressive enough to preserve information of diagnostic value while abstract enough to prevent processor-specific leakage.
interface AuthorizeRequest {
amount: Money;
paymentMethod: PaymentMethodRef;
merchantId: string;
idempotencyKey: string;
metadata?: Record<string, string>;
}
interface AuthorizeResult {
status: 'approved' | 'declined' | 'error';
authorizationCode?: string;
declineReason?: DeclineReason;
processorTransactionId: string;
processorResponseCode: string;
riskScore?: number;
}
interface ProcessorAdapter {
authorize(request: AuthorizeRequest): Promise<AuthorizeResult>;
capture(authorizationId: string, amount: Money): Promise<CaptureResult>;
void(authorizationId: string): Promise<VoidResult>;
refund(captureId: string, amount: Money): Promise<RefundResult>;
status(transactionId: string): Promise<TransactionStatus>;
}
The DeclineReason type is the locus of the most consequential abstraction decision. We adopt a two-level taxonomy: a coarse normalized category consumed by business logic (issuer_declined, insufficient_funds, suspected_fraud, card_problem, network_error) and the raw processor response code retained for logging and debugging. This preserves fidelity without forcing application code to reason over per-processor codes.
4.3 Routing Policy
Routing decisions — selecting the processor to handle a given request — must be externalized behind a policy interface even when the initial implementation is trivial. Routing requirements reliably grow in expressiveness over time (amount-based routing, card-brand routing, merchant-category routing, real-time cost optimization), and a policy abstraction permits evolution without orchestration-layer changes.
interface RoutingPolicy {
selectProcessor(
request: AuthorizeRequest,
availableProcessors: ProcessorAdapter[],
processorHealth: Map<string, ProcessorHealth>
): ProcessorAdapter;
}
Processor health is a first-class input to the routing decision. Real-time metrics — authorization success rate, latency percentiles, recent error events — are consumed by the policy to avoid routing traffic to degraded processors.
4.4 Transaction Lifecycle State Machine
Every transaction traverses a sequence of states. Explicit modeling of these states — and of the ambiguous intermediate states produced by network or processor-side uncertainty — is essential for correctness. Each transition must be persisted atomically, and the persistence record must exist before the processor call is attempted, enabling recovery after crashes or network failures.
The ERROR state is distinguished from DECLINED specifically to represent the processor-side state uncertainty condition: a condition in which the orchestration layer does not know whether the processor received and acted upon the request. Resolution requires status-check operations and, for operations where silent retry is unsafe, human or policy-driven adjudication.
4.5 Reconciliation Architecture
Reconciliation verifies that the orchestration layer's transaction records match the processor's settlement records. It consists of four sub-components:
- Settlement ingestion — heterogeneous processor formats (CSV via SFTP, JSON webhooks, REST endpoints) are parsed into a normalized internal schema.
- Matching — settlement records are matched against internal transaction records, with the processor transaction ID as the primary key and heuristic matching for post-authorization adjustments that lack direct correspondence.
- Discrepancy detection — matched records are checked for amount equality; unmatched records are classified as missing settlements, unexpected settlements, or amount mismatches.
- Reporting — matched and unmatched records are presented to merchants in a form that permits corrective action.
Reconciliation complexity scales with the number of processors and the diversity of transaction types. We recommend beginning with simple matching and robust discrepancy logging, deferring automated resolution until each discrepancy class is individually understood and characterized.
5. Operational Considerations
Payment orchestration systems handle money, and consequently the cost of opacity is high. The minimum observability surface includes:
- Transaction-level transition logging. Every state transition is recorded with timestamp, prior state, new state, and causal context.
- Processor-level health metrics. Authorization success rate, latency percentiles, and error rates per processor, with alerts on statistically significant deviations.
- Offline-queue depth monitoring. Unexpected growth indicates either prolonged connectivity loss or a sync pipeline failure.
- Reconciliation drift metrics. Discrepancy rates, unmatched settlement counts, and time-to-reconciliation tracked over time.
These are not dashboard ornaments. They are the primary signal channel for a class of silent failures — particularly reconciliation drift and processor-behavior change — that produce no conventional error signal.
6. Design Decisions and Trade-offs
We identify four design decisions whose resolution determines the correctness of the system under adverse conditions:
Idempotency model. The choice of idempotency key scope, lifetime, and persistence locality determines whether retry logic is safe. Orchestration-layer-generated keys scoped to (merchant, operation type, client-supplied key) with request-fingerprint validation provide the strongest safety, at the cost of additional storage and a non-trivial expiration policy.
State persistence locality. Whether authoritative state is stored locally in the orchestration layer or derived from processor APIs determines resilience to processor unavailability. Local persistence is more complex (requiring reconciliation against processor state) but substantially more resilient.
Failure semantics. Ambiguous failures (timeouts, unexpected responses) require per-operation policy. Authorization timeouts are generally safe to retry against an idempotent endpoint; capture timeouts without idempotency guarantees require status-check adjudication. Encoding these policies explicitly — rather than defaulting uniformly to retry or to failure — is essential.
Adapter contract strictness. Strict enforcement of the adapter interface prevents processor-specific data leakage into application code but requires investment in richer normalized types. Lax enforcement is cheaper initially but erodes the abstraction over time; the failure is not visible until application code becomes coupled to processor-specific data and the orchestration layer can no longer be independently evolved.
7. Limitations
The architecture presented here has several limitations.
Adapter construction is expensive. Each processor integration requires substantial engineering effort — not only to implement the adapter interface, but to characterize the processor's undocumented behaviors, certification process, and settlement format. The marginal cost of adding a processor decreases with investment in tooling but does not asymptote to zero.
Reconciliation at tenant scale is unresolved. For multi-tenant platforms with heterogeneous merchant segments, reconciliation complexity compounds: per-processor × per-merchant × per-currency × per-settlement-schedule. We describe the architecture, but the scale-specific operational patterns (partitioning, parallelism, fairness under noisy tenants) remain implementation-specific.
Cross-processor identity is an open problem. When a payment method is tokenized differently by each processor, the orchestration layer has limited ability to preserve a customer's payment-method identity across processor migrations. Network tokenization (Visa, Mastercard) partially addresses this but is not yet universally supported.
Routing policy expressiveness versus auditability. More expressive routing policies (arbitrary code, ML models, cost-optimization engines) are harder to audit and harder to reason about under incident response. Declarative rule-based policies are more auditable but less expressive. The tension is unresolved.
Offline semantics are not fully specified. The OFFLINE_QUEUED state conceals significant complexity around payment-method data caching, acceptable risk thresholds, and resynchronization ordering. A full treatment is beyond the scope of this paper and is the subject of companion work.
Empirical evaluation is outside this paper's scope. We present the architecture as a design artifact informed by industry practice. Rigorous empirical evaluation — authorization success rate improvements under failover, reconciliation drift reduction, incident-to-resolution time — requires longitudinal production data that we do not reproduce here.
8. Future Work
Several directions merit further investigation.
Formal verification of state-machine invariants. The transaction lifecycle state machine can be specified formally and model-checked against invariants such as "no transaction reaches a terminal state without a corresponding settlement or explicit non-settlement classification." Integration of formal methods into the development workflow remains an open engineering problem.
Adaptive routing under cost and risk optimization. Current routing policies typically optimize along a single dimension (availability, cost, or risk). A generalized policy framework that accepts multi-objective optimization — cost subject to availability bounds, risk subject to authorization-rate bounds — would be operationally valuable.
Cross-processor tokenization and identity. A unified tokenization layer that maintains a merchant-portable identity across processor boundaries, while preserving processor-specific token semantics where required, is an unsolved design problem with substantial practical value.
Reconciliation at interactive latency. Current reconciliation is typically batch-oriented (daily settlement cadence). Moving reconciliation closer to real-time — enabling merchants to see authoritative settlement state within minutes rather than hours — requires rethinking both the pipeline architecture and the settlement data contracts with processors.
Offline capability as a first-class concern. Formal treatment of offline semantics, including the safety conditions under which an offline-queued transaction can be optimistically acknowledged to the merchant, and the adversarial ordering problems introduced by bulk resynchronization, warrants its own architectural study.
Empirical studies. Production deployments of orchestration architectures produce measurable outcomes (authorization success rate improvements, mean time to recovery, reconciliation accuracy) that are rarely published. A systematic body of empirical evidence would inform architectural choices that are currently made on the basis of practitioner intuition.
9. Conclusion
Payment orchestration for POS SaaS platforms is a pragmatic architectural necessity that reduces to a small number of consequential design decisions: the adapter contract, the routing policy interface, the transaction lifecycle state machine, and the reconciliation pipeline. The decisions are not independent — each interacts with the others through idempotency, state locality, and failure semantics — and a coherent architecture must resolve them jointly.
We have presented a layered architecture for such a system, compared it with existing commercial offerings, and articulated the design decisions and limitations that govern its correctness. The architecture is not a finished product; it is a scaffolding for systems that must evolve as processors change, as merchants scale, and as the operational environment produces failure modes that no upfront design fully anticipates. The value of the scaffolding is that it localizes change — a new processor is an adapter, a new routing consideration is a policy update, a new settlement format is an ingestion parser — rather than diffusing complexity through the system.
The remaining open problems — cross-processor identity, reconciliation at scale, formal verification of lifecycle invariants, and rigorous empirical evaluation — are, in our view, the most productive directions for future work in this area.
References
- Gamma, E., Helm, R., Johnson, R., Vlissides, J. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley, 1994. (Adapter pattern.)
- Garcia-Molina, H., Salem, K. "Sagas." Proceedings of the ACM SIGMOD International Conference on Management of Data, 1987.
- Fowler, M. "Event Sourcing." martinfowler.com, 2005.
- Richardson, C. "Pattern: Transactional Outbox." microservices.io, 2018.
- Payment Card Industry Data Security Standard (PCI DSS), v4.0. PCI Security Standards Council, 2022.
- ISO 8583: Financial transaction card originated messages — Interchange message specifications, 2003.
- EMV Integrated Circuit Card Specifications for Payment Systems. EMVCo, 2022.
- Lamport, L. "Time, Clocks, and the Ordering of Events in a Distributed System." Communications of the ACM, 21(7), 1978.
- Helland, P. "Life Beyond Distributed Transactions: An Apostate's Opinion." CIDR, 2007.
- Visa Token Service technical documentation; Mastercard Digital Enablement Service technical documentation. (Network tokenization.)
See also the companion essay Designing a Unified Payment Orchestration Architecture for POS SaaS for a more discursive treatment of the same material.