OptionalcompleteRequired when the adapter reports requiresServerCompletion.
Failure paths — each must reject with PayFanoutError, raw PSP error preserved.
OptionalidempotencyIdempotency-replay: same key twice -> same result, exactly one side effect.
OptionalmoneyMoney-path fixtures against the adapter's fake backend. REQUIRED —
refunds, capture, and cancel are where broken adapters cost real money,
so they are proven at the contract level, not left to per-adapter
discipline: completedPayment whenever supportsRefunds,
authorizedPayment whenever supportsManualCapture, cancelablePayment
always (every PSP has a pre-completion state).
Optionalexpectations?: { idRoundTrip?: boolean; metadataEcho?: boolean }Honesty flags for documented PSP limitations (default true): set idRoundTrip false when the PSP has no field to carry the host id, metadataEcho false when metadata cannot be read back on retrieve.
An authorized, NOT yet captured payment of input.amount (manual capture PSPs).
A payment in a cancelable (pre-completion / pre-capture) state.
Creates a COMPLETED payment (money moved) of input.amount, carrying
the host input.id and input.metadata; resolves its pspPaymentId.
OptionalnativeRequired when ANY getCapabilities().nativeSubscriptions flag is true — drives the capability-gated round-trip (create/seed -> retrieve -> paged list -> cancel, cancel repeated to prove verified idempotency).
create-capable adapters: fresh, valid input the fake accepts. Called several times per run — every call must be independently creatable (unique idempotency key, a cadence the PSP supports).
Adapters whose PSP has no server-only create (capability create: false):
plant count live subscriptions in the fake and resolve their keys.
OptionalonboardingThe adapter's exported onboarding descriptor. When provided, the suite asserts it is well-formed and consistent with the adapter (pspName match, credential fields, webhook events, CSP hosts) via validateOnboardingDescriptor.
OptionalvaultRequired when the adapter reports supportsSavedPaymentMethods: drives the vault round-trip (create customer -> save -> list -> charge twice -> delete).
Fresh single-use clientToken for savePaymentMethod (tokenize-first PSPs).
Confirm-on-client PSPs (no savePaymentMethod method): given a customer id, produce a stored token by whatever save-during-checkout simulation the fake supports.
OptionalexpectedAmount?: numberAsserted against the parsed event's normalized amount, when the payload carries one.
OptionaltamperedSignedValueBody?: stringA copy of validRawBody in which one SIGNED value has been altered (an amount moved, say) while the delivered signature is left as sent. REQUIRED when the adapter declares webhookSignatureScope "field-values": such a signature survives re-encoding, so this is the forgery that proves it still covers what it claims. Declared rather than derived — only the adapter knows which values its provider signs.
OptionalunknownEvent?: { headers: Record<string, string>; rawBody: string }A correctly SIGNED delivery of an event type the adapter does not recognize.
Exact raw body bytes as the PSP would send them, signature-matching validHeaders.
Fresh, valid input for a 2-decimal-currency session (e.g. USD/EUR).
OptionalthreeProves three-decimal handling (e.g. BHD). Strongly recommended.
OptionalzeroProves zero-decimal handling (e.g. JPY). Strongly recommended.
The contract every ServerPaymentAdapter — present or future — must pass. This is what makes "extensible" verifiable rather than aspirational: a new PSP ships by writing an adapter package that passes this suite, with zero changes to core or to consuming applications.