Files
2026-05-27 23:29:53 +01:00

5.6 KiB

OpenSpec Change: enterprise-payment-providers

  • Change ID: enterprise-payment-providers
  • Package: @suaveplan/payment-providers
  • Category: universal
  • Target path: universal/commerce/payment-providers
  • Status: IN PROGRESS
  • Date: 2026-04-24
  • Reference spec: /mnt/s/web/suaveplan/enterprise/payment-providers.md

Summary

Deliver @suaveplan/payment-providers on the genesis branch from scratch at enterprise quality. The package provides concrete PaymentAdapter implementations for Stripe, PayPal, Square, Mollie, and Adyen. Each adapter wraps the provider's REST API using injectable fetch (no provider SDK dependency), implements the full PaymentAdapter interface from @suaveplan/payment, handles provider-specific webhook signature verification, and normalises provider error codes to the canonical PAYMENT.* code registry. The main-branch version sat at 100% coverage. Genesis adds structured errors, Zod schemas, OTel instrumentation, retry with circuit breaker, and integration-test harnesses.


Current-state audit (genesis)

The package does not exist on genesis yet — this is a fresh build.


Available workspace deps on genesis

Package Role
@suaveplan/error (workspace:^) PaymentProviderError; extends PAYMENT.* code set
@suaveplan/types (workspace:^) LoggerLike, Clock
@suaveplan/payment (workspace:^) PaymentAdapter interface; PaymentIntent, PaymentWebhookEvent types
@suaveplan/retry (workspace:^) Retry + circuit breaker for provider API calls
@suaveplan/crypto (workspace:^) HMAC webhook signature verification
zod (catalog:forms) Provider response schema validation
@opentelemetry/api (catalog:observability) Spans + counters

Dev deps: vitest, @vitest/coverage-istanbul (all catalog:testing).


Public API surface

Provider factories

function createStripeAdapter(options: StripeAdapterOptions): PaymentAdapter
function createPayPalAdapter(options: PayPalAdapterOptions): PaymentAdapter
function createSquareAdapter(options: SquareAdapterOptions): PaymentAdapter
function createMollieAdapter(options: MollieAdapterOptions): PaymentAdapter
function createAdyenAdapter(options: AdyenAdapterOptions): PaymentAdapter

All option types share a common base:

interface BaseAdapterOptions {
  apiKey: string
  webhookSecret?: string
  environment?: 'sandbox' | 'production'    // default 'production'
  retryOptions?: RetryOptions
  fetch?: typeof globalThis.fetch
  clock?: Clock
  logger?: LoggerLike
}

interface StripeAdapterOptions extends BaseAdapterOptions {
  apiVersion?: string   // default 'latest'
}

interface PayPalAdapterOptions extends BaseAdapterOptions {
  clientId: string
  clientSecret: string
}

interface AdyenAdapterOptions extends BaseAdapterOptions {
  merchantAccount: string
  liveUrlPrefix?: string
}

Provider-normalised types

Each provider's raw response is normalised to PaymentIntent via a per-provider mapper; these mappers are exported for testing:

function normalizeStripePaymentIntent(raw: unknown): PaymentIntent
function normalizePayPalOrder(raw: unknown): PaymentIntent
function normalizeSquarePayment(raw: unknown): PaymentIntent
function normalizeMolliePayment(raw: unknown): PaymentIntent
function normalizeAdyenPayment(raw: unknown): PaymentIntent

Error codes

Provider errors are wrapped in PaymentError with existing PAYMENT_PROVIDER_ERROR code plus an added detail field:

interface PaymentProviderErrorDetail {
  provider: string
  providerCode?: string
  providerMessage?: string
}

Genesis additions

  1. Zod schemas for all provider-specific option types and raw response shapes.
  2. Sandbox/production switching — environment: 'sandbox' routes to provider test endpoints automatically.
  3. Idempotency key passthrough — all create/capture/refund calls forward the caller-supplied idempotency key as the provider-specific header (Idempotency-Key for Stripe, etc.).
  4. Circuit breaker — wraps all provider API calls via @suaveplan/retry; opens after 5 consecutive provider errors.
  5. OTel instrumentation — span payment_provider.api_call with attributes payment_provider.name, payment_provider.method; counter payment_provider.api_total; histogram payment_provider.api_duration_ms.
  6. Provider error normalisation — 4xx/5xx provider responses are mapped to the closest PAYMENT.* error code with provider details preserved in the error context.

File layout

universal/commerce/payment-providers/
  package.json
  tsconfig.json
  vitest.config.ts
  src/
    index.ts
    error-codes.ts
    constants/
      index.ts
    types/
      common.ts
      common.md
    providers/
      stripe/
        stripe.ts
        stripe.md
        stripe.types.ts
        stripe.test.ts
        index.ts
      paypal/
        paypal.ts
        paypal.md
        paypal.types.ts
        paypal.test.ts
        index.ts
      square/
        square.ts
        square.md
        square.types.ts
        square.test.ts
        index.ts
      mollie/
        mollie.ts
        mollie.md
        mollie.types.ts
        mollie.test.ts
        index.ts
      adyen/
        adyen.ts
        adyen.md
        adyen.types.ts
        adyen.test.ts
        index.ts
    __benchmarks__/
      payment-providers.bench.ts
  tests/
    integration.test.ts

Impact

Downstream consumers: @suaveplan/booking, any server-side checkout flow.

Workspace dep prerequisites: @suaveplan/error, @suaveplan/types, @suaveplan/payment, @suaveplan/retry, @suaveplan/crypto.