Inkress ADRsarchitecture decisions
Overview / Payments
ADR 0009

commerce-payments supersedes commerce-adapters via a PanToken FAC compat shim

AcceptedPayments

Context

commerce-adapters was the original payment-integration service (FAC hosted page, Lynk, PayPal). It predates the edge-CDE design (ADR 0006): its FAC integration is built around a hosted payment page, its interface grew ad hoc, and it is not structured for the PanToken control-plane model or the security spine (HMAC callers, idempotency, append-only audit) we now want.

Rather than keep hardening the old service, we chose to build its successor, commerce-payments, with the new abstraction (ADR 0008) and PCI posture (ADR 0006/0007). The problem was cutting over without a flag day: commerce-api and commerce-worker already speak the legacy /inkress/adapters/fac* contract in production, and rewriting all callers at once is exactly the risky big-bang change we wanted to avoid.

Decision

Treat commerce-payments as the successor to commerce-adapters, and cut over incrementally behind a wire-compatible shim rather than in one move.

  • New service, clean interface. commerce-payments implements the normalized PaymentAdapter interface (ADR 0008) and a clean /v1 API (authorize, sale, capture, void, refund, tokenize, sessions, risk, webhooks). Its first and only adapter today is PowerTranz (= FAC).
  • A PanToken-based FAC compat shim. commerce-payments also exposes the legacy /inkress/adapters/fac* routes (marked deprecated, removable post-cutover) that return the old StandardizedResponse, so an existing caller can be pointed at the new service with no code change. The legacy contract is itself PanToken-based, so nothing about the shim reintroduces a raw PAN — the control plane stays PAN-free (ADR 0006).
  • Migrate money paths one at a time. commerce-api reaches the new service through a Service.Payment.Provider.CommercePayments adapter. The newer FAC card-on-file / 3-D Secure paths already call commerce-payments /v1, while FAC hosted-page, refunds, Lynk and PayPal still run on commerce-adapters (the CommercePayments adapter has no refund yet). The migration is deliberately partial: each path moves when it is ready, not on a single date.

Consequences

  • Positive: the successor ships with the right abstraction and security spine without a flag day; a path is cut over by changing where it points, and rolled back the same way.
  • Positive: the compat shim means the majority of callers need no change during the transition.
  • Neutral / to revisit: two payment services run in parallel during the migration — a path may be on either service, so "which service handles this?" is answered per path, not globally. This is intended but is operational surface to track.
  • Follow-ups: move the remaining commerce-adapters paths (FAC hosted page, Lynk, PayPal) onto commerce-payments; once no caller uses it, retire the compat shim and decommission commerce-adapters.

Alternatives considered

  • Big-bang rewrite and cutover: rejected — swapping every production money path to a new service on one date is the highest-risk option for the most sensitive subsystem.
  • Keep extending commerce-adapters in place: rejected — it would have to be retrofitted with the PanToken model, the security spine and the clean adapter interface; a purpose-built successor with a compat shim is less risky than surgery on the live service.
  • A translation gateway in front of the old service: rejected — it adds a hop and a second place to maintain the legacy contract; the shim lives inside the successor, so there is one service to cut over to and one to retire.
← 0008 Payments run through a provider-agnostic adapter, chosen per merchant 0010 Card charges use PowerTranz SPI with server-finalized 3-D Secure (strict Y+CAVV) →