|

Implement a payment adapter

Implement the current payment contract in a local module or external route app.

Use features/keystone/utils/paymentProviderAdapter.ts as the dispatch contract and the built-in manual, paypal, and stripe modules as local examples. A payment app can live outside Openfront: store its HTTPS operation routes on the PaymentProvider record instead of importing its code into the Openfront repository.

Operations

Current dispatch covers:

createPaymentFunction({ provider, cart, amount, currency })
capturePaymentFunction({ provider, paymentId, amount })
refundPaymentFunction({ provider, paymentId, amount })
getPaymentStatusFunction({ provider, paymentId })
generatePaymentLinkFunction({ provider, paymentId })
handleWebhookFunction({ provider, event, headers })

A local module exports these functions. An HTTP adapter route receives POST JSON containing provider plus the listed operation arguments and returns the corresponding result as JSON.

An adapter may omit an operation it cannot support, but every caller and UI must fail explicitly rather than fabricate success.

Implementation rules

  • derive amount, currency, cart/order identity, and allowed transition from persisted Openfront state;
  • use integer minor-unit amounts while honoring currencies without fractional units;
  • give every create, capture, and refund intent an idempotency key and reconciliation path;
  • return provider-neutral IDs, status, amount, and only the browser handoff fields required by the caller;
  • never return raw credentials or unrestricted provider payloads to the browser;
  • authenticate Openfront-to-adapter HTTP requests and protect against replay;
  • verify webhook authenticity using the exact raw-body protocol required by the provider;
  • validate the adapter's runtime JSON before changing Openfront state;
  • separate authorization, capture, refund, cancellation, and unknown outcomes.

End-to-end boundary

Generic route dispatch does not by itself make checkout provider-neutral. In the current source, completeActiveCart.ts and invoice completion contain hard-coded provider-code switches. Before calling a custom adapter complete, replace those switches with a bounded completion contract that invokes the configured adapter operation, verifies the current amount/currency and selected session, handles idempotency, and reconciles uncertain provider outcomes.

Verification

  • unit-test every request/response mapping;
  • contract-test each HTTP operation route with malformed and delayed responses;
  • run provider sandbox initiation, capture, refund, status, link, and webhook scenarios;
  • prove duplicate calls have one provider effect;
  • prove wrong-cart, wrong-user, stale-session, and altered-amount calls fail;
  • verify endpoint and credential changes require privileged operator authority;
  • run complete checkout and invoice workflows against isolated PostgreSQL.

See Add a payment adapter for provider configuration and current limitations.

On this page